/* $Source: /var/local/cvs/gasnet/tests/testlockcontend.c,v $ * $Date: 2006/10/03 23:00:46 $ * $Revision: 1.3 $ * Description: GASNet lock performance test * Measures the overhead associated with contended locks * Copyright 2002, Dan Bonachea * Terms of use are as specified in license.txt */ #include #ifndef GASNET_PAR #error This test can only be built for GASNet PAR configuration #endif int mynode = 0; int iters=0; void *myseg = NULL; int accuracy = 0; int maxthreads = 2; int threads = 1; void header(const char *desc) { printf("\n---- %s ----\n" " Threads Total time Avg. time\n" " ------- ---------- ---------\n", desc); } void report(int threads, int64_t totaltime, int iters) { char format[80]; sprintf(format, "%c: %%6i %%%i.%if s %%%i.%if us\n", TEST_SECTION_NAME(), (4+accuracy), accuracy, (4+accuracy), accuracy); printf(format, threads, totaltime/1.0E9, (totaltime/1000.0)/iters); fflush(stdout); } /* placed in a function to avoid excessive inlining */ gasnett_tick_t ticktime() { return gasnett_ticks_now(); } uint64_t tickcvt(gasnett_tick_t ticks) { return gasnett_ticks_to_ns(ticks); } void* thread_fn1(void*); void* thread_fn2(void*); void* thread_fn3(void*); void* thread_fn4(void*); /* ------------------------------------------------------------------------------------ */ /* This tester measures the performance of contended HSLs and pthread mutexes. */ int main(int argc, char **argv) { GASNET_Safe(gasnet_init(&argc, &argv)); GASNET_Safe(gasnet_attach(NULL, 0, TEST_SEGSZ_REQUEST, TEST_MINHEAPOFFSET)); test_init("testlockcontend",1,"(maxthreads) (iters) (accuracy) (test sections)"); if (argc > 1) maxthreads = atoi(argv[1]); if (maxthreads > TEST_MAXTHREADS || maxthreads < 1) { printf("Threads must be between 1 and %i\n", TEST_MAXTHREADS); gasnet_exit(-1); } if (argc > 2) iters = atoi(argv[2]); if (!iters) iters = 1000000; if (argc > 3) accuracy = atoi(argv[3]); if (!accuracy) accuracy = 3; if (argc > 4) TEST_SECTION_PARSE(argv[4]); if (argc > 5) test_usage(); mynode = gasnet_mynode(); myseg = TEST_MYSEG(); if (mynode == 0) { printf("Running locks performance test with 1..%i threads and %i iterations...\n",maxthreads,iters); fflush(stdout); MSG0("Spawning pthreads..."); if (TEST_SECTION_BEGIN_ENABLED()) { header("lock/unlock contended pthread mutex (others in thread barrier)"); test_createandjoin_pthreads(threads = maxthreads, &thread_fn1, NULL, 0); } if (TEST_SECTION_BEGIN_ENABLED()) { header("lock/unlock contended HSL (others in thread barrier)"); test_createandjoin_pthreads(threads = maxthreads, &thread_fn2, NULL, 0); } if (TEST_SECTION_BEGIN_ENABLED()) { header("lock/unlock contended pthread mutex (no other threads)"); for (threads=1; threads<=maxthreads; ++threads) { test_createandjoin_pthreads(threads, &thread_fn3, NULL, 0); } } if (TEST_SECTION_BEGIN_ENABLED()) { header("lock/unlock contended HSL (no other threads)"); for (threads=1; threads<=maxthreads; ++threads) { test_createandjoin_pthreads(threads, &thread_fn4, NULL, 0); } } } BARRIER(); MSG("done."); gasnet_exit(0); return 0; } /* ------------------------------------------------------------------------------------ */ #undef MSG0 #undef ERR #define MSG0 THREAD_MSG0(id) #define ERR THREAD_ERR(id) pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; gasnet_hsl_t hsl = GASNET_HSL_INITIALIZER; /* ------------------------------------------------------------------------------------ */ #define TIME_OPERATION_SOME(id, op) \ do { \ PTHREAD_LOCALBARRIER(threads); \ { int i, _thr, _iters = iters, _warmupiters = MAX(1,iters/10);\ gasnett_tick_t start,end; /* use ticks interface */ \ for (i=0; i < _warmupiters; i++) { op; } /* warm-up */ \ for (_thr = 1; _thr <= threads; ++_thr) { \ PTHREAD_LOCALBARRIER(threads); \ start = ticktime(); \ if (id < _thr) for (i=0; i < _iters; i++) { op; } \ PTHREAD_LOCALBARRIER(threads); \ end = ticktime(); \ if (!id) \ report(_thr, tickcvt(end - start), iters); \ } \ } \ } while (0) void * thread_fn1(void *arg) { GASNET_BEGIN_FUNCTION(); int id = (int)(uintptr_t)arg; TIME_OPERATION_SOME(id, { pthread_mutex_lock(&mutex); pthread_mutex_unlock(&mutex); }); return NULL; } void * thread_fn2(void *arg) { GASNET_BEGIN_FUNCTION(); int id = (int)(uintptr_t)arg; TIME_OPERATION_SOME(id, { gasnet_hsl_lock(&hsl); gasnet_hsl_unlock(&hsl); }); return NULL; } /* ------------------------------------------------------------------------------------ */ #define TIME_OPERATION_ALL(id, op) \ do { \ PTHREAD_LOCALBARRIER(threads); \ { int i, _iters = iters, _warmupiters = MAX(1,iters/10); \ gasnett_tick_t start,end; /* use ticks interface */ \ for (i=0; i < _warmupiters; i++) { op; } /* warm-up */ \ PTHREAD_LOCALBARRIER(threads); \ start = ticktime(); \ for (i=0; i < _iters; i++) { op; } \ PTHREAD_LOCALBARRIER(threads); \ end = ticktime(); \ if (!id) \ report(threads, tickcvt(end - start), iters); \ } \ } while (0) void * thread_fn3(void *arg) { GASNET_BEGIN_FUNCTION(); int id = (int)(uintptr_t)arg; TIME_OPERATION_ALL(id, { pthread_mutex_lock(&mutex); pthread_mutex_unlock(&mutex); }); return NULL; } void * thread_fn4(void *arg) { GASNET_BEGIN_FUNCTION(); int id = (int)(uintptr_t)arg; TIME_OPERATION_ALL(id, { gasnet_hsl_lock(&hsl); gasnet_hsl_unlock(&hsl); }); return NULL; } /* ------------------------------------------------------------------------------------ */