Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/tools/perf/bench/futex-lock-pi.c
26285 views
1
// SPDX-License-Identifier: GPL-2.0
2
/*
3
* Copyright (C) 2015 Davidlohr Bueso.
4
*/
5
6
/* For the CLR_() macros */
7
#include <string.h>
8
#include <pthread.h>
9
10
#include <signal.h>
11
#include "../util/mutex.h"
12
#include "../util/stat.h"
13
#include <subcmd/parse-options.h>
14
#include <linux/compiler.h>
15
#include <linux/kernel.h>
16
#include <linux/zalloc.h>
17
#include <errno.h>
18
#include <perf/cpumap.h>
19
#include "bench.h"
20
#include "futex.h"
21
22
#include <err.h>
23
#include <stdlib.h>
24
#include <sys/time.h>
25
#include <sys/mman.h>
26
27
struct worker {
28
int tid;
29
u_int32_t *futex;
30
pthread_t thread;
31
unsigned long ops;
32
};
33
34
static u_int32_t global_futex = 0;
35
static struct worker *worker;
36
static bool done = false;
37
static int futex_flag = 0;
38
static struct mutex thread_lock;
39
static unsigned int threads_starting;
40
static struct stats throughput_stats;
41
static struct cond thread_parent, thread_worker;
42
43
static struct bench_futex_parameters params = {
44
.nbuckets = -1,
45
.runtime = 10,
46
};
47
48
static const struct option options[] = {
49
OPT_INTEGER( 'b', "buckets", &params.nbuckets, "Specify amount of hash buckets"),
50
OPT_UINTEGER('t', "threads", &params.nthreads, "Specify amount of threads"),
51
OPT_UINTEGER('r', "runtime", &params.runtime, "Specify runtime (in seconds)"),
52
OPT_BOOLEAN( 'M', "multi", &params.multi, "Use multiple futexes"),
53
OPT_BOOLEAN( 's', "silent", &params.silent, "Silent mode: do not display data/details"),
54
OPT_BOOLEAN( 'S', "shared", &params.fshared, "Use shared futexes instead of private ones"),
55
OPT_BOOLEAN( 'm', "mlockall", &params.mlockall, "Lock all current and future memory"),
56
OPT_END()
57
};
58
59
static const char * const bench_futex_lock_pi_usage[] = {
60
"perf bench futex lock-pi <options>",
61
NULL
62
};
63
64
static void print_summary(void)
65
{
66
unsigned long avg = avg_stats(&throughput_stats);
67
double stddev = stddev_stats(&throughput_stats);
68
69
printf("%sAveraged %ld operations/sec (+- %.2f%%), total secs = %d\n",
70
!params.silent ? "\n" : "", avg, rel_stddev_stats(stddev, avg),
71
(int)bench__runtime.tv_sec);
72
futex_print_nbuckets(&params);
73
}
74
75
static void toggle_done(int sig __maybe_unused,
76
siginfo_t *info __maybe_unused,
77
void *uc __maybe_unused)
78
{
79
/* inform all threads that we're done for the day */
80
done = true;
81
gettimeofday(&bench__end, NULL);
82
timersub(&bench__end, &bench__start, &bench__runtime);
83
}
84
85
static void *workerfn(void *arg)
86
{
87
struct worker *w = (struct worker *) arg;
88
unsigned long ops = w->ops;
89
90
mutex_lock(&thread_lock);
91
threads_starting--;
92
if (!threads_starting)
93
cond_signal(&thread_parent);
94
cond_wait(&thread_worker, &thread_lock);
95
mutex_unlock(&thread_lock);
96
97
do {
98
int ret;
99
again:
100
ret = futex_lock_pi(w->futex, NULL, futex_flag);
101
102
if (ret) { /* handle lock acquisition */
103
if (!params.silent)
104
warn("thread %d: Could not lock pi-lock for %p (%d)",
105
w->tid, w->futex, ret);
106
if (done)
107
break;
108
109
goto again;
110
}
111
112
usleep(1);
113
ret = futex_unlock_pi(w->futex, futex_flag);
114
if (ret && !params.silent)
115
warn("thread %d: Could not unlock pi-lock for %p (%d)",
116
w->tid, w->futex, ret);
117
ops++; /* account for thread's share of work */
118
} while (!done);
119
120
w->ops = ops;
121
return NULL;
122
}
123
124
static void create_threads(struct worker *w, struct perf_cpu_map *cpu)
125
{
126
cpu_set_t *cpuset;
127
unsigned int i;
128
int nrcpus = cpu__max_cpu().cpu;
129
size_t size;
130
131
threads_starting = params.nthreads;
132
133
cpuset = CPU_ALLOC(nrcpus);
134
BUG_ON(!cpuset);
135
size = CPU_ALLOC_SIZE(nrcpus);
136
137
for (i = 0; i < params.nthreads; i++) {
138
pthread_attr_t thread_attr;
139
140
pthread_attr_init(&thread_attr);
141
worker[i].tid = i;
142
143
if (params.multi) {
144
worker[i].futex = calloc(1, sizeof(u_int32_t));
145
if (!worker[i].futex)
146
err(EXIT_FAILURE, "calloc");
147
} else
148
worker[i].futex = &global_futex;
149
150
CPU_ZERO_S(size, cpuset);
151
CPU_SET_S(perf_cpu_map__cpu(cpu, i % perf_cpu_map__nr(cpu)).cpu, size, cpuset);
152
153
if (pthread_attr_setaffinity_np(&thread_attr, size, cpuset)) {
154
CPU_FREE(cpuset);
155
err(EXIT_FAILURE, "pthread_attr_setaffinity_np");
156
}
157
158
if (pthread_create(&w[i].thread, &thread_attr, workerfn, &worker[i])) {
159
CPU_FREE(cpuset);
160
err(EXIT_FAILURE, "pthread_create");
161
}
162
pthread_attr_destroy(&thread_attr);
163
}
164
CPU_FREE(cpuset);
165
}
166
167
int bench_futex_lock_pi(int argc, const char **argv)
168
{
169
int ret = 0;
170
unsigned int i;
171
struct sigaction act;
172
struct perf_cpu_map *cpu;
173
174
argc = parse_options(argc, argv, options, bench_futex_lock_pi_usage, 0);
175
if (argc)
176
goto err;
177
178
cpu = perf_cpu_map__new_online_cpus();
179
if (!cpu)
180
err(EXIT_FAILURE, "calloc");
181
182
memset(&act, 0, sizeof(act));
183
sigfillset(&act.sa_mask);
184
act.sa_sigaction = toggle_done;
185
sigaction(SIGINT, &act, NULL);
186
187
if (params.mlockall) {
188
if (mlockall(MCL_CURRENT | MCL_FUTURE))
189
err(EXIT_FAILURE, "mlockall");
190
}
191
192
if (!params.nthreads)
193
params.nthreads = perf_cpu_map__nr(cpu);
194
195
worker = calloc(params.nthreads, sizeof(*worker));
196
if (!worker)
197
err(EXIT_FAILURE, "calloc");
198
199
if (!params.fshared)
200
futex_flag = FUTEX_PRIVATE_FLAG;
201
202
printf("Run summary [PID %d]: %d threads doing pi lock/unlock pairing for %d secs.\n\n",
203
getpid(), params.nthreads, params.runtime);
204
205
init_stats(&throughput_stats);
206
mutex_init(&thread_lock);
207
cond_init(&thread_parent);
208
cond_init(&thread_worker);
209
futex_set_nbuckets_param(&params);
210
211
threads_starting = params.nthreads;
212
gettimeofday(&bench__start, NULL);
213
214
create_threads(worker, cpu);
215
216
mutex_lock(&thread_lock);
217
while (threads_starting)
218
cond_wait(&thread_parent, &thread_lock);
219
cond_broadcast(&thread_worker);
220
mutex_unlock(&thread_lock);
221
222
sleep(params.runtime);
223
toggle_done(0, NULL, NULL);
224
225
for (i = 0; i < params.nthreads; i++) {
226
ret = pthread_join(worker[i].thread, NULL);
227
if (ret)
228
err(EXIT_FAILURE, "pthread_join");
229
}
230
231
/* cleanup & report results */
232
cond_destroy(&thread_parent);
233
cond_destroy(&thread_worker);
234
mutex_destroy(&thread_lock);
235
236
for (i = 0; i < params.nthreads; i++) {
237
unsigned long t = bench__runtime.tv_sec > 0 ?
238
worker[i].ops / bench__runtime.tv_sec : 0;
239
240
update_stats(&throughput_stats, t);
241
if (!params.silent)
242
printf("[thread %3d] futex: %p [ %ld ops/sec ]\n",
243
worker[i].tid, worker[i].futex, t);
244
245
if (params.multi)
246
zfree(&worker[i].futex);
247
}
248
249
print_summary();
250
251
free(worker);
252
perf_cpu_map__put(cpu);
253
return ret;
254
err:
255
usage_with_options(bench_futex_lock_pi_usage, options);
256
exit(EXIT_FAILURE);
257
}
258
259