Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/tools/perf/bench/uprobe.c
26285 views
1
// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
2
/*
3
* uprobe.c
4
*
5
* uprobe benchmarks
6
*
7
* Copyright (C) 2023, Red Hat Inc, Arnaldo Carvalho de Melo <[email protected]>
8
*/
9
#include "../perf.h"
10
#include "../util/util.h"
11
#include <subcmd/parse-options.h>
12
#include "../builtin.h"
13
#include "bench.h"
14
#include <linux/compiler.h>
15
#include <linux/time64.h>
16
17
#include <inttypes.h>
18
#include <stdio.h>
19
#include <sys/time.h>
20
#include <sys/types.h>
21
#include <time.h>
22
#include <unistd.h>
23
#include <stdlib.h>
24
25
#define LOOPS_DEFAULT 1000
26
static int loops = LOOPS_DEFAULT;
27
28
enum bench_uprobe {
29
BENCH_UPROBE__BASELINE,
30
BENCH_UPROBE__EMPTY,
31
BENCH_UPROBE__TRACE_PRINTK,
32
BENCH_UPROBE__EMPTY_RET,
33
BENCH_UPROBE__TRACE_PRINTK_RET,
34
};
35
36
static const struct option options[] = {
37
OPT_INTEGER('l', "loop", &loops, "Specify number of loops"),
38
OPT_END()
39
};
40
41
static const char * const bench_uprobe_usage[] = {
42
"perf bench uprobe <options>",
43
NULL
44
};
45
46
#ifdef HAVE_BPF_SKEL
47
#include "bpf_skel/bench_uprobe.skel.h"
48
49
#define bench_uprobe__attach_uprobe(prog) \
50
skel->links.prog = bpf_program__attach_uprobe_opts(/*prog=*/skel->progs.prog, \
51
/*pid=*/-1, \
52
/*binary_path=*/"libc.so.6", \
53
/*func_offset=*/0, \
54
/*opts=*/&uprobe_opts); \
55
if (!skel->links.prog) { \
56
err = -errno; \
57
fprintf(stderr, "Failed to attach bench uprobe \"%s\": %s\n", #prog, strerror(errno)); \
58
goto cleanup; \
59
}
60
61
struct bench_uprobe_bpf *skel;
62
63
static int bench_uprobe__setup_bpf_skel(enum bench_uprobe bench)
64
{
65
DECLARE_LIBBPF_OPTS(bpf_uprobe_opts, uprobe_opts);
66
int err;
67
68
/* Load and verify BPF application */
69
skel = bench_uprobe_bpf__open();
70
if (!skel) {
71
fprintf(stderr, "Failed to open and load uprobes bench BPF skeleton\n");
72
return -1;
73
}
74
75
err = bench_uprobe_bpf__load(skel);
76
if (err) {
77
fprintf(stderr, "Failed to load and verify BPF skeleton\n");
78
goto cleanup;
79
}
80
81
uprobe_opts.func_name = "usleep";
82
switch (bench) {
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;
88
default:
89
fprintf(stderr, "Invalid bench: %d\n", bench);
90
goto cleanup;
91
}
92
93
return err;
94
cleanup:
95
bench_uprobe_bpf__destroy(skel);
96
skel = NULL;
97
return err;
98
}
99
100
static void bench_uprobe__teardown_bpf_skel(void)
101
{
102
if (skel) {
103
bench_uprobe_bpf__destroy(skel);
104
skel = NULL;
105
}
106
}
107
#else
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) {};
110
#endif
111
112
static int bench_uprobe_format__default_fprintf(const char *name, const char *unit, u64 diff, FILE *fp)
113
{
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);
118
119
printed += fprintf(fp, " %14s: %'" PRIu64 " %ss", "Total time", diff, unit);
120
121
if (baseline) {
122
printed += fprintf(fp, " %s%'" PRId64 " to baseline", diff_to_baseline > 0 ? "+" : "", diff_to_baseline);
123
124
if (previous != baseline)
125
fprintf(stdout, " %s%'" PRId64 " to previous", diff_to_previous > 0 ? "+" : "", diff_to_previous);
126
}
127
128
printed += fprintf(fp, "\n\n %'.3f %ss/op", (double)diff / (double)loops, unit);
129
130
if (baseline) {
131
printed += fprintf(fp, " %'.3f %ss/op to baseline", (double)diff_to_baseline / (double)loops, unit);
132
133
if (previous != baseline)
134
printed += fprintf(fp, " %'.3f %ss/op to previous", (double)diff_to_previous / (double)loops, unit);
135
} else {
136
baseline = diff;
137
}
138
139
fputc('\n', fp);
140
141
previous = diff;
142
143
return printed + 1;
144
}
145
146
static int bench_uprobe(int argc, const char **argv, enum bench_uprobe bench)
147
{
148
const char *name = "usleep(1000)", *unit = "usec";
149
struct timespec start, end;
150
u64 diff;
151
int i;
152
153
argc = parse_options(argc, argv, options, bench_uprobe_usage, 0);
154
155
if (bench != BENCH_UPROBE__BASELINE && bench_uprobe__setup_bpf_skel(bench) < 0)
156
return 0;
157
158
clock_gettime(CLOCK_REALTIME, &start);
159
160
for (i = 0; i < loops; i++) {
161
usleep(USEC_PER_MSEC);
162
}
163
164
clock_gettime(CLOCK_REALTIME, &end);
165
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;
168
169
switch (bench_format) {
170
case BENCH_FORMAT_DEFAULT:
171
bench_uprobe_format__default_fprintf(name, unit, diff, stdout);
172
break;
173
174
case BENCH_FORMAT_SIMPLE:
175
printf("%" PRIu64 "\n", diff);
176
break;
177
178
default:
179
/* reaching here is something of a disaster */
180
fprintf(stderr, "Unknown format:%d\n", bench_format);
181
exit(1);
182
}
183
184
if (bench != BENCH_UPROBE__BASELINE)
185
bench_uprobe__teardown_bpf_skel();
186
187
return 0;
188
}
189
190
int bench_uprobe_baseline(int argc, const char **argv)
191
{
192
return bench_uprobe(argc, argv, BENCH_UPROBE__BASELINE);
193
}
194
195
int bench_uprobe_empty(int argc, const char **argv)
196
{
197
return bench_uprobe(argc, argv, BENCH_UPROBE__EMPTY);
198
}
199
200
int bench_uprobe_trace_printk(int argc, const char **argv)
201
{
202
return bench_uprobe(argc, argv, BENCH_UPROBE__TRACE_PRINTK);
203
}
204
205
int bench_uprobe_empty_ret(int argc, const char **argv)
206
{
207
return bench_uprobe(argc, argv, BENCH_UPROBE__EMPTY_RET);
208
}
209
210
int bench_uprobe_trace_printk_ret(int argc, const char **argv)
211
{
212
return bench_uprobe(argc, argv, BENCH_UPROBE__TRACE_PRINTK_RET);
213
}
214
215