xref: /linux/tools/tracing/rtla/src/timerlat_bpf.c (revision 8cd0f08ac72e25e2a048c72d76730676ab0106f3)
1 // SPDX-License-Identifier: GPL-2.0
2 #ifdef HAVE_BPF_SKEL
3 #define _GNU_SOURCE
4 #include "timerlat.h"
5 #include "timerlat_bpf.h"
6 #include "timerlat.skel.h"
7 
8 static struct timerlat_bpf *bpf;
9 
10 /*
11  * timerlat_bpf_init - load and initialize BPF program to collect timerlat data
12  */
13 int timerlat_bpf_init(struct timerlat_params *params)
14 {
15 	int err;
16 
17 	debug_msg("Loading BPF program\n");
18 
19 	bpf = timerlat_bpf__open();
20 	if (!bpf)
21 		return 1;
22 
23 	/* Pass common options */
24 	bpf->rodata->output_divisor = params->common.output_divisor;
25 	bpf->rodata->entries = params->common.hist.entries;
26 	bpf->rodata->irq_threshold = params->common.stop_us;
27 	bpf->rodata->thread_threshold = params->common.stop_total_us;
28 	bpf->rodata->aa_only = params->common.aa_only;
29 
30 	if (params->common.hist.entries != 0) {
31 		/* Pass histogram options */
32 		bpf->rodata->bucket_size = params->common.hist.bucket_size;
33 
34 		/* Set histogram array sizes */
35 		bpf_map__set_max_entries(bpf->maps.hist_irq, params->common.hist.entries);
36 		bpf_map__set_max_entries(bpf->maps.hist_thread, params->common.hist.entries);
37 		bpf_map__set_max_entries(bpf->maps.hist_user, params->common.hist.entries);
38 	} else {
39 		/* No entries, disable histogram */
40 		bpf_map__set_autocreate(bpf->maps.hist_irq, false);
41 		bpf_map__set_autocreate(bpf->maps.hist_thread, false);
42 		bpf_map__set_autocreate(bpf->maps.hist_user, false);
43 	}
44 
45 	if (params->common.aa_only) {
46 		/* Auto-analysis only, disable summary */
47 		bpf_map__set_autocreate(bpf->maps.summary_irq, false);
48 		bpf_map__set_autocreate(bpf->maps.summary_thread, false);
49 		bpf_map__set_autocreate(bpf->maps.summary_user, false);
50 	}
51 
52 	/* Load and verify BPF program */
53 	err = timerlat_bpf__load(bpf);
54 	if (err) {
55 		timerlat_bpf__destroy(bpf);
56 		return err;
57 	}
58 
59 	return 0;
60 }
61 
62 /*
63  * timerlat_bpf_set_action - set action on threshold executed on BPF side
64  */
65 static int timerlat_bpf_set_action(struct bpf_program *prog)
66 {
67 	unsigned int key = 0, value = bpf_program__fd(prog);
68 
69 	return bpf_map__update_elem(bpf->maps.bpf_action,
70 				    &key, sizeof(key),
71 				    &value, sizeof(value),
72 				    BPF_ANY);
73 }
74 
75 /*
76  * timerlat_bpf_attach - attach BPF program to collect timerlat data
77  */
78 int timerlat_bpf_attach(void)
79 {
80 	debug_msg("Attaching BPF program\n");
81 
82 	return timerlat_bpf__attach(bpf);
83 }
84 
85 /*
86  * timerlat_bpf_detach - detach BPF program to collect timerlat data
87  */
88 void timerlat_bpf_detach(void)
89 {
90 	timerlat_bpf__detach(bpf);
91 }
92 
93 /*
94  * timerlat_bpf_detach - destroy BPF program to collect timerlat data
95  */
96 void timerlat_bpf_destroy(void)
97 {
98 	timerlat_bpf__destroy(bpf);
99 }
100 
101 static int handle_rb_event(void *ctx, void *data, size_t data_sz)
102 {
103 	return 0;
104 }
105 
106 /*
107  * timerlat_bpf_wait - wait until tracing is stopped or signal
108  */
109 int timerlat_bpf_wait(int timeout)
110 {
111 	struct ring_buffer *rb;
112 	int retval;
113 
114 	rb = ring_buffer__new(bpf_map__fd(bpf->maps.signal_stop_tracing),
115 			      handle_rb_event, NULL, NULL);
116 	retval = ring_buffer__poll(rb, timeout * 1000);
117 	ring_buffer__free(rb);
118 
119 	return retval;
120 }
121 
122 /*
123  * timerlat_bpf_restart_tracing - restart stopped tracing
124  */
125 int timerlat_bpf_restart_tracing(void)
126 {
127 	unsigned int key = 0;
128 	unsigned long long value = 0;
129 
130 	return bpf_map__update_elem(bpf->maps.stop_tracing,
131 				    &key, sizeof(key),
132 				    &value, sizeof(value), BPF_ANY);
133 }
134 
135 static int get_value(struct bpf_map *map_irq,
136 		     struct bpf_map *map_thread,
137 		     struct bpf_map *map_user,
138 		     int key,
139 		     long long *value_irq,
140 		     long long *value_thread,
141 		     long long *value_user,
142 		     int cpus)
143 {
144 	int err;
145 
146 	err = bpf_map__lookup_elem(map_irq, &key,
147 				   sizeof(unsigned int), value_irq,
148 				   sizeof(long long) * cpus, 0);
149 	if (err)
150 		return err;
151 	err = bpf_map__lookup_elem(map_thread, &key,
152 				   sizeof(unsigned int), value_thread,
153 				   sizeof(long long) * cpus, 0);
154 	if (err)
155 		return err;
156 	err = bpf_map__lookup_elem(map_user, &key,
157 				   sizeof(unsigned int), value_user,
158 				   sizeof(long long) * cpus, 0);
159 	if (err)
160 		return err;
161 	return 0;
162 }
163 
164 /*
165  * timerlat_bpf_get_hist_value - get value from BPF hist map
166  */
167 int timerlat_bpf_get_hist_value(int key,
168 				long long *value_irq,
169 				long long *value_thread,
170 				long long *value_user,
171 				int cpus)
172 {
173 	return get_value(bpf->maps.hist_irq,
174 			 bpf->maps.hist_thread,
175 			 bpf->maps.hist_user,
176 			 key, value_irq, value_thread, value_user, cpus);
177 }
178 
179 /*
180  * timerlat_bpf_get_summary_value - get value from BPF summary map
181  */
182 int timerlat_bpf_get_summary_value(enum summary_field key,
183 				   long long *value_irq,
184 				   long long *value_thread,
185 				   long long *value_user,
186 				   int cpus)
187 {
188 	return get_value(bpf->maps.summary_irq,
189 			 bpf->maps.summary_thread,
190 			 bpf->maps.summary_user,
191 			 key, value_irq, value_thread, value_user, cpus);
192 }
193 #endif /* HAVE_BPF_SKEL */
194