summaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
Diffstat (limited to 'tests')
-rw-r--r--tests/Bmakefile5
-rw-r--r--tests/GNUmakefile22
-rw-r--r--tests/Makefile66
-rw-r--r--tests/README.BENCHTESTS37
-rw-r--r--tests/stress1.c271
5 files changed, 351 insertions, 50 deletions
diff --git a/tests/Bmakefile b/tests/Bmakefile
index 2e3d48b..ff8c95b 100644
--- a/tests/Bmakefile
+++ b/tests/Bmakefile
@@ -110,7 +110,7 @@ PASSES= loadfree.pass \
spin1.pass spin2.pass spin3.pass spin4.pass \
barrier1.pass barrier2.pass barrier3.pass barrier4.pass barrier5.pass \
exception1.pass exception2.pass exception3.pass \
- cancel9.pass create3.pass
+ cancel9.pass create3.pass stress1.pass
BENCHRESULTS = \
benchtest1.bench benchtest2.bench benchtest3.bench benchtest4.bench benchtest5.bench
@@ -234,6 +234,7 @@ cancel6a.pass: cancel3.pass
cancel6d.pass: cancel3.pass
cancel7.pass: kill1.pass
cancel8.pass: cancel7.pass
+cancel9.pass: cancel8.pass
cleanup0.pass: cancel5.pass
cleanup1.pass: cleanup0.pass
cleanup2.pass: cleanup1.pass
@@ -339,7 +340,7 @@ spin1.pass:
spin2.pass: spin1.pass
spin3.pass: spin2.pass
spin4.pass: spin3.pass
+stress1.pass: barrier5.pass
tsd1.pass: join1.pass
valid1.pass: join1.pass
valid2.pass: valid1.pass
-cancel9.pass: cancel8.pass
diff --git a/tests/GNUmakefile b/tests/GNUmakefile
index 8700572..fc36c32 100644
--- a/tests/GNUmakefile
+++ b/tests/GNUmakefile
@@ -104,6 +104,9 @@ TESTS = sizes loadfree \
exception1 exception2 exception3 \
cancel9 create3
+STRESSTESTS = \
+ stress1
+
BENCHTESTS = \
benchtest1 benchtest2 benchtest3 benchtest4 benchtest5
@@ -112,6 +115,7 @@ STATICTESTS = \
PASSES = $(TESTS:%=%.pass)
BENCHRESULTS = $(BENCHTESTS:%=%.bench)
+STRESSRESULTS = $(STRESSTESTS:%=%.pass)
STATICRESULTS = $(STATICTESTS:%=%.pass)
help:
@@ -121,6 +125,8 @@ help:
@ $(ECHO) "make clean GCE (to test using GCE dll with C++ (EH) applications)"
@ $(ECHO) "make clean GC-bench (to benchtest using GNU C dll with C cleanup code)"
@ $(ECHO) "make clean GCE-bench (to benchtest using GNU C dll with C++ exception handling)"
+ @ $(ECHO) "make clean GC-stress (to stresstest using GNU C dll with C cleanup code)"
+ @ $(ECHO) "make clean GCE-stress (to stresstest using GNU C dll with C++ exception handling)"
@ $(ECHO) "make clean GC-static (to test using GC static lib with C (no EH) applications)"
all:
@@ -146,12 +152,24 @@ GCE-bench:
GC-static:
$(MAKE) TEST=GC CC=gcc XXCFLAGS="-D__CLEANUP_C -DPTW32_STATIC_LIB" DLL="" all-static
+GC-stress:
+ $(ECHO) Stress tests can take a long time since they are trying to
+ $(ECHO) expose weaknesses that may be intermittant or statistically rare.
+ $(ECHO) A pass does not prove correctness, but may give greater confidence.
+ $(MAKE) TEST=GC CC=gcc XXCFLAGS="-D__CLEANUP_C" all-stress
+
+GCE-stress:
+ $(MAKE) TEST=GCE CC=g++ XXCFLAGS="-mthreads -D__CLEANUP_CXX" all-stress
+
all-pass: $(PASSES)
@ $(ECHO) ALL TESTS PASSED! Congratulations!
all-bench: $(BENCHRESULTS)
@ $(ECHO) BENCH TESTS COMPLETED.
+all-stress: $(STRESSRESULTS)
+ @ $(ECHO) STRESS TESTS COMPLETED.
+
all-static: $(STATICRESULTS)
@ $(ECHO) ALL STATIC TESTS PASSED! Congratulations!
@ $(ECHO) Build and test the DLL to run all tests.
@@ -163,6 +181,8 @@ benchtest3.bench:
benchtest4.bench:
benchtest5.bench:
+stress1.pass:
+
barrier1.pass:
barrier2.pass: barrier1.pass
barrier3.pass: barrier2.pass
@@ -178,6 +198,7 @@ cancel6a.pass: cancel3.pass
cancel6d.pass: cancel3.pass
cancel7.pass: kill1.pass
cancel8.pass: cancel7.pass
+cancel9.pass: cancel8.pass
cleanup0.pass: cancel5.pass
cleanup1.pass: cleanup0.pass
cleanup2.pass: cleanup1.pass
@@ -286,7 +307,6 @@ spin4.pass: spin3.pass
tsd1.pass: join1.pass
valid1.pass: join1.pass
valid2.pass: valid1.pass
-cancel9.pass: cancel8.pass
sizes.pass: sizes.exe
@ $(ECHO) Running $*
diff --git a/tests/Makefile b/tests/Makefile
index 6a82a58..f227914 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -115,25 +115,32 @@ PASSES= sizes.pass loadfree.pass \
spin1.pass spin2.pass spin3.pass spin4.pass \
barrier1.pass barrier2.pass barrier3.pass barrier4.pass barrier5.pass \
exception1.pass exception2.pass exception3.pass \
- cancel9.pass create3.pass
+ cancel9.pass create3.pass
BENCHRESULTS = \
benchtest1.bench benchtest2.bench benchtest3.bench benchtest4.bench benchtest5.bench
+STRESSRESULTS = \
+ stress1.pass
+
STATICRESULTS = \
self1.pass
help:
@ $(ECHO) Run one of the following command lines:
- @ $(ECHO) nmake clean VC (to test using VC dll with VC (no EH) applications)
- @ $(ECHO) nmake clean VCX (to test using VC dll with VC++ (EH) applications)
- @ $(ECHO) nmake clean VCE (to test using the VCE dll with VC++ EH applications)
- @ $(ECHO) nmake clean VSE (to test using VSE dll with VC (SEH) applications)
- @ $(ECHO) nmake clean VC-bench (to benchtest using VC dll with C bench app)
- @ $(ECHO) nmake clean VCX-bench (to benchtest using VC dll with C++ bench app)
- @ $(ECHO) nmake clean VCE-bench (to benchtest using VCE dll with C++ bench app)
- @ $(ECHO) nmake clean VSE-bench (to benchtest using VSE dll with SEH bench app)
- @ $(ECHO) nmake clean VC-static (to test using VC static lib with VC (no EH) applications)
+ @ $(ECHO) nmake clean VC (to test using VC dll with VC (no EH) apps)
+ @ $(ECHO) nmake clean VC-bench (to benchtest using VC dll with C bench apps)
+ @ $(ECHO) nmake clean VC-stress (to stresstest using VC dll with C stress apps)
+ @ $(ECHO) nmake clean VC-static (to test using VC static lib with VC (no EH) apps)
+ @ $(ECHO) nmake clean VCX (to test using VC dll with VC++ (EH) applications)
+ @ $(ECHO) nmake clean VCX-bench (to benchtest using VC dll with C++ bench apps)
+ @ $(ECHO) nmake clean VCX-stress (to stresstest using VC dll with C++ stress apps)
+ @ $(ECHO) nmake clean VCE (to test using the VCE dll with VC++ EH applications)
+ @ $(ECHO) nmake clean VCE-bench (to benchtest using VCE dll with C++ bench apps)
+ @ $(ECHO) nmake clean VCE-stress (to stresstest using VCE dll with C++ stress apps)
+ @ $(ECHO) nmake clean VSE (to test using VSE dll with VC (SEH) apps)
+ @ $(ECHO) nmake clean VSE-bench (to benchtest using VSE dll with SEH bench apps)
+ @ $(ECHO) nmake clean VSE-stress (to stresstest using VSE dll with SEH stress apps)
all:
@ nmake clean VC
@@ -141,6 +148,7 @@ all:
@ nmake clean VCE
@ nmake clean VSE
@ nmake clean VC-bench
+ @ nmake clean VC-stress
# This allows an individual test application to be made using the default lib.
# e.g. nmake clean test cancel3.exe
@@ -152,6 +160,9 @@ tests: $(CPLIB) $(CPDLL) $(CPHDR) $(QAPC) $(PASSES)
benchtests: $(CPLIB) $(CPDLL) $(CPHDR) $(XXLIBS) $(BENCHRESULTS)
@ $(ECHO) ALL BENCH TESTS DONE.
+stresstests: $(CPLIB) $(CPDLL) $(CPHDR) $(STRESSRESULTS)
+ @ $(ECHO) ALL STRESS TESTS DONE.
+
statictests: $(CPLIB) $(CPDLL) $(CPHDR) $(STATICRESULTS)
@ $(ECHO) ALL STATIC TESTS DONE.
@ $(ECHO) Build and test the DLL to run all tests.
@@ -176,30 +187,48 @@ $(BENCHRESULTS): $*.exe
@ $(ECHO) ...... Done
@ $(TOUCH) $*.bench
+$(STRESSRESULTS): $*.exe
+ @ $(ECHO) ... Running $(TEST) stresstest: $*.exe
+ @ .\$*.exe
+ @ $(ECHO) ...... Done
+ @ $(TOUCH) $*.pass
+
+VC:
+ @ nmake TEST="$@" CPLIB="$(VCLIB)" CPDLL="$(VCDLL)" EHFLAGS="$(VCFLAGS)" tests
+
VCE:
@ nmake TEST="$@" CPLIB="$(VCELIB)" CPDLL="$(VCEDLL)" EHFLAGS="$(VCEFLAGS)" tests
VSE:
@ nmake TEST="$@" CPLIB="$(VSELIB)" CPDLL="$(VSEDLL)" EHFLAGS="$(VSEFLAGS)" tests
-VC:
- @ nmake TEST="$@" CPLIB="$(VCLIB)" CPDLL="$(VCDLL)" EHFLAGS="$(VCFLAGS)" tests
-
VCX:
@ nmake TEST="$@" CPLIB="$(VCLIB)" CPDLL="$(VCDLL)" EHFLAGS="$(VCXFLAGS)" tests
+VC-bench:
+ @ nmake TEST="$@" CPLIB="$(VCLIB)" CPDLL="$(VCDLL)" EHFLAGS="$(VCFLAGS)" XXLIBS="benchlib.o" benchtests
+
VCE-bench:
@ nmake TEST="$@" CPLIB="$(VCELIB)" CPDLL="$(VCEDLL)" EHFLAGS="$(VCEFLAGS)" XXLIBS="benchlib.o" benchtests
VSE-bench:
@ nmake TEST="$@" CPLIB="$(VSELIB)" CPDLL="$(VSEDLL)" EHFLAGS="$(VSEFLAGS)" XXLIBS="benchlib.o" benchtests
-VC-bench:
- @ nmake TEST="$@" CPLIB="$(VCLIB)" CPDLL="$(VCDLL)" EHFLAGS="$(VCFLAGS)" XXLIBS="benchlib.o" benchtests
-
VCX-bench:
@ nmake TEST="$@" CPLIB="$(VCLIB)" CPDLL="$(VCDLL)" EHFLAGS="$(VCXFLAGS)" XXLIBS="benchlib.o" benchtests
+VC-stress:
+ @ nmake TEST="$@" CPLIB="$(VCLIB)" CPDLL="$(VCDLL)" EHFLAGS="$(VCFLAGS)" stresstests
+
+VCE-stress:
+ @ nmake TEST="$@" CPLIB="$(VCELIB)" CPDLL="$(VCEDLL)" EHFLAGS="$(VCEFLAGS)" stresstests
+
+VSE-stress:
+ @ nmake TEST="$@" CPLIB="$(VSELIB)" CPDLL="$(VSEDLL)" EHFLAGS="$(VSEFLAGS)" stresstests
+
+VCX-stress:
+ @ nmake TEST="$@" CPLIB="$(VCLIB)" CPDLL="$(VCDLL)" EHFLAGS="$(VCXFLAGS)" stresstests
+
VC-static:
@ nmake TEST="$@" CPLIB="$(VCLIB)" CPDLL="" EHFLAGS="$(VCFLAGS) /DPTW32_STATIC_LIB" statictests
@@ -244,6 +273,9 @@ benchtest2.bench:
benchtest3.bench:
benchtest4.bench:
benchtest5.bench:
+
+stress1.pass:
+
barrier1.pass:
barrier2.pass: barrier1.pass
barrier3.pass: barrier2.pass
@@ -258,6 +290,7 @@ cancel6a.pass: cancel3.pass
cancel6d.pass: cancel3.pass
cancel7.pass: kill1.pass
cancel8.pass: cancel7.pass
+cancel9.pass: cancel8.pass
cleanup0.pass: cancel5.pass
cleanup1.pass: cleanup0.pass
cleanup2.pass: cleanup1.pass
@@ -366,4 +399,3 @@ spin4.pass: spin3.pass
tsd1.pass: join1.pass
valid1.pass: join1.pass
valid2.pass: valid1.pass
-cancel9.pass: cancel8.pass
diff --git a/tests/README.BENCHTESTS b/tests/README.BENCHTESTS
index e02cb3e..448570c 100644
--- a/tests/README.BENCHTESTS
+++ b/tests/README.BENCHTESTS
@@ -2,7 +2,7 @@
------------
Benchmarking
------------
-There is a new but growing set a benchmarking programs in the
+There is a set a benchmarking programs in the
"tests" directory. These should be runnable using the
following command-lines corresponding to each of the possible
library builds:
@@ -62,36 +62,13 @@ irrespective of the Windows variant, and should therefore
have consistent performance.
+Semaphore benchtests
+--------------------
+
+benchtest5 - Timing for various uncontended cases.
+
+
In all benchtests, the operation is repeated a large
number of times and an average is calculated. Loop
overhead is measured and subtracted from all test times.
-Comment on the results
-----------------------
-The gain in performance for Win9x systems is enormous - up to
-40 times faster for unlocked mutexes (2 times faster for locked
-mutexes).
-
-Pthread_mutex_trylock also appears to be faster for locked mutexes.
-
-The price for the new consistency between WinNT and Win9x is
-slower performance (up to twice as long) across a lock/unlock
-sequence. It is difficult to get a good split timing for lock
-and unlock operations, but by code inspection, it is the unlock
-operation that is slowing the pair down in comparison with the
-old-style CS mutexes, even for the fast PTHREAD_MUTEX_NORMAL mutex
-type with no other waiting threads. However, comparitive
-performance for operations on already locked mutexes is very close.
-
-When this is translated to real-world applications, the overall
-camparitive performance should be almost identical on NT class
-systems. That is, applications with heavy mutex contention should
-have almost equal performance, while applications with only light
-mutex contention should also have almost equal performance because
-the most critical operation in this case is the lock operation.
-
-Overall, the newer pthreads-win32 mutex routines are only slower
-(on NT class systems) where and when it is least critical.
-
-Thanks go to Thomas Pfaff for the current implementation of mutex
-routines.
diff --git a/tests/stress1.c b/tests/stress1.c
new file mode 100644
index 0000000..b8d1c77
--- /dev/null
+++ b/tests/stress1.c
@@ -0,0 +1,271 @@
+/*
+ * stress1.c
+ *
+ *
+ * --------------------------------------------------------------------------
+ *
+ * Pthreads-win32 - POSIX Threads Library for Win32
+ * Copyright(C) 1998 John E. Bossom
+ * Copyright(C) 1999,2005 Pthreads-win32 contributors
+ *
+ * Contact Email: rpj@callisto.canberra.edu.au
+ *
+ * The current list of contributors is contained
+ * in the file CONTRIBUTORS included with the source
+ * code distribution. The list can also be seen at the
+ * following World Wide Web location:
+ * http://sources.redhat.com/pthreads-win32/contributors.html
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library in the file COPYING.LIB;
+ * if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ *
+ * --------------------------------------------------------------------------
+ *
+ * Test Synopsis:
+ * - Stress test condition variables, mutexes, semaphores.
+ *
+ * Test Method (Validation or Falsification):
+ * - Validation
+ *
+ * Requirements Tested:
+ * - Correct accounting of semaphore and condition variable waiters.
+ *
+ * Features Tested:
+ * -
+ *
+ * Cases Tested:
+ * -
+ *
+ * Description:
+ * Attempting to expose race conditions in cond vars, semaphores etc.
+ * - Master attempts to signal slave close to when timeout is due.
+ * - Master and slave do battle continuously until main tells them to stop.
+ * - Afterwards, the CV must be successfully destroyed (will return an
+ * error if there are waiters (including any internal semaphore waiters,
+ * which, if there are, cannot not be real waiters).
+ *
+ * Environment:
+ * -
+ *
+ * Input:
+ * - None.
+ *
+ * Output:
+ * - File name, Line number, and failed expression on failure.
+ * - No output on success.
+ *
+ * Assumptions:
+ * -
+ *
+ * Pass Criteria:
+ * - CV is successfully destroyed.
+ *
+ * Fail Criteria:
+ * - CV destroy fails.
+ */
+
+#include "test.h"
+#include <string.h>
+#include <sys/timeb.h>
+
+
+const unsigned int ITERATIONS = 1000;
+
+static pthread_t master, slave;
+typedef struct {
+ int value;
+ pthread_cond_t cv;
+ pthread_mutex_t mx;
+} mysig_t;
+
+static int allExit;
+static mysig_t control = {0, PTHREAD_COND_INITIALIZER, PTHREAD_MUTEX_INITIALIZER};
+static pthread_barrier_t startBarrier, readyBarrier, holdBarrier;
+static int timeoutCount = 0;
+static int signalsTakenCount = 0;
+static int signalsSent = 0;
+static int bias = 0;
+static int timeout = 10; // Must be > 0
+
+enum {
+ CTL_STOP = -1
+};
+
+/*
+ * Returns abstime 'milliseconds' from 'now'.
+ */
+struct timespec *
+millisecondsFromNow (struct timespec * time, int millisecs)
+{
+ struct _timeb currSysTime;
+ int64_t nanosecs, secs;
+ const int64_t NANOSEC_PER_MILLISEC = 1000000;
+ const int64_t NANOSEC_PER_SEC = 1000000000;
+
+ /* get current system time and add millisecs */
+ _ftime(&currSysTime);
+
+ nanosecs = ((int64_t) (millisecs + currSysTime.millitm)) * NANOSEC_PER_MILLISEC;
+ if (nanosecs >= NANOSEC_PER_SEC)
+ {
+ secs = currSysTime.time + 1;
+ nanosecs %= NANOSEC_PER_SEC;
+ }
+ else
+ {
+ secs = currSysTime.time;
+ }
+
+ time->tv_nsec = (long)nanosecs;
+ time->tv_sec = (long)secs;
+
+ return time;
+}
+
+void *
+masterThread (void * arg)
+{
+ int dither = (int) arg;
+
+ timeout = (int) arg;
+
+ pthread_barrier_wait(&startBarrier);
+
+ do
+ {
+ int sleepTime;
+
+ assert(pthread_mutex_lock(&control.mx) == 0);
+ control.value = timeout;
+ assert(pthread_mutex_unlock(&control.mx) == 0);
+
+ /*
+ * We are attempting to send the signal close to when the slave
+ * is due to timeout. We feel around by adding some [non-random] dither.
+ *
+ * with dither added, sleep time range is 2*timeout peak-to-peak centred on timeout,
+ * e.g.
+ * if timeout = 10 then dither = 20 and
+ * sleep millisecs is: 5 <= ms <= 15
+ *
+ * The bias value attempts to apply some negative feedback to keep
+ * the ratio of timeouts to signals taken close to 1:1.
+ * bias changes more slowly than dither so as to average more.
+ */
+ if (signalsSent % timeout == 0)
+ {
+ if (timeoutCount > signalsTakenCount)
+ {
+ bias++;
+ }
+ else if (timeoutCount < signalsTakenCount)
+ {
+ bias--;
+ }
+ if (bias < -timeout || bias > timeout)
+ {
+ timeout++;
+ }
+ }
+ dither = (dither + 1 ) % (timeout * 2);
+ sleepTime = (timeout - bias + dither) / 2;
+ Sleep(sleepTime);
+ assert(pthread_cond_signal(&control.cv) == 0);
+ signalsSent++;
+
+ pthread_barrier_wait(&holdBarrier);
+ pthread_barrier_wait(&readyBarrier);
+ }
+ while (!allExit);
+
+ return NULL;
+}
+
+void *
+slaveThread (void * arg)
+{
+ struct timespec time;
+
+ pthread_barrier_wait(&startBarrier);
+
+ do
+ {
+ assert(pthread_mutex_lock(&control.mx) == 0);
+ if (pthread_cond_timedwait(&control.cv,
+ &control.mx,
+ millisecondsFromNow(&time, control.value)) == ETIMEDOUT)
+ {
+ timeoutCount++;
+ }
+ else
+ {
+ signalsTakenCount++;
+ }
+ assert(pthread_mutex_unlock(&control.mx) == 0);
+
+ pthread_barrier_wait(&holdBarrier);
+ pthread_barrier_wait(&readyBarrier);
+ }
+ while (!allExit);
+
+ return NULL;
+}
+
+int
+main ()
+{
+ unsigned int i;
+
+ assert(pthread_barrier_init(&startBarrier, NULL, 3) == 0);
+ assert(pthread_barrier_init(&readyBarrier, NULL, 3) == 0);
+ assert(pthread_barrier_init(&holdBarrier, NULL, 3) == 0);
+
+ assert(pthread_create(&master, NULL, masterThread, (void *) timeout) == 0);
+ assert(pthread_create(&slave, NULL, slaveThread, NULL) == 0);
+
+ allExit = FALSE;
+
+ pthread_barrier_wait(&startBarrier);
+
+ for (i = 1; !allExit; i++)
+ {
+ pthread_barrier_wait(&holdBarrier);
+ if (i >= ITERATIONS)
+ {
+ allExit = TRUE;
+ }
+ pthread_barrier_wait(&readyBarrier);
+ }
+
+ assert(pthread_join(slave, NULL) == 0);
+ assert(pthread_join(master, NULL) == 0);
+
+ printf("Signals sent = %d\nWait timeouts = %d\nSignals taken = %d\nBias = %d\nTimeout = %d\n",
+ signalsSent,
+ timeoutCount,
+ signalsTakenCount,
+ (int) bias,
+ timeout);
+
+ /* Cleanup */
+ assert(pthread_barrier_destroy(&holdBarrier) == 0);
+ assert(pthread_barrier_destroy(&readyBarrier) == 0);
+ assert(pthread_barrier_destroy(&startBarrier) == 0);
+ assert(pthread_cond_destroy(&control.cv) == 0);
+ assert(pthread_mutex_destroy(&control.mx) == 0);
+
+ /* Success. */
+ return 0;
+}