1 // SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
7 * Copyright (C) 2023, Red Hat Inc, Arnaldo Carvalho de Melo <acme@redhat.com>
10 #include "../util/util.h"
11 #include <subcmd/parse-options.h>
12 #include "../builtin.h"
14 #include <linux/compiler.h>
15 #include <linux/time64.h>
20 #include <sys/types.h>
25 #define LOOPS_DEFAULT 1000
26 static int loops
= LOOPS_DEFAULT
;
29 BENCH_UPROBE__BASELINE
,
31 BENCH_UPROBE__TRACE_PRINTK
,
32 BENCH_UPROBE__EMPTY_RET
,
33 BENCH_UPROBE__TRACE_PRINTK_RET
,
36 static const struct option options
[] = {
37 OPT_INTEGER('l', "loop", &loops
, "Specify number of loops"),
41 static const char * const bench_uprobe_usage
[] = {
42 "perf bench uprobe <options>",
47 #include "bpf_skel/bench_uprobe.skel.h"
49 #define bench_uprobe__attach_uprobe(prog) \
50 skel->links.prog = bpf_program__attach_uprobe_opts(/*prog=*/skel->progs.prog, \
52 /*binary_path=*/"libc.so.6", \
54 /*opts=*/&uprobe_opts); \
55 if (!skel->links.prog) { \
57 fprintf(stderr, "Failed to attach bench uprobe \"%s\": %s\n", #prog, strerror(errno)); \
61 struct bench_uprobe_bpf
*skel
;
63 static int bench_uprobe__setup_bpf_skel(enum bench_uprobe bench
)
65 DECLARE_LIBBPF_OPTS(bpf_uprobe_opts
, uprobe_opts
);
68 /* Load and verify BPF application */
69 skel
= bench_uprobe_bpf__open();
71 fprintf(stderr
, "Failed to open and load uprobes bench BPF skeleton\n");
75 err
= bench_uprobe_bpf__load(skel
);
77 fprintf(stderr
, "Failed to load and verify BPF skeleton\n");
81 uprobe_opts
.func_name
= "usleep";
83 case BENCH_UPROBE__BASELINE
: break;
84 case BENCH_UPROBE__EMPTY
: bench_uprobe__attach_uprobe(empty
); break;
85 case BENCH_UPROBE__TRACE_PRINTK
: bench_uprobe__attach_uprobe(trace_printk
); break;
86 case BENCH_UPROBE__EMPTY_RET
: bench_uprobe__attach_uprobe(empty_ret
); break;
87 case BENCH_UPROBE__TRACE_PRINTK_RET
: bench_uprobe__attach_uprobe(trace_printk_ret
); break;
89 fprintf(stderr
, "Invalid bench: %d\n", bench
);
95 bench_uprobe_bpf__destroy(skel
);
100 static void bench_uprobe__teardown_bpf_skel(void)
103 bench_uprobe_bpf__destroy(skel
);
108 static int bench_uprobe__setup_bpf_skel(enum bench_uprobe bench __maybe_unused
) { return 0; }
109 static void bench_uprobe__teardown_bpf_skel(void) {};
112 static int bench_uprobe_format__default_fprintf(const char *name
, const char *unit
, u64 diff
, FILE *fp
)
114 static u64 baseline
, previous
;
115 s64 diff_to_baseline
= diff
- baseline
,
116 diff_to_previous
= diff
- previous
;
117 int printed
= fprintf(fp
, "# Executed %'d %s calls\n", loops
, name
);
119 printed
+= fprintf(fp
, " %14s: %'" PRIu64
" %ss", "Total time", diff
, unit
);
122 printed
+= fprintf(fp
, " %s%'" PRId64
" to baseline", diff_to_baseline
> 0 ? "+" : "", diff_to_baseline
);
124 if (previous
!= baseline
)
125 fprintf(stdout
, " %s%'" PRId64
" to previous", diff_to_previous
> 0 ? "+" : "", diff_to_previous
);
128 printed
+= fprintf(fp
, "\n\n %'.3f %ss/op", (double)diff
/ (double)loops
, unit
);
131 printed
+= fprintf(fp
, " %'.3f %ss/op to baseline", (double)diff_to_baseline
/ (double)loops
, unit
);
133 if (previous
!= baseline
)
134 printed
+= fprintf(fp
, " %'.3f %ss/op to previous", (double)diff_to_previous
/ (double)loops
, unit
);
146 static int bench_uprobe(int argc
, const char **argv
, enum bench_uprobe bench
)
148 const char *name
= "usleep(1000)", *unit
= "usec";
149 struct timespec start
, end
;
153 argc
= parse_options(argc
, argv
, options
, bench_uprobe_usage
, 0);
155 if (bench
!= BENCH_UPROBE__BASELINE
&& bench_uprobe__setup_bpf_skel(bench
) < 0)
158 clock_gettime(CLOCK_REALTIME
, &start
);
160 for (i
= 0; i
< loops
; i
++) {
161 usleep(USEC_PER_MSEC
);
164 clock_gettime(CLOCK_REALTIME
, &end
);
166 diff
= end
.tv_sec
* NSEC_PER_SEC
+ end
.tv_nsec
- (start
.tv_sec
* NSEC_PER_SEC
+ start
.tv_nsec
);
167 diff
/= NSEC_PER_USEC
;
169 switch (bench_format
) {
170 case BENCH_FORMAT_DEFAULT
:
171 bench_uprobe_format__default_fprintf(name
, unit
, diff
, stdout
);
174 case BENCH_FORMAT_SIMPLE
:
175 printf("%" PRIu64
"\n", diff
);
179 /* reaching here is something of a disaster */
180 fprintf(stderr
, "Unknown format:%d\n", bench_format
);
184 if (bench
!= BENCH_UPROBE__BASELINE
)
185 bench_uprobe__teardown_bpf_skel();
190 int bench_uprobe_baseline(int argc
, const char **argv
)
192 return bench_uprobe(argc
, argv
, BENCH_UPROBE__BASELINE
);
195 int bench_uprobe_empty(int argc
, const char **argv
)
197 return bench_uprobe(argc
, argv
, BENCH_UPROBE__EMPTY
);
200 int bench_uprobe_trace_printk(int argc
, const char **argv
)
202 return bench_uprobe(argc
, argv
, BENCH_UPROBE__TRACE_PRINTK
);
205 int bench_uprobe_empty_ret(int argc
, const char **argv
)
207 return bench_uprobe(argc
, argv
, BENCH_UPROBE__EMPTY_RET
);
210 int bench_uprobe_trace_printk_ret(int argc
, const char **argv
)
212 return bench_uprobe(argc
, argv
, BENCH_UPROBE__TRACE_PRINTK_RET
);