2 //********************************************************************
3 // Copyright (C) 2002-2011, International Business Machines
4 // Corporation and others. All Rights Reserved.
5 //********************************************************************
14 #include "unicode/utypes.h"
15 #include "unicode/uclean.h"
17 #include "threadtest.h"
19 AbstractThreadTest::~AbstractThreadTest() {}
21 //------------------------------------------------------------------------------
23 // Factory functions for creating different test types.
25 //------------------------------------------------------------------------------
26 extern AbstractThreadTest *createStringTest();
27 extern AbstractThreadTest *createConvertTest();
31 //------------------------------------------------------------------------------
33 // Windows specific code for starting threads
35 //------------------------------------------------------------------------------
36 #if U_PLATFORM_USES_ONLY_WIN32_API
43 typedef void (*ThreadFunc)(void *);
45 class ThreadFuncs // This class isolates OS dependent threading
46 { // functions from the rest of ThreadTest program.
48 static void Sleep(int millis) {::Sleep(millis);};
49 static void startThread(ThreadFunc, void *param);
50 static unsigned long getCurrentMillis();
51 static void yield() {::Sleep(0);};
54 void ThreadFuncs::startThread(ThreadFunc func, void *param)
57 x = _beginthread(func, 0x10000, param);
60 fprintf(stderr, "Error starting thread. Errno = %d\n", errno);
65 unsigned long ThreadFuncs::getCurrentMillis()
67 return (unsigned long)::GetTickCount();
73 // #elif defined (POSIX)
76 //------------------------------------------------------------------------------
78 // UNIX specific code for starting threads
80 //------------------------------------------------------------------------------
85 #include <sys/timeb.h>
91 typedef void (*ThreadFunc)(void *);
92 typedef void *(*pthreadfunc)(void *);
94 class ThreadFuncs // This class isolates OS dependent threading
95 { // functions from the rest of ThreadTest program.
97 static void Sleep(int millis);
98 static void startThread(ThreadFunc, void *param);
99 static unsigned long getCurrentMillis();
100 static void yield() {sched_yield();};
103 void ThreadFuncs::Sleep(int millis)
105 int seconds = millis/1000;
106 if (seconds <= 0) seconds = 1;
111 void ThreadFuncs::startThread(ThreadFunc func, void *param)
117 #if defined(_HP_UX) && defined(XML_USE_DCE)
118 x = pthread_create( &tId, pthread_attr_default, (pthreadfunc)func, param);
121 pthread_attr_init(&attr);
122 x = pthread_create( &tId, &attr, (pthreadfunc)func, param);
126 fprintf(stderr, "Error starting thread. Errno = %d\n", errno);
131 unsigned long ThreadFuncs::getCurrentMillis() {
134 return (unsigned long)(aTime.time*1000 + aTime.millitm);
140 // #error This platform is not supported
145 //------------------------------------------------------------------------------
147 // struct runInfo Holds the info extracted from the command line and data
148 // that is shared by all threads.
149 // There is only one of these, and it is static.
150 // During the test, the threads will access this info without
151 // any synchronization.
153 //------------------------------------------------------------------------------
154 const int MAXINFILES = 25;
162 AbstractThreadTest *fTest;
165 int32_t runningThreads;
169 //------------------------------------------------------------------------------
171 // struct threadInfo Holds information specific to an individual thread.
172 // One of these is set up for each thread in the test.
173 // The main program monitors the threads by looking
174 // at the status stored in these structs.
176 //------------------------------------------------------------------------------
179 bool fHeartBeat; // Set true by the thread each time it finishes
181 unsigned int fCycles; // Number of cycles completed.
182 int fThreadNum; // Identifying number for this thread.
192 //------------------------------------------------------------------------------
196 //------------------------------------------------------------------------------
198 ThreadInfo *gThreadInfo;
199 UMTX gStopMutex; // Lets main thread suspend test threads.
200 UMTX gInfoMutex; // Synchronize access to data passed between
201 // worker threads and the main thread
204 //----------------------------------------------------------------------
206 // parseCommandLine Read through the command line, and save all
207 // of the options in the gRunInfo struct.
209 // Display the usage message if the command line
212 // Probably ought to be a member function of RunInfo.
214 //----------------------------------------------------------------------
216 void parseCommandLine(int argc, char **argv)
218 gRunInfo.quiet = false; // Set up defaults for run.
219 gRunInfo.verbose = false;
220 gRunInfo.numThreads = 2;
221 gRunInfo.totalTime = 0;
222 gRunInfo.checkTime = 10;
224 try // Use exceptions for command line syntax errors.
227 while (argnum < argc)
229 if (strcmp(argv[argnum], "-quiet") == 0)
230 gRunInfo.quiet = true;
231 else if (strcmp(argv[argnum], "-verbose") == 0)
232 gRunInfo.verbose = true;
233 else if (strcmp(argv[argnum], "--help") == 0 ||
234 (strcmp(argv[argnum], "?") == 0)) {throw 1; }
236 else if (strcmp(argv[argnum], "-threads") == 0)
241 gRunInfo.numThreads = atoi(argv[argnum]);
242 if (gRunInfo.numThreads < 0)
245 else if (strcmp(argv[argnum], "-time") == 0)
250 gRunInfo.totalTime = atoi(argv[argnum]);
251 if (gRunInfo.totalTime < 1)
254 else if (strcmp(argv[argnum], "-ctime") == 0)
259 gRunInfo.checkTime = atoi(argv[argnum]);
260 if (gRunInfo.checkTime < 1)
263 else if (strcmp(argv[argnum], "string") == 0)
265 gRunInfo.fTest = createStringTest();
267 else if (strcmp(argv[argnum], "convert") == 0)
269 gRunInfo.fTest = createConvertTest();
273 fprintf(stderr, "Unrecognized command line option. Scanning \"%s\"\n",
279 // We've reached the end of the command line parameters.
280 // Fail if no test name was specified.
281 if (gRunInfo.fTest == NULL) {
282 fprintf(stderr, "No test specified.\n");
289 fprintf(stderr, "usage: threadtest [-threads nnn] [-time nnn] [-quiet] [-verbose] test-name\n"
290 " -quiet Suppress periodic status display. \n"
291 " -verbose Display extra messages. \n"
292 " -threads nnn Number of threads. Default is 2. \n"
293 " -time nnn Total time to run, in seconds. Default is forever.\n"
294 " -ctime nnn Time between extra consistency checks, in seconds. Default 10\n"
295 " testname string | convert\n"
305 //----------------------------------------------------------------------
307 // threadMain The main function for each of the swarm of test threads.
308 // Run in a loop, executing the runOnce() test function each time.
311 //----------------------------------------------------------------------
315 void threadMain (void *param)
317 ThreadInfo *thInfo = (ThreadInfo *)param;
319 if (gRunInfo.verbose)
320 printf("Thread #%d: starting\n", thInfo->fThreadNum);
321 umtx_atomic_inc(&gRunInfo.runningThreads);
327 if (gRunInfo.verbose )
328 printf("Thread #%d: starting loop\n", thInfo->fThreadNum);
331 // If the main thread is asking us to wait, do so by locking gStopMutex
332 // which will block us, since the main thread will be holding it already.
334 umtx_lock(&gInfoMutex);
335 UBool stop = gRunInfo.stopFlag; // Need mutex for processors with flakey memory models.
336 umtx_unlock(&gInfoMutex);
339 if (gRunInfo.verbose) {
340 fprintf(stderr, "Thread #%d: suspending\n", thInfo->fThreadNum);
342 umtx_atomic_dec(&gRunInfo.runningThreads);
343 while (gRunInfo.stopFlag) {
344 umtx_lock(&gStopMutex);
345 umtx_unlock(&gStopMutex);
347 umtx_atomic_inc(&gRunInfo.runningThreads);
348 if (gRunInfo.verbose) {
349 fprintf(stderr, "Thread #%d: restarting\n", thInfo->fThreadNum);
354 // The real work of the test happens here.
356 gRunInfo.fTest->runOnce();
358 umtx_lock(&gInfoMutex);
359 thInfo->fHeartBeat = true;
361 UBool exitNow = gRunInfo.exitFlag;
362 umtx_unlock(&gInfoMutex);
365 // If main thread says it's time to exit, break out of the loop.
372 umtx_atomic_dec(&gRunInfo.runningThreads);
374 // Returning will kill the thread.
383 //----------------------------------------------------------------------
387 //----------------------------------------------------------------------
389 int main (int argc, char **argv)
392 // Parse the command line options, and create the specified kind of test.
394 parseCommandLine(argc, argv);
398 // Fire off the requested number of parallel threads
401 if (gRunInfo.numThreads == 0)
404 gRunInfo.exitFlag = FALSE;
405 gRunInfo.stopFlag = TRUE; // Will cause the new threads to block
406 umtx_lock(&gStopMutex);
408 gThreadInfo = new ThreadInfo[gRunInfo.numThreads];
410 for (threadNum=0; threadNum < gRunInfo.numThreads; threadNum++)
412 gThreadInfo[threadNum].fThreadNum = threadNum;
413 ThreadFuncs::startThread(threadMain, &gThreadInfo[threadNum]);
417 unsigned long startTime = ThreadFuncs::getCurrentMillis();
418 int elapsedSeconds = 0;
419 int timeSinceCheck = 0;
422 // Unblock the threads.
424 gRunInfo.stopFlag = FALSE; // Unblocks the worker threads.
425 umtx_unlock(&gStopMutex);
428 // Loop, watching the heartbeat of the worker threads.
430 // display "+" if all threads have completed at least one loop
431 // display "." if some thread hasn't since previous "+"
432 // Each "ctime" seconds,
433 // Stop all the worker threads at the top of their loop, then
434 // call the test's check function.
436 while (gRunInfo.totalTime == 0 || gRunInfo.totalTime > elapsedSeconds)
438 ThreadFuncs::Sleep(1000); // We sleep while threads do their work ...
440 if (gRunInfo.quiet == false && gRunInfo.verbose == false)
444 umtx_lock(&gInfoMutex);
445 for (threadNum=0; threadNum < gRunInfo.numThreads; threadNum++)
447 if (gThreadInfo[threadNum].fHeartBeat == false)
453 umtx_unlock(&gInfoMutex);
457 for (threadNum=0; threadNum < gRunInfo.numThreads; threadNum++)
458 gThreadInfo[threadNum].fHeartBeat = false;
462 // Update running times.
464 timeSinceCheck -= elapsedSeconds;
465 elapsedSeconds = (ThreadFuncs::getCurrentMillis() - startTime) / 1000;
466 timeSinceCheck += elapsedSeconds;
469 // Call back to the test to let it check its internal validity
471 if (timeSinceCheck >= gRunInfo.checkTime) {
472 if (gRunInfo.verbose) {
473 fprintf(stderr, "Main: suspending all threads\n");
475 umtx_lock(&gStopMutex); // Block the worker threads at the top of their loop
476 gRunInfo.stopFlag = TRUE;
478 umtx_lock(&gInfoMutex);
479 UBool done = gRunInfo.runningThreads == 0;
480 umtx_unlock(&gInfoMutex);
482 ThreadFuncs::yield();
487 gRunInfo.fTest->check();
488 if (gRunInfo.quiet == false && gRunInfo.verbose == false) {
492 if (gRunInfo.verbose) {
493 fprintf(stderr, "Main: starting all threads.\n");
495 gRunInfo.stopFlag = FALSE; // Unblock the worker threads.
496 umtx_unlock(&gStopMutex);
502 // Time's up, we are done. (We only get here if this was a timed run)
503 // Tell the threads to exit.
505 gRunInfo.exitFlag = true;
507 umtx_lock(&gInfoMutex);
508 UBool done = gRunInfo.runningThreads == 0;
509 umtx_unlock(&gInfoMutex);
511 ThreadFuncs::yield();
515 // Tally up the total number of cycles completed by each of the threads.
517 double totalCyclesCompleted = 0;
518 for (threadNum=0; threadNum < gRunInfo.numThreads; threadNum++) {
519 totalCyclesCompleted += gThreadInfo[threadNum].fCycles;
522 double cyclesPerMinute = totalCyclesCompleted / (double(gRunInfo.totalTime) / double(60));
523 printf("\n%8.1f cycles per minute.", cyclesPerMinute);
526 // Memory should be clean coming out
528 delete gRunInfo.fTest;
529 delete [] gThreadInfo;
530 umtx_destroy(&gInfoMutex);
531 umtx_destroy(&gStopMutex);