1 // SPDX-License-Identifier: GPL-2.0
3 * Benchmark scanning sysfs files for PMU information.
5 * Copyright 2023 Google LLC.
9 #include "util/debug.h"
11 #include "util/pmus.h"
12 #include "util/stat.h"
13 #include <linux/atomic.h>
14 #include <linux/err.h>
15 #include <linux/time64.h>
16 #include <subcmd/parse-options.h>
18 static unsigned int iterations
= 100;
20 struct pmu_scan_result
{
28 static const struct option options
[] = {
29 OPT_UINTEGER('i', "iterations", &iterations
,
30 "Number of iterations used to compute average"),
34 static const char *const bench_usage
[] = {
35 "perf bench internals pmu-scan <options>",
40 static struct pmu_scan_result
*results
;
42 static int save_result(void)
44 struct perf_pmu
*pmu
= NULL
;
45 struct list_head
*list
;
46 struct pmu_scan_result
*r
;
48 while ((pmu
= perf_pmus__scan(pmu
)) != NULL
) {
49 r
= realloc(results
, (nr_pmus
+ 1) * sizeof(*r
));
54 r
= results
+ nr_pmus
;
56 r
->name
= strdup(pmu
->name
);
57 r
->is_core
= pmu
->is_core
;
58 r
->nr_caps
= pmu
->nr_caps
;
60 r
->nr_aliases
= perf_pmu__num_events(pmu
);
63 list_for_each(list
, &pmu
->format
)
66 pr_debug("pmu[%d] name=%s, nr_caps=%d, nr_aliases=%d, nr_formats=%d\n",
67 nr_pmus
, r
->name
, r
->nr_caps
, r
->nr_aliases
, r
->nr_formats
);
75 static int check_result(bool core_only
)
77 struct pmu_scan_result
*r
;
79 struct list_head
*list
;
82 for (int i
= 0; i
< nr_pmus
; i
++) {
84 if (core_only
&& !r
->is_core
)
87 pmu
= perf_pmus__find(r
->name
);
89 pr_err("Cannot find PMU %s\n", r
->name
);
93 if (pmu
->nr_caps
!= (u32
)r
->nr_caps
) {
94 pr_err("Unmatched number of event caps in %s: expect %d vs got %d\n",
95 pmu
->name
, r
->nr_caps
, pmu
->nr_caps
);
99 nr
= perf_pmu__num_events(pmu
);
100 if (nr
!= r
->nr_aliases
) {
101 pr_err("Unmatched number of event aliases in %s: expect %d vs got %d\n",
102 pmu
->name
, r
->nr_aliases
, nr
);
107 list_for_each(list
, &pmu
->format
)
109 if (nr
!= r
->nr_formats
) {
110 pr_err("Unmatched number of event formats in %s: expect %d vs got %d\n",
111 pmu
->name
, r
->nr_formats
, nr
);
118 static void delete_result(void)
120 for (int i
= 0; i
< nr_pmus
; i
++)
121 free(results
[i
].name
);
128 static int run_pmu_scan(void)
131 struct timeval start
, end
, diff
;
132 double time_average
, time_stddev
;
137 pr_info("Computing performance of sysfs PMU event scan for %u times\n",
140 if (save_result() < 0) {
141 pr_err("Failed to initialize PMU scan result\n");
145 for (int j
= 0; j
< 2; j
++) {
146 bool core_only
= (j
== 0);
148 for (unsigned int i
= 0; i
< iterations
; i
++) {
149 gettimeofday(&start
, NULL
);
151 perf_pmus__scan_core(NULL
);
153 perf_pmus__scan(NULL
);
154 gettimeofday(&end
, NULL
);
155 timersub(&end
, &start
, &diff
);
156 runtime_us
= diff
.tv_sec
* USEC_PER_SEC
+ diff
.tv_usec
;
157 update_stats(&stats
, runtime_us
);
159 ret
= check_result(core_only
);
160 perf_pmus__destroy();
164 time_average
= avg_stats(&stats
);
165 time_stddev
= stddev_stats(&stats
);
166 pr_info(" Average%s PMU scanning took: %.3f usec (+- %.3f usec)\n",
167 core_only
? " core" : "", time_average
, time_stddev
);
173 int bench_pmu_scan(int argc
, const char **argv
)
177 argc
= parse_options(argc
, argv
, options
, bench_usage
, 0);
179 usage_with_options(bench_usage
, options
);
183 err
= run_pmu_scan();