From 20bf310ac72677961e55867dd64d058f77e0d7e6 Mon Sep 17 00:00:00 2001 From: Mathieu Desnoyers Date: Sun, 8 Feb 2009 15:42:08 -0500 Subject: [PATCH] Add timing tests initial results : On a 8-cores x86_64 test_rwlock_timing.c : 4339.07 cycles test_urcu_timing.c : 14.16 cycles Speedup : 306 Signed-off-by: Mathieu Desnoyers --- Makefile | 21 ++++- test_rwlock_timing.c | 163 ++++++++++++++++++++++++++++++++++++++ test_urcu.c | 3 +- test_urcu_timing.c | 181 +++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 364 insertions(+), 4 deletions(-) create mode 100644 test_rwlock_timing.c create mode 100644 test_urcu_timing.c diff --git a/Makefile b/Makefile index d787820..1bc089f 100644 --- a/Makefile +++ b/Makefile @@ -1,11 +1,26 @@ +CFLAGS=-Wall -O2 +#debug +#CFLAGS=-Wall -g +LDFLAGS=-lpthread + +SRC_DEP=`echo $^ | sed 's/[^ ]*.h//g'` + +all: test_urcu test_urcu_timing test_rwlock_timing + test_urcu: urcu.o test_urcu.c - gcc -Wall -lpthread -g -o test_urcu urcu.o test_urcu.c + $(CC) ${CFLAGS} $(LDFLAGS) -o $@ $(SRC_DEP) + +test_urcu_timing: urcu.o test_urcu_timing.c + $(CC) ${CFLAGS} $(LDFLAGS) -o $@ $(SRC_DEP) + +test_rwlock_timing: urcu.o test_rwlock_timing.c + $(CC) ${CFLAGS} $(LDFLAGS) -o $@ $(SRC_DEP) urcu.o: urcu.c urcu.h - gcc -Wall -lpthread -g -c -o urcu.o urcu.c + $(CC) ${CFLAGS} $(LDFLAGS) -c -o $@ $(SRC_DEP) .PHONY: clean clean: - rm -f urcu.o test_urcu + rm -f urcu.o test_urcu test_urcu_timing diff --git a/test_rwlock_timing.c b/test_rwlock_timing.c new file mode 100644 index 0000000..065c2d3 --- /dev/null +++ b/test_rwlock_timing.c @@ -0,0 +1,163 @@ +/* + * test_urcu.c + * + * Userspace RCU library - test program + * + * Copyright February 2009 - Mathieu Desnoyers + * + * Distributed under GPLv2 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(_syscall0) +_syscall0(pid_t, gettid) +#elif defined(__NR_gettid) +static inline pid_t gettid(void) +{ + return syscall(__NR_gettid); +} +#else +#warning "use pid as tid" +static inline pid_t gettid(void) +{ + return getpid(); +} +#endif + +#define rdtscll(val) do { \ + unsigned int __a,__d; \ + asm volatile("rdtsc" : "=a" (__a), "=d" (__d)); \ + (val) = ((unsigned long)__a) | (((unsigned long)__d)<<32); \ +} while(0) + +typedef unsigned long long cycles_t; + +static inline cycles_t get_cycles (void) +{ + unsigned long long ret = 0; + + rdtscll(ret); + return ret; +} + +#include "urcu.h" + +struct test_array { + int a; +}; + +pthread_rwlock_t lock = PTHREAD_RWLOCK_INITIALIZER; + +static struct test_array test_array = { 8 }; + +#define OUTER_READ_LOOP 200U +#define INNER_READ_LOOP 100000U +#define READ_LOOP ((unsigned long long)OUTER_READ_LOOP * INNER_READ_LOOP) + +#define WRITE_LOOP 2000U + +#define NR_READ 10 +#define NR_WRITE 9 + +static cycles_t reader_time[NR_READ] __attribute__((aligned(128))); + +void *thr_reader(void *arg) +{ + int i, j; + cycles_t time1, time2; + + printf("thread_begin %s, thread id : %lx, tid %lu\n", + "reader", pthread_self(), (unsigned long)gettid()); + sleep(2); + + time1 = get_cycles(); + for (i = 0; i < OUTER_READ_LOOP; i++) { + for (j = 0; j < INNER_READ_LOOP; j++) { + pthread_rwlock_rdlock(&lock); + assert(test_array.a == 8); + pthread_rwlock_unlock(&lock); + } + } + time2 = get_cycles(); + + reader_time[(unsigned long)arg] = time2 - time1; + + sleep(2); + printf("thread_end %s, thread id : %lx, tid %lu\n", + "reader", pthread_self(), (unsigned long)gettid()); + return ((void*)1); + +} + +void *thr_writer(void *arg) +{ + int i; + + printf("thread_begin %s, thread id : %lx, tid %lu\n", + "writer", pthread_self(), (unsigned long)gettid()); + sleep(2); + + for (i = 0; i < WRITE_LOOP; i++) { + pthread_rwlock_wrlock(&lock); + test_array.a = 8; + pthread_rwlock_unlock(&lock); + usleep(1); + } + + printf("thread_end %s, thread id : %lx, tid %lu\n", + "writer", pthread_self(), (unsigned long)gettid()); + return ((void*)2); +} + +int main() +{ + int err; + pthread_t tid_reader[NR_READ], tid_writer[NR_WRITE]; + void *tret; + int i; + cycles_t tot_time = 0; + + printf("thread %-6s, thread id : %lx, tid %lu\n", + "main", pthread_self(), (unsigned long)gettid()); + + for (i = 0; i < NR_READ; i++) { + err = pthread_create(&tid_reader[i], NULL, thr_reader, + (void *)(long)i); + if (err != 0) + exit(1); + } + for (i = 0; i < NR_WRITE; i++) { + err = pthread_create(&tid_writer[i], NULL, thr_writer, NULL); + if (err != 0) + exit(1); + } + + sleep(10); + + for (i = 0; i < NR_READ; i++) { + err = pthread_join(tid_reader[i], &tret); + if (err != 0) + exit(1); + tot_time += reader_time[i]; + } + for (i = 0; i < NR_WRITE; i++) { + err = pthread_join(tid_writer[i], &tret); + if (err != 0) + exit(1); + } + printf("Time per read : %g cycles\n", + (double)tot_time / ((double)NR_READ * (double)READ_LOOP)); + + return 0; +} diff --git a/test_urcu.c b/test_urcu.c index ea5a784..7752e6e 100644 --- a/test_urcu.c +++ b/test_urcu.c @@ -137,7 +137,7 @@ int main() sleep(10); - for (i = 0; i < NR_WRITE; i++) { + for (i = 0; i < NR_READ; i++) { err = pthread_join(tid_reader[i], &tret); if (err != 0) exit(1); @@ -147,6 +147,7 @@ int main() if (err != 0) exit(1); } + free(test_rcu_pointer); return 0; } diff --git a/test_urcu_timing.c b/test_urcu_timing.c new file mode 100644 index 0000000..6161192 --- /dev/null +++ b/test_urcu_timing.c @@ -0,0 +1,181 @@ +/* + * test_urcu.c + * + * Userspace RCU library - test program + * + * Copyright February 2009 - Mathieu Desnoyers + * + * Distributed under GPLv2 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(_syscall0) +_syscall0(pid_t, gettid) +#elif defined(__NR_gettid) +static inline pid_t gettid(void) +{ + return syscall(__NR_gettid); +} +#else +#warning "use pid as tid" +static inline pid_t gettid(void) +{ + return getpid(); +} +#endif + +#define rdtscll(val) do { \ + unsigned int __a,__d; \ + asm volatile("rdtsc" : "=a" (__a), "=d" (__d)); \ + (val) = ((unsigned long)__a) | (((unsigned long)__d)<<32); \ +} while(0) + +typedef unsigned long long cycles_t; + +static inline cycles_t get_cycles (void) +{ + unsigned long long ret = 0; + + rdtscll(ret); + return ret; +} + +#include "urcu.h" + +struct test_array { + int a; +}; + +static struct test_array *test_rcu_pointer; + +#define OUTER_READ_LOOP 2000U +#define INNER_READ_LOOP 100000U +#define READ_LOOP ((unsigned long long)OUTER_READ_LOOP * INNER_READ_LOOP) + +#define WRITE_LOOP 2000U + +#define NR_READ 10 +#define NR_WRITE 9 + +static cycles_t reader_time[NR_READ] __attribute__((aligned(128))); + +void *thr_reader(void *arg) +{ + int qparity, i, j; + struct test_array *local_ptr; + cycles_t time1, time2; + + printf("thread_begin %s, thread id : %lx, tid %lu\n", + "reader", pthread_self(), (unsigned long)gettid()); + sleep(2); + + urcu_register_thread(); + + time1 = get_cycles(); + for (i = 0; i < OUTER_READ_LOOP; i++) { + for (j = 0; j < INNER_READ_LOOP; j++) { + qparity = rcu_read_lock(); + local_ptr = rcu_dereference(test_rcu_pointer); + if (local_ptr) { + assert(local_ptr->a == 8); + } + rcu_read_unlock(qparity); + } + } + time2 = get_cycles(); + + urcu_unregister_thread(); + + reader_time[(unsigned long)arg] = time2 - time1; + + sleep(2); + printf("thread_end %s, thread id : %lx, tid %lu\n", + "reader", pthread_self(), (unsigned long)gettid()); + return ((void*)1); + +} + +void *thr_writer(void *arg) +{ + int i; + struct test_array *new, *old; + + printf("thread_begin %s, thread id : %lx, tid %lu\n", + "writer", pthread_self(), (unsigned long)gettid()); + sleep(2); + + for (i = 0; i < WRITE_LOOP; i++) { + new = malloc(sizeof(struct test_array)); + rcu_write_lock(); + old = test_rcu_pointer; + if (old) { + assert(old->a == 8); + } + new->a = 8; + old = urcu_publish_content((void **)&test_rcu_pointer, new); + rcu_write_unlock(); + /* can be done after unlock */ + if (old) { + old->a = 0; + } + free(old); + usleep(1); + } + + printf("thread_end %s, thread id : %lx, tid %lu\n", + "writer", pthread_self(), (unsigned long)gettid()); + return ((void*)2); +} + +int main() +{ + int err; + pthread_t tid_reader[NR_READ], tid_writer[NR_WRITE]; + void *tret; + int i; + cycles_t tot_time = 0; + + printf("thread %-6s, thread id : %lx, tid %lu\n", + "main", pthread_self(), (unsigned long)gettid()); + + for (i = 0; i < NR_READ; i++) { + err = pthread_create(&tid_reader[i], NULL, thr_reader, + (void *)(long)i); + if (err != 0) + exit(1); + } + for (i = 0; i < NR_WRITE; i++) { + err = pthread_create(&tid_writer[i], NULL, thr_writer, NULL); + if (err != 0) + exit(1); + } + + sleep(10); + + for (i = 0; i < NR_READ; i++) { + err = pthread_join(tid_reader[i], &tret); + if (err != 0) + exit(1); + tot_time += reader_time[i]; + } + for (i = 0; i < NR_WRITE; i++) { + err = pthread_join(tid_writer[i], &tret); + if (err != 0) + exit(1); + } + free(test_rcu_pointer); + printf("Time per read : %g cycles\n", + (double)tot_time / ((double)NR_READ * (double)READ_LOOP)); + + return 0; +} -- 2.34.1