Index: source/test/threadtest/threadtest.cpp |
diff --git a/source/test/threadtest/threadtest.cpp b/source/test/threadtest/threadtest.cpp |
deleted file mode 100644 |
index 85e53a552a44a5a26e0f3b8bf948d2c02e1a0e80..0000000000000000000000000000000000000000 |
--- a/source/test/threadtest/threadtest.cpp |
+++ /dev/null |
@@ -1,537 +0,0 @@ |
-// |
-//******************************************************************** |
-// Copyright (C) 2002-2011, International Business Machines |
-// Corporation and others. All Rights Reserved. |
-//******************************************************************** |
-// |
-// File threadtest.cpp |
-// |
- |
-#include <stdlib.h> |
-#include <stdio.h> |
-#include <string.h> |
- |
-#include "unicode/utypes.h" |
-#include "unicode/uclean.h" |
-#include "umutex.h" |
-#include "threadtest.h" |
- |
-AbstractThreadTest::~AbstractThreadTest() {} |
- |
-//------------------------------------------------------------------------------ |
-// |
-// Factory functions for creating different test types. |
-// |
-//------------------------------------------------------------------------------ |
-extern AbstractThreadTest *createStringTest(); |
-extern AbstractThreadTest *createConvertTest(); |
- |
- |
- |
-//------------------------------------------------------------------------------ |
-// |
-// Windows specific code for starting threads |
-// |
-//------------------------------------------------------------------------------ |
-#if U_PLATFORM_USES_ONLY_WIN32_API |
- |
-#include "Windows.h" |
-#include "process.h" |
- |
- |
- |
-typedef void (*ThreadFunc)(void *); |
- |
-class ThreadFuncs // This class isolates OS dependent threading |
-{ // functions from the rest of ThreadTest program. |
-public: |
- static void Sleep(int millis) {::Sleep(millis);}; |
- static void startThread(ThreadFunc, void *param); |
- static unsigned long getCurrentMillis(); |
- static void yield() {::Sleep(0);}; |
-}; |
- |
-void ThreadFuncs::startThread(ThreadFunc func, void *param) |
-{ |
- unsigned long x; |
- x = _beginthread(func, 0x10000, param); |
- if (x == -1) |
- { |
- fprintf(stderr, "Error starting thread. Errno = %d\n", errno); |
- exit(-1); |
- } |
-} |
- |
-unsigned long ThreadFuncs::getCurrentMillis() |
-{ |
- return (unsigned long)::GetTickCount(); |
-} |
- |
- |
- |
- |
-// #elif defined (POSIX) |
-#else |
- |
-//------------------------------------------------------------------------------ |
-// |
-// UNIX specific code for starting threads |
-// |
-//------------------------------------------------------------------------------ |
-#include <pthread.h> |
-#include <unistd.h> |
-#include <errno.h> |
-#include <sched.h> |
-#include <sys/timeb.h> |
- |
- |
-extern "C" { |
- |
- |
-typedef void (*ThreadFunc)(void *); |
-typedef void *(*pthreadfunc)(void *); |
- |
-class ThreadFuncs // This class isolates OS dependent threading |
-{ // functions from the rest of ThreadTest program. |
-public: |
- static void Sleep(int millis); |
- static void startThread(ThreadFunc, void *param); |
- static unsigned long getCurrentMillis(); |
- static void yield() {sched_yield();}; |
-}; |
- |
-void ThreadFuncs::Sleep(int millis) |
-{ |
- int seconds = millis/1000; |
- if (seconds <= 0) seconds = 1; |
- ::sleep(seconds); |
-} |
- |
- |
-void ThreadFuncs::startThread(ThreadFunc func, void *param) |
-{ |
- unsigned long x; |
- |
- pthread_t tId; |
- //thread_t tId; |
-#if defined(_HP_UX) && defined(XML_USE_DCE) |
- x = pthread_create( &tId, pthread_attr_default, (pthreadfunc)func, param); |
-#else |
- pthread_attr_t attr; |
- pthread_attr_init(&attr); |
- x = pthread_create( &tId, &attr, (pthreadfunc)func, param); |
-#endif |
- if (x == -1) |
- { |
- fprintf(stderr, "Error starting thread. Errno = %d\n", errno); |
- exit(-1); |
- } |
-} |
- |
-unsigned long ThreadFuncs::getCurrentMillis() { |
- timeb aTime; |
- ftime(&aTime); |
- return (unsigned long)(aTime.time*1000 + aTime.millitm); |
-} |
-} |
- |
- |
-// #else |
-// #error This platform is not supported |
-#endif |
- |
- |
- |
-//------------------------------------------------------------------------------ |
-// |
-// struct runInfo Holds the info extracted from the command line and data |
-// that is shared by all threads. |
-// There is only one of these, and it is static. |
-// During the test, the threads will access this info without |
-// any synchronization. |
-// |
-//------------------------------------------------------------------------------ |
-const int MAXINFILES = 25; |
-struct RunInfo |
-{ |
- bool quiet; |
- bool verbose; |
- int numThreads; |
- int totalTime; |
- int checkTime; |
- AbstractThreadTest *fTest; |
- bool stopFlag; |
- bool exitFlag; |
- int32_t runningThreads; |
-}; |
- |
- |
-//------------------------------------------------------------------------------ |
-// |
-// struct threadInfo Holds information specific to an individual thread. |
-// One of these is set up for each thread in the test. |
-// The main program monitors the threads by looking |
-// at the status stored in these structs. |
-// |
-//------------------------------------------------------------------------------ |
-struct ThreadInfo |
-{ |
- bool fHeartBeat; // Set true by the thread each time it finishes |
- // a test. |
- unsigned int fCycles; // Number of cycles completed. |
- int fThreadNum; // Identifying number for this thread. |
- ThreadInfo() { |
- fHeartBeat = false; |
- fCycles = 0; |
- fThreadNum = -1; |
- } |
-}; |
- |
- |
-// |
-//------------------------------------------------------------------------------ |
-// |
-// Global Data |
-// |
-//------------------------------------------------------------------------------ |
-RunInfo gRunInfo; |
-ThreadInfo *gThreadInfo; |
-UMTX gStopMutex; // Lets main thread suspend test threads. |
-UMTX gInfoMutex; // Synchronize access to data passed between |
- // worker threads and the main thread |
- |
- |
-//---------------------------------------------------------------------- |
-// |
-// parseCommandLine Read through the command line, and save all |
-// of the options in the gRunInfo struct. |
-// |
-// Display the usage message if the command line |
-// is no good. |
-// |
-// Probably ought to be a member function of RunInfo. |
-// |
-//---------------------------------------------------------------------- |
- |
-void parseCommandLine(int argc, char **argv) |
-{ |
- gRunInfo.quiet = false; // Set up defaults for run. |
- gRunInfo.verbose = false; |
- gRunInfo.numThreads = 2; |
- gRunInfo.totalTime = 0; |
- gRunInfo.checkTime = 10; |
- |
- try // Use exceptions for command line syntax errors. |
- { |
- int argnum = 1; |
- while (argnum < argc) |
- { |
- if (strcmp(argv[argnum], "-quiet") == 0) |
- gRunInfo.quiet = true; |
- else if (strcmp(argv[argnum], "-verbose") == 0) |
- gRunInfo.verbose = true; |
- else if (strcmp(argv[argnum], "--help") == 0 || |
- (strcmp(argv[argnum], "?") == 0)) {throw 1; } |
- |
- else if (strcmp(argv[argnum], "-threads") == 0) |
- { |
- ++argnum; |
- if (argnum >= argc) |
- throw 1; |
- gRunInfo.numThreads = atoi(argv[argnum]); |
- if (gRunInfo.numThreads < 0) |
- throw 1; |
- } |
- else if (strcmp(argv[argnum], "-time") == 0) |
- { |
- ++argnum; |
- if (argnum >= argc) |
- throw 1; |
- gRunInfo.totalTime = atoi(argv[argnum]); |
- if (gRunInfo.totalTime < 1) |
- throw 1; |
- } |
- else if (strcmp(argv[argnum], "-ctime") == 0) |
- { |
- ++argnum; |
- if (argnum >= argc) |
- throw 1; |
- gRunInfo.checkTime = atoi(argv[argnum]); |
- if (gRunInfo.checkTime < 1) |
- throw 1; |
- } |
- else if (strcmp(argv[argnum], "string") == 0) |
- { |
- gRunInfo.fTest = createStringTest(); |
- } |
- else if (strcmp(argv[argnum], "convert") == 0) |
- { |
- gRunInfo.fTest = createConvertTest(); |
- } |
- else |
- { |
- fprintf(stderr, "Unrecognized command line option. Scanning \"%s\"\n", |
- argv[argnum]); |
- throw 1; |
- } |
- argnum++; |
- } |
- // We've reached the end of the command line parameters. |
- // Fail if no test name was specified. |
- if (gRunInfo.fTest == NULL) { |
- fprintf(stderr, "No test specified.\n"); |
- throw 1; |
- } |
- |
- } |
- catch (int) |
- { |
- fprintf(stderr, "usage: threadtest [-threads nnn] [-time nnn] [-quiet] [-verbose] test-name\n" |
- " -quiet Suppress periodic status display. \n" |
- " -verbose Display extra messages. \n" |
- " -threads nnn Number of threads. Default is 2. \n" |
- " -time nnn Total time to run, in seconds. Default is forever.\n" |
- " -ctime nnn Time between extra consistency checks, in seconds. Default 10\n" |
- " testname string | convert\n" |
- ); |
- exit(1); |
- } |
-} |
- |
- |
- |
- |
- |
-//---------------------------------------------------------------------- |
-// |
-// threadMain The main function for each of the swarm of test threads. |
-// Run in a loop, executing the runOnce() test function each time. |
-// |
-// |
-//---------------------------------------------------------------------- |
- |
-extern "C" { |
- |
-void threadMain (void *param) |
-{ |
- ThreadInfo *thInfo = (ThreadInfo *)param; |
- |
- if (gRunInfo.verbose) |
- printf("Thread #%d: starting\n", thInfo->fThreadNum); |
- umtx_atomic_inc(&gRunInfo.runningThreads); |
- |
- // |
- // |
- while (true) |
- { |
- if (gRunInfo.verbose ) |
- printf("Thread #%d: starting loop\n", thInfo->fThreadNum); |
- |
- // |
- // If the main thread is asking us to wait, do so by locking gStopMutex |
- // which will block us, since the main thread will be holding it already. |
- // |
- umtx_lock(&gInfoMutex); |
- UBool stop = gRunInfo.stopFlag; // Need mutex for processors with flakey memory models. |
- umtx_unlock(&gInfoMutex); |
- |
- if (stop) { |
- if (gRunInfo.verbose) { |
- fprintf(stderr, "Thread #%d: suspending\n", thInfo->fThreadNum); |
- } |
- umtx_atomic_dec(&gRunInfo.runningThreads); |
- while (gRunInfo.stopFlag) { |
- umtx_lock(&gStopMutex); |
- umtx_unlock(&gStopMutex); |
- } |
- umtx_atomic_inc(&gRunInfo.runningThreads); |
- if (gRunInfo.verbose) { |
- fprintf(stderr, "Thread #%d: restarting\n", thInfo->fThreadNum); |
- } |
- } |
- |
- // |
- // The real work of the test happens here. |
- // |
- gRunInfo.fTest->runOnce(); |
- |
- umtx_lock(&gInfoMutex); |
- thInfo->fHeartBeat = true; |
- thInfo->fCycles++; |
- UBool exitNow = gRunInfo.exitFlag; |
- umtx_unlock(&gInfoMutex); |
- |
- // |
- // If main thread says it's time to exit, break out of the loop. |
- // |
- if (exitNow) { |
- break; |
- } |
- } |
- |
- umtx_atomic_dec(&gRunInfo.runningThreads); |
- |
- // Returning will kill the thread. |
- return; |
-} |
- |
-} |
- |
- |
- |
- |
-//---------------------------------------------------------------------- |
-// |
-// main |
-// |
-//---------------------------------------------------------------------- |
- |
-int main (int argc, char **argv) |
-{ |
- // |
- // Parse the command line options, and create the specified kind of test. |
- // |
- parseCommandLine(argc, argv); |
- |
- |
- // |
- // Fire off the requested number of parallel threads |
- // |
- |
- if (gRunInfo.numThreads == 0) |
- exit(0); |
- |
- gRunInfo.exitFlag = FALSE; |
- gRunInfo.stopFlag = TRUE; // Will cause the new threads to block |
- umtx_lock(&gStopMutex); |
- |
- gThreadInfo = new ThreadInfo[gRunInfo.numThreads]; |
- int threadNum; |
- for (threadNum=0; threadNum < gRunInfo.numThreads; threadNum++) |
- { |
- gThreadInfo[threadNum].fThreadNum = threadNum; |
- ThreadFuncs::startThread(threadMain, &gThreadInfo[threadNum]); |
- } |
- |
- |
- unsigned long startTime = ThreadFuncs::getCurrentMillis(); |
- int elapsedSeconds = 0; |
- int timeSinceCheck = 0; |
- |
- // |
- // Unblock the threads. |
- // |
- gRunInfo.stopFlag = FALSE; // Unblocks the worker threads. |
- umtx_unlock(&gStopMutex); |
- |
- // |
- // Loop, watching the heartbeat of the worker threads. |
- // Each second, |
- // display "+" if all threads have completed at least one loop |
- // display "." if some thread hasn't since previous "+" |
- // Each "ctime" seconds, |
- // Stop all the worker threads at the top of their loop, then |
- // call the test's check function. |
- // |
- while (gRunInfo.totalTime == 0 || gRunInfo.totalTime > elapsedSeconds) |
- { |
- ThreadFuncs::Sleep(1000); // We sleep while threads do their work ... |
- |
- if (gRunInfo.quiet == false && gRunInfo.verbose == false) |
- { |
- char c = '+'; |
- int threadNum; |
- umtx_lock(&gInfoMutex); |
- for (threadNum=0; threadNum < gRunInfo.numThreads; threadNum++) |
- { |
- if (gThreadInfo[threadNum].fHeartBeat == false) |
- { |
- c = '.'; |
- break; |
- }; |
- } |
- umtx_unlock(&gInfoMutex); |
- fputc(c, stdout); |
- fflush(stdout); |
- if (c == '+') |
- for (threadNum=0; threadNum < gRunInfo.numThreads; threadNum++) |
- gThreadInfo[threadNum].fHeartBeat = false; |
- } |
- |
- // |
- // Update running times. |
- // |
- timeSinceCheck -= elapsedSeconds; |
- elapsedSeconds = (ThreadFuncs::getCurrentMillis() - startTime) / 1000; |
- timeSinceCheck += elapsedSeconds; |
- |
- // |
- // Call back to the test to let it check its internal validity |
- // |
- if (timeSinceCheck >= gRunInfo.checkTime) { |
- if (gRunInfo.verbose) { |
- fprintf(stderr, "Main: suspending all threads\n"); |
- } |
- umtx_lock(&gStopMutex); // Block the worker threads at the top of their loop |
- gRunInfo.stopFlag = TRUE; |
- for (;;) { |
- umtx_lock(&gInfoMutex); |
- UBool done = gRunInfo.runningThreads == 0; |
- umtx_unlock(&gInfoMutex); |
- if (done) { break;} |
- ThreadFuncs::yield(); |
- } |
- |
- |
- |
- gRunInfo.fTest->check(); |
- if (gRunInfo.quiet == false && gRunInfo.verbose == false) { |
- fputc('C', stdout); |
- } |
- |
- if (gRunInfo.verbose) { |
- fprintf(stderr, "Main: starting all threads.\n"); |
- } |
- gRunInfo.stopFlag = FALSE; // Unblock the worker threads. |
- umtx_unlock(&gStopMutex); |
- timeSinceCheck = 0; |
- } |
- }; |
- |
- // |
- // Time's up, we are done. (We only get here if this was a timed run) |
- // Tell the threads to exit. |
- // |
- gRunInfo.exitFlag = true; |
- for (;;) { |
- umtx_lock(&gInfoMutex); |
- UBool done = gRunInfo.runningThreads == 0; |
- umtx_unlock(&gInfoMutex); |
- if (done) { break;} |
- ThreadFuncs::yield(); |
- } |
- |
- // |
- // Tally up the total number of cycles completed by each of the threads. |
- // |
- double totalCyclesCompleted = 0; |
- for (threadNum=0; threadNum < gRunInfo.numThreads; threadNum++) { |
- totalCyclesCompleted += gThreadInfo[threadNum].fCycles; |
- } |
- |
- double cyclesPerMinute = totalCyclesCompleted / (double(gRunInfo.totalTime) / double(60)); |
- printf("\n%8.1f cycles per minute.", cyclesPerMinute); |
- |
- // |
- // Memory should be clean coming out |
- // |
- delete gRunInfo.fTest; |
- delete [] gThreadInfo; |
- umtx_destroy(&gInfoMutex); |
- umtx_destroy(&gStopMutex); |
- u_cleanup(); |
- |
- return 0; |
-} |
- |
- |