// SPDX-License-Identifier: GPL-2.0 /* * Copyright (C) 2015 Davidlohr Bueso. * * Block a bunch of threads and let parallel waker threads wakeup an * equal amount of them. The program output reflects the avg latency * for each individual thread to service its share of work. Ultimately * it can be used to measure futex_wake() changes.
*/ #include"bench.h" #include <linux/compiler.h> #include"../util/debug.h" #include"../util/mutex.h"
#ifndef HAVE_PTHREAD_BARRIER int bench_futex_wake_parallel(int argc __maybe_unused, constchar **argv __maybe_unused)
{
pr_err("%s: pthread_barrier_t unavailable, disabling this test...\n", __func__); return 0;
} #else/* HAVE_PTHREAD_BARRIER */ /* For the CLR_() macros */ #include <string.h> #include <pthread.h>
/* create and block all threads */ for (i = 0; i < params.nwakes; i++) { /* * Thread creation order will impact per-thread latency * as it will affect the order to acquire the hb spinlock. * For now let the scheduler decide.
*/ if (pthread_create(&td[i].worker, &thread_attr,
waking_workerfn, (void *)&td[i]))
err(EXIT_FAILURE, "pthread_create");
}
pthread_barrier_wait(&barrier);
for (i = 0; i < params.nwakes; i++) if (pthread_join(td[i].worker, NULL))
err(EXIT_FAILURE, "pthread_join");
for (i = 0; i < params.nwakes; i++) {
update_stats(&__waketime_stats, waking_worker[i].runtime.tv_usec);
update_stats(&__wakeup_stats, waking_worker[i].nwoken);
}
for (i = 0; i < params.nwakes; i++) {
update_stats(&waketime_stats, waking_worker[i].runtime.tv_usec);
update_stats(&wakeup_stats, waking_worker[i].nwoken);
}
if (params.mlockall) { if (mlockall(MCL_CURRENT | MCL_FUTURE))
err(EXIT_FAILURE, "mlockall");
}
cpu = perf_cpu_map__new_online_cpus(); if (!cpu)
err(EXIT_FAILURE, "calloc");
if (!params.nthreads)
params.nthreads = perf_cpu_map__nr(cpu);
/* some sanity checks */ if (params.nwakes > params.nthreads ||
!params.nwakes)
params.nwakes = params.nthreads;
if (params.nthreads % params.nwakes)
errx(EXIT_FAILURE, "Must be perfectly divisible"); /* * Each thread will wakeup nwakes tasks in * a single futex_wait call.
*/
nwakes = params.nthreads/params.nwakes;
blocked_worker = calloc(params.nthreads, sizeof(*blocked_worker)); if (!blocked_worker)
err(EXIT_FAILURE, "calloc");
if (!params.fshared)
futex_flag = FUTEX_PRIVATE_FLAG;
futex_set_nbuckets_param(¶ms);
printf("Run summary [PID %d]: blocking on %d threads (at [%s] " "futex %p), %d threads waking up %d at a time.\n\n",
getpid(), params.nthreads, params.fshared ? "shared":"private",
&futex, params.nwakes, nwakes);
for (j = 0; j < bench_repeat && !done; j++) {
waking_worker = calloc(params.nwakes, sizeof(*waking_worker)); if (!waking_worker)
err(EXIT_FAILURE, "calloc");
/* create, launch & block all threads */
block_threads(blocked_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(200000);
/* Ok, all threads are patiently blocked, start waking folks up */
wakeup_threads(waking_worker);
for (i = 0; i < params.nthreads; i++) {
ret = pthread_join(blocked_worker[i], NULL); if (ret)
err(EXIT_FAILURE, "pthread_join");
}
do_run_stats(waking_worker); if (!params.silent)
print_run(waking_worker, j);
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.