diff options
Diffstat (limited to 'tools/perf/bench')
-rw-r--r-- | tools/perf/bench/Build | 1 | ||||
-rw-r--r-- | tools/perf/bench/bench.h | 2 | ||||
-rw-r--r-- | tools/perf/bench/find-bit-bench.c | 8 | ||||
-rw-r--r-- | tools/perf/bench/inject-buildid.c | 3 | ||||
-rw-r--r-- | tools/perf/bench/numa.c | 2 | ||||
-rw-r--r-- | tools/perf/bench/pmu-scan.c | 184 | ||||
-rw-r--r-- | tools/perf/bench/syscall.c | 35 |
7 files changed, 231 insertions, 4 deletions
diff --git a/tools/perf/bench/Build b/tools/perf/bench/Build index 6b6155a8ad09..0f158dc8139b 100644 --- a/tools/perf/bench/Build +++ b/tools/perf/bench/Build @@ -15,6 +15,7 @@ perf-y += find-bit-bench.o perf-y += inject-buildid.o perf-y += evlist-open-close.o perf-y += breakpoint.o +perf-y += pmu-scan.o perf-$(CONFIG_X86_64) += mem-memcpy-x86-64-asm.o perf-$(CONFIG_X86_64) += mem-memset-x86-64-asm.o diff --git a/tools/perf/bench/bench.h b/tools/perf/bench/bench.h index e43893151a3e..0d2b65976212 100644 --- a/tools/perf/bench/bench.h +++ b/tools/perf/bench/bench.h @@ -23,6 +23,7 @@ int bench_sched_messaging(int argc, const char **argv); int bench_sched_pipe(int argc, const char **argv); int bench_syscall_basic(int argc, const char **argv); int bench_syscall_getpgid(int argc, const char **argv); +int bench_syscall_fork(int argc, const char **argv); int bench_syscall_execve(int argc, const char **argv); int bench_mem_memcpy(int argc, const char **argv); int bench_mem_memset(int argc, const char **argv); @@ -41,6 +42,7 @@ int bench_inject_build_id(int argc, const char **argv); int bench_evlist_open_close(int argc, const char **argv); int bench_breakpoint_thread(int argc, const char **argv); int bench_breakpoint_enable(int argc, const char **argv); +int bench_pmu_scan(int argc, const char **argv); #define BENCH_FORMAT_DEFAULT_STR "default" #define BENCH_FORMAT_DEFAULT 0 diff --git a/tools/perf/bench/find-bit-bench.c b/tools/perf/bench/find-bit-bench.c index d103c3136983..7e25b0e413f6 100644 --- a/tools/perf/bench/find-bit-bench.c +++ b/tools/perf/bench/find-bit-bench.c @@ -61,7 +61,6 @@ static int do_for_each_set_bit(unsigned int num_bits) double time_average, time_stddev; unsigned int bit, i, j; unsigned int set_bits, skip; - unsigned int old; init_stats(&fb_time_stats); init_stats(&tb_time_stats); @@ -73,7 +72,10 @@ static int do_for_each_set_bit(unsigned int num_bits) __set_bit(i, to_test); for (i = 0; i < outer_iterations; i++) { - old = accumulator; +#ifndef NDEBUG + unsigned int old = accumulator; +#endif + gettimeofday(&start, NULL); for (j = 0; j < inner_iterations; j++) { for_each_set_bit(bit, to_test, num_bits) @@ -85,7 +87,9 @@ static int do_for_each_set_bit(unsigned int num_bits) runtime_us = diff.tv_sec * USEC_PER_SEC + diff.tv_usec; update_stats(&fb_time_stats, runtime_us); +#ifndef NDEBUG old = accumulator; +#endif gettimeofday(&start, NULL); for (j = 0; j < inner_iterations; j++) { for (bit = 0; bit < num_bits; bit++) { diff --git a/tools/perf/bench/inject-buildid.c b/tools/perf/bench/inject-buildid.c index 4561bda0ce6a..49331743c743 100644 --- a/tools/perf/bench/inject-buildid.c +++ b/tools/perf/bench/inject-buildid.c @@ -12,6 +12,7 @@ #include <linux/time64.h> #include <linux/list.h> #include <linux/err.h> +#include <linux/zalloc.h> #include <internal/lib.h> #include <subcmd/parse-options.h> @@ -122,7 +123,7 @@ static void release_dso(void) for (i = 0; i < nr_dsos; i++) { struct bench_dso *dso = &dsos[i]; - free(dso->name); + zfree(&dso->name); } free(dsos); } diff --git a/tools/perf/bench/numa.c b/tools/perf/bench/numa.c index 9717c6c17433..1fbd7c947abc 100644 --- a/tools/perf/bench/numa.c +++ b/tools/perf/bench/numa.c @@ -847,7 +847,7 @@ static u64 do_work(u8 *__data, long bytes, int nr, int nr_max, int loop, u64 val if (g->p.data_rand_walk) { u32 lfsr = nr + loop + val; - int j; + long j; for (i = 0; i < words/1024; i++) { long start, end; diff --git a/tools/perf/bench/pmu-scan.c b/tools/perf/bench/pmu-scan.c new file mode 100644 index 000000000000..f0f007843bb8 --- /dev/null +++ b/tools/perf/bench/pmu-scan.c @@ -0,0 +1,184 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Benchmark scanning sysfs files for PMU information. + * + * Copyright 2023 Google LLC. + */ +#include <stdio.h> +#include "bench.h" +#include "util/debug.h" +#include "util/pmu.h" +#include "util/pmus.h" +#include "util/stat.h" +#include <linux/atomic.h> +#include <linux/err.h> +#include <linux/time64.h> +#include <subcmd/parse-options.h> + +static unsigned int iterations = 100; + +struct pmu_scan_result { + char *name; + int nr_aliases; + int nr_formats; + int nr_caps; +}; + +static const struct option options[] = { + OPT_UINTEGER('i', "iterations", &iterations, + "Number of iterations used to compute average"), + OPT_END() +}; + +static const char *const bench_usage[] = { + "perf bench internals pmu-scan <options>", + NULL +}; + +static int nr_pmus; +static struct pmu_scan_result *results; + +static int save_result(void) +{ + struct perf_pmu *pmu; + struct list_head *list; + struct pmu_scan_result *r; + + perf_pmu__scan(NULL); + + perf_pmus__for_each_pmu(pmu) { + r = realloc(results, (nr_pmus + 1) * sizeof(*r)); + if (r == NULL) + return -ENOMEM; + + results = r; + r = results + nr_pmus; + + r->name = strdup(pmu->name); + r->nr_caps = pmu->nr_caps; + + r->nr_aliases = 0; + list_for_each(list, &pmu->aliases) + r->nr_aliases++; + + r->nr_formats = 0; + list_for_each(list, &pmu->format) + r->nr_formats++; + + pr_debug("pmu[%d] name=%s, nr_caps=%d, nr_aliases=%d, nr_formats=%d\n", + nr_pmus, r->name, r->nr_caps, r->nr_aliases, r->nr_formats); + nr_pmus++; + } + + perf_pmu__destroy(); + return 0; +} + +static int check_result(void) +{ + struct pmu_scan_result *r; + struct perf_pmu *pmu; + struct list_head *list; + int nr; + + for (int i = 0; i < nr_pmus; i++) { + r = &results[i]; + pmu = perf_pmu__find(r->name); + if (pmu == NULL) { + pr_err("Cannot find PMU %s\n", r->name); + return -1; + } + + if (pmu->nr_caps != (u32)r->nr_caps) { + pr_err("Unmatched number of event caps in %s: expect %d vs got %d\n", + pmu->name, r->nr_caps, pmu->nr_caps); + return -1; + } + + nr = 0; + list_for_each(list, &pmu->aliases) + nr++; + if (nr != r->nr_aliases) { + pr_err("Unmatched number of event aliases in %s: expect %d vs got %d\n", + pmu->name, r->nr_aliases, nr); + return -1; + } + + nr = 0; + list_for_each(list, &pmu->format) + nr++; + if (nr != r->nr_formats) { + pr_err("Unmatched number of event formats in %s: expect %d vs got %d\n", + pmu->name, r->nr_formats, nr); + return -1; + } + } + return 0; +} + +static void delete_result(void) +{ + for (int i = 0; i < nr_pmus; i++) + free(results[i].name); + free(results); + + results = NULL; + nr_pmus = 0; +} + +static int run_pmu_scan(void) +{ + struct stats stats; + struct timeval start, end, diff; + double time_average, time_stddev; + u64 runtime_us; + unsigned int i; + int ret; + + init_stats(&stats); + pr_info("Computing performance of sysfs PMU event scan for %u times\n", + iterations); + + if (save_result() < 0) { + pr_err("Failed to initialize PMU scan result\n"); + return -1; + } + + for (i = 0; i < iterations; i++) { + gettimeofday(&start, NULL); + perf_pmu__scan(NULL); + gettimeofday(&end, NULL); + + timersub(&end, &start, &diff); + runtime_us = diff.tv_sec * USEC_PER_SEC + diff.tv_usec; + update_stats(&stats, runtime_us); + + ret = check_result(); + perf_pmu__destroy(); + if (ret < 0) + break; + } + + time_average = avg_stats(&stats); + time_stddev = stddev_stats(&stats); + pr_info(" Average PMU scanning took: %.3f usec (+- %.3f usec)\n", + time_average, time_stddev); + + delete_result(); + return 0; +} + +int bench_pmu_scan(int argc, const char **argv) +{ + int err = 0; + + argc = parse_options(argc, argv, options, bench_usage, 0); + if (argc) { + usage_with_options(bench_usage, options); + exit(EXIT_FAILURE); + } + + err = run_pmu_scan(); + + return err; +} diff --git a/tools/perf/bench/syscall.c b/tools/perf/bench/syscall.c index fe79f7f3091e..ea4dfc07cbd6 100644 --- a/tools/perf/bench/syscall.c +++ b/tools/perf/bench/syscall.c @@ -18,6 +18,10 @@ #include <unistd.h> #include <stdlib.h> +#ifndef __NR_fork +#define __NR_fork -1 +#endif + #define LOOPS_DEFAULT 10000000 static int loops = LOOPS_DEFAULT; @@ -31,6 +35,23 @@ static const char * const bench_syscall_usage[] = { NULL }; +static void test_fork(void) +{ + pid_t pid = fork(); + + if (pid < 0) { + fprintf(stderr, "fork failed\n"); + exit(1); + } else if (pid == 0) { + exit(0); + } else { + if (waitpid(pid, NULL, 0) < 0) { + fprintf(stderr, "waitpid failed\n"); + exit(1); + } + } +} + static void test_execve(void) { const char *pathname = "/bin/true"; @@ -71,6 +92,12 @@ static int bench_syscall_common(int argc, const char **argv, int syscall) case __NR_getpgid: getpgid(0); break; + case __NR_fork: + test_fork(); + /* Only loop 10000 times to save time */ + if (i == 10000) + loops = 10000; + break; case __NR_execve: test_execve(); /* Only loop 10000 times to save time */ @@ -92,6 +119,9 @@ static int bench_syscall_common(int argc, const char **argv, int syscall) case __NR_getpgid: name = "getpgid()"; break; + case __NR_fork: + name = "fork()"; + break; case __NR_execve: name = "execve()"; break; @@ -143,6 +173,11 @@ int bench_syscall_getpgid(int argc, const char **argv) return bench_syscall_common(argc, argv, __NR_getpgid); } +int bench_syscall_fork(int argc, const char **argv) +{ + return bench_syscall_common(argc, argv, __NR_fork); +} + int bench_syscall_execve(int argc, const char **argv) { return bench_syscall_common(argc, argv, __NR_execve); |