xref: /linux/tools/tracing/rtla/src/timerlat.bpf.c (revision 4fa118e5b79fcc537dcb1a860ed319a6106935eb)
1*e34293ddSTomas Glozar // SPDX-License-Identifier: GPL-2.0
2*e34293ddSTomas Glozar #include <linux/bpf.h>
3*e34293ddSTomas Glozar #include <bpf/bpf_tracing.h>
4*e34293ddSTomas Glozar #include <stdbool.h>
5*e34293ddSTomas Glozar #include "timerlat_bpf.h"
6*e34293ddSTomas Glozar 
7*e34293ddSTomas Glozar #define nosubprog __always_inline
8*e34293ddSTomas Glozar #define MAX_ENTRIES_DEFAULT 4096
9*e34293ddSTomas Glozar 
10*e34293ddSTomas Glozar char LICENSE[] SEC("license") = "GPL";
11*e34293ddSTomas Glozar 
12*e34293ddSTomas Glozar struct trace_event_raw_timerlat_sample {
13*e34293ddSTomas Glozar 	unsigned long long timer_latency;
14*e34293ddSTomas Glozar 	int context;
15*e34293ddSTomas Glozar } __attribute__((preserve_access_index));
16*e34293ddSTomas Glozar 
17*e34293ddSTomas Glozar struct {
18*e34293ddSTomas Glozar 	__uint(type, BPF_MAP_TYPE_PERCPU_ARRAY);
19*e34293ddSTomas Glozar 	__uint(max_entries, MAX_ENTRIES_DEFAULT);
20*e34293ddSTomas Glozar 	__type(key, unsigned int);
21*e34293ddSTomas Glozar 	__type(value, unsigned long long);
22*e34293ddSTomas Glozar } hist_irq SEC(".maps"), hist_thread SEC(".maps"), hist_user SEC(".maps");
23*e34293ddSTomas Glozar 
24*e34293ddSTomas Glozar struct {
25*e34293ddSTomas Glozar 	__uint(type, BPF_MAP_TYPE_PERCPU_ARRAY);
26*e34293ddSTomas Glozar 	__uint(max_entries, SUMMARY_FIELD_N);
27*e34293ddSTomas Glozar 	__type(key, unsigned int);
28*e34293ddSTomas Glozar 	__type(value, unsigned long long);
29*e34293ddSTomas Glozar } summary_irq SEC(".maps"), summary_thread SEC(".maps"), summary_user SEC(".maps");
30*e34293ddSTomas Glozar 
31*e34293ddSTomas Glozar struct {
32*e34293ddSTomas Glozar 	__uint(type, BPF_MAP_TYPE_RINGBUF);
33*e34293ddSTomas Glozar 	__uint(max_entries, 1);
34*e34293ddSTomas Glozar } signal_stop_tracing SEC(".maps");
35*e34293ddSTomas Glozar 
36*e34293ddSTomas Glozar /* Params to be set by rtla */
37*e34293ddSTomas Glozar const volatile int bucket_size = 1;
38*e34293ddSTomas Glozar const volatile int output_divisor = 1000;
39*e34293ddSTomas Glozar const volatile int entries = 256;
40*e34293ddSTomas Glozar const volatile int irq_threshold;
41*e34293ddSTomas Glozar const volatile int thread_threshold;
42*e34293ddSTomas Glozar const volatile bool aa_only;
43*e34293ddSTomas Glozar 
44*e34293ddSTomas Glozar int stop_tracing;
45*e34293ddSTomas Glozar 
46*e34293ddSTomas Glozar nosubprog unsigned long long map_get(void *map,
47*e34293ddSTomas Glozar 				     unsigned int key)
48*e34293ddSTomas Glozar {
49*e34293ddSTomas Glozar 	unsigned long long *value_ptr;
50*e34293ddSTomas Glozar 
51*e34293ddSTomas Glozar 	value_ptr = bpf_map_lookup_elem(map, &key);
52*e34293ddSTomas Glozar 
53*e34293ddSTomas Glozar 	return !value_ptr ? 0 : *value_ptr;
54*e34293ddSTomas Glozar }
55*e34293ddSTomas Glozar 
56*e34293ddSTomas Glozar nosubprog void map_set(void *map,
57*e34293ddSTomas Glozar 		       unsigned int key,
58*e34293ddSTomas Glozar 		       unsigned long long value)
59*e34293ddSTomas Glozar {
60*e34293ddSTomas Glozar 	bpf_map_update_elem(map, &key, &value, BPF_ANY);
61*e34293ddSTomas Glozar }
62*e34293ddSTomas Glozar 
63*e34293ddSTomas Glozar nosubprog void map_increment(void *map,
64*e34293ddSTomas Glozar 			     unsigned int key)
65*e34293ddSTomas Glozar {
66*e34293ddSTomas Glozar 	map_set(map, key, map_get(map, key) + 1);
67*e34293ddSTomas Glozar }
68*e34293ddSTomas Glozar 
69*e34293ddSTomas Glozar nosubprog void update_main_hist(void *map,
70*e34293ddSTomas Glozar 				int bucket)
71*e34293ddSTomas Glozar {
72*e34293ddSTomas Glozar 	if (entries == 0)
73*e34293ddSTomas Glozar 		/* No histogram */
74*e34293ddSTomas Glozar 		return;
75*e34293ddSTomas Glozar 
76*e34293ddSTomas Glozar 	if (bucket >= entries)
77*e34293ddSTomas Glozar 		/* Overflow */
78*e34293ddSTomas Glozar 		return;
79*e34293ddSTomas Glozar 
80*e34293ddSTomas Glozar 	map_increment(map, bucket);
81*e34293ddSTomas Glozar }
82*e34293ddSTomas Glozar 
83*e34293ddSTomas Glozar nosubprog void update_summary(void *map,
84*e34293ddSTomas Glozar 			      unsigned long long latency,
85*e34293ddSTomas Glozar 			      int bucket)
86*e34293ddSTomas Glozar {
87*e34293ddSTomas Glozar 	if (aa_only)
88*e34293ddSTomas Glozar 		/* Auto-analysis only, nothing to be done here */
89*e34293ddSTomas Glozar 		return;
90*e34293ddSTomas Glozar 
91*e34293ddSTomas Glozar 	map_set(map, SUMMARY_CURRENT, latency);
92*e34293ddSTomas Glozar 
93*e34293ddSTomas Glozar 	if (bucket >= entries)
94*e34293ddSTomas Glozar 		/* Overflow */
95*e34293ddSTomas Glozar 		map_increment(map, SUMMARY_OVERFLOW);
96*e34293ddSTomas Glozar 
97*e34293ddSTomas Glozar 	if (latency > map_get(map, SUMMARY_MAX))
98*e34293ddSTomas Glozar 		map_set(map, SUMMARY_MAX, latency);
99*e34293ddSTomas Glozar 
100*e34293ddSTomas Glozar 	if (latency < map_get(map, SUMMARY_MIN) || map_get(map, SUMMARY_COUNT) == 0)
101*e34293ddSTomas Glozar 		map_set(map, SUMMARY_MIN, latency);
102*e34293ddSTomas Glozar 
103*e34293ddSTomas Glozar 	map_increment(map, SUMMARY_COUNT);
104*e34293ddSTomas Glozar 	map_set(map, SUMMARY_SUM, map_get(map, SUMMARY_SUM) + latency);
105*e34293ddSTomas Glozar }
106*e34293ddSTomas Glozar 
107*e34293ddSTomas Glozar nosubprog void set_stop_tracing(void)
108*e34293ddSTomas Glozar {
109*e34293ddSTomas Glozar 	int value = 0;
110*e34293ddSTomas Glozar 
111*e34293ddSTomas Glozar 	/* Suppress further sample processing */
112*e34293ddSTomas Glozar 	stop_tracing = 1;
113*e34293ddSTomas Glozar 
114*e34293ddSTomas Glozar 	/* Signal to userspace */
115*e34293ddSTomas Glozar 	bpf_ringbuf_output(&signal_stop_tracing, &value, sizeof(value), 0);
116*e34293ddSTomas Glozar }
117*e34293ddSTomas Glozar 
118*e34293ddSTomas Glozar SEC("tp/osnoise/timerlat_sample")
119*e34293ddSTomas Glozar int handle_timerlat_sample(struct trace_event_raw_timerlat_sample *tp_args)
120*e34293ddSTomas Glozar {
121*e34293ddSTomas Glozar 	unsigned long long latency, latency_us;
122*e34293ddSTomas Glozar 	int bucket;
123*e34293ddSTomas Glozar 
124*e34293ddSTomas Glozar 	if (stop_tracing)
125*e34293ddSTomas Glozar 		return 0;
126*e34293ddSTomas Glozar 
127*e34293ddSTomas Glozar 	latency = tp_args->timer_latency / output_divisor;
128*e34293ddSTomas Glozar 	latency_us = tp_args->timer_latency / 1000;
129*e34293ddSTomas Glozar 	bucket = latency / bucket_size;
130*e34293ddSTomas Glozar 
131*e34293ddSTomas Glozar 	if (tp_args->context == 0) {
132*e34293ddSTomas Glozar 		update_main_hist(&hist_irq, bucket);
133*e34293ddSTomas Glozar 		update_summary(&summary_irq, latency, bucket);
134*e34293ddSTomas Glozar 
135*e34293ddSTomas Glozar 		if (irq_threshold != 0 && latency_us >= irq_threshold)
136*e34293ddSTomas Glozar 			set_stop_tracing();
137*e34293ddSTomas Glozar 	} else if (tp_args->context == 1) {
138*e34293ddSTomas Glozar 		update_main_hist(&hist_thread, bucket);
139*e34293ddSTomas Glozar 		update_summary(&summary_thread, latency, bucket);
140*e34293ddSTomas Glozar 
141*e34293ddSTomas Glozar 		if (thread_threshold != 0 && latency_us >= thread_threshold)
142*e34293ddSTomas Glozar 			set_stop_tracing();
143*e34293ddSTomas Glozar 	} else {
144*e34293ddSTomas Glozar 		update_main_hist(&hist_user, bucket);
145*e34293ddSTomas Glozar 		update_summary(&summary_user, latency, bucket);
146*e34293ddSTomas Glozar 	}
147*e34293ddSTomas Glozar 
148*e34293ddSTomas Glozar 	return 0;
149*e34293ddSTomas Glozar }
150