linux/tools/testing/selftests/bpf/benchs/bench_trigger.c
<<
>>
Prefs
   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        ssize_t base_addr;
 158        struct bpf_link *link;
 159
 160        setup_libbpf();
 161
 162        ctx.skel = trigger_bench__open_and_load();
 163        if (!ctx.skel) {
 164                fprintf(stderr, "failed to open skeleton\n");
 165                exit(1);
 166        }
 167
 168        base_addr = get_base_addr();
 169        if (use_nop)
 170                uprobe_offset = get_uprobe_offset(&uprobe_target_with_nop, base_addr);
 171        else
 172                uprobe_offset = get_uprobe_offset(&uprobe_target_without_nop, base_addr);
 173
 174        link = bpf_program__attach_uprobe(ctx.skel->progs.bench_trigger_uprobe,
 175                                          use_retprobe,
 176                                          -1 /* all PIDs */,
 177                                          "/proc/self/exe",
 178                                          uprobe_offset);
 179        if (!link) {
 180                fprintf(stderr, "failed to attach uprobe!\n");
 181                exit(1);
 182        }
 183        ctx.skel->links.bench_trigger_uprobe = link;
 184}
 185
 186static void uprobe_setup_with_nop(void)
 187{
 188        usetup(false, true);
 189}
 190
 191static void uretprobe_setup_with_nop(void)
 192{
 193        usetup(true, true);
 194}
 195
 196static void uprobe_setup_without_nop(void)
 197{
 198        usetup(false, false);
 199}
 200
 201static void uretprobe_setup_without_nop(void)
 202{
 203        usetup(true, false);
 204}
 205
 206const struct bench bench_trig_base = {
 207        .name = "trig-base",
 208        .validate = trigger_validate,
 209        .producer_thread = trigger_base_producer,
 210        .consumer_thread = trigger_consumer,
 211        .measure = trigger_base_measure,
 212        .report_progress = hits_drops_report_progress,
 213        .report_final = hits_drops_report_final,
 214};
 215
 216const struct bench bench_trig_tp = {
 217        .name = "trig-tp",
 218        .validate = trigger_validate,
 219        .setup = trigger_tp_setup,
 220        .producer_thread = trigger_producer,
 221        .consumer_thread = trigger_consumer,
 222        .measure = trigger_measure,
 223        .report_progress = hits_drops_report_progress,
 224        .report_final = hits_drops_report_final,
 225};
 226
 227const struct bench bench_trig_rawtp = {
 228        .name = "trig-rawtp",
 229        .validate = trigger_validate,
 230        .setup = trigger_rawtp_setup,
 231        .producer_thread = trigger_producer,
 232        .consumer_thread = trigger_consumer,
 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_kprobe = {
 239        .name = "trig-kprobe",
 240        .validate = trigger_validate,
 241        .setup = trigger_kprobe_setup,
 242        .producer_thread = trigger_producer,
 243        .consumer_thread = trigger_consumer,
 244        .measure = trigger_measure,
 245        .report_progress = hits_drops_report_progress,
 246        .report_final = hits_drops_report_final,
 247};
 248
 249const struct bench bench_trig_fentry = {
 250        .name = "trig-fentry",
 251        .validate = trigger_validate,
 252        .setup = trigger_fentry_setup,
 253        .producer_thread = trigger_producer,
 254        .consumer_thread = trigger_consumer,
 255        .measure = trigger_measure,
 256        .report_progress = hits_drops_report_progress,
 257        .report_final = hits_drops_report_final,
 258};
 259
 260const struct bench bench_trig_fentry_sleep = {
 261        .name = "trig-fentry-sleep",
 262        .validate = trigger_validate,
 263        .setup = trigger_fentry_sleep_setup,
 264        .producer_thread = trigger_producer,
 265        .consumer_thread = trigger_consumer,
 266        .measure = trigger_measure,
 267        .report_progress = hits_drops_report_progress,
 268        .report_final = hits_drops_report_final,
 269};
 270
 271const struct bench bench_trig_fmodret = {
 272        .name = "trig-fmodret",
 273        .validate = trigger_validate,
 274        .setup = trigger_fmodret_setup,
 275        .producer_thread = trigger_producer,
 276        .consumer_thread = trigger_consumer,
 277        .measure = trigger_measure,
 278        .report_progress = hits_drops_report_progress,
 279        .report_final = hits_drops_report_final,
 280};
 281
 282const struct bench bench_trig_uprobe_base = {
 283        .name = "trig-uprobe-base",
 284        .setup = NULL, /* no uprobe/uretprobe is attached */
 285        .producer_thread = uprobe_base_producer,
 286        .consumer_thread = trigger_consumer,
 287        .measure = trigger_base_measure,
 288        .report_progress = hits_drops_report_progress,
 289        .report_final = hits_drops_report_final,
 290};
 291
 292const struct bench bench_trig_uprobe_with_nop = {
 293        .name = "trig-uprobe-with-nop",
 294        .setup = uprobe_setup_with_nop,
 295        .producer_thread = uprobe_producer_with_nop,
 296        .consumer_thread = trigger_consumer,
 297        .measure = trigger_measure,
 298        .report_progress = hits_drops_report_progress,
 299        .report_final = hits_drops_report_final,
 300};
 301
 302const struct bench bench_trig_uretprobe_with_nop = {
 303        .name = "trig-uretprobe-with-nop",
 304        .setup = uretprobe_setup_with_nop,
 305        .producer_thread = uprobe_producer_with_nop,
 306        .consumer_thread = trigger_consumer,
 307        .measure = trigger_measure,
 308        .report_progress = hits_drops_report_progress,
 309        .report_final = hits_drops_report_final,
 310};
 311
 312const struct bench bench_trig_uprobe_without_nop = {
 313        .name = "trig-uprobe-without-nop",
 314        .setup = uprobe_setup_without_nop,
 315        .producer_thread = uprobe_producer_without_nop,
 316        .consumer_thread = trigger_consumer,
 317        .measure = trigger_measure,
 318        .report_progress = hits_drops_report_progress,
 319        .report_final = hits_drops_report_final,
 320};
 321
 322const struct bench bench_trig_uretprobe_without_nop = {
 323        .name = "trig-uretprobe-without-nop",
 324        .setup = uretprobe_setup_without_nop,
 325        .producer_thread = uprobe_producer_without_nop,
 326        .consumer_thread = trigger_consumer,
 327        .measure = trigger_measure,
 328        .report_progress = hits_drops_report_progress,
 329        .report_final = hits_drops_report_final,
 330};
 331