xref: /linux/tools/perf/bench/pmu-scan.c (revision f6a7bbbfe61cc34c4e443141d3eb110a80473d8c)
1*f6a7bbbfSNamhyung Kim // SPDX-License-Identifier: GPL-2.0
2*f6a7bbbfSNamhyung Kim /*
3*f6a7bbbfSNamhyung Kim  * Benchmark scanning sysfs files for PMU information.
4*f6a7bbbfSNamhyung Kim  *
5*f6a7bbbfSNamhyung Kim  * Copyright 2023 Google LLC.
6*f6a7bbbfSNamhyung Kim  */
7*f6a7bbbfSNamhyung Kim #include <stdio.h>
8*f6a7bbbfSNamhyung Kim #include "bench.h"
9*f6a7bbbfSNamhyung Kim #include "util/debug.h"
10*f6a7bbbfSNamhyung Kim #include "util/pmu.h"
11*f6a7bbbfSNamhyung Kim #include "util/pmus.h"
12*f6a7bbbfSNamhyung Kim #include "util/stat.h"
13*f6a7bbbfSNamhyung Kim #include <linux/atomic.h>
14*f6a7bbbfSNamhyung Kim #include <linux/err.h>
15*f6a7bbbfSNamhyung Kim #include <linux/time64.h>
16*f6a7bbbfSNamhyung Kim #include <subcmd/parse-options.h>
17*f6a7bbbfSNamhyung Kim 
18*f6a7bbbfSNamhyung Kim static unsigned int iterations = 100;
19*f6a7bbbfSNamhyung Kim 
20*f6a7bbbfSNamhyung Kim struct pmu_scan_result {
21*f6a7bbbfSNamhyung Kim 	char *name;
22*f6a7bbbfSNamhyung Kim 	int nr_aliases;
23*f6a7bbbfSNamhyung Kim 	int nr_formats;
24*f6a7bbbfSNamhyung Kim 	int nr_caps;
25*f6a7bbbfSNamhyung Kim };
26*f6a7bbbfSNamhyung Kim 
27*f6a7bbbfSNamhyung Kim static const struct option options[] = {
28*f6a7bbbfSNamhyung Kim 	OPT_UINTEGER('i', "iterations", &iterations,
29*f6a7bbbfSNamhyung Kim 		"Number of iterations used to compute average"),
30*f6a7bbbfSNamhyung Kim 	OPT_END()
31*f6a7bbbfSNamhyung Kim };
32*f6a7bbbfSNamhyung Kim 
33*f6a7bbbfSNamhyung Kim static const char *const bench_usage[] = {
34*f6a7bbbfSNamhyung Kim 	"perf bench internals pmu-scan <options>",
35*f6a7bbbfSNamhyung Kim 	NULL
36*f6a7bbbfSNamhyung Kim };
37*f6a7bbbfSNamhyung Kim 
38*f6a7bbbfSNamhyung Kim static int nr_pmus;
39*f6a7bbbfSNamhyung Kim static struct pmu_scan_result *results;
40*f6a7bbbfSNamhyung Kim 
41*f6a7bbbfSNamhyung Kim static int save_result(void)
42*f6a7bbbfSNamhyung Kim {
43*f6a7bbbfSNamhyung Kim 	struct perf_pmu *pmu;
44*f6a7bbbfSNamhyung Kim 	struct list_head *list;
45*f6a7bbbfSNamhyung Kim 	struct pmu_scan_result *r;
46*f6a7bbbfSNamhyung Kim 
47*f6a7bbbfSNamhyung Kim 	perf_pmu__scan(NULL);
48*f6a7bbbfSNamhyung Kim 
49*f6a7bbbfSNamhyung Kim 	perf_pmus__for_each_pmu(pmu) {
50*f6a7bbbfSNamhyung Kim 		r = realloc(results, (nr_pmus + 1) * sizeof(*r));
51*f6a7bbbfSNamhyung Kim 		if (r == NULL)
52*f6a7bbbfSNamhyung Kim 			return -ENOMEM;
53*f6a7bbbfSNamhyung Kim 
54*f6a7bbbfSNamhyung Kim 		results = r;
55*f6a7bbbfSNamhyung Kim 		r = results + nr_pmus;
56*f6a7bbbfSNamhyung Kim 
57*f6a7bbbfSNamhyung Kim 		r->name = strdup(pmu->name);
58*f6a7bbbfSNamhyung Kim 		r->nr_caps = pmu->nr_caps;
59*f6a7bbbfSNamhyung Kim 
60*f6a7bbbfSNamhyung Kim 		r->nr_aliases = 0;
61*f6a7bbbfSNamhyung Kim 		list_for_each(list, &pmu->aliases)
62*f6a7bbbfSNamhyung Kim 			r->nr_aliases++;
63*f6a7bbbfSNamhyung Kim 
64*f6a7bbbfSNamhyung Kim 		r->nr_formats = 0;
65*f6a7bbbfSNamhyung Kim 		list_for_each(list, &pmu->format)
66*f6a7bbbfSNamhyung Kim 			r->nr_formats++;
67*f6a7bbbfSNamhyung Kim 
68*f6a7bbbfSNamhyung Kim 		pr_debug("pmu[%d] name=%s, nr_caps=%d, nr_aliases=%d, nr_formats=%d\n",
69*f6a7bbbfSNamhyung Kim 			nr_pmus, r->name, r->nr_caps, r->nr_aliases, r->nr_formats);
70*f6a7bbbfSNamhyung Kim 		nr_pmus++;
71*f6a7bbbfSNamhyung Kim 	}
72*f6a7bbbfSNamhyung Kim 
73*f6a7bbbfSNamhyung Kim 	perf_pmu__destroy();
74*f6a7bbbfSNamhyung Kim 	return 0;
75*f6a7bbbfSNamhyung Kim }
76*f6a7bbbfSNamhyung Kim 
77*f6a7bbbfSNamhyung Kim static int check_result(void)
78*f6a7bbbfSNamhyung Kim {
79*f6a7bbbfSNamhyung Kim 	struct pmu_scan_result *r;
80*f6a7bbbfSNamhyung Kim 	struct perf_pmu *pmu;
81*f6a7bbbfSNamhyung Kim 	struct list_head *list;
82*f6a7bbbfSNamhyung Kim 	int nr;
83*f6a7bbbfSNamhyung Kim 
84*f6a7bbbfSNamhyung Kim 	for (int i = 0; i < nr_pmus; i++) {
85*f6a7bbbfSNamhyung Kim 		r = &results[i];
86*f6a7bbbfSNamhyung Kim 		pmu = perf_pmu__find(r->name);
87*f6a7bbbfSNamhyung Kim 		if (pmu == NULL) {
88*f6a7bbbfSNamhyung Kim 			pr_err("Cannot find PMU %s\n", r->name);
89*f6a7bbbfSNamhyung Kim 			return -1;
90*f6a7bbbfSNamhyung Kim 		}
91*f6a7bbbfSNamhyung Kim 
92*f6a7bbbfSNamhyung Kim 		if (pmu->nr_caps != (u32)r->nr_caps) {
93*f6a7bbbfSNamhyung Kim 			pr_err("Unmatched number of event caps in %s: expect %d vs got %d\n",
94*f6a7bbbfSNamhyung Kim 				pmu->name, r->nr_caps, pmu->nr_caps);
95*f6a7bbbfSNamhyung Kim 			return -1;
96*f6a7bbbfSNamhyung Kim 		}
97*f6a7bbbfSNamhyung Kim 
98*f6a7bbbfSNamhyung Kim 		nr = 0;
99*f6a7bbbfSNamhyung Kim 		list_for_each(list, &pmu->aliases)
100*f6a7bbbfSNamhyung Kim 			nr++;
101*f6a7bbbfSNamhyung Kim 		if (nr != r->nr_aliases) {
102*f6a7bbbfSNamhyung Kim 			pr_err("Unmatched number of event aliases in %s: expect %d vs got %d\n",
103*f6a7bbbfSNamhyung Kim 				pmu->name, r->nr_aliases, nr);
104*f6a7bbbfSNamhyung Kim 			return -1;
105*f6a7bbbfSNamhyung Kim 		}
106*f6a7bbbfSNamhyung Kim 
107*f6a7bbbfSNamhyung Kim 		nr = 0;
108*f6a7bbbfSNamhyung Kim 		list_for_each(list, &pmu->format)
109*f6a7bbbfSNamhyung Kim 			nr++;
110*f6a7bbbfSNamhyung Kim 		if (nr != r->nr_formats) {
111*f6a7bbbfSNamhyung Kim 			pr_err("Unmatched number of event formats in %s: expect %d vs got %d\n",
112*f6a7bbbfSNamhyung Kim 				pmu->name, r->nr_formats, nr);
113*f6a7bbbfSNamhyung Kim 			return -1;
114*f6a7bbbfSNamhyung Kim 		}
115*f6a7bbbfSNamhyung Kim 	}
116*f6a7bbbfSNamhyung Kim 	return 0;
117*f6a7bbbfSNamhyung Kim }
118*f6a7bbbfSNamhyung Kim 
119*f6a7bbbfSNamhyung Kim static void delete_result(void)
120*f6a7bbbfSNamhyung Kim {
121*f6a7bbbfSNamhyung Kim 	for (int i = 0; i < nr_pmus; i++)
122*f6a7bbbfSNamhyung Kim 		free(results[i].name);
123*f6a7bbbfSNamhyung Kim 	free(results);
124*f6a7bbbfSNamhyung Kim 
125*f6a7bbbfSNamhyung Kim 	results = NULL;
126*f6a7bbbfSNamhyung Kim 	nr_pmus = 0;
127*f6a7bbbfSNamhyung Kim }
128*f6a7bbbfSNamhyung Kim 
129*f6a7bbbfSNamhyung Kim static int run_pmu_scan(void)
130*f6a7bbbfSNamhyung Kim {
131*f6a7bbbfSNamhyung Kim 	struct stats stats;
132*f6a7bbbfSNamhyung Kim 	struct timeval start, end, diff;
133*f6a7bbbfSNamhyung Kim 	double time_average, time_stddev;
134*f6a7bbbfSNamhyung Kim 	u64 runtime_us;
135*f6a7bbbfSNamhyung Kim 	unsigned int i;
136*f6a7bbbfSNamhyung Kim 	int ret;
137*f6a7bbbfSNamhyung Kim 
138*f6a7bbbfSNamhyung Kim 	init_stats(&stats);
139*f6a7bbbfSNamhyung Kim 	pr_info("Computing performance of sysfs PMU event scan for %u times\n",
140*f6a7bbbfSNamhyung Kim 		iterations);
141*f6a7bbbfSNamhyung Kim 
142*f6a7bbbfSNamhyung Kim 	if (save_result() < 0) {
143*f6a7bbbfSNamhyung Kim 		pr_err("Failed to initialize PMU scan result\n");
144*f6a7bbbfSNamhyung Kim 		return -1;
145*f6a7bbbfSNamhyung Kim 	}
146*f6a7bbbfSNamhyung Kim 
147*f6a7bbbfSNamhyung Kim 	for (i = 0; i < iterations; i++) {
148*f6a7bbbfSNamhyung Kim 		gettimeofday(&start, NULL);
149*f6a7bbbfSNamhyung Kim 		perf_pmu__scan(NULL);
150*f6a7bbbfSNamhyung Kim 		gettimeofday(&end, NULL);
151*f6a7bbbfSNamhyung Kim 
152*f6a7bbbfSNamhyung Kim 		timersub(&end, &start, &diff);
153*f6a7bbbfSNamhyung Kim 		runtime_us = diff.tv_sec * USEC_PER_SEC + diff.tv_usec;
154*f6a7bbbfSNamhyung Kim 		update_stats(&stats, runtime_us);
155*f6a7bbbfSNamhyung Kim 
156*f6a7bbbfSNamhyung Kim 		ret = check_result();
157*f6a7bbbfSNamhyung Kim 		perf_pmu__destroy();
158*f6a7bbbfSNamhyung Kim 		if (ret < 0)
159*f6a7bbbfSNamhyung Kim 			break;
160*f6a7bbbfSNamhyung Kim 	}
161*f6a7bbbfSNamhyung Kim 
162*f6a7bbbfSNamhyung Kim 	time_average = avg_stats(&stats);
163*f6a7bbbfSNamhyung Kim 	time_stddev = stddev_stats(&stats);
164*f6a7bbbfSNamhyung Kim 	pr_info("  Average PMU scanning took: %.3f usec (+- %.3f usec)\n",
165*f6a7bbbfSNamhyung Kim 		time_average, time_stddev);
166*f6a7bbbfSNamhyung Kim 
167*f6a7bbbfSNamhyung Kim 	delete_result();
168*f6a7bbbfSNamhyung Kim 	return 0;
169*f6a7bbbfSNamhyung Kim }
170*f6a7bbbfSNamhyung Kim 
171*f6a7bbbfSNamhyung Kim int bench_pmu_scan(int argc, const char **argv)
172*f6a7bbbfSNamhyung Kim {
173*f6a7bbbfSNamhyung Kim 	int err = 0;
174*f6a7bbbfSNamhyung Kim 
175*f6a7bbbfSNamhyung Kim 	argc = parse_options(argc, argv, options, bench_usage, 0);
176*f6a7bbbfSNamhyung Kim 	if (argc) {
177*f6a7bbbfSNamhyung Kim 		usage_with_options(bench_usage, options);
178*f6a7bbbfSNamhyung Kim 		exit(EXIT_FAILURE);
179*f6a7bbbfSNamhyung Kim 	}
180*f6a7bbbfSNamhyung Kim 
181*f6a7bbbfSNamhyung Kim 	err = run_pmu_scan();
182*f6a7bbbfSNamhyung Kim 
183*f6a7bbbfSNamhyung Kim 	return err;
184*f6a7bbbfSNamhyung Kim }
185