Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /* Copyright (c) 2020 Facebook */
0003 #include "bench.h"
0004 #include "trigger_bench.skel.h"
0005 #include "trace_helpers.h"
0006 
0007 /* BPF triggering benchmarks */
0008 static struct trigger_ctx {
0009     struct trigger_bench *skel;
0010 } ctx;
0011 
0012 static struct counter base_hits;
0013 
0014 static void trigger_validate(void)
0015 {
0016     if (env.consumer_cnt != 1) {
0017         fprintf(stderr, "benchmark doesn't support multi-consumer!\n");
0018         exit(1);
0019     }
0020 }
0021 
0022 static void *trigger_base_producer(void *input)
0023 {
0024     while (true) {
0025         (void)syscall(__NR_getpgid);
0026         atomic_inc(&base_hits.value);
0027     }
0028     return NULL;
0029 }
0030 
0031 static void trigger_base_measure(struct bench_res *res)
0032 {
0033     res->hits = atomic_swap(&base_hits.value, 0);
0034 }
0035 
0036 static void *trigger_producer(void *input)
0037 {
0038     while (true)
0039         (void)syscall(__NR_getpgid);
0040     return NULL;
0041 }
0042 
0043 static void trigger_measure(struct bench_res *res)
0044 {
0045     res->hits = atomic_swap(&ctx.skel->bss->hits, 0);
0046 }
0047 
0048 static void setup_ctx(void)
0049 {
0050     setup_libbpf();
0051 
0052     ctx.skel = trigger_bench__open_and_load();
0053     if (!ctx.skel) {
0054         fprintf(stderr, "failed to open skeleton\n");
0055         exit(1);
0056     }
0057 }
0058 
0059 static void attach_bpf(struct bpf_program *prog)
0060 {
0061     struct bpf_link *link;
0062 
0063     link = bpf_program__attach(prog);
0064     if (!link) {
0065         fprintf(stderr, "failed to attach program!\n");
0066         exit(1);
0067     }
0068 }
0069 
0070 static void trigger_tp_setup(void)
0071 {
0072     setup_ctx();
0073     attach_bpf(ctx.skel->progs.bench_trigger_tp);
0074 }
0075 
0076 static void trigger_rawtp_setup(void)
0077 {
0078     setup_ctx();
0079     attach_bpf(ctx.skel->progs.bench_trigger_raw_tp);
0080 }
0081 
0082 static void trigger_kprobe_setup(void)
0083 {
0084     setup_ctx();
0085     attach_bpf(ctx.skel->progs.bench_trigger_kprobe);
0086 }
0087 
0088 static void trigger_fentry_setup(void)
0089 {
0090     setup_ctx();
0091     attach_bpf(ctx.skel->progs.bench_trigger_fentry);
0092 }
0093 
0094 static void trigger_fentry_sleep_setup(void)
0095 {
0096     setup_ctx();
0097     attach_bpf(ctx.skel->progs.bench_trigger_fentry_sleep);
0098 }
0099 
0100 static void trigger_fmodret_setup(void)
0101 {
0102     setup_ctx();
0103     attach_bpf(ctx.skel->progs.bench_trigger_fmodret);
0104 }
0105 
0106 static void *trigger_consumer(void *input)
0107 {
0108     return NULL;
0109 }
0110 
0111 /* make sure call is not inlined and not avoided by compiler, so __weak and
0112  * inline asm volatile in the body of the function
0113  *
0114  * There is a performance difference between uprobing at nop location vs other
0115  * instructions. So use two different targets, one of which starts with nop
0116  * and another doesn't.
0117  *
0118  * GCC doesn't generate stack setup preample for these functions due to them
0119  * having no input arguments and doing nothing in the body.
0120  */
0121 __weak void uprobe_target_with_nop(void)
0122 {
0123     asm volatile ("nop");
0124 }
0125 
0126 __weak void uprobe_target_without_nop(void)
0127 {
0128     asm volatile ("");
0129 }
0130 
0131 static void *uprobe_base_producer(void *input)
0132 {
0133     while (true) {
0134         uprobe_target_with_nop();
0135         atomic_inc(&base_hits.value);
0136     }
0137     return NULL;
0138 }
0139 
0140 static void *uprobe_producer_with_nop(void *input)
0141 {
0142     while (true)
0143         uprobe_target_with_nop();
0144     return NULL;
0145 }
0146 
0147 static void *uprobe_producer_without_nop(void *input)
0148 {
0149     while (true)
0150         uprobe_target_without_nop();
0151     return NULL;
0152 }
0153 
0154 static void usetup(bool use_retprobe, bool use_nop)
0155 {
0156     size_t uprobe_offset;
0157     struct bpf_link *link;
0158 
0159     setup_libbpf();
0160 
0161     ctx.skel = trigger_bench__open_and_load();
0162     if (!ctx.skel) {
0163         fprintf(stderr, "failed to open skeleton\n");
0164         exit(1);
0165     }
0166 
0167     if (use_nop)
0168         uprobe_offset = get_uprobe_offset(&uprobe_target_with_nop);
0169     else
0170         uprobe_offset = get_uprobe_offset(&uprobe_target_without_nop);
0171 
0172     link = bpf_program__attach_uprobe(ctx.skel->progs.bench_trigger_uprobe,
0173                       use_retprobe,
0174                       -1 /* all PIDs */,
0175                       "/proc/self/exe",
0176                       uprobe_offset);
0177     if (!link) {
0178         fprintf(stderr, "failed to attach uprobe!\n");
0179         exit(1);
0180     }
0181     ctx.skel->links.bench_trigger_uprobe = link;
0182 }
0183 
0184 static void uprobe_setup_with_nop(void)
0185 {
0186     usetup(false, true);
0187 }
0188 
0189 static void uretprobe_setup_with_nop(void)
0190 {
0191     usetup(true, true);
0192 }
0193 
0194 static void uprobe_setup_without_nop(void)
0195 {
0196     usetup(false, false);
0197 }
0198 
0199 static void uretprobe_setup_without_nop(void)
0200 {
0201     usetup(true, false);
0202 }
0203 
0204 const struct bench bench_trig_base = {
0205     .name = "trig-base",
0206     .validate = trigger_validate,
0207     .producer_thread = trigger_base_producer,
0208     .consumer_thread = trigger_consumer,
0209     .measure = trigger_base_measure,
0210     .report_progress = hits_drops_report_progress,
0211     .report_final = hits_drops_report_final,
0212 };
0213 
0214 const struct bench bench_trig_tp = {
0215     .name = "trig-tp",
0216     .validate = trigger_validate,
0217     .setup = trigger_tp_setup,
0218     .producer_thread = trigger_producer,
0219     .consumer_thread = trigger_consumer,
0220     .measure = trigger_measure,
0221     .report_progress = hits_drops_report_progress,
0222     .report_final = hits_drops_report_final,
0223 };
0224 
0225 const struct bench bench_trig_rawtp = {
0226     .name = "trig-rawtp",
0227     .validate = trigger_validate,
0228     .setup = trigger_rawtp_setup,
0229     .producer_thread = trigger_producer,
0230     .consumer_thread = trigger_consumer,
0231     .measure = trigger_measure,
0232     .report_progress = hits_drops_report_progress,
0233     .report_final = hits_drops_report_final,
0234 };
0235 
0236 const struct bench bench_trig_kprobe = {
0237     .name = "trig-kprobe",
0238     .validate = trigger_validate,
0239     .setup = trigger_kprobe_setup,
0240     .producer_thread = trigger_producer,
0241     .consumer_thread = trigger_consumer,
0242     .measure = trigger_measure,
0243     .report_progress = hits_drops_report_progress,
0244     .report_final = hits_drops_report_final,
0245 };
0246 
0247 const struct bench bench_trig_fentry = {
0248     .name = "trig-fentry",
0249     .validate = trigger_validate,
0250     .setup = trigger_fentry_setup,
0251     .producer_thread = trigger_producer,
0252     .consumer_thread = trigger_consumer,
0253     .measure = trigger_measure,
0254     .report_progress = hits_drops_report_progress,
0255     .report_final = hits_drops_report_final,
0256 };
0257 
0258 const struct bench bench_trig_fentry_sleep = {
0259     .name = "trig-fentry-sleep",
0260     .validate = trigger_validate,
0261     .setup = trigger_fentry_sleep_setup,
0262     .producer_thread = trigger_producer,
0263     .consumer_thread = trigger_consumer,
0264     .measure = trigger_measure,
0265     .report_progress = hits_drops_report_progress,
0266     .report_final = hits_drops_report_final,
0267 };
0268 
0269 const struct bench bench_trig_fmodret = {
0270     .name = "trig-fmodret",
0271     .validate = trigger_validate,
0272     .setup = trigger_fmodret_setup,
0273     .producer_thread = trigger_producer,
0274     .consumer_thread = trigger_consumer,
0275     .measure = trigger_measure,
0276     .report_progress = hits_drops_report_progress,
0277     .report_final = hits_drops_report_final,
0278 };
0279 
0280 const struct bench bench_trig_uprobe_base = {
0281     .name = "trig-uprobe-base",
0282     .setup = NULL, /* no uprobe/uretprobe is attached */
0283     .producer_thread = uprobe_base_producer,
0284     .consumer_thread = trigger_consumer,
0285     .measure = trigger_base_measure,
0286     .report_progress = hits_drops_report_progress,
0287     .report_final = hits_drops_report_final,
0288 };
0289 
0290 const struct bench bench_trig_uprobe_with_nop = {
0291     .name = "trig-uprobe-with-nop",
0292     .setup = uprobe_setup_with_nop,
0293     .producer_thread = uprobe_producer_with_nop,
0294     .consumer_thread = trigger_consumer,
0295     .measure = trigger_measure,
0296     .report_progress = hits_drops_report_progress,
0297     .report_final = hits_drops_report_final,
0298 };
0299 
0300 const struct bench bench_trig_uretprobe_with_nop = {
0301     .name = "trig-uretprobe-with-nop",
0302     .setup = uretprobe_setup_with_nop,
0303     .producer_thread = uprobe_producer_with_nop,
0304     .consumer_thread = trigger_consumer,
0305     .measure = trigger_measure,
0306     .report_progress = hits_drops_report_progress,
0307     .report_final = hits_drops_report_final,
0308 };
0309 
0310 const struct bench bench_trig_uprobe_without_nop = {
0311     .name = "trig-uprobe-without-nop",
0312     .setup = uprobe_setup_without_nop,
0313     .producer_thread = uprobe_producer_without_nop,
0314     .consumer_thread = trigger_consumer,
0315     .measure = trigger_measure,
0316     .report_progress = hits_drops_report_progress,
0317     .report_final = hits_drops_report_final,
0318 };
0319 
0320 const struct bench bench_trig_uretprobe_without_nop = {
0321     .name = "trig-uretprobe-without-nop",
0322     .setup = uretprobe_setup_without_nop,
0323     .producer_thread = uprobe_producer_without_nop,
0324     .consumer_thread = trigger_consumer,
0325     .measure = trigger_measure,
0326     .report_progress = hits_drops_report_progress,
0327     .report_final = hits_drops_report_final,
0328 };