diff options
Diffstat (limited to 'tools/perf/bench')
| -rw-r--r-- | tools/perf/bench/Build | 6 | ||||
| -rw-r--r-- | tools/perf/bench/bpf_skel/.gitignore | 4 | ||||
| -rw-r--r-- | tools/perf/bench/bpf_skel/bench_uprobe.bpf.c | 39 | ||||
| -rw-r--r-- | tools/perf/bench/breakpoint.c | 4 | ||||
| -rw-r--r-- | tools/perf/bench/evlist-open-close.c | 29 | ||||
| -rw-r--r-- | tools/perf/bench/inject-buildid.c | 9 | ||||
| -rw-r--r-- | tools/perf/bench/mem-functions.c | 111 | ||||
| -rw-r--r-- | tools/perf/bench/numa.c | 15 | ||||
| -rw-r--r-- | tools/perf/bench/sched-messaging.c | 2 | ||||
| -rw-r--r-- | tools/perf/bench/sched-pipe.c | 129 | ||||
| -rw-r--r-- | tools/perf/bench/uprobe.c | 4 |
11 files changed, 285 insertions, 67 deletions
diff --git a/tools/perf/bench/Build b/tools/perf/bench/Build index b558ab98719f..67b76fe20ba6 100644 --- a/tools/perf/bench/Build +++ b/tools/perf/bench/Build @@ -24,3 +24,9 @@ perf-bench-$(CONFIG_X86_64) += mem-memcpy-x86-64-asm.o perf-bench-$(CONFIG_X86_64) += mem-memset-x86-64-asm.o perf-bench-$(CONFIG_NUMA) += numa.o + +ifeq ($(CONFIG_PERF_BPF_SKEL),y) +include $(srctree)/tools/perf/bpf_skel.mak + +$(OUTPUT)bench/uprobe.o: $(SKEL_OUT)/bench_uprobe.skel.h +endif diff --git a/tools/perf/bench/bpf_skel/.gitignore b/tools/perf/bench/bpf_skel/.gitignore new file mode 100644 index 000000000000..cd01455e1b53 --- /dev/null +++ b/tools/perf/bench/bpf_skel/.gitignore @@ -0,0 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0-only +.tmp +*.skel.h +vmlinux.h diff --git a/tools/perf/bench/bpf_skel/bench_uprobe.bpf.c b/tools/perf/bench/bpf_skel/bench_uprobe.bpf.c new file mode 100644 index 000000000000..a01c7f791fcd --- /dev/null +++ b/tools/perf/bench/bpf_skel/bench_uprobe.bpf.c @@ -0,0 +1,39 @@ +// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +// Copyright (c) 2023 Red Hat +#include "vmlinux.h" +#include <bpf/bpf_tracing.h> + +unsigned int nr_uprobes; +unsigned int nr_uretprobes; + +SEC("uprobe") +int BPF_UPROBE(empty) +{ + return 0; +} + +SEC("uprobe") +int BPF_UPROBE(trace_printk) +{ + char fmt[] = "perf bench uprobe %u"; + + bpf_trace_printk(fmt, sizeof(fmt), ++nr_uprobes); + return 0; +} + +SEC("uretprobe") +int BPF_URETPROBE(empty_ret) +{ + return 0; +} + +SEC("uretprobe") +int BPF_URETPROBE(trace_printk_ret) +{ + char fmt[] = "perf bench uretprobe %u"; + + bpf_trace_printk(fmt, sizeof(fmt), ++nr_uretprobes); + return 0; +} + +char LICENSE[] SEC("license") = "Dual BSD/GPL"; diff --git a/tools/perf/bench/breakpoint.c b/tools/perf/bench/breakpoint.c index dfd18f5db97d..1b7cd4481bd2 100644 --- a/tools/perf/bench/breakpoint.c +++ b/tools/perf/bench/breakpoint.c @@ -16,7 +16,7 @@ #include "bench.h" #include "futex.h" -struct { +static struct { unsigned int nbreakpoints; unsigned int nparallel; unsigned int nthreads; @@ -173,7 +173,7 @@ int bench_breakpoint_thread(int argc, const char **argv) return 0; } -struct { +static struct { unsigned int npassive; unsigned int nactive; } enable_params = { diff --git a/tools/perf/bench/evlist-open-close.c b/tools/perf/bench/evlist-open-close.c index faf9c34b4a5d..748ebbe458f4 100644 --- a/tools/perf/bench/evlist-open-close.c +++ b/tools/perf/bench/evlist-open-close.c @@ -76,7 +76,7 @@ static struct evlist *bench__create_evlist(char *evstr, const char *uid_str) parse_events_error__exit(&err); pr_err("Run 'perf list' for a list of valid events\n"); ret = 1; - goto out_delete_evlist; + goto out_put_evlist; } parse_events_error__exit(&err); if (uid_str) { @@ -85,24 +85,24 @@ static struct evlist *bench__create_evlist(char *evstr, const char *uid_str) if (uid == UINT_MAX) { pr_err("Invalid User: %s", uid_str); ret = -EINVAL; - goto out_delete_evlist; + goto out_put_evlist; } ret = parse_uid_filter(evlist, uid); if (ret) - goto out_delete_evlist; + goto out_put_evlist; } ret = evlist__create_maps(evlist, &opts.target); if (ret < 0) { pr_err("Not enough memory to create thread/cpu maps\n"); - goto out_delete_evlist; + goto out_put_evlist; } evlist__config(evlist, &opts, NULL); return evlist; -out_delete_evlist: - evlist__delete(evlist); +out_put_evlist: + evlist__put(evlist); return NULL; } @@ -116,7 +116,7 @@ static int bench__do_evlist_open_close(struct evlist *evlist) return err; } - err = evlist__mmap(evlist, opts.mmap_pages); + err = evlist__do_mmap(evlist, opts.mmap_pages); if (err < 0) { pr_err("evlist__mmap: %s\n", str_error_r(errno, sbuf, sizeof(sbuf))); return err; @@ -124,7 +124,7 @@ static int bench__do_evlist_open_close(struct evlist *evlist) evlist__enable(evlist); evlist__disable(evlist); - evlist__munmap(evlist); + evlist__do_munmap(evlist); evlist__close(evlist); return 0; @@ -145,13 +145,14 @@ static int bench_evlist_open_close__run(char *evstr, const char *uid_str) init_stats(&time_stats); - printf(" Number of cpus:\t%d\n", perf_cpu_map__nr(evlist->core.user_requested_cpus)); - printf(" Number of threads:\t%d\n", evlist->core.threads->nr); + printf(" Number of cpus:\t%d\n", + perf_cpu_map__nr(evlist__core(evlist)->user_requested_cpus)); + printf(" Number of threads:\t%d\n", evlist__core(evlist)->threads->nr); printf(" Number of events:\t%d (%d fds)\n", - evlist->core.nr_entries, evlist__count_evsel_fds(evlist)); + evlist__nr_entries(evlist), evlist__count_evsel_fds(evlist)); printf(" Number of iterations:\t%d\n", iterations); - evlist__delete(evlist); + evlist__put(evlist); for (i = 0; i < iterations; i++) { pr_debug("Started iteration %d\n", i); @@ -162,7 +163,7 @@ static int bench_evlist_open_close__run(char *evstr, const char *uid_str) gettimeofday(&start, NULL); err = bench__do_evlist_open_close(evlist); if (err) { - evlist__delete(evlist); + evlist__put(evlist); return err; } @@ -171,7 +172,7 @@ static int bench_evlist_open_close__run(char *evstr, const char *uid_str) runtime_us = timeval2usec(&diff); update_stats(&time_stats, runtime_us); - evlist__delete(evlist); + evlist__put(evlist); pr_debug("Iteration %d took:\t%" PRIu64 "us\n", i, runtime_us); } diff --git a/tools/perf/bench/inject-buildid.c b/tools/perf/bench/inject-buildid.c index aad572a78d7f..bfd2c5ec9488 100644 --- a/tools/perf/bench/inject-buildid.c +++ b/tools/perf/bench/inject-buildid.c @@ -228,9 +228,12 @@ static ssize_t synthesize_sample(struct bench_data *data, struct bench_dso *dso, event.header.type = PERF_RECORD_SAMPLE; event.header.misc = PERF_RECORD_MISC_USER; - event.header.size = perf_event__sample_event_size(&sample, bench_sample_type, 0); - - perf_event__synthesize_sample(&event, bench_sample_type, 0, &sample); + event.header.size = perf_event__sample_event_size(&sample, bench_sample_type, + /*read_format=*/0, + /*branch_sample_type=*/0); + perf_event__synthesize_sample(&event, bench_sample_type, + /*read_format=*/0, + /*branch_sample_type=*/0, &sample); return writen(data->input_pipe[1], &event, event.header.size); } diff --git a/tools/perf/bench/mem-functions.c b/tools/perf/bench/mem-functions.c index 2908a3a796c9..5ede52853953 100644 --- a/tools/perf/bench/mem-functions.c +++ b/tools/perf/bench/mem-functions.c @@ -7,13 +7,14 @@ * Written by Hitoshi Mitake <mitake@dcl.info.waseda.ac.jp> */ -#include "debug.h" +#include "bench.h" #include "../perf-sys.h" #include <subcmd/parse-options.h> -#include "../util/header.h" -#include "../util/cloexec.h" -#include "../util/string2.h" -#include "bench.h" +#include "util/cloexec.h" +#include "util/debug.h" +#include "util/header.h" +#include "util/stat.h" +#include "util/string2.h" #include "mem-memcpy-arch.h" #include "mem-memset-arch.h" @@ -26,6 +27,7 @@ #include <errno.h> #include <linux/time64.h> #include <linux/log2.h> +#include <pthread.h> #define K 1024 @@ -41,6 +43,7 @@ static unsigned int nr_loops = 1; static bool use_cycles; static int cycles_fd; static unsigned int seed; +static unsigned int nr_threads = 1; static const struct option bench_common_options[] = { OPT_STRING('s', "size", &size_str, "1MB", @@ -121,6 +124,8 @@ static struct perf_event_attr cycle_attr = { .config = PERF_COUNT_HW_CPU_CYCLES }; +static struct stats stats; + static int init_cycles(void) { cycles_fd = sys_perf_event_open(&cycle_attr, getpid(), -1, -1, perf_event_open_cloexec_flag()); @@ -174,18 +179,18 @@ static void clock_accum(union bench_clock *a, union bench_clock *b) static double timeval2double(struct timeval *ts) { - return (double)ts->tv_sec + (double)ts->tv_usec / (double)USEC_PER_SEC; + return ((double)ts->tv_sec + (double)ts->tv_usec / (double)USEC_PER_SEC) / nr_threads; } #define print_bps(x) do { \ if (x < K) \ - printf(" %14lf bytes/sec\n", x); \ + printf(" %14lf bytes/sec", x); \ else if (x < K * K) \ - printf(" %14lfd KB/sec\n", x / K); \ + printf(" %14lfd KB/sec", x / K); \ else if (x < K * K * K) \ - printf(" %14lf MB/sec\n", x / K / K); \ + printf(" %14lf MB/sec", x / K / K); \ else \ - printf(" %14lf GB/sec\n", x / K / K / K); \ + printf(" %14lf GB/sec", x / K / K / K); \ } while (0) static void __bench_mem_function(struct bench_mem_info *info, struct bench_params *p, @@ -196,6 +201,7 @@ static void __bench_mem_function(struct bench_mem_info *info, struct bench_param union bench_clock rt = { 0 }; void *src = NULL, *dst = NULL; + init_stats(&stats); printf("# function '%s' (%s)\n", r->name, r->desc); if (r->fn.init && r->fn.init(info, p, &src, &dst)) @@ -210,11 +216,16 @@ static void __bench_mem_function(struct bench_mem_info *info, struct bench_param switch (bench_format) { case BENCH_FORMAT_DEFAULT: if (use_cycles) { - printf(" %14lf cycles/byte\n", (double)rt.cycles/(double)p->size_total); + printf(" %14lf cycles/byte", (double)rt.cycles/(double)p->size_total); } else { result_bps = (double)p->size_total/timeval2double(&rt.tv); print_bps(result_bps); } + if (nr_threads > 1) { + printf("/thread\t( +- %6.2f%% )", + rel_stddev_stats(stddev_stats(&stats), avg_stats(&stats))); + } + printf("\n"); break; case BENCH_FORMAT_SIMPLE: @@ -388,7 +399,7 @@ static void mem_free(struct bench_mem_info *info __maybe_unused, *dst = *src = NULL; } -struct function memcpy_functions[] = { +static struct function memcpy_functions[] = { { .name = "default", .desc = "Default memcpy() provided by glibc", .fn.init = mem_alloc, @@ -494,16 +505,27 @@ static void mmap_page_touch(void *dst, size_t size, unsigned int page_shift, boo } } -static int do_mmap(const struct function *r, struct bench_params *p, - void *src __maybe_unused, void *dst __maybe_unused, - union bench_clock *accum) +struct mmap_data { + pthread_t id; + const struct function *func; + struct bench_params *params; + union bench_clock result; + unsigned int seed; + int error; +}; + +static void *do_mmap_thread(void *arg) { + struct mmap_data *data = arg; + const struct function *r = data->func; + struct bench_params *p = data->params; union bench_clock start, end, diff; mmap_op_t fn = r->fn.mmap_op; bool populate = strcmp(r->name, "populate") == 0; + void *dst; - if (p->seed) - srand(p->seed); + if (data->seed) + srand(data->seed); for (unsigned int i = 0; i < p->nr_loops; i++) { clock_get(&start); @@ -514,16 +536,59 @@ static int do_mmap(const struct function *r, struct bench_params *p, fn(dst, p->size, p->page_shift, p->seed); clock_get(&end); diff = clock_diff(&start, &end); - clock_accum(accum, &diff); + clock_accum(&data->result, &diff); bench_munmap(dst, p->size); } - return 0; + return data; out: - printf("# Memory allocation failed - maybe size (%s) %s?\n", size_str, - p->page_shift != PAGE_SHIFT_4KB ? "has insufficient hugepages" : "is too large"); - return -1; + data->error = -ENOMEM; + return NULL; +} + +static int do_mmap(const struct function *r, struct bench_params *p, + void *src __maybe_unused, void *dst __maybe_unused, + union bench_clock *accum) +{ + struct mmap_data *data; + int error = 0; + + data = calloc(nr_threads, sizeof(*data)); + if (!data) { + printf("# Failed to allocate thread resources\n"); + return -1; + } + + for (unsigned int i = 0; i < nr_threads; i++) { + data[i].func = r; + data[i].params = p; + if (p->seed) + data[i].seed = p->seed + i; + + if (pthread_create(&data[i].id, NULL, do_mmap_thread, &data[i]) < 0) + data[i].error = -errno; + } + + for (unsigned int i = 0; i < nr_threads; i++) { + union bench_clock *t = &data[i].result; + + pthread_join(data[i].id, NULL); + + clock_accum(accum, t); + if (use_cycles) + update_stats(&stats, t->cycles); + else + update_stats(&stats, t->tv.tv_sec * 1e6 + t->tv.tv_usec); + error |= data[i].error; + } + free(data); + + if (error) { + printf("# Memory allocation failed - maybe size (%s) %s?\n", size_str, + p->page_shift != PAGE_SHIFT_4KB ? "has insufficient hugepages" : "is too large"); + } + return error ? -1 : 0; } static const char * const bench_mem_mmap_usage[] = { @@ -548,6 +613,8 @@ int bench_mem_mmap(int argc, const char **argv) static const struct option bench_mmap_options[] = { OPT_UINTEGER('r', "randomize", &seed, "Seed to randomize page access offset."), + OPT_UINTEGER('t', "threads", &nr_threads, + "Number of threads to run concurrently (default: 1)."), OPT_PARENT(bench_common_options), OPT_END() }; diff --git a/tools/perf/bench/numa.c b/tools/perf/bench/numa.c index 19be2aaf4dc0..42d7afc03f9b 100644 --- a/tools/perf/bench/numa.c +++ b/tools/perf/bench/numa.c @@ -32,7 +32,6 @@ #include <linux/kernel.h> #include <linux/time64.h> #include <linux/numa.h> -#include <linux/zalloc.h> #include "../util/header.h" #include "../util/mutex.h" @@ -166,7 +165,7 @@ static struct global_info *g = NULL; static int parse_cpus_opt(const struct option *opt, const char *arg, int unset); static int parse_nodes_opt(const struct option *opt, const char *arg, int unset); -struct params p0; +static struct params p0; static const struct option options[] = { OPT_INTEGER('p', "nr_proc" , &p0.nr_proc, "number of processes"), @@ -980,10 +979,8 @@ static int count_process_nodes(int process_nr) int nodes; int n, t; - node_present = (char *)malloc(g->p.nr_nodes * sizeof(char)); + node_present = calloc(g->p.nr_nodes, sizeof(char)); BUG_ON(!node_present); - for (nodes = 0; nodes < g->p.nr_nodes; nodes++) - node_present[nodes] = 0; for (t = 0; t < g->p.nr_threads; t++) { struct thread_data *td; @@ -1090,10 +1087,8 @@ static void calc_convergence(double runtime_ns_max, double *convergence) if (!g->p.show_convergence && !g->p.measure_convergence) return; - nodes = (int *)malloc(g->p.nr_nodes * sizeof(int)); + nodes = calloc(g->p.nr_nodes, sizeof(int)); BUG_ON(!nodes); - for (node = 0; node < g->p.nr_nodes; node++) - nodes[node] = 0; loops_done_min = -1; loops_done_max = 0; @@ -1423,7 +1418,7 @@ static void worker_process(int process_nr) bind_to_memnode(td->bind_node); bind_to_cpumask(td->bind_cpumask); - pthreads = zalloc(g->p.nr_threads * sizeof(pthread_t)); + pthreads = calloc(g->p.nr_threads, sizeof(pthread_t)); process_data = setup_private_data(g->p.bytes_process); if (g->p.show_details >= 3) { @@ -1629,7 +1624,7 @@ static int __bench_numa(const char *name) if (init()) return -1; - pids = zalloc(g->p.nr_proc * sizeof(*pids)); + pids = calloc(g->p.nr_proc, sizeof(*pids)); pid = -1; if (g->p.serialize_startup) { diff --git a/tools/perf/bench/sched-messaging.c b/tools/perf/bench/sched-messaging.c index 93dcd9dba3d0..4fb6657fc826 100644 --- a/tools/perf/bench/sched-messaging.c +++ b/tools/perf/bench/sched-messaging.c @@ -301,7 +301,7 @@ int bench_sched_messaging(int argc, const char **argv) argc = parse_options(argc, argv, options, bench_sched_message_usage, 0); - worker_tab = malloc(num_fds * 2 * num_groups * sizeof(union messaging_worker)); + worker_tab = calloc(num_fds * 2 * num_groups, sizeof(union messaging_worker)); if (!worker_tab) err(EXIT_FAILURE, "main:malloc()"); diff --git a/tools/perf/bench/sched-pipe.c b/tools/perf/bench/sched-pipe.c index 70139036d68f..eb20c6d73d06 100644 --- a/tools/perf/bench/sched-pipe.c +++ b/tools/perf/bench/sched-pipe.c @@ -22,7 +22,9 @@ #include <string.h> #include <errno.h> #include <fcntl.h> +#include <limits.h> #include <assert.h> +#include <poll.h> #include <sys/epoll.h> #include <sys/time.h> #include <sys/types.h> @@ -39,6 +41,7 @@ struct thread_data { int epoll_fd; bool cgroup_failed; pthread_t pthread; + char *buf; }; #define LOOPS_DEFAULT 1000000 @@ -48,6 +51,7 @@ static int loops = LOOPS_DEFAULT; static bool threaded; static bool nonblocking; +static unsigned int write_size = sizeof(int); static char *cgrp_names[2]; static struct cgroup *cgrps[2]; @@ -88,6 +92,8 @@ static const struct option options[] = { OPT_BOOLEAN('n', "nonblocking", &nonblocking, "Use non-blocking operations"), OPT_INTEGER('l', "loop", &loops, "Specify number of loops"), OPT_BOOLEAN('T', "threaded", &threaded, "Specify threads/process based task setup"), + OPT_UINTEGER('s', "write-size", &write_size, + "Bytes per ping-pong write (default 4-bytes). Use larger values to exercise the pipe page-allocation path."), OPT_CALLBACK('G', "cgroups", NULL, "SEND,RECV", "Put sender and receivers in given cgroups", parse_two_cgroups), @@ -170,25 +176,77 @@ static void exit_cgroup(int nr) free(cgrp_names[nr]); } +/* Sleep until @fd is writable, so we don't busy-spin on EWOULDBLOCK. */ +static inline void wait_writable(int fd) +{ + struct pollfd pfd = { + .fd = fd, + .events = POLLOUT, + }; + + poll(&pfd, 1, -1); +} + +/* + * Loop on short read()/write(): the kernel may return fewer bytes than + * requested, retry on EINTR, and in non-blocking mode wait via poll() + * when the writer transiently hits EWOULDBLOCK while the peer is still + * draining a full pipe (capacity is sized to write_size). + */ +static inline int write_pipe(struct thread_data *td) +{ + unsigned int done = 0; + int ret; + + while (done < write_size) { + ret = write(td->pipe_write, td->buf + done, write_size - done); + if (ret < 0) { + if (errno == EINTR) + continue; + if (nonblocking && errno == EWOULDBLOCK) { + wait_writable(td->pipe_write); + continue; + } + return ret; + } + done += ret; + } + return done; +} + static inline int read_pipe(struct thread_data *td) { - int ret, m; -retry: - if (nonblocking) { - ret = epoll_wait(td->epoll_fd, &td->epoll_ev, 1, -1); - if (ret < 0) + unsigned int done = 0; + int ret; + + while (done < write_size) { + if (nonblocking) { + ret = epoll_wait(td->epoll_fd, &td->epoll_ev, 1, -1); + if (ret < 0) { + if (errno == EINTR) + continue; + return ret; + } + } + ret = read(td->pipe_read, td->buf + done, write_size - done); + if (ret < 0) { + if (errno == EINTR) + continue; + if (nonblocking && errno == EWOULDBLOCK) + continue; return ret; + } + if (ret == 0) + return done; + done += ret; } - ret = read(td->pipe_read, &m, sizeof(int)); - if (nonblocking && ret < 0 && errno == EWOULDBLOCK) - goto retry; - return ret; + return done; } static void *worker_thread(void *__tdata) { struct thread_data *td = __tdata; - int i, ret, m = 0; + int i, ret; ret = enter_cgroup(td->nr); if (ret < 0) { @@ -204,15 +262,38 @@ static void *worker_thread(void *__tdata) } for (i = 0; i < loops; i++) { - ret = write(td->pipe_write, &m, sizeof(int)); - BUG_ON(ret != sizeof(int)); + ret = write_pipe(td); + BUG_ON(ret != (int)write_size); ret = read_pipe(td); - BUG_ON(ret != sizeof(int)); + BUG_ON(ret != (int)write_size); } return NULL; } +/* + * On a custom write_size, resize the pipes so a single payload fits. + */ +static int resize_pipes(int wfd1, int wfd2) +{ + int r1, r2; + + if (write_size <= sizeof(int)) + return 0; + + r1 = fcntl(wfd1, F_SETPIPE_SZ, write_size); + r2 = fcntl(wfd2, F_SETPIPE_SZ, write_size); + if (r1 < 0 || r2 < 0 || + (unsigned int)r1 < write_size || + (unsigned int)r2 < write_size) { + fprintf(stderr, + "--write-size %u exceeds /proc/sys/fs/pipe-max-size\n", + write_size); + return -1; + } + return 0; +} + int bench_sched_pipe(int argc, const char **argv) { struct thread_data threads[2] = {}; @@ -233,12 +314,31 @@ int bench_sched_pipe(int argc, const char **argv) argc = parse_options(argc, argv, options, bench_sched_pipe_usage, 0); + /* + * The error paths below return early without closing the pipes or + * freeing the cgroup state. That is fine: bench_sched_pipe() runs + * once and the process exits right after it returns, so these are + * not real leaks. + */ + if (write_size == 0 || write_size > INT_MAX) { + fprintf(stderr, "--write-size must be in 1..%d\n", INT_MAX); + return -1; + } + if (nonblocking) flags |= O_NONBLOCK; BUG_ON(pipe2(pipe_1, flags)); BUG_ON(pipe2(pipe_2, flags)); + if (resize_pipes(pipe_1[1], pipe_2[1]) < 0) + return -1; + + for (t = 0; t < nr_threads; t++) { + threads[t].buf = calloc(1, write_size); + BUG_ON(!threads[t].buf); + } + gettimeofday(&start, NULL); for (t = 0; t < nr_threads; t++) { @@ -287,6 +387,9 @@ int bench_sched_pipe(int argc, const char **argv) gettimeofday(&stop, NULL); timersub(&stop, &start, &diff); + for (t = 0; t < nr_threads; t++) + free(threads[t].buf); + exit_cgroup(0); exit_cgroup(1); diff --git a/tools/perf/bench/uprobe.c b/tools/perf/bench/uprobe.c index c4dac868f1ee..616873bca243 100644 --- a/tools/perf/bench/uprobe.c +++ b/tools/perf/bench/uprobe.c @@ -44,7 +44,7 @@ static const char * const bench_uprobe_usage[] = { }; #ifdef HAVE_BPF_SKEL -#include "bpf_skel/bench_uprobe.skel.h" +#include "bench/bpf_skel/bench_uprobe.skel.h" #define bench_uprobe__attach_uprobe(prog) \ skel->links.prog = bpf_program__attach_uprobe_opts(/*prog=*/skel->progs.prog, \ @@ -58,7 +58,7 @@ static const char * const bench_uprobe_usage[] = { goto cleanup; \ } -struct bench_uprobe_bpf *skel; +static struct bench_uprobe_bpf *skel; static int bench_uprobe__setup_bpf_skel(enum bench_uprobe bench) { |
