187 lines · c
1// SPDX-License-Identifier: GPL-2.02/*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 18static unsigned int iterations = 100;19 20struct pmu_scan_result {21 char *name;22 int nr_aliases;23 int nr_formats;24 int nr_caps;25 bool is_core;26};27 28static const struct option options[] = {29 OPT_UINTEGER('i', "iterations", &iterations,30 "Number of iterations used to compute average"),31 OPT_END()32};33 34static const char *const bench_usage[] = {35 "perf bench internals pmu-scan <options>",36 NULL37};38 39static int nr_pmus;40static struct pmu_scan_result *results;41 42static 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 75static 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 118static 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 128static 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 else153 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 173int 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}187