]>
git.saurik.com Git - apple/icu.git/blob - icuSources/test/threadtest/threadtest.cpp
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
);