bench_trigger.c (7861B)
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 != 1) { 17 fprintf(stderr, "benchmark doesn't support multi-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 106static void *trigger_consumer(void *input) 107{ 108 return NULL; 109} 110 111/* make sure call is not inlined and not avoided by compiler, so __weak and 112 * inline asm volatile in the body of the function 113 * 114 * There is a performance difference between uprobing at nop location vs other 115 * instructions. So use two different targets, one of which starts with nop 116 * and another doesn't. 117 * 118 * GCC doesn't generate stack setup preample for these functions due to them 119 * having no input arguments and doing nothing in the body. 120 */ 121__weak void uprobe_target_with_nop(void) 122{ 123 asm volatile ("nop"); 124} 125 126__weak void uprobe_target_without_nop(void) 127{ 128 asm volatile (""); 129} 130 131static void *uprobe_base_producer(void *input) 132{ 133 while (true) { 134 uprobe_target_with_nop(); 135 atomic_inc(&base_hits.value); 136 } 137 return NULL; 138} 139 140static void *uprobe_producer_with_nop(void *input) 141{ 142 while (true) 143 uprobe_target_with_nop(); 144 return NULL; 145} 146 147static void *uprobe_producer_without_nop(void *input) 148{ 149 while (true) 150 uprobe_target_without_nop(); 151 return NULL; 152} 153 154static void usetup(bool use_retprobe, bool use_nop) 155{ 156 size_t uprobe_offset; 157 struct bpf_link *link; 158 159 setup_libbpf(); 160 161 ctx.skel = trigger_bench__open_and_load(); 162 if (!ctx.skel) { 163 fprintf(stderr, "failed to open skeleton\n"); 164 exit(1); 165 } 166 167 if (use_nop) 168 uprobe_offset = get_uprobe_offset(&uprobe_target_with_nop); 169 else 170 uprobe_offset = get_uprobe_offset(&uprobe_target_without_nop); 171 172 link = bpf_program__attach_uprobe(ctx.skel->progs.bench_trigger_uprobe, 173 use_retprobe, 174 -1 /* all PIDs */, 175 "/proc/self/exe", 176 uprobe_offset); 177 if (!link) { 178 fprintf(stderr, "failed to attach uprobe!\n"); 179 exit(1); 180 } 181 ctx.skel->links.bench_trigger_uprobe = link; 182} 183 184static void uprobe_setup_with_nop(void) 185{ 186 usetup(false, true); 187} 188 189static void uretprobe_setup_with_nop(void) 190{ 191 usetup(true, true); 192} 193 194static void uprobe_setup_without_nop(void) 195{ 196 usetup(false, false); 197} 198 199static void uretprobe_setup_without_nop(void) 200{ 201 usetup(true, false); 202} 203 204const struct bench bench_trig_base = { 205 .name = "trig-base", 206 .validate = trigger_validate, 207 .producer_thread = trigger_base_producer, 208 .consumer_thread = trigger_consumer, 209 .measure = trigger_base_measure, 210 .report_progress = hits_drops_report_progress, 211 .report_final = hits_drops_report_final, 212}; 213 214const struct bench bench_trig_tp = { 215 .name = "trig-tp", 216 .validate = trigger_validate, 217 .setup = trigger_tp_setup, 218 .producer_thread = trigger_producer, 219 .consumer_thread = trigger_consumer, 220 .measure = trigger_measure, 221 .report_progress = hits_drops_report_progress, 222 .report_final = hits_drops_report_final, 223}; 224 225const struct bench bench_trig_rawtp = { 226 .name = "trig-rawtp", 227 .validate = trigger_validate, 228 .setup = trigger_rawtp_setup, 229 .producer_thread = trigger_producer, 230 .consumer_thread = trigger_consumer, 231 .measure = trigger_measure, 232 .report_progress = hits_drops_report_progress, 233 .report_final = hits_drops_report_final, 234}; 235 236const struct bench bench_trig_kprobe = { 237 .name = "trig-kprobe", 238 .validate = trigger_validate, 239 .setup = trigger_kprobe_setup, 240 .producer_thread = trigger_producer, 241 .consumer_thread = trigger_consumer, 242 .measure = trigger_measure, 243 .report_progress = hits_drops_report_progress, 244 .report_final = hits_drops_report_final, 245}; 246 247const struct bench bench_trig_fentry = { 248 .name = "trig-fentry", 249 .validate = trigger_validate, 250 .setup = trigger_fentry_setup, 251 .producer_thread = trigger_producer, 252 .consumer_thread = trigger_consumer, 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_fentry_sleep = { 259 .name = "trig-fentry-sleep", 260 .validate = trigger_validate, 261 .setup = trigger_fentry_sleep_setup, 262 .producer_thread = trigger_producer, 263 .consumer_thread = trigger_consumer, 264 .measure = trigger_measure, 265 .report_progress = hits_drops_report_progress, 266 .report_final = hits_drops_report_final, 267}; 268 269const struct bench bench_trig_fmodret = { 270 .name = "trig-fmodret", 271 .validate = trigger_validate, 272 .setup = trigger_fmodret_setup, 273 .producer_thread = trigger_producer, 274 .consumer_thread = trigger_consumer, 275 .measure = trigger_measure, 276 .report_progress = hits_drops_report_progress, 277 .report_final = hits_drops_report_final, 278}; 279 280const struct bench bench_trig_uprobe_base = { 281 .name = "trig-uprobe-base", 282 .setup = NULL, /* no uprobe/uretprobe is attached */ 283 .producer_thread = uprobe_base_producer, 284 .consumer_thread = trigger_consumer, 285 .measure = trigger_base_measure, 286 .report_progress = hits_drops_report_progress, 287 .report_final = hits_drops_report_final, 288}; 289 290const struct bench bench_trig_uprobe_with_nop = { 291 .name = "trig-uprobe-with-nop", 292 .setup = uprobe_setup_with_nop, 293 .producer_thread = uprobe_producer_with_nop, 294 .consumer_thread = trigger_consumer, 295 .measure = trigger_measure, 296 .report_progress = hits_drops_report_progress, 297 .report_final = hits_drops_report_final, 298}; 299 300const struct bench bench_trig_uretprobe_with_nop = { 301 .name = "trig-uretprobe-with-nop", 302 .setup = uretprobe_setup_with_nop, 303 .producer_thread = uprobe_producer_with_nop, 304 .consumer_thread = trigger_consumer, 305 .measure = trigger_measure, 306 .report_progress = hits_drops_report_progress, 307 .report_final = hits_drops_report_final, 308}; 309 310const struct bench bench_trig_uprobe_without_nop = { 311 .name = "trig-uprobe-without-nop", 312 .setup = uprobe_setup_without_nop, 313 .producer_thread = uprobe_producer_without_nop, 314 .consumer_thread = trigger_consumer, 315 .measure = trigger_measure, 316 .report_progress = hits_drops_report_progress, 317 .report_final = hits_drops_report_final, 318}; 319 320const struct bench bench_trig_uretprobe_without_nop = { 321 .name = "trig-uretprobe-without-nop", 322 .setup = uretprobe_setup_without_nop, 323 .producer_thread = uprobe_producer_without_nop, 324 .consumer_thread = trigger_consumer, 325 .measure = trigger_measure, 326 .report_progress = hits_drops_report_progress, 327 .report_final = hits_drops_report_final, 328};