summaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
authorrpj <rpj>2004-10-16 02:34:44 +0000
committerrpj <rpj>2004-10-16 02:34:44 +0000
commit45b1b8cb2a6588f9316f780d8cefe11c181a9a17 (patch)
tree24753e298d9933d48d764177baf183ef97f04156 /tests
parent9da8fdcb33373b4b2e1de2a8b7af3ed4b5811245 (diff)
Mutex speedups cont'd
Diffstat (limited to 'tests')
-rw-r--r--tests/ChangeLog20
-rw-r--r--tests/GNUmakefile5
-rw-r--r--tests/Makefile4
-rw-r--r--tests/benchtest1.c2
-rw-r--r--tests/rwlock7.c56
-rw-r--r--tests/rwlock8.c205
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;
+}