// SPDX-License-Identifier: GPL-2.0 /* * Copyright (C) 2013 Davidlohr Bueso <davidlohr@hp.com> * * futex-requeue: Block a bunch of threads on futex1 and requeue them * on futex2, N at a time. * * This program is particularly useful to measure the latency of nthread * requeues without waking up any tasks (in the non-pi case) -- thus * mimicking a regular futex_wait.
*/
/* For the CLR_() macros */ #include <string.h> #include <pthread.h>
staticstruct bench_futex_parameters params = {
.nbuckets = -1, /* * How many tasks to requeue at a time. * Default to 1 in order to make the kernel work more.
*/
.nrequeue = 1,
};
staticconststruct option options[] = {
OPT_INTEGER( 'b', "buckets", ¶ms.nbuckets, "Specify amount of hash buckets"),
OPT_UINTEGER('t', "threads", ¶ms.nthreads, "Specify amount of threads"),
OPT_UINTEGER('q', "nrequeue", ¶ms.nrequeue, "Specify amount of threads to requeue at once"),
OPT_BOOLEAN( 's', "silent", ¶ms.silent, "Silent mode: do not display data/details"),
OPT_BOOLEAN( 'S', "shared", ¶ms.fshared, "Use shared futexes instead of private ones"),
OPT_BOOLEAN( 'm', "mlockall", ¶ms.mlockall, "Lock all current and future memory"),
OPT_BOOLEAN( 'B', "broadcast", ¶ms.broadcast, "Requeue all threads at once"),
OPT_BOOLEAN( 'p', "pi", ¶ms.pi, "Use PI-aware variants of FUTEX_CMP_REQUEUE"),
/* create, launch & block all threads */
block_threads(worker, cpu);
/* make sure all threads are already blocked */
mutex_lock(&thread_lock); while (threads_starting)
cond_wait(&thread_parent, &thread_lock);
cond_broadcast(&thread_worker);
mutex_unlock(&thread_lock);
usleep(100000);
/* Ok, all threads are patiently blocked, start requeueing */
gettimeofday(&start, NULL); while (nrequeued < params.nthreads) { int r;
/* * For the regular non-pi case, do not wakeup any tasks * blocked on futex1, allowing us to really measure * futex_wait functionality. For the PI case the first * waiter is always awoken.
*/ if (!params.pi) {
r = futex_cmp_requeue(&futex1, 0, &futex2, 0,
params.nrequeue,
futex_flag);
} else {
r = futex_cmp_requeue_pi(&futex1, 0, &futex2,
params.nrequeue,
futex_flag);
wakeups++; /* assume no error */
}
if (r < 0)
err(EXIT_FAILURE, "couldn't requeue from %p to %p",
&futex1, &futex2);
if (!params.silent) { if (!params.pi)
printf("[Run %d]: Requeued %d of %d threads in " "%.4f ms\n", j + 1, nrequeued,
params.nthreads,
runtime.tv_usec / (double)USEC_PER_MSEC); else {
nrequeued -= wakeups;
printf("[Run %d]: Awoke and Requeued (%d+%d) of " "%d threads in %.4f ms\n",
j + 1, wakeups, nrequeued,
params.nthreads,
runtime.tv_usec / (double)USEC_PER_MSEC);
}
}
if (!params.pi) { /* everybody should be blocked on futex2, wake'em up */
nrequeued = futex_wake(&futex2, nrequeued, futex_flag); if (params.nthreads != nrequeued)
warnx("couldn't wakeup all tasks (%d/%d)",
nrequeued, params.nthreads);
}
for (i = 0; i < params.nthreads; i++) {
ret = pthread_join(worker[i], NULL); if (ret)
err(EXIT_FAILURE, "pthread_join");
}
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.