summaryrefslogtreecommitdiff
path: root/tests/benchtest2.c
diff options
context:
space:
mode:
authorrpj <rpj>2001-07-01 13:23:10 +0000
committerrpj <rpj>2001-07-01 13:23:10 +0000
commita311086d622d3c778e1da57cfae167c0ab1c0fb4 (patch)
tree760a76a351c18331ff92239366804bd4b866dea6 /tests/benchtest2.c
parent528fccade9ca5f90db376e08b2cb85b3fc822a45 (diff)
2001-06-25 Ross Johnson <rpj@setup1.ise.canberra.edu.au>
* create.c (pthread_create): Add priority inheritance attributes. * mutex.c (pthread_mutex_lock): Remove some overhead for PTHREAD_MUTEX_NORMAL mutex types. Specifically, avoid calling pthread_self() and pthread_equal() to check/set the mutex owner. Introduce a new pseudo owner for this type. Test results suggest increases in speed of up to 90% for non-blocking locks. This is the default type of mutex used internally by other synchronising objects, ie. condition variables and read-write locks. The test rwlock7.c shows about a 30-35% speed increase over snapshot 2001-06-06. The price of this is that the application developer must ensure correct behaviour, or explicitly set the mutex to a safer type such as PTHREAD_MUTEX_ERRORCHECK. For example, PTHREAD_MUTEX_NORMAL (or PTHREAD_MUTEX_DEFAULT) type mutexes will not return an error if a thread which is not the owner calls pthread_mutex_unlock. The call will succeed in unlocking the mutex if it is currently locked, but a subsequent unlock by the true owner will then fail with EPERM. This is however consistent with some other implementations. (pthread_mutex_unlock): Likewise. (pthread_mutex_trylock): Likewise. (pthread_mutex_destroy): Likewise. * attr.c (pthread_attr_init): PTHREAD_EXPLICIT_SCHED is the default inheritance attribute; THREAD_PRIORITY_NORMAL is the default priority for new threads. * sched.c (pthread_attr_setschedpolicy): Added routine. (pthread_attr_getschedpolicy): Added routine. (pthread_attr_setinheritsched): Added routine. (pthread_attr_getinheritsched): Added routine. * pthread.h (sched_rr_set_interval): Added as a macro; returns -1 with errno set to ENOSYS. 2001-06-23 Ross Johnson <rpj@setup1.ise.canberra.edu.au> *sched.c (pthread_attr_setschedparam): Add priority range check. (sched_setscheduler): New function; checks for a valid pid and policy; checks for permission to set information in the target process; expects pid to be a Win32 process ID, not a process handle; the only scheduler policy allowed is SCHED_OTHER. (sched_getscheduler): Likewise, but checks for permission to query. * pthread.h (SCHED_*): Moved to sched.h as defined in the POSIX standard. * sched.h (SCHED_*): Moved from pthread.h. (pid_t): Defined if necessary. (sched_setscheduler): Defined. (sched_getscheduler): Defined. * pthread.def (sched_setscheduler): Exported. (sched_getscheduler): Likewise. 2001-06-23 Ross Johnson <rpj@setup1.ise.canberra.edu.au> Contributed by - Ralf Brese <Ralf.Brese@pdb4.siemens.de> * create.c (pthread_create): Set thread priority from thread attributes.
Diffstat (limited to 'tests/benchtest2.c')
-rw-r--r--tests/benchtest2.c183
1 files changed, 183 insertions, 0 deletions
diff --git a/tests/benchtest2.c b/tests/benchtest2.c
new file mode 100644
index 0000000..f2932b9
--- /dev/null
+++ b/tests/benchtest2.c
@@ -0,0 +1,183 @@
+/*
+ * benchtest1.c
+ *
+ * Measure time taken to complete an elementary operation.
+ *
+ * - Mutex
+ * Two threads iterate over lock/unlock for each mutex type.
+ * The two threads are forced into lock-step using two mutexes,
+ * forcing the threads to block on each lock operation. The
+ * time measured is therefore the worst case senario.
+ */
+
+#include "test.h"
+#include <sys/timeb.h>
+
+#ifdef __GNUC__
+#include <stdlib.h>
+#endif
+
+#define ITERATIONS 100000L
+
+pthread_mutex_t gate1, gate2;
+pthread_mutexattr_t ma;
+long durationMilliSecs;
+long overHeadMilliSecs = 0;
+struct _timeb currSysTimeStart;
+struct _timeb currSysTimeStop;
+pthread_t worker;
+int running = 0;
+
+#define GetDurationMilliSecs(_TStart, _TStop) ((_TStop.time*1000+_TStop.millitm) \
+ - (_TStart.time*1000+_TStart.millitm))
+
+/*
+ * Dummy use of j, otherwise the loop may be removed by the optimiser
+ * when doing the overhead timing with an empty loop.
+ */
+#define TESTSTART \
+ { int i, j = 0, k = 0; _ftime(&currSysTimeStart); for (i = 0; i < ITERATIONS; i++) { j++;
+
+#define TESTSTOP \
+ }; _ftime(&currSysTimeStop); if (j + k == i) j++; }
+
+
+void *
+overheadThread(void * arg)
+{
+ do
+ {
+ sched_yield();
+ }
+ while (running);
+
+ return NULL;
+}
+
+
+void *
+workerThread(void * arg)
+{
+ do
+ {
+ (void) pthread_mutex_lock(&gate1);
+ (void) pthread_mutex_lock(&gate2);
+ (void) pthread_mutex_unlock(&gate1);
+ sched_yield();
+ (void) pthread_mutex_unlock(&gate2);
+ }
+ while (running);
+
+ return NULL;
+}
+
+void
+runTest (char * testNameString, int mType)
+{
+#ifdef PTHREAD_MUTEX_DEFAULT
+ pthread_mutexattr_settype(&ma, mType);
+#endif
+ pthread_mutex_init(&gate1, &ma);
+ pthread_mutex_init(&gate2, &ma);
+
+ (void) pthread_mutex_lock(&gate1);
+ (void) pthread_mutex_lock(&gate2);
+
+ running = 1;
+
+ (void) pthread_create(&worker, NULL, workerThread, NULL);
+
+ TESTSTART
+ (void) pthread_mutex_unlock(&gate1);
+ sched_yield();
+ (void) pthread_mutex_unlock(&gate2);
+ (void) pthread_mutex_lock(&gate1);
+ (void) pthread_mutex_lock(&gate2);
+ TESTSTOP
+
+ running = 0;
+
+ (void) pthread_mutex_unlock(&gate2);
+ (void) pthread_mutex_unlock(&gate1);
+
+ (void) pthread_join(worker, NULL);
+
+ pthread_mutex_destroy(&gate2);
+ pthread_mutex_destroy(&gate1);
+
+ durationMilliSecs = GetDurationMilliSecs(currSysTimeStart, currSysTimeStop)
+ - overHeadMilliSecs;
+
+ printf( "%-25s %15ld %15ld %15.3f\n",
+ testNameString,
+ ITERATIONS,
+ durationMilliSecs,
+ (float) durationMilliSecs * 1E3 / ITERATIONS / 4 /* Four locks/unlocks per iteration */);
+}
+
+
+int
+main (int argc, char *argv[])
+{
+ pthread_mutexattr_init(&ma);
+
+ printf( "Two threads, blocking mutex locks/unlocks.\n\n");
+
+ printf( "%-25s %15s %15s %15s\n",
+ "Test",
+ "Iterations",
+ "Total(msec)",
+ "lock/unlock(usec)");
+
+ /*
+ * Time the loop overhead so we can subtract it from the actual test times.
+ */
+
+ running = 1;
+
+ (void) pthread_create(&worker, NULL, overheadThread, NULL);
+
+ TESTSTART
+ sched_yield();
+ TESTSTOP
+
+ running = 0;
+
+ (void) pthread_join(worker, NULL);
+
+ pthread_mutex_destroy(&gate2);
+ pthread_mutex_destroy(&gate1);
+
+ durationMilliSecs = GetDurationMilliSecs(currSysTimeStart, currSysTimeStop)
+ - overHeadMilliSecs;
+
+ printf( "%-25s %15ld %15ld\n",
+ "Overhead",
+ ITERATIONS,
+ durationMilliSecs);
+
+ overHeadMilliSecs = durationMilliSecs;
+
+ /*
+ * Now we can start the actual tests
+ */
+#ifdef PTHREAD_MUTEX_DEFAULT
+ runTest("PTHREAD_MUTEX_DEFAULT", PTHREAD_MUTEX_DEFAULT);
+
+ runTest("PTHREAD_MUTEX_NORMAL", PTHREAD_MUTEX_NORMAL);
+
+ runTest("PTHREAD_MUTEX_ERRORCHECK", PTHREAD_MUTEX_ERRORCHECK);
+
+ runTest("PTHREAD_MUTEX_RECURSIVE", PTHREAD_MUTEX_RECURSIVE);
+#else
+ runTest("Blocking locks", 0);
+#endif
+
+ /*
+ * End of tests.
+ */
+
+ pthread_mutexattr_destroy(&ma);
+
+ return 0;
+}