diff options
Diffstat (limited to 'tests')
| -rw-r--r-- | tests/ChangeLog | 20 | ||||
| -rw-r--r-- | tests/GNUmakefile | 5 | ||||
| -rw-r--r-- | tests/Makefile | 4 | ||||
| -rw-r--r-- | tests/benchtest1.c | 2 | ||||
| -rw-r--r-- | tests/rwlock7.c | 56 | ||||
| -rw-r--r-- | tests/rwlock8.c | 205 | 
6 files changed, 260 insertions, 32 deletions
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  <alexgirao@gmail.com> +2004-10-14  Ross Johnson  <rpj@callisto.canberra.edu.au> -	* 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  <alexgirao@gmail.com>
 + +	* 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  <rpj@callisto.canberra.edu.au>
 -	* create3.c: New test. +	* create3.c: New test.
  2004-06-21  Ross Johnson  <rpj@callisto.canberra.edu.au>
 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 <sys/timeb.h> + +#ifdef __GNUC__ +#include <stdlib.h> +#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; +}  | 
