File Index
Files and directories
Sign in
FILE

pmu-scan.c

File preview with syntax highlighting.

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