Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v6.16 269 lines 6.8 kB view raw
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 24static int iterations = 100; 25static int nr_events = 1; 26static const char *event_string = "dummy"; 27 28static inline u64 timeval2usec(struct timeval *tv) 29{ 30 return tv->tv_sec * USEC_PER_SEC + tv->tv_usec; 31} 32 33static 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 49static 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 60static struct evlist *bench__create_evlist(char *evstr) 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 ret = evlist__create_maps(evlist, &opts.target); 82 if (ret < 0) { 83 pr_err("Not enough memory to create thread/cpu maps\n"); 84 goto out_delete_evlist; 85 } 86 87 evlist__config(evlist, &opts, NULL); 88 89 return evlist; 90 91out_delete_evlist: 92 evlist__delete(evlist); 93 return NULL; 94} 95 96static int bench__do_evlist_open_close(struct evlist *evlist) 97{ 98 char sbuf[STRERR_BUFSIZE]; 99 int err = evlist__open(evlist); 100 101 if (err < 0) { 102 pr_err("evlist__open: %s\n", str_error_r(errno, sbuf, sizeof(sbuf))); 103 return err; 104 } 105 106 err = evlist__mmap(evlist, opts.mmap_pages); 107 if (err < 0) { 108 pr_err("evlist__mmap: %s\n", str_error_r(errno, sbuf, sizeof(sbuf))); 109 return err; 110 } 111 112 evlist__enable(evlist); 113 evlist__disable(evlist); 114 evlist__munmap(evlist); 115 evlist__close(evlist); 116 117 return 0; 118} 119 120static int bench_evlist_open_close__run(char *evstr) 121{ 122 // used to print statistics only 123 struct evlist *evlist = bench__create_evlist(evstr); 124 double time_average, time_stddev; 125 struct timeval start, end, diff; 126 struct stats time_stats; 127 u64 runtime_us; 128 int i, err; 129 130 if (!evlist) 131 return -ENOMEM; 132 133 init_stats(&time_stats); 134 135 printf(" Number of cpus:\t%d\n", perf_cpu_map__nr(evlist->core.user_requested_cpus)); 136 printf(" Number of threads:\t%d\n", evlist->core.threads->nr); 137 printf(" Number of events:\t%d (%d fds)\n", 138 evlist->core.nr_entries, evlist__count_evsel_fds(evlist)); 139 printf(" Number of iterations:\t%d\n", iterations); 140 141 evlist__delete(evlist); 142 143 for (i = 0; i < iterations; i++) { 144 pr_debug("Started iteration %d\n", i); 145 evlist = bench__create_evlist(evstr); 146 if (!evlist) 147 return -ENOMEM; 148 149 gettimeofday(&start, NULL); 150 err = bench__do_evlist_open_close(evlist); 151 if (err) { 152 evlist__delete(evlist); 153 return err; 154 } 155 156 gettimeofday(&end, NULL); 157 timersub(&end, &start, &diff); 158 runtime_us = timeval2usec(&diff); 159 update_stats(&time_stats, runtime_us); 160 161 evlist__delete(evlist); 162 pr_debug("Iteration %d took:\t%" PRIu64 "us\n", i, runtime_us); 163 } 164 165 time_average = avg_stats(&time_stats); 166 time_stddev = stddev_stats(&time_stats); 167 printf(" Average open-close took: %.3f usec (+- %.3f usec)\n", time_average, time_stddev); 168 169 return 0; 170} 171 172static char *bench__repeat_event_string(const char *evstr, int n) 173{ 174 char sbuf[STRERR_BUFSIZE]; 175 struct strbuf buf; 176 int i, str_size = strlen(evstr), 177 final_size = str_size * n + n, 178 err = strbuf_init(&buf, final_size); 179 180 if (err) { 181 pr_err("strbuf_init: %s\n", str_error_r(err, sbuf, sizeof(sbuf))); 182 goto out_error; 183 } 184 185 for (i = 0; i < n; i++) { 186 err = strbuf_add(&buf, evstr, str_size); 187 if (err) { 188 pr_err("strbuf_add: %s\n", str_error_r(err, sbuf, sizeof(sbuf))); 189 goto out_error; 190 } 191 192 err = strbuf_addch(&buf, i == n-1 ? '\0' : ','); 193 if (err) { 194 pr_err("strbuf_addch: %s\n", str_error_r(err, sbuf, sizeof(sbuf))); 195 goto out_error; 196 } 197 } 198 199 return strbuf_detach(&buf, NULL); 200 201out_error: 202 strbuf_release(&buf); 203 return NULL; 204} 205 206 207int bench_evlist_open_close(int argc, const char **argv) 208{ 209 const struct option options[] = { 210 OPT_STRING('e', "event", &event_string, "event", 211 "event selector. use 'perf list' to list available events"), 212 OPT_INTEGER('n', "nr-events", &nr_events, 213 "number of dummy events to create (default 1). If used with -e, it clones those events n times (1 = no change)"), 214 OPT_INTEGER('i', "iterations", &iterations, 215 "Number of iterations used to compute average (default=100)"), 216 OPT_BOOLEAN('a', "all-cpus", &opts.target.system_wide, 217 "system-wide collection from all CPUs"), 218 OPT_STRING('C', "cpu", &opts.target.cpu_list, "cpu", 219 "list of cpus where to open events"), 220 OPT_STRING('p', "pid", &opts.target.pid, "pid", 221 "record events on existing process id"), 222 OPT_STRING('t', "tid", &opts.target.tid, "tid", 223 "record events on existing thread id"), 224 OPT_STRING('u', "uid", &opts.target.uid_str, "user", "user to profile"), 225 OPT_BOOLEAN(0, "per-thread", &opts.target.per_thread, "use per-thread mmaps"), 226 OPT_END() 227 }; 228 const char *const bench_usage[] = { 229 "perf bench internals evlist-open-close <options>", 230 NULL 231 }; 232 char *evstr, errbuf[BUFSIZ]; 233 int err; 234 235 argc = parse_options(argc, argv, options, bench_usage, 0); 236 if (argc) { 237 usage_with_options(bench_usage, options); 238 exit(EXIT_FAILURE); 239 } 240 241 err = target__validate(&opts.target); 242 if (err) { 243 target__strerror(&opts.target, err, errbuf, sizeof(errbuf)); 244 pr_err("%s\n", errbuf); 245 goto out; 246 } 247 248 err = target__parse_uid(&opts.target); 249 if (err) { 250 target__strerror(&opts.target, err, errbuf, sizeof(errbuf)); 251 pr_err("%s", errbuf); 252 goto out; 253 } 254 255 /* Enable ignoring missing threads when -u/-p option is defined. */ 256 opts.ignore_missing_thread = opts.target.uid != UINT_MAX || opts.target.pid; 257 258 evstr = bench__repeat_event_string(event_string, nr_events); 259 if (!evstr) { 260 err = -ENOMEM; 261 goto out; 262 } 263 264 err = bench_evlist_open_close__run(evstr); 265 266 free(evstr); 267out: 268 return err; 269}