Loading...
Note: File does not exist in v4.6.
1// SPDX-License-Identifier: GPL-2.0
2/* Copyright (c) 2020 Facebook */
3#include "bench.h"
4#include "trigger_bench.skel.h"
5#include "trace_helpers.h"
6
7/* BPF triggering benchmarks */
8static struct trigger_ctx {
9 struct trigger_bench *skel;
10} ctx;
11
12static struct counter base_hits;
13
14static void trigger_validate(void)
15{
16 if (env.consumer_cnt != 0) {
17 fprintf(stderr, "benchmark doesn't support consumer!\n");
18 exit(1);
19 }
20}
21
22static void *trigger_base_producer(void *input)
23{
24 while (true) {
25 (void)syscall(__NR_getpgid);
26 atomic_inc(&base_hits.value);
27 }
28 return NULL;
29}
30
31static void trigger_base_measure(struct bench_res *res)
32{
33 res->hits = atomic_swap(&base_hits.value, 0);
34}
35
36static void *trigger_producer(void *input)
37{
38 while (true)
39 (void)syscall(__NR_getpgid);
40 return NULL;
41}
42
43static void trigger_measure(struct bench_res *res)
44{
45 res->hits = atomic_swap(&ctx.skel->bss->hits, 0);
46}
47
48static void setup_ctx(void)
49{
50 setup_libbpf();
51
52 ctx.skel = trigger_bench__open_and_load();
53 if (!ctx.skel) {
54 fprintf(stderr, "failed to open skeleton\n");
55 exit(1);
56 }
57}
58
59static void attach_bpf(struct bpf_program *prog)
60{
61 struct bpf_link *link;
62
63 link = bpf_program__attach(prog);
64 if (!link) {
65 fprintf(stderr, "failed to attach program!\n");
66 exit(1);
67 }
68}
69
70static void trigger_tp_setup(void)
71{
72 setup_ctx();
73 attach_bpf(ctx.skel->progs.bench_trigger_tp);
74}
75
76static void trigger_rawtp_setup(void)
77{
78 setup_ctx();
79 attach_bpf(ctx.skel->progs.bench_trigger_raw_tp);
80}
81
82static void trigger_kprobe_setup(void)
83{
84 setup_ctx();
85 attach_bpf(ctx.skel->progs.bench_trigger_kprobe);
86}
87
88static void trigger_fentry_setup(void)
89{
90 setup_ctx();
91 attach_bpf(ctx.skel->progs.bench_trigger_fentry);
92}
93
94static void trigger_fentry_sleep_setup(void)
95{
96 setup_ctx();
97 attach_bpf(ctx.skel->progs.bench_trigger_fentry_sleep);
98}
99
100static void trigger_fmodret_setup(void)
101{
102 setup_ctx();
103 attach_bpf(ctx.skel->progs.bench_trigger_fmodret);
104}
105
106/* make sure call is not inlined and not avoided by compiler, so __weak and
107 * inline asm volatile in the body of the function
108 *
109 * There is a performance difference between uprobing at nop location vs other
110 * instructions. So use two different targets, one of which starts with nop
111 * and another doesn't.
112 *
113 * GCC doesn't generate stack setup preample for these functions due to them
114 * having no input arguments and doing nothing in the body.
115 */
116__weak void uprobe_target_with_nop(void)
117{
118 asm volatile ("nop");
119}
120
121__weak void uprobe_target_without_nop(void)
122{
123 asm volatile ("");
124}
125
126static void *uprobe_base_producer(void *input)
127{
128 while (true) {
129 uprobe_target_with_nop();
130 atomic_inc(&base_hits.value);
131 }
132 return NULL;
133}
134
135static void *uprobe_producer_with_nop(void *input)
136{
137 while (true)
138 uprobe_target_with_nop();
139 return NULL;
140}
141
142static void *uprobe_producer_without_nop(void *input)
143{
144 while (true)
145 uprobe_target_without_nop();
146 return NULL;
147}
148
149static void usetup(bool use_retprobe, bool use_nop)
150{
151 size_t uprobe_offset;
152 struct bpf_link *link;
153
154 setup_libbpf();
155
156 ctx.skel = trigger_bench__open_and_load();
157 if (!ctx.skel) {
158 fprintf(stderr, "failed to open skeleton\n");
159 exit(1);
160 }
161
162 if (use_nop)
163 uprobe_offset = get_uprobe_offset(&uprobe_target_with_nop);
164 else
165 uprobe_offset = get_uprobe_offset(&uprobe_target_without_nop);
166
167 link = bpf_program__attach_uprobe(ctx.skel->progs.bench_trigger_uprobe,
168 use_retprobe,
169 -1 /* all PIDs */,
170 "/proc/self/exe",
171 uprobe_offset);
172 if (!link) {
173 fprintf(stderr, "failed to attach uprobe!\n");
174 exit(1);
175 }
176 ctx.skel->links.bench_trigger_uprobe = link;
177}
178
179static void uprobe_setup_with_nop(void)
180{
181 usetup(false, true);
182}
183
184static void uretprobe_setup_with_nop(void)
185{
186 usetup(true, true);
187}
188
189static void uprobe_setup_without_nop(void)
190{
191 usetup(false, false);
192}
193
194static void uretprobe_setup_without_nop(void)
195{
196 usetup(true, false);
197}
198
199const struct bench bench_trig_base = {
200 .name = "trig-base",
201 .validate = trigger_validate,
202 .producer_thread = trigger_base_producer,
203 .measure = trigger_base_measure,
204 .report_progress = hits_drops_report_progress,
205 .report_final = hits_drops_report_final,
206};
207
208const struct bench bench_trig_tp = {
209 .name = "trig-tp",
210 .validate = trigger_validate,
211 .setup = trigger_tp_setup,
212 .producer_thread = trigger_producer,
213 .measure = trigger_measure,
214 .report_progress = hits_drops_report_progress,
215 .report_final = hits_drops_report_final,
216};
217
218const struct bench bench_trig_rawtp = {
219 .name = "trig-rawtp",
220 .validate = trigger_validate,
221 .setup = trigger_rawtp_setup,
222 .producer_thread = trigger_producer,
223 .measure = trigger_measure,
224 .report_progress = hits_drops_report_progress,
225 .report_final = hits_drops_report_final,
226};
227
228const struct bench bench_trig_kprobe = {
229 .name = "trig-kprobe",
230 .validate = trigger_validate,
231 .setup = trigger_kprobe_setup,
232 .producer_thread = trigger_producer,
233 .measure = trigger_measure,
234 .report_progress = hits_drops_report_progress,
235 .report_final = hits_drops_report_final,
236};
237
238const struct bench bench_trig_fentry = {
239 .name = "trig-fentry",
240 .validate = trigger_validate,
241 .setup = trigger_fentry_setup,
242 .producer_thread = trigger_producer,
243 .measure = trigger_measure,
244 .report_progress = hits_drops_report_progress,
245 .report_final = hits_drops_report_final,
246};
247
248const struct bench bench_trig_fentry_sleep = {
249 .name = "trig-fentry-sleep",
250 .validate = trigger_validate,
251 .setup = trigger_fentry_sleep_setup,
252 .producer_thread = trigger_producer,
253 .measure = trigger_measure,
254 .report_progress = hits_drops_report_progress,
255 .report_final = hits_drops_report_final,
256};
257
258const struct bench bench_trig_fmodret = {
259 .name = "trig-fmodret",
260 .validate = trigger_validate,
261 .setup = trigger_fmodret_setup,
262 .producer_thread = trigger_producer,
263 .measure = trigger_measure,
264 .report_progress = hits_drops_report_progress,
265 .report_final = hits_drops_report_final,
266};
267
268const struct bench bench_trig_uprobe_base = {
269 .name = "trig-uprobe-base",
270 .setup = NULL, /* no uprobe/uretprobe is attached */
271 .producer_thread = uprobe_base_producer,
272 .measure = trigger_base_measure,
273 .report_progress = hits_drops_report_progress,
274 .report_final = hits_drops_report_final,
275};
276
277const struct bench bench_trig_uprobe_with_nop = {
278 .name = "trig-uprobe-with-nop",
279 .setup = uprobe_setup_with_nop,
280 .producer_thread = uprobe_producer_with_nop,
281 .measure = trigger_measure,
282 .report_progress = hits_drops_report_progress,
283 .report_final = hits_drops_report_final,
284};
285
286const struct bench bench_trig_uretprobe_with_nop = {
287 .name = "trig-uretprobe-with-nop",
288 .setup = uretprobe_setup_with_nop,
289 .producer_thread = uprobe_producer_with_nop,
290 .measure = trigger_measure,
291 .report_progress = hits_drops_report_progress,
292 .report_final = hits_drops_report_final,
293};
294
295const struct bench bench_trig_uprobe_without_nop = {
296 .name = "trig-uprobe-without-nop",
297 .setup = uprobe_setup_without_nop,
298 .producer_thread = uprobe_producer_without_nop,
299 .measure = trigger_measure,
300 .report_progress = hits_drops_report_progress,
301 .report_final = hits_drops_report_final,
302};
303
304const struct bench bench_trig_uretprobe_without_nop = {
305 .name = "trig-uretprobe-without-nop",
306 .setup = uretprobe_setup_without_nop,
307 .producer_thread = uprobe_producer_without_nop,
308 .measure = trigger_measure,
309 .report_progress = hits_drops_report_progress,
310 .report_final = hits_drops_report_final,
311};