| 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;
|
| -}
|
| -
|
| -
|
|
|