OSDN Git Service

Merge tag 'perf-urgent-2023-09-10' of git://git.kernel.org/pub/scm/linux/kernel/git...
[tomoyo/tomoyo-test1.git] / tools / perf / bench / pmu-scan.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 <stdio.h>
8 #include "bench.h"
9 #include "util/debug.h"
10 #include "util/pmu.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>
17
18 static unsigned int iterations = 100;
19
20 struct pmu_scan_result {
21         char *name;
22         int nr_aliases;
23         int nr_formats;
24         int nr_caps;
25         bool is_core;
26 };
27
28 static const struct option options[] = {
29         OPT_UINTEGER('i', "iterations", &iterations,
30                 "Number of iterations used to compute average"),
31         OPT_END()
32 };
33
34 static const char *const bench_usage[] = {
35         "perf bench internals pmu-scan <options>",
36         NULL
37 };
38
39 static int nr_pmus;
40 static struct pmu_scan_result *results;
41
42 static int save_result(void)
43 {
44         struct perf_pmu *pmu = NULL;
45         struct list_head *list;
46         struct pmu_scan_result *r;
47
48         while ((pmu = perf_pmus__scan(pmu)) != NULL) {
49                 r = realloc(results, (nr_pmus + 1) * sizeof(*r));
50                 if (r == NULL)
51                         return -ENOMEM;
52
53                 results = r;
54                 r = results + nr_pmus;
55
56                 r->name = strdup(pmu->name);
57                 r->is_core = pmu->is_core;
58                 r->nr_caps = pmu->nr_caps;
59
60                 r->nr_aliases = perf_pmu__num_events(pmu);
61
62                 r->nr_formats = 0;
63                 list_for_each(list, &pmu->format)
64                         r->nr_formats++;
65
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);
68                 nr_pmus++;
69         }
70
71         perf_pmus__destroy();
72         return 0;
73 }
74
75 static int check_result(bool core_only)
76 {
77         struct pmu_scan_result *r;
78         struct perf_pmu *pmu;
79         struct list_head *list;
80         int nr;
81
82         for (int i = 0; i < nr_pmus; i++) {
83                 r = &results[i];
84                 if (core_only && !r->is_core)
85                         continue;
86
87                 pmu = perf_pmus__find(r->name);
88                 if (pmu == NULL) {
89                         pr_err("Cannot find PMU %s\n", r->name);
90                         return -1;
91                 }
92
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);
96                         return -1;
97                 }
98
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);
103                         return -1;
104                 }
105
106                 nr = 0;
107                 list_for_each(list, &pmu->format)
108                         nr++;
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);
112                         return -1;
113                 }
114         }
115         return 0;
116 }
117
118 static void delete_result(void)
119 {
120         for (int i = 0; i < nr_pmus; i++)
121                 free(results[i].name);
122         free(results);
123
124         results = NULL;
125         nr_pmus = 0;
126 }
127
128 static int run_pmu_scan(void)
129 {
130         struct stats stats;
131         struct timeval start, end, diff;
132         double time_average, time_stddev;
133         u64 runtime_us;
134         int ret;
135
136         init_stats(&stats);
137         pr_info("Computing performance of sysfs PMU event scan for %u times\n",
138                 iterations);
139
140         if (save_result() < 0) {
141                 pr_err("Failed to initialize PMU scan result\n");
142                 return -1;
143         }
144
145         for (int j = 0; j < 2; j++) {
146                 bool core_only = (j == 0);
147
148                 for (unsigned int i = 0; i < iterations; i++) {
149                         gettimeofday(&start, NULL);
150                         if (core_only)
151                                 perf_pmus__scan_core(NULL);
152                         else
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);
158
159                         ret = check_result(core_only);
160                         perf_pmus__destroy();
161                         if (ret < 0)
162                                 break;
163                 }
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);
168         }
169         delete_result();
170         return 0;
171 }
172
173 int bench_pmu_scan(int argc, const char **argv)
174 {
175         int err = 0;
176
177         argc = parse_options(argc, argv, options, bench_usage, 0);
178         if (argc) {
179                 usage_with_options(bench_usage, options);
180                 exit(EXIT_FAILURE);
181         }
182
183         err = run_pmu_scan();
184
185         return err;
186 }