From 45b1b8cb2a6588f9316f780d8cefe11c181a9a17 Mon Sep 17 00:00:00 2001 From: rpj Date: Sat, 16 Oct 2004 02:34:44 +0000 Subject: Mutex speedups cont'd --- tests/ChangeLog | 20 ++++-- tests/GNUmakefile | 5 +- tests/Makefile | 4 +- tests/benchtest1.c | 2 +- tests/rwlock7.c | 56 +++++++++------ tests/rwlock8.c | 205 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 260 insertions(+), 32 deletions(-) create mode 100644 tests/rwlock8.c (limited to 'tests') diff --git a/tests/ChangeLog b/tests/ChangeLog index 2d0c570..f55b2b6 100644 --- a/tests/ChangeLog +++ b/tests/ChangeLog @@ -1,14 +1,20 @@ -2004-09-08 Alexandre Girao +2004-10-14 Ross Johnson - * cancel7.c (main): Win98 wants a valid (non-NULL) location - for the last arg of _beginthreadex(). - * cancel8.c (main): Likewise. - * exit4.c (main): Likewise. - * exit5.c (main): Likewise. + * rwlock7.c (main): Tidy up statistics reporting; randomise + update accesses. + * rwlock8.c: New test. + +2004-09-08 Alexandre Girao + + * cancel7.c (main): Win98 wants a valid (non-NULL) location + for the last arg of _beginthreadex(). + * cancel8.c (main): Likewise. + * exit4.c (main): Likewise. + * exit5.c (main): Likewise. 2004-08-26 Ross Johnson - * create3.c: New test. + * create3.c: New test. 2004-06-21 Ross Johnson diff --git a/tests/GNUmakefile b/tests/GNUmakefile index cc36b53..0979fda 100644 --- a/tests/GNUmakefile +++ b/tests/GNUmakefile @@ -70,7 +70,7 @@ COPYFILES = $(HDR) $(LIB) $(DLL) $(QAPC) # stop. TESTS = sizes loadfree \ - semaphore1 semaphore2 self1 mutex5 mutex1 mutex1e mutex1n mutex1r \ + self1 mutex5 mutex1 mutex1e mutex1n mutex1r semaphore1 semaphore2 \ condvar1 condvar1_1 condvar1_2 condvar2 condvar2_1 exit1 \ create1 create2 reuse1 reuse2 equal1 \ kill1 valid1 valid2 \ @@ -85,7 +85,7 @@ TESTS = sizes loadfree \ condvar3 condvar3_1 condvar3_2 condvar3_3 \ condvar4 condvar5 condvar6 condvar7 condvar8 condvar9 \ errno1 \ - rwlock1 rwlock2 rwlock3 rwlock4 rwlock5 rwlock6 rwlock7 \ + rwlock1 rwlock2 rwlock3 rwlock4 rwlock5 rwlock6 rwlock7 rwlock8 \ rwlock2_t rwlock3_t rwlock4_t rwlock5_t rwlock6_t rwlock6_t2 \ context1 cancel3 cancel4 cancel5 cancel6a cancel6d \ cancel7 cancel8 \ @@ -240,6 +240,7 @@ rwlock4.pass: rwlock3.pass rwlock5.pass: rwlock4.pass rwlock6.pass: rwlock5.pass rwlock7.pass: rwlock6.pass +rwlock8.pass: rwlock7.pass rwlock2_t.pass: rwlock2.pass rwlock3_t.pass: rwlock2_t.pass rwlock4_t.pass: rwlock3_t.pass diff --git a/tests/Makefile b/tests/Makefile index 31979a4..535347f 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -100,7 +100,8 @@ PASSES= sizes.pass loadfree.pass \ condvar4.pass condvar5.pass condvar6.pass \ condvar7.pass condvar8.pass condvar9.pass \ errno1.pass \ - rwlock1.pass rwlock2.pass rwlock3.pass rwlock4.pass rwlock5.pass rwlock6.pass rwlock7.pass \ + rwlock1.pass rwlock2.pass rwlock3.pass rwlock4.pass \ + rwlock5.pass rwlock6.pass rwlock7.pass rwlock8.pass \ rwlock2_t.pass rwlock3_t.pass rwlock4_t.pass rwlock5_t.pass rwlock6_t.pass rwlock6_t2.pass \ context1.pass \ cancel3.pass cancel4.pass cancel5.pass cancel6a.pass cancel6d.pass \ @@ -324,6 +325,7 @@ rwlock4.pass: rwlock3.pass rwlock5.pass: rwlock4.pass rwlock6.pass: rwlock5.pass rwlock7.pass: rwlock6.pass +rwlock8.pass: rwlock7.pass rwlock2_t.pass: rwlock2.pass rwlock3_t.pass: rwlock2_t.pass rwlock4_t.pass: rwlock3_t.pass diff --git a/tests/benchtest1.c b/tests/benchtest1.c index ce45cf2..120eb19 100644 --- a/tests/benchtest1.c +++ b/tests/benchtest1.c @@ -179,7 +179,7 @@ main (int argc, char *argv[]) durationMilliSecs = GetDurationMilliSecs(currSysTimeStart, currSysTimeStop) - overHeadMilliSecs; printf( "%-45s %15ld %15.3f\n", - "Simple Critical Section x 2", + "Simple Critical Section", durationMilliSecs, (float) durationMilliSecs * 1E3 / ITERATIONS); diff --git a/tests/rwlock7.c b/tests/rwlock7.c index 8706d4a..91466e4 100644 --- a/tests/rwlock7.c +++ b/tests/rwlock7.c @@ -13,7 +13,7 @@ #endif #define THREADS 5 -#define DATASIZE 15 +#define DATASIZE 7 #define ITERATIONS 1000000 /* @@ -24,7 +24,8 @@ typedef struct thread_tag { pthread_t thread_id; int updates; int reads; - int interval; + int changed; + int seed; } thread_t; /* @@ -45,9 +46,12 @@ static data_t data[DATASIZE]; void *thread_routine (void *arg) { thread_t *self = (thread_t*)arg; - int repeats = 0; int iteration; int element = 0; + int seed = self->seed; + int interval = 1 + rand_r (&seed) % 71; + + self->changed = 0; for (iteration = 0; iteration < ITERATIONS; iteration++) { @@ -61,12 +65,13 @@ void *thread_routine (void *arg) * update operation (write lock instead of read * lock). */ - if ((iteration % self->interval) == 0) + if ((iteration % interval) == 0) { assert(pthread_rwlock_wrlock (&data[element].lock) == 0); data[element].data = self->thread_num; data[element].updates++; self->updates++; + interval = 1 + rand_r (&seed) % 71; assert(pthread_rwlock_unlock (&data[element].lock) == 0); } else { /* @@ -78,27 +83,17 @@ void *thread_routine (void *arg) self->reads++; - if (data[element].data == self->thread_num) + if (data[element].data != self->thread_num) { - repeats++; + self->changed++; + interval = 1 + self->changed % 71; } assert(pthread_rwlock_unlock (&data[element].lock) == 0); } - element++; - - if (element >= DATASIZE) - { - element = 0; - } - } + element = (element + 1) % DATASIZE; - if (repeats > 0) - { - printf ("\nThread %d found unchanged elements %d times", - self->thread_num, repeats); - fflush(stdout); } return NULL; @@ -137,7 +132,7 @@ main (int argc, char *argv[]) threads[count].thread_num = count; threads[count].updates = 0; threads[count].reads = 0; - threads[count].interval = rand_r (&seed) % 71; + threads[count].seed = 1 + rand_r (&seed) % 71; assert(pthread_create (&threads[count].thread_id, NULL, thread_routine, (void*)&threads[count]) == 0); @@ -150,9 +145,28 @@ main (int argc, char *argv[]) for (count = 0; count < THREADS; count++) { assert(pthread_join (threads[count].thread_id, NULL) == 0); + } + + putchar('\n'); + fflush(stdout); + + for (count = 0; count < THREADS; count++) + { + if (threads[count].changed > 0) + { + printf ("Thread %d found changed elements %d times\n", + count, threads[count].changed); + } + } + + putchar('\n'); + fflush(stdout); + + for (count = 0; count < THREADS; count++) + { thread_updates += threads[count].updates; - printf ("\n%02d: interval %d, updates %d, reads %d\n", - count, threads[count].interval, + printf ("%02d: seed %d, updates %d, reads %d\n", + count, threads[count].seed, threads[count].updates, threads[count].reads); } diff --git a/tests/rwlock8.c b/tests/rwlock8.c new file mode 100644 index 0000000..c83a775 --- /dev/null +++ b/tests/rwlock8.c @@ -0,0 +1,205 @@ +/* + * rwlock8.c + * + * Hammer on a bunch of rwlocks to test robustness and fairness. + * Printed stats should be roughly even for each thread. + * + * Yield during each access to exercise lock contention code paths + * more than rwlock7.c does (particularly on uni-processor systems). + */ + +#include "test.h" +#include + +#ifdef __GNUC__ +#include +#endif + +#define THREADS 5 +#define DATASIZE 7 +#define ITERATIONS 100000 + +/* + * Keep statistics for each thread. + */ +typedef struct thread_tag { + int thread_num; + pthread_t thread_id; + int updates; + int reads; + int changed; + int seed; +} thread_t; + +/* + * Read-write lock and shared data + */ +typedef struct data_tag { + pthread_rwlock_t lock; + int data; + int updates; +} data_t; + +static thread_t threads[THREADS]; +static data_t data[DATASIZE]; + +/* + * Thread start routine that uses read-write locks + */ +void *thread_routine (void *arg) +{ + thread_t *self = (thread_t*)arg; + int iteration; + int element = 0; + int seed = self->seed; + int interval = 1 + rand_r (&seed) % 71; + + self->changed = 0; + + for (iteration = 0; iteration < ITERATIONS; iteration++) + { + if (iteration % (ITERATIONS / 10) == 0) + { + putchar('.'); + fflush(stdout); + } + /* + * Each "self->interval" iterations, perform an + * update operation (write lock instead of read + * lock). + */ + if ((iteration % interval) == 0) + { + assert(pthread_rwlock_wrlock (&data[element].lock) == 0); + data[element].data = self->thread_num; + data[element].updates++; + self->updates++; + interval = 1 + rand_r (&seed) % 71; + sched_yield(); + assert(pthread_rwlock_unlock (&data[element].lock) == 0); + } else { + /* + * Look at the current data element to see whether + * the current thread last updated it. Count the + * times, to report later. + */ + assert(pthread_rwlock_rdlock (&data[element].lock) == 0); + + self->reads++; + + if (data[element].data != self->thread_num) + { + self->changed++; + interval = 1 + self->changed % 71; + } + + sched_yield(); + + assert(pthread_rwlock_unlock (&data[element].lock) == 0); + } + + element = (element + 1) % DATASIZE; + + } + + return NULL; +} + +int +main (int argc, char *argv[]) +{ + int count; + int data_count; + int thread_updates = 0; + int data_updates = 0; + int seed = 1; + + struct _timeb currSysTime1; + struct _timeb currSysTime2; + + /* + * Initialize the shared data. + */ + for (data_count = 0; data_count < DATASIZE; data_count++) + { + data[data_count].data = 0; + data[data_count].updates = 0; + + assert(pthread_rwlock_init (&data[data_count].lock, NULL) == 0); + } + + _ftime(&currSysTime1); + + /* + * Create THREADS threads to access shared data. + */ + for (count = 0; count < THREADS; count++) + { + threads[count].thread_num = count; + threads[count].updates = 0; + threads[count].reads = 0; + threads[count].seed = 1 + rand_r (&seed) % 71; + + assert(pthread_create (&threads[count].thread_id, + NULL, thread_routine, (void*)&threads[count]) == 0); + } + + /* + * Wait for all threads to complete, and collect + * statistics. + */ + for (count = 0; count < THREADS; count++) + { + assert(pthread_join (threads[count].thread_id, NULL) == 0); + } + + putchar('\n'); + fflush(stdout); + + for (count = 0; count < THREADS; count++) + { + if (threads[count].changed > 0) + { + printf ("Thread %d found changed elements %d times\n", + count, threads[count].changed); + } + } + + putchar('\n'); + fflush(stdout); + + for (count = 0; count < THREADS; count++) + { + thread_updates += threads[count].updates; + printf ("%02d: seed %d, updates %d, reads %d\n", + count, threads[count].seed, + threads[count].updates, threads[count].reads); + } + + putchar('\n'); + fflush(stdout); + + /* + * Collect statistics for the data. + */ + for (data_count = 0; data_count < DATASIZE; data_count++) + { + data_updates += data[data_count].updates; + printf ("data %02d: value %d, %d updates\n", + data_count, data[data_count].data, data[data_count].updates); + assert(pthread_rwlock_destroy (&data[data_count].lock) == 0); + } + + printf ("%d thread updates, %d data updates\n", + thread_updates, data_updates); + + _ftime(&currSysTime2); + + printf( "\nstart: %ld/%d, stop: %ld/%d, duration:%ld\n", + currSysTime1.time,currSysTime1.millitm, + currSysTime2.time,currSysTime2.millitm, + (currSysTime2.time*1000+currSysTime2.millitm) - + (currSysTime1.time*1000+currSysTime1.millitm)); + + return 0; +} -- cgit v1.2.3