Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/tools/perf/bench/evlist-open-close.c
26285 views
1
// SPDX-License-Identifier: GPL-2.0
2
#include <inttypes.h>
3
#include <stdio.h>
4
#include <stdlib.h>
5
#include <limits.h>
6
#include "bench.h"
7
#include "../util/debug.h"
8
#include "../util/stat.h"
9
#include "../util/evlist.h"
10
#include "../util/evsel.h"
11
#include "../util/strbuf.h"
12
#include "../util/record.h"
13
#include "../util/parse-events.h"
14
#include "internal/threadmap.h"
15
#include "internal/cpumap.h"
16
#include <linux/perf_event.h>
17
#include <linux/kernel.h>
18
#include <linux/time64.h>
19
#include <linux/string.h>
20
#include <subcmd/parse-options.h>
21
22
#define MMAP_FLUSH_DEFAULT 1
23
24
static int iterations = 100;
25
static int nr_events = 1;
26
static const char *event_string = "dummy";
27
28
static inline u64 timeval2usec(struct timeval *tv)
29
{
30
return tv->tv_sec * USEC_PER_SEC + tv->tv_usec;
31
}
32
33
static struct record_opts opts = {
34
.sample_time = true,
35
.mmap_pages = UINT_MAX,
36
.user_freq = UINT_MAX,
37
.user_interval = ULLONG_MAX,
38
.freq = 4000,
39
.target = {
40
.uses_mmap = true,
41
.default_per_cpu = true,
42
},
43
.mmap_flush = MMAP_FLUSH_DEFAULT,
44
.nr_threads_synthesize = 1,
45
.ctl_fd = -1,
46
.ctl_fd_ack = -1,
47
};
48
49
static int evlist__count_evsel_fds(struct evlist *evlist)
50
{
51
struct evsel *evsel;
52
int cnt = 0;
53
54
evlist__for_each_entry(evlist, evsel)
55
cnt += evsel->core.threads->nr * perf_cpu_map__nr(evsel->core.cpus);
56
57
return cnt;
58
}
59
60
static struct evlist *bench__create_evlist(char *evstr, const char *uid_str)
61
{
62
struct parse_events_error err;
63
struct evlist *evlist = evlist__new();
64
int ret;
65
66
if (!evlist) {
67
pr_err("Not enough memory to create evlist\n");
68
return NULL;
69
}
70
71
parse_events_error__init(&err);
72
ret = parse_events(evlist, evstr, &err);
73
if (ret) {
74
parse_events_error__print(&err, evstr);
75
parse_events_error__exit(&err);
76
pr_err("Run 'perf list' for a list of valid events\n");
77
ret = 1;
78
goto out_delete_evlist;
79
}
80
parse_events_error__exit(&err);
81
if (uid_str) {
82
uid_t uid = parse_uid(uid_str);
83
84
if (uid == UINT_MAX) {
85
pr_err("Invalid User: %s", uid_str);
86
ret = -EINVAL;
87
goto out_delete_evlist;
88
}
89
ret = parse_uid_filter(evlist, uid);
90
if (ret)
91
goto out_delete_evlist;
92
}
93
ret = evlist__create_maps(evlist, &opts.target);
94
if (ret < 0) {
95
pr_err("Not enough memory to create thread/cpu maps\n");
96
goto out_delete_evlist;
97
}
98
99
evlist__config(evlist, &opts, NULL);
100
101
return evlist;
102
103
out_delete_evlist:
104
evlist__delete(evlist);
105
return NULL;
106
}
107
108
static int bench__do_evlist_open_close(struct evlist *evlist)
109
{
110
char sbuf[STRERR_BUFSIZE];
111
int err = evlist__open(evlist);
112
113
if (err < 0) {
114
pr_err("evlist__open: %s\n", str_error_r(errno, sbuf, sizeof(sbuf)));
115
return err;
116
}
117
118
err = evlist__mmap(evlist, opts.mmap_pages);
119
if (err < 0) {
120
pr_err("evlist__mmap: %s\n", str_error_r(errno, sbuf, sizeof(sbuf)));
121
return err;
122
}
123
124
evlist__enable(evlist);
125
evlist__disable(evlist);
126
evlist__munmap(evlist);
127
evlist__close(evlist);
128
129
return 0;
130
}
131
132
static int bench_evlist_open_close__run(char *evstr, const char *uid_str)
133
{
134
// used to print statistics only
135
struct evlist *evlist = bench__create_evlist(evstr, uid_str);
136
double time_average, time_stddev;
137
struct timeval start, end, diff;
138
struct stats time_stats;
139
u64 runtime_us;
140
int i, err;
141
142
if (!evlist)
143
return -ENOMEM;
144
145
init_stats(&time_stats);
146
147
printf(" Number of cpus:\t%d\n", perf_cpu_map__nr(evlist->core.user_requested_cpus));
148
printf(" Number of threads:\t%d\n", evlist->core.threads->nr);
149
printf(" Number of events:\t%d (%d fds)\n",
150
evlist->core.nr_entries, evlist__count_evsel_fds(evlist));
151
printf(" Number of iterations:\t%d\n", iterations);
152
153
evlist__delete(evlist);
154
155
for (i = 0; i < iterations; i++) {
156
pr_debug("Started iteration %d\n", i);
157
evlist = bench__create_evlist(evstr, uid_str);
158
if (!evlist)
159
return -ENOMEM;
160
161
gettimeofday(&start, NULL);
162
err = bench__do_evlist_open_close(evlist);
163
if (err) {
164
evlist__delete(evlist);
165
return err;
166
}
167
168
gettimeofday(&end, NULL);
169
timersub(&end, &start, &diff);
170
runtime_us = timeval2usec(&diff);
171
update_stats(&time_stats, runtime_us);
172
173
evlist__delete(evlist);
174
pr_debug("Iteration %d took:\t%" PRIu64 "us\n", i, runtime_us);
175
}
176
177
time_average = avg_stats(&time_stats);
178
time_stddev = stddev_stats(&time_stats);
179
printf(" Average open-close took: %.3f usec (+- %.3f usec)\n", time_average, time_stddev);
180
181
return 0;
182
}
183
184
static char *bench__repeat_event_string(const char *evstr, int n)
185
{
186
char sbuf[STRERR_BUFSIZE];
187
struct strbuf buf;
188
int i, str_size = strlen(evstr),
189
final_size = str_size * n + n,
190
err = strbuf_init(&buf, final_size);
191
192
if (err) {
193
pr_err("strbuf_init: %s\n", str_error_r(err, sbuf, sizeof(sbuf)));
194
goto out_error;
195
}
196
197
for (i = 0; i < n; i++) {
198
err = strbuf_add(&buf, evstr, str_size);
199
if (err) {
200
pr_err("strbuf_add: %s\n", str_error_r(err, sbuf, sizeof(sbuf)));
201
goto out_error;
202
}
203
204
err = strbuf_addch(&buf, i == n-1 ? '\0' : ',');
205
if (err) {
206
pr_err("strbuf_addch: %s\n", str_error_r(err, sbuf, sizeof(sbuf)));
207
goto out_error;
208
}
209
}
210
211
return strbuf_detach(&buf, NULL);
212
213
out_error:
214
strbuf_release(&buf);
215
return NULL;
216
}
217
218
219
int bench_evlist_open_close(int argc, const char **argv)
220
{
221
const char *uid_str = NULL;
222
const struct option options[] = {
223
OPT_STRING('e', "event", &event_string, "event",
224
"event selector. use 'perf list' to list available events"),
225
OPT_INTEGER('n', "nr-events", &nr_events,
226
"number of dummy events to create (default 1). If used with -e, it clones those events n times (1 = no change)"),
227
OPT_INTEGER('i', "iterations", &iterations,
228
"Number of iterations used to compute average (default=100)"),
229
OPT_BOOLEAN('a', "all-cpus", &opts.target.system_wide,
230
"system-wide collection from all CPUs"),
231
OPT_STRING('C', "cpu", &opts.target.cpu_list, "cpu",
232
"list of cpus where to open events"),
233
OPT_STRING('p', "pid", &opts.target.pid, "pid",
234
"record events on existing process id"),
235
OPT_STRING('t', "tid", &opts.target.tid, "tid",
236
"record events on existing thread id"),
237
OPT_STRING('u', "uid", &uid_str, "user", "user to profile"),
238
OPT_BOOLEAN(0, "per-thread", &opts.target.per_thread, "use per-thread mmaps"),
239
OPT_END()
240
};
241
const char *const bench_usage[] = {
242
"perf bench internals evlist-open-close <options>",
243
NULL
244
};
245
char *evstr, errbuf[BUFSIZ];
246
int err;
247
248
argc = parse_options(argc, argv, options, bench_usage, 0);
249
if (argc) {
250
usage_with_options(bench_usage, options);
251
exit(EXIT_FAILURE);
252
}
253
254
err = target__validate(&opts.target);
255
if (err) {
256
target__strerror(&opts.target, err, errbuf, sizeof(errbuf));
257
pr_err("%s\n", errbuf);
258
goto out;
259
}
260
261
/* Enable ignoring missing threads when -p option is defined. */
262
opts.ignore_missing_thread = opts.target.pid;
263
264
evstr = bench__repeat_event_string(event_string, nr_events);
265
if (!evstr) {
266
err = -ENOMEM;
267
goto out;
268
}
269
270
err = bench_evlist_open_close__run(evstr, uid_str);
271
272
free(evstr);
273
out:
274
return err;
275
}
276
277