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 */ 8 static struct trigger_ctx { 9 struct trigger_bench *skel; 10 } ctx; 11 12 static struct counter base_hits; 13 14 static 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 22 static 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 31 static void trigger_base_measure(struct bench_res *res) 32 { 33 res->hits = atomic_swap(&base_hits.value, 0); 34 } 35 36 static void *trigger_producer(void *input) 37 { 38 while (true) 39 (void)syscall(__NR_getpgid); 40 return NULL; 41 } 42 43 static void trigger_measure(struct bench_res *res) 44 { 45 res->hits = atomic_swap(&ctx.skel->bss->hits, 0); 46 } 47 48 static 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 59 static 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 70 static void trigger_tp_setup(void) 71 { 72 setup_ctx(); 73 attach_bpf(ctx.skel->progs.bench_trigger_tp); 74 } 75 76 static void trigger_rawtp_setup(void) 77 { 78 setup_ctx(); 79 attach_bpf(ctx.skel->progs.bench_trigger_raw_tp); 80 } 81 82 static void trigger_kprobe_setup(void) 83 { 84 setup_ctx(); 85 attach_bpf(ctx.skel->progs.bench_trigger_kprobe); 86 } 87 88 static void trigger_fentry_setup(void) 89 { 90 setup_ctx(); 91 attach_bpf(ctx.skel->progs.bench_trigger_fentry); 92 } 93 94 static void trigger_fentry_sleep_setup(void) 95 { 96 setup_ctx(); 97 attach_bpf(ctx.skel->progs.bench_trigger_fentry_sleep); 98 } 99 100 static 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 126 static 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 135 static void *uprobe_producer_with_nop(void *input) 136 { 137 while (true) 138 uprobe_target_with_nop(); 139 return NULL; 140 } 141 142 static void *uprobe_producer_without_nop(void *input) 143 { 144 while (true) 145 uprobe_target_without_nop(); 146 return NULL; 147 } 148 149 static 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 179 static void uprobe_setup_with_nop(void) 180 { 181 usetup(false, true); 182 } 183 184 static void uretprobe_setup_with_nop(void) 185 { 186 usetup(true, true); 187 } 188 189 static void uprobe_setup_without_nop(void) 190 { 191 usetup(false, false); 192 } 193 194 static void uretprobe_setup_without_nop(void) 195 { 196 usetup(true, false); 197 } 198 199 const 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 208 const 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 218 const 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 228 const 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 238 const 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 248 const 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 258 const 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 268 const 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 277 const 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 286 const 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 295 const 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 304 const 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 }; 312