diff options
author | Darren Hart <dvhltc@us.ibm.com> | 2009-11-18 22:31:37 -0800 |
---|---|---|
committer | Darren Hart <dvhltc@us.ibm.com> | 2009-11-23 09:59:27 -0800 |
commit | b9f837800ff7b64a56274760044585c92ad8866b (patch) | |
tree | 550a1e50e1d57228da579bc66e6f5874ae8f7739 | |
parent | d5bdd21887e66f7af6a631083a15104cebc82a52 (diff) | |
download | futextest-b9f837800ff7b64a56274760044585c92ad8866b.tar.gz |
Add futex_wait performance test
This is the first half of a patch from Michel adding futex_set_wait and
futex_wait performance tests. This patch adds the futex_wait performance
test and the necessary infrastructure.
Signed-off-by: Michel Lespinasse <walken@google.com>
Signed-off-by: Darren Hart <dvhltc@us.ibm.com>
-rw-r--r-- | .gitignore | 4 | ||||
-rw-r--r-- | performance/Makefile | 2 | ||||
-rw-r--r-- | performance/futex_wait.c | 56 | ||||
-rw-r--r-- | performance/harness.h | 103 | ||||
-rwxr-xr-x | performance/run.sh | 1 |
5 files changed, 164 insertions, 2 deletions
@@ -1,6 +1,8 @@ functional/futex_requeue_pi functional/futex_requeue_pi_signal_restart functional/futex_wait_timeout - functional/futex_requeue_pi_mismatched_ops functional/futex_wait_wouldblock + +performance/futex_wait +performance/futex_set_wait diff --git a/performance/Makefile b/performance/Makefile index 9589e49..abd4dd8 100644 --- a/performance/Makefile +++ b/performance/Makefile @@ -3,7 +3,7 @@ CFLAGS := $(CFLAGS) -g -O2 -Wall -D_GNU_SOURCE $(INCLUDES) LDFLAGS := $(LDFLAGS) -lpthread -lrt HEADERS := ../include/futextest.h -TARGETS := +TARGETS := futex_wait .PHONY: all clean all: $(TARGETS) diff --git a/performance/futex_wait.c b/performance/futex_wait.c new file mode 100644 index 0000000..88ce2f2 --- /dev/null +++ b/performance/futex_wait.c @@ -0,0 +1,56 @@ +// Copyright 2009 Google Inc. +// Author: walken@google.com (Michel Lespinasse) + +#include "futextest.h" +#include "harness.h" + +#include <stdio.h> + + +static inline void futex_wait_lock(futex_t *futex) +{ + int status = *futex; + if (status == 0) + status = futex_cmpxchg(futex, 0, 1); + while (status != 0) { + if (status == 1) + status = futex_cmpxchg(futex, 1, 2); + if (status != 0) { + futex_wait(futex, 2, NULL, FUTEX_PRIVATE_FLAG); + status = *futex; + } + if (status == 0) + status = futex_cmpxchg(futex, 0, 2); + } +} + +static inline void futex_cmpxchg_unlock(futex_t *futex) +{ + int status = *futex; + if (status == 1) + status = futex_cmpxchg(futex, 1, 0); + if (status == 2) { + futex_cmpxchg(futex, 2, 0); + futex_wake(futex, 1, FUTEX_PRIVATE_FLAG); + } +} + +static void * futex_wait_test(void * dummy) +{ + struct locktest_shared * shared = dummy; + int i = shared->loops; + barrier_sync(&shared->barrier_before); + while (i--) { + futex_wait_lock(&shared->futex); + futex_cmpxchg_unlock(&shared->futex); + } + barrier_sync(&shared->barrier_after); + return NULL; +} + +int main (void) +{ + printf("FUTEX_WAIT test\n"); + locktest(futex_wait_test, 100000000); + return 0; +} diff --git a/performance/harness.h b/performance/harness.h new file mode 100644 index 0000000..9d74d17 --- /dev/null +++ b/performance/harness.h @@ -0,0 +1,103 @@ +// Copyright 2009 Google Inc. +// Author: walken@google.com (Michel Lespinasse) + +#include <limits.h> +#include <sys/times.h> +#include <stdio.h> +#include <pthread.h> + + +struct thread_barrier { + futex_t threads; + futex_t unblock; +}; + +struct locktest_shared { + struct thread_barrier barrier_before; + struct thread_barrier barrier_after; + int loops; + futex_t futex; +}; + +static inline void decrement(futex_t *ptr) +{ + __sync_fetch_and_add(ptr, -1); +} + +/* Called by main thread to initialize barrier */ +static void barrier_init(struct thread_barrier *barrier, int threads) +{ + barrier->threads = threads; + barrier->unblock = 0; +} + +/* Called by worker threads to synchronize with main thread */ +static void barrier_sync(struct thread_barrier *barrier) +{ + decrement(&barrier->threads); + if (barrier->threads == 0) + futex_wake(&barrier->threads, 1, FUTEX_PRIVATE_FLAG); + while (barrier->unblock == 0) + futex_wait(&barrier->unblock, 0, NULL, FUTEX_PRIVATE_FLAG); +} + +/* Called by main thread to wait for all workers to reach sync point */ +static void barrier_wait(struct thread_barrier *barrier) +{ + int threads; + while ((threads = barrier->threads) > 0) + futex_wait(&barrier->threads, threads, NULL, + FUTEX_PRIVATE_FLAG); +} + +/* Called by main thread to unblock worker threads from their sync point */ +static void barrier_unblock(struct thread_barrier *barrier) +{ + barrier->unblock = 1; + futex_wake(&barrier->unblock, INT_MAX, FUTEX_PRIVATE_FLAG); +} + + +static void locktest(void * thread_function(void *), int iterations) +{ + int threads[] = { 1, 2, 3, 4, 5, 6, 8, 10, 12, 16, 24, 32, + 64, 128, 256, 512, 1024, 0 }; + int t; + for (t = 0; threads[t]; t++) { + int num_threads = threads[t]; + struct locktest_shared shared; + pthread_t thread[num_threads]; + int i; + clock_t before, after; + struct tms tms_before, tms_after; + int wall, user, system; + double tick; + + barrier_init(&shared.barrier_before, num_threads); + barrier_init(&shared.barrier_after, num_threads); + shared.loops = iterations / num_threads; + shared.futex = 0; + + for (i = 0; i < num_threads; i++) + pthread_create(thread + i, NULL, thread_function, + &shared); + barrier_wait(&shared.barrier_before); + before = times(&tms_before); + barrier_unblock(&shared.barrier_before); + barrier_wait(&shared.barrier_after); + after = times(&tms_after); + wall = after - before; + user = tms_after.tms_utime - tms_before.tms_utime; + system = tms_after.tms_stime - tms_before.tms_stime; + tick = 1.0 / sysconf(_SC_CLK_TCK); + printf("%d threads: %.0f Kiter/s " + "(%.2fs user %.2fs system %.2fs wall %.2f cores)\n", + num_threads, + (num_threads * shared.loops) / (wall * tick * 1000), + user * tick, system * tick, wall * tick, + wall ? (user + system) * 1. / wall : 1.); + barrier_unblock(&shared.barrier_after); + for (i = 0; i < num_threads; i++) + pthread_join(thread[i], NULL); + } +} diff --git a/performance/run.sh b/performance/run.sh index c5acf10..a64332e 100755 --- a/performance/run.sh +++ b/performance/run.sh @@ -44,5 +44,6 @@ if [ "$USE_COLOR" -eq 1 ]; then COLOR="-c" fi +./futex_wait exit 0 |