]>
git.saurik.com Git - apple/icu.git/blob - icuSources/test/threadtest/threadtest.cpp
2 //********************************************************************
3 // Copyright (C) 2002-2003, 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"
20 //------------------------------------------------------------------------------
22 // Factory functions for creating different test types.
24 //------------------------------------------------------------------------------
25 extern AbstractThreadTest
*createStringTest();
26 extern AbstractThreadTest
*createConvertTest();
30 //------------------------------------------------------------------------------
32 // Windows specific code for starting threads
34 //------------------------------------------------------------------------------
42 typedef void (*ThreadFunc
)(void *);
44 class ThreadFuncs
// This class isolates OS dependent threading
45 { // functions from the rest of ThreadTest program.
47 static void Sleep(int millis
) {::Sleep(millis
);};
48 static void startThread(ThreadFunc
, void *param
);
49 static unsigned long getCurrentMillis();
50 static void yield() {::Sleep(0);};
53 void ThreadFuncs::startThread(ThreadFunc func
, void *param
)
56 x
= _beginthread(func
, 0x10000, param
);
59 fprintf(stderr
, "Error starting thread. Errno = %d\n", errno
);
64 unsigned long ThreadFuncs::getCurrentMillis()
66 return (unsigned long)::GetTickCount();
72 // #elif defined (POSIX)
75 //------------------------------------------------------------------------------
77 // UNIX specific code for starting threads
79 //------------------------------------------------------------------------------
84 #include <sys/timeb.h>
90 typedef void (*ThreadFunc
)(void *);
91 typedef void *(*pthreadfunc
)(void *);
93 class ThreadFuncs
// This class isolates OS dependent threading
94 { // functions from the rest of ThreadTest program.
96 static void Sleep(int millis
);
97 static void startThread(ThreadFunc
, void *param
);
98 static unsigned long getCurrentMillis();
99 static void yield() {sched_yield();};
102 void ThreadFuncs::Sleep(int millis
)
104 int seconds
= millis
/1000;
105 if (seconds
<= 0) seconds
= 1;
110 void ThreadFuncs::startThread(ThreadFunc func
, void *param
)
116 #if defined(_HP_UX) && defined(XML_USE_DCE)
117 x
= pthread_create( &tId
, pthread_attr_default
, (pthreadfunc
)func
, param
);
120 pthread_attr_init(&attr
);
121 x
= pthread_create( &tId
, &attr
, (pthreadfunc
)func
, param
);
125 fprintf(stderr
, "Error starting thread. Errno = %d\n", errno
);
130 unsigned long ThreadFuncs::getCurrentMillis() {
133 return (unsigned long)(aTime
.time
*1000 + aTime
.millitm
);
139 // #error This platform is not supported
144 //------------------------------------------------------------------------------
146 // struct runInfo Holds the info extracted from the command line and data
147 // that is shared by all threads.
148 // There is only one of these, and it is static.
149 // During the test, the threads will access this info without
150 // any synchronization.
152 //------------------------------------------------------------------------------
153 const int MAXINFILES
= 25;
161 AbstractThreadTest
*fTest
;
164 int32_t runningThreads
;
168 //------------------------------------------------------------------------------
170 // struct threadInfo Holds information specific to an individual thread.
171 // One of these is set up for each thread in the test.
172 // The main program monitors the threads by looking
173 // at the status stored in these structs.
175 //------------------------------------------------------------------------------
178 bool fHeartBeat
; // Set true by the thread each time it finishes
180 unsigned int fCycles
; // Number of cycles completed.
181 int fThreadNum
; // Identifying number for this thread.
191 //------------------------------------------------------------------------------
195 //------------------------------------------------------------------------------
197 ThreadInfo
*gThreadInfo
;
198 UMTX gStopMutex
; // Lets main thread suspend test threads.
199 UMTX gInfoMutex
; // Synchronize access to data passed between
200 // worker threads and the main thread
203 //----------------------------------------------------------------------
205 // parseCommandLine Read through the command line, and save all
206 // of the options in the gRunInfo struct.
208 // Display the usage message if the command line
211 // Probably ought to be a member function of RunInfo.
213 //----------------------------------------------------------------------
215 void parseCommandLine(int argc
, char **argv
)
217 gRunInfo
.quiet
= false; // Set up defaults for run.
218 gRunInfo
.verbose
= false;
219 gRunInfo
.numThreads
= 2;
220 gRunInfo
.totalTime
= 0;
221 gRunInfo
.checkTime
= 10;
223 try // Use exceptions for command line syntax errors.
226 while (argnum
< argc
)
228 if (strcmp(argv
[argnum
], "-quiet") == 0)
229 gRunInfo
.quiet
= true;
230 else if (strcmp(argv
[argnum
], "-verbose") == 0)
231 gRunInfo
.verbose
= true;
232 else if (strcmp(argv
[argnum
], "--help") == 0 ||
233 (strcmp(argv
[argnum
], "?") == 0)) {throw 1; }
235 else if (strcmp(argv
[argnum
], "-threads") == 0)
240 gRunInfo
.numThreads
= atoi(argv
[argnum
]);
241 if (gRunInfo
.numThreads
< 0)
244 else if (strcmp(argv
[argnum
], "-time") == 0)
249 gRunInfo
.totalTime
= atoi(argv
[argnum
]);
250 if (gRunInfo
.totalTime
< 1)
253 else if (strcmp(argv
[argnum
], "-ctime") == 0)
258 gRunInfo
.checkTime
= atoi(argv
[argnum
]);
259 if (gRunInfo
.checkTime
< 1)
262 else if (strcmp(argv
[argnum
], "string") == 0)
264 gRunInfo
.fTest
= createStringTest();
266 else if (strcmp(argv
[argnum
], "convert") == 0)
268 gRunInfo
.fTest
= createConvertTest();
272 fprintf(stderr
, "Unrecognized command line option. Scanning \"%s\"\n",
278 // We've reached the end of the command line parameters.
279 // Fail if no test name was specified.
280 if (gRunInfo
.fTest
== NULL
) {
281 fprintf(stderr
, "No test specified.\n");
288 fprintf(stderr
, "usage: threadtest [-threads nnn] [-time nnn] [-quiet] [-verbose] test-name\n"
289 " -quiet Suppress periodic status display. \n"
290 " -verbose Display extra messages. \n"
291 " -threads nnn Number of threads. Default is 2. \n"
292 " -time nnn Total time to run, in seconds. Default is forever.\n"
293 " -ctime nnn Time between extra consistency checks, in seconds. Default 10\n"
294 " testname string | convert\n"
304 //----------------------------------------------------------------------
306 // threadMain The main function for each of the swarm of test threads.
307 // Run in a loop, executing the runOnce() test function each time.
310 //----------------------------------------------------------------------
314 void threadMain (void *param
)
316 ThreadInfo
*thInfo
= (ThreadInfo
*)param
;
318 if (gRunInfo
.verbose
)
319 printf("Thread #%d: starting\n", thInfo
->fThreadNum
);
320 umtx_atomic_inc(&gRunInfo
.runningThreads
);
326 if (gRunInfo
.verbose
)
327 printf("Thread #%d: starting loop\n", thInfo
->fThreadNum
);
330 // If the main thread is asking us to wait, do so by locking gStopMutex
331 // which will block us, since the main thread will be holding it already.
333 umtx_lock(&gInfoMutex
);
334 UBool stop
= gRunInfo
.stopFlag
; // Need mutex for processors with flakey memory models.
335 umtx_unlock(&gInfoMutex
);
338 if (gRunInfo
.verbose
) {
339 fprintf(stderr
, "Thread #%d: suspending\n", thInfo
->fThreadNum
);
341 umtx_atomic_dec(&gRunInfo
.runningThreads
);
342 while (gRunInfo
.stopFlag
) {
343 umtx_lock(&gStopMutex
);
344 umtx_unlock(&gStopMutex
);
346 umtx_atomic_inc(&gRunInfo
.runningThreads
);
347 if (gRunInfo
.verbose
) {
348 fprintf(stderr
, "Thread #%d: restarting\n", thInfo
->fThreadNum
);
353 // The real work of the test happens here.
355 gRunInfo
.fTest
->runOnce();
357 umtx_lock(&gInfoMutex
);
358 thInfo
->fHeartBeat
= true;
360 UBool exitNow
= gRunInfo
.exitFlag
;
361 umtx_unlock(&gInfoMutex
);
364 // If main thread says it's time to exit, break out of the loop.
371 umtx_atomic_dec(&gRunInfo
.runningThreads
);
373 // Returning will kill the thread.
382 //----------------------------------------------------------------------
386 //----------------------------------------------------------------------
388 int main (int argc
, char **argv
)
391 // Parse the command line options, and create the specified kind of test.
393 parseCommandLine(argc
, argv
);
397 // Fire off the requested number of parallel threads
400 if (gRunInfo
.numThreads
== 0)
403 gRunInfo
.exitFlag
= FALSE
;
404 gRunInfo
.stopFlag
= TRUE
; // Will cause the new threads to block
405 umtx_lock(&gStopMutex
);
407 gThreadInfo
= new ThreadInfo
[gRunInfo
.numThreads
];
409 for (threadNum
=0; threadNum
< gRunInfo
.numThreads
; threadNum
++)
411 gThreadInfo
[threadNum
].fThreadNum
= threadNum
;
412 ThreadFuncs::startThread(threadMain
, &gThreadInfo
[threadNum
]);
416 unsigned long startTime
= ThreadFuncs::getCurrentMillis();
417 int elapsedSeconds
= 0;
418 int timeSinceCheck
= 0;
421 // Unblock the threads.
423 gRunInfo
.stopFlag
= FALSE
; // Unblocks the worker threads.
424 umtx_unlock(&gStopMutex
);
427 // Loop, watching the heartbeat of the worker threads.
429 // display "+" if all threads have completed at least one loop
430 // display "." if some thread hasn't since previous "+"
431 // Each "ctime" seconds,
432 // Stop all the worker threads at the top of their loop, then
433 // call the test's check function.
435 while (gRunInfo
.totalTime
== 0 || gRunInfo
.totalTime
> elapsedSeconds
)
437 ThreadFuncs::Sleep(1000); // We sleep while threads do their work ...
439 if (gRunInfo
.quiet
== false && gRunInfo
.verbose
== false)
443 umtx_lock(&gInfoMutex
);
444 for (threadNum
=0; threadNum
< gRunInfo
.numThreads
; threadNum
++)
446 if (gThreadInfo
[threadNum
].fHeartBeat
== false)
452 umtx_unlock(&gInfoMutex
);
456 for (threadNum
=0; threadNum
< gRunInfo
.numThreads
; threadNum
++)
457 gThreadInfo
[threadNum
].fHeartBeat
= false;
461 // Update running times.
463 timeSinceCheck
-= elapsedSeconds
;
464 elapsedSeconds
= (ThreadFuncs::getCurrentMillis() - startTime
) / 1000;
465 timeSinceCheck
+= elapsedSeconds
;
468 // Call back to the test to let it check its internal validity
470 if (timeSinceCheck
>= gRunInfo
.checkTime
) {
471 if (gRunInfo
.verbose
) {
472 fprintf(stderr
, "Main: suspending all threads\n");
474 umtx_lock(&gStopMutex
); // Block the worker threads at the top of their loop
475 gRunInfo
.stopFlag
= TRUE
;
477 umtx_lock(&gInfoMutex
);
478 UBool done
= gRunInfo
.runningThreads
== 0;
479 umtx_unlock(&gInfoMutex
);
481 ThreadFuncs::yield();
486 gRunInfo
.fTest
->check();
487 if (gRunInfo
.quiet
== false && gRunInfo
.verbose
== false) {
491 if (gRunInfo
.verbose
) {
492 fprintf(stderr
, "Main: starting all threads.\n");
494 gRunInfo
.stopFlag
= FALSE
; // Unblock the worker threads.
495 umtx_unlock(&gStopMutex
);
501 // Time's up, we are done. (We only get here if this was a timed run)
502 // Tell the threads to exit.
504 gRunInfo
.exitFlag
= true;
506 umtx_lock(&gInfoMutex
);
507 UBool done
= gRunInfo
.runningThreads
== 0;
508 umtx_unlock(&gInfoMutex
);
510 ThreadFuncs::yield();
514 // Tally up the total number of cycles completed by each of the threads.
516 double totalCyclesCompleted
= 0;
517 for (threadNum
=0; threadNum
< gRunInfo
.numThreads
; threadNum
++) {
518 totalCyclesCompleted
+= gThreadInfo
[threadNum
].fCycles
;
521 double cyclesPerMinute
= totalCyclesCompleted
/ (double(gRunInfo
.totalTime
) / double(60));
522 printf("\n%8.1f cycles per minute.", cyclesPerMinute
);
525 // Memory should be clean coming out
527 delete gRunInfo
.fTest
;
528 delete [] gThreadInfo
;
529 umtx_destroy(&gInfoMutex
);
530 umtx_destroy(&gStopMutex
);