Skip to content

Commit 60035a3

Browse files
Sebastian Andrzej SiewiorPeter Zijlstra
authored andcommitted
tools/perf: Allow to select the number of hash buckets
Add the -b/ --buckets argument to specify the number of hash buckets for the private futex hash. This is directly passed to prctl(PR_FUTEX_HASH, PR_FUTEX_HASH_SET_SLOTS, buckets, immutable) and must return without an error if specified. The `immutable' is 0 by default and can be set to 1 via the -I/ --immutable argument. The size of the private hash is verified with PR_FUTEX_HASH_GET_SLOTS. If PR_FUTEX_HASH_GET_SLOTS failed then it is assumed that an older kernel was used without the support and that the global hash is used. Signed-off-by: Sebastian Andrzej Siewior <[email protected]> Signed-off-by: Peter Zijlstra (Intel) <[email protected]> Link: https://lore.kernel.org/r/[email protected]
1 parent f25051d commit 60035a3

File tree

8 files changed

+101
-1
lines changed

8 files changed

+101
-1
lines changed

tools/perf/bench/Build

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ perf-bench-y += sched-pipe.o
33
perf-bench-y += sched-seccomp-notify.o
44
perf-bench-y += syscall.o
55
perf-bench-y += mem-functions.o
6+
perf-bench-y += futex.o
67
perf-bench-y += futex-hash.o
78
perf-bench-y += futex-wake.o
89
perf-bench-y += futex-wake-parallel.o

tools/perf/bench/futex-hash.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,11 @@
1818
#include <stdlib.h>
1919
#include <linux/compiler.h>
2020
#include <linux/kernel.h>
21+
#include <linux/prctl.h>
2122
#include <linux/zalloc.h>
2223
#include <sys/time.h>
2324
#include <sys/mman.h>
25+
#include <sys/prctl.h>
2426
#include <perf/cpumap.h>
2527

2628
#include "../util/mutex.h"
@@ -50,9 +52,12 @@ struct worker {
5052
static struct bench_futex_parameters params = {
5153
.nfutexes = 1024,
5254
.runtime = 10,
55+
.nbuckets = -1,
5356
};
5457

5558
static const struct option options[] = {
59+
OPT_INTEGER( 'b', "buckets", &params.nbuckets, "Specify amount of hash buckets"),
60+
OPT_BOOLEAN( 'I', "immutable", &params.buckets_immutable, "Make the hash buckets immutable"),
5661
OPT_UINTEGER('t', "threads", &params.nthreads, "Specify amount of threads"),
5762
OPT_UINTEGER('r', "runtime", &params.runtime, "Specify runtime (in seconds)"),
5863
OPT_UINTEGER('f', "futexes", &params.nfutexes, "Specify amount of futexes per threads"),
@@ -118,6 +123,7 @@ static void print_summary(void)
118123
printf("%sAveraged %ld operations/sec (+- %.2f%%), total secs = %d\n",
119124
!params.silent ? "\n" : "", avg, rel_stddev_stats(stddev, avg),
120125
(int)bench__runtime.tv_sec);
126+
futex_print_nbuckets(&params);
121127
}
122128

123129
int bench_futex_hash(int argc, const char **argv)
@@ -161,6 +167,7 @@ int bench_futex_hash(int argc, const char **argv)
161167

162168
if (!params.fshared)
163169
futex_flag = FUTEX_PRIVATE_FLAG;
170+
futex_set_nbuckets_param(&params);
164171

165172
printf("Run summary [PID %d]: %d threads, each operating on %d [%s] futexes for %d secs.\n\n",
166173
getpid(), params.nthreads, params.nfutexes, params.fshared ? "shared":"private", params.runtime);

tools/perf/bench/futex-lock-pi.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,10 +41,13 @@ static struct stats throughput_stats;
4141
static struct cond thread_parent, thread_worker;
4242

4343
static struct bench_futex_parameters params = {
44+
.nbuckets = -1,
4445
.runtime = 10,
4546
};
4647

4748
static const struct option options[] = {
49+
OPT_INTEGER( 'b', "buckets", &params.nbuckets, "Specify amount of hash buckets"),
50+
OPT_BOOLEAN( 'I', "immutable", &params.buckets_immutable, "Make the hash buckets immutable"),
4851
OPT_UINTEGER('t', "threads", &params.nthreads, "Specify amount of threads"),
4952
OPT_UINTEGER('r', "runtime", &params.runtime, "Specify runtime (in seconds)"),
5053
OPT_BOOLEAN( 'M', "multi", &params.multi, "Use multiple futexes"),
@@ -67,6 +70,7 @@ static void print_summary(void)
6770
printf("%sAveraged %ld operations/sec (+- %.2f%%), total secs = %d\n",
6871
!params.silent ? "\n" : "", avg, rel_stddev_stats(stddev, avg),
6972
(int)bench__runtime.tv_sec);
73+
futex_print_nbuckets(&params);
7074
}
7175

7276
static void toggle_done(int sig __maybe_unused,
@@ -203,6 +207,7 @@ int bench_futex_lock_pi(int argc, const char **argv)
203207
mutex_init(&thread_lock);
204208
cond_init(&thread_parent);
205209
cond_init(&thread_worker);
210+
futex_set_nbuckets_param(&params);
206211

207212
threads_starting = params.nthreads;
208213
gettimeofday(&bench__start, NULL);

tools/perf/bench/futex-requeue.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ static unsigned int threads_starting;
4242
static int futex_flag = 0;
4343

4444
static struct bench_futex_parameters params = {
45+
.nbuckets = -1,
4546
/*
4647
* How many tasks to requeue at a time.
4748
* Default to 1 in order to make the kernel work more.
@@ -50,6 +51,8 @@ static struct bench_futex_parameters params = {
5051
};
5152

5253
static const struct option options[] = {
54+
OPT_INTEGER( 'b', "buckets", &params.nbuckets, "Specify amount of hash buckets"),
55+
OPT_BOOLEAN( 'I', "immutable", &params.buckets_immutable, "Make the hash buckets immutable"),
5356
OPT_UINTEGER('t', "threads", &params.nthreads, "Specify amount of threads"),
5457
OPT_UINTEGER('q', "nrequeue", &params.nrequeue, "Specify amount of threads to requeue at once"),
5558
OPT_BOOLEAN( 's', "silent", &params.silent, "Silent mode: do not display data/details"),
@@ -77,6 +80,7 @@ static void print_summary(void)
7780
params.nthreads,
7881
requeuetime_avg / USEC_PER_MSEC,
7982
rel_stddev_stats(requeuetime_stddev, requeuetime_avg));
83+
futex_print_nbuckets(&params);
8084
}
8185

8286
static void *workerfn(void *arg __maybe_unused)
@@ -204,6 +208,8 @@ int bench_futex_requeue(int argc, const char **argv)
204208
if (params.broadcast)
205209
params.nrequeue = params.nthreads;
206210

211+
futex_set_nbuckets_param(&params);
212+
207213
printf("Run summary [PID %d]: Requeuing %d threads (from [%s] %p to %s%p), "
208214
"%d at a time.\n\n", getpid(), params.nthreads,
209215
params.fshared ? "shared":"private", &futex1,

tools/perf/bench/futex-wake-parallel.c

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,9 +57,13 @@ static struct stats waketime_stats, wakeup_stats;
5757
static unsigned int threads_starting;
5858
static int futex_flag = 0;
5959

60-
static struct bench_futex_parameters params;
60+
static struct bench_futex_parameters params = {
61+
.nbuckets = -1,
62+
};
6163

6264
static const struct option options[] = {
65+
OPT_INTEGER( 'b', "buckets", &params.nbuckets, "Specify amount of hash buckets"),
66+
OPT_BOOLEAN( 'I', "immutable", &params.buckets_immutable, "Make the hash buckets immutable"),
6367
OPT_UINTEGER('t', "threads", &params.nthreads, "Specify amount of threads"),
6468
OPT_UINTEGER('w', "nwakers", &params.nwakes, "Specify amount of waking threads"),
6569
OPT_BOOLEAN( 's', "silent", &params.silent, "Silent mode: do not display data/details"),
@@ -218,6 +222,7 @@ static void print_summary(void)
218222
params.nthreads,
219223
waketime_avg / USEC_PER_MSEC,
220224
rel_stddev_stats(waketime_stddev, waketime_avg));
225+
futex_print_nbuckets(&params);
221226
}
222227

223228

@@ -291,6 +296,8 @@ int bench_futex_wake_parallel(int argc, const char **argv)
291296
if (!params.fshared)
292297
futex_flag = FUTEX_PRIVATE_FLAG;
293298

299+
futex_set_nbuckets_param(&params);
300+
294301
printf("Run summary [PID %d]: blocking on %d threads (at [%s] "
295302
"futex %p), %d threads waking up %d at a time.\n\n",
296303
getpid(), params.nthreads, params.fshared ? "shared":"private",

tools/perf/bench/futex-wake.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ static unsigned int threads_starting;
4242
static int futex_flag = 0;
4343

4444
static struct bench_futex_parameters params = {
45+
.nbuckets = -1,
4546
/*
4647
* How many wakeups to do at a time.
4748
* Default to 1 in order to make the kernel work more.
@@ -50,6 +51,8 @@ static struct bench_futex_parameters params = {
5051
};
5152

5253
static const struct option options[] = {
54+
OPT_INTEGER( 'b', "buckets", &params.nbuckets, "Specify amount of hash buckets"),
55+
OPT_BOOLEAN( 'I', "immutable", &params.buckets_immutable, "Make the hash buckets immutable"),
5356
OPT_UINTEGER('t', "threads", &params.nthreads, "Specify amount of threads"),
5457
OPT_UINTEGER('w', "nwakes", &params.nwakes, "Specify amount of threads to wake at once"),
5558
OPT_BOOLEAN( 's', "silent", &params.silent, "Silent mode: do not display data/details"),
@@ -93,6 +96,7 @@ static void print_summary(void)
9396
params.nthreads,
9497
waketime_avg / USEC_PER_MSEC,
9598
rel_stddev_stats(waketime_stddev, waketime_avg));
99+
futex_print_nbuckets(&params);
96100
}
97101

98102
static void block_threads(pthread_t *w, struct perf_cpu_map *cpu)

tools/perf/bench/futex.c

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
#include <err.h>
3+
#include <stdio.h>
4+
#include <stdlib.h>
5+
#include <linux/prctl.h>
6+
#include <sys/prctl.h>
7+
8+
#include "futex.h"
9+
10+
void futex_set_nbuckets_param(struct bench_futex_parameters *params)
11+
{
12+
int ret;
13+
14+
if (params->nbuckets < 0)
15+
return;
16+
17+
ret = prctl(PR_FUTEX_HASH, PR_FUTEX_HASH_SET_SLOTS, params->nbuckets, params->buckets_immutable);
18+
if (ret) {
19+
printf("Requesting %d hash buckets failed: %d/%m\n",
20+
params->nbuckets, ret);
21+
err(EXIT_FAILURE, "prctl(PR_FUTEX_HASH)");
22+
}
23+
}
24+
25+
void futex_print_nbuckets(struct bench_futex_parameters *params)
26+
{
27+
char *futex_hash_mode;
28+
int ret;
29+
30+
ret = prctl(PR_FUTEX_HASH, PR_FUTEX_HASH_GET_SLOTS);
31+
if (params->nbuckets >= 0) {
32+
if (ret != params->nbuckets) {
33+
if (ret < 0) {
34+
printf("Can't query number of buckets: %m\n");
35+
err(EXIT_FAILURE, "prctl(PR_FUTEX_HASH)");
36+
}
37+
printf("Requested number of hash buckets does not currently used.\n");
38+
printf("Requested: %d in usage: %d\n", params->nbuckets, ret);
39+
err(EXIT_FAILURE, "prctl(PR_FUTEX_HASH)");
40+
}
41+
if (params->nbuckets == 0) {
42+
ret = asprintf(&futex_hash_mode, "Futex hashing: global hash");
43+
} else {
44+
ret = prctl(PR_FUTEX_HASH, PR_FUTEX_HASH_GET_IMMUTABLE);
45+
if (ret < 0) {
46+
printf("Can't check if the hash is immutable: %m\n");
47+
err(EXIT_FAILURE, "prctl(PR_FUTEX_HASH)");
48+
}
49+
ret = asprintf(&futex_hash_mode, "Futex hashing: %d hash buckets %s",
50+
params->nbuckets,
51+
ret == 1 ? "(immutable)" : "");
52+
}
53+
} else {
54+
if (ret <= 0) {
55+
ret = asprintf(&futex_hash_mode, "Futex hashing: global hash");
56+
} else {
57+
ret = asprintf(&futex_hash_mode, "Futex hashing: auto resized to %d buckets",
58+
ret);
59+
}
60+
}
61+
if (ret < 0)
62+
err(EXIT_FAILURE, "ENOMEM, futex_hash_mode");
63+
printf("%s\n", futex_hash_mode);
64+
free(futex_hash_mode);
65+
}

tools/perf/bench/futex.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ struct bench_futex_parameters {
2525
unsigned int nfutexes;
2626
unsigned int nwakes;
2727
unsigned int nrequeue;
28+
int nbuckets;
29+
bool buckets_immutable;
2830
};
2931

3032
/**
@@ -143,4 +145,7 @@ futex_cmp_requeue_pi(u_int32_t *uaddr, u_int32_t val, u_int32_t *uaddr2,
143145
val, opflags);
144146
}
145147

148+
void futex_set_nbuckets_param(struct bench_futex_parameters *params);
149+
void futex_print_nbuckets(struct bench_futex_parameters *params);
150+
146151
#endif /* _FUTEX_H */

0 commit comments

Comments
 (0)