summaryrefslogtreecommitdiff
path: root/tools/perf/bench
diff options
context:
space:
mode:
Diffstat (limited to 'tools/perf/bench')
-rw-r--r--tools/perf/bench/Build6
-rw-r--r--tools/perf/bench/bpf_skel/.gitignore4
-rw-r--r--tools/perf/bench/bpf_skel/bench_uprobe.bpf.c39
-rw-r--r--tools/perf/bench/breakpoint.c4
-rw-r--r--tools/perf/bench/evlist-open-close.c29
-rw-r--r--tools/perf/bench/inject-buildid.c9
-rw-r--r--tools/perf/bench/mem-functions.c111
-rw-r--r--tools/perf/bench/numa.c15
-rw-r--r--tools/perf/bench/sched-messaging.c2
-rw-r--r--tools/perf/bench/sched-pipe.c129
-rw-r--r--tools/perf/bench/uprobe.c4
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)
{