2
//********************************************************************
3
// Copyright (C) 2002, 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;
201
//----------------------------------------------------------------------
203
// parseCommandLine Read through the command line, and save all
204
// of the options in the gRunInfo struct.
206
// Display the usage message if the command line
209
// Probably ought to be a member function of RunInfo.
211
//----------------------------------------------------------------------
213
void parseCommandLine(int argc, char **argv)
215
gRunInfo.quiet = false; // Set up defaults for run.
216
gRunInfo.verbose = false;
217
gRunInfo.numThreads = 2;
218
gRunInfo.totalTime = 0;
219
gRunInfo.checkTime = 10;
221
try // Use exceptions for command line syntax errors.
224
while (argnum < argc)
226
if (strcmp(argv[argnum], "-quiet") == 0)
227
gRunInfo.quiet = true;
228
else if (strcmp(argv[argnum], "-verbose") == 0)
229
gRunInfo.verbose = true;
230
else if (strcmp(argv[argnum], "--help") == 0 ||
231
(strcmp(argv[argnum], "?") == 0)) {throw 1; }
233
else if (strcmp(argv[argnum], "-threads") == 0)
238
gRunInfo.numThreads = atoi(argv[argnum]);
239
if (gRunInfo.numThreads < 0)
242
else if (strcmp(argv[argnum], "-time") == 0)
247
gRunInfo.totalTime = atoi(argv[argnum]);
248
if (gRunInfo.totalTime < 1)
251
else if (strcmp(argv[argnum], "-ctime") == 0)
256
gRunInfo.checkTime = atoi(argv[argnum]);
257
if (gRunInfo.checkTime < 1)
260
else if (strcmp(argv[argnum], "string") == 0)
262
gRunInfo.fTest = createStringTest();
264
else if (strcmp(argv[argnum], "convert") == 0)
266
gRunInfo.fTest = createConvertTest();
270
fprintf(stderr, "Unrecognized command line option. Scanning \"%s\"\n",
276
// We've reached the end of the command line parameters.
277
// Fail if no test name was specified.
278
if (gRunInfo.fTest == NULL) {
279
fprintf(stderr, "No test specified.\n");
286
fprintf(stderr, "usage: threadtest [-threads nnn] [-time nnn] [-quiet] [-verbose] test-name\n"
287
" -quiet Suppress periodic status display. \n"
288
" -verbose Display extra messages. \n"
289
" -threads nnn Number of threads. Default is 2. \n"
290
" -time nnn Total time to run, in seconds. Default is forever.\n"
291
" -ctime nnn Time between extra consistency checks, in seconds. Default 10\n"
292
" testname string | convert\n"
302
//----------------------------------------------------------------------
304
// threadMain The main function for each of the swarm of test threads.
305
// Run in a loop, executing the runOnce() test function each time.
308
//----------------------------------------------------------------------
312
void threadMain (void *param)
314
ThreadInfo *thInfo = (ThreadInfo *)param;
316
if (gRunInfo.verbose)
317
printf("Thread #%d: starting\n", thInfo->fThreadNum);
318
umtx_atomic_inc(&gRunInfo.runningThreads);
324
if (gRunInfo.verbose )
325
printf("Thread #%d: starting loop\n", thInfo->fThreadNum);
328
// If the main thread is asking us to wait, do so by locking gMutex
329
// which will block us, since the main thread will be holding it already.
331
if (gRunInfo.stopFlag) {
332
if (gRunInfo.verbose) {
333
fprintf(stderr, "Thread #%d: suspending\n", thInfo->fThreadNum);
335
umtx_atomic_dec(&gRunInfo.runningThreads);
336
while (gRunInfo.stopFlag) {
338
umtx_unlock(&gMutex);
340
umtx_atomic_inc(&gRunInfo.runningThreads);
341
if (gRunInfo.verbose) {
342
fprintf(stderr, "Thread #%d: restarting\n", thInfo->fThreadNum);
347
// The real work of the test happens here.
349
gRunInfo.fTest->runOnce();
351
thInfo->fHeartBeat = true;
355
// If main thread says it's time to exit, break out of the loop.
357
if (gRunInfo.exitFlag) {
362
umtx_atomic_dec(&gRunInfo.runningThreads);
364
// Returning will kill the thread.
373
//----------------------------------------------------------------------
377
//----------------------------------------------------------------------
379
int main (int argc, char **argv)
382
// Parse the command line options, and create the specified kind of test.
384
parseCommandLine(argc, argv);
388
// Fire off the requested number of parallel threads
391
if (gRunInfo.numThreads == 0)
394
gRunInfo.exitFlag = FALSE;
395
gRunInfo.stopFlag = TRUE; // Will cause the new threads to block
398
gThreadInfo = new ThreadInfo[gRunInfo.numThreads];
400
for (threadNum=0; threadNum < gRunInfo.numThreads; threadNum++)
402
gThreadInfo[threadNum].fThreadNum = threadNum;
403
ThreadFuncs::startThread(threadMain, &gThreadInfo[threadNum]);
407
unsigned long startTime = ThreadFuncs::getCurrentMillis();
408
int elapsedSeconds = 0;
409
int timeSinceCheck = 0;
412
// Unblock the threads.
414
gRunInfo.stopFlag = FALSE; // Unblocks the worker threads.
415
umtx_unlock(&gMutex);
418
// Loop, watching the heartbeat of the worker threads.
420
// display "+" if all threads have completed at least one loop
421
// display "." if some thread hasn't since previous "+"
422
// Each "ctime" seconds,
423
// Stop all the worker threads at the top of their loop, then
424
// call the test's check function.
426
while (gRunInfo.totalTime == 0 || gRunInfo.totalTime > elapsedSeconds)
428
ThreadFuncs::Sleep(1000); // We sleep while threads do their work ...
430
if (gRunInfo.quiet == false && gRunInfo.verbose == false)
434
for (threadNum=0; threadNum < gRunInfo.numThreads; threadNum++)
436
if (gThreadInfo[threadNum].fHeartBeat == false)
445
for (threadNum=0; threadNum < gRunInfo.numThreads; threadNum++)
446
gThreadInfo[threadNum].fHeartBeat = false;
450
// Update running times.
452
timeSinceCheck -= elapsedSeconds;
453
elapsedSeconds = (ThreadFuncs::getCurrentMillis() - startTime) / 1000;
454
timeSinceCheck += elapsedSeconds;
457
// Call back to the test to let it check its internal validity
459
if (timeSinceCheck >= gRunInfo.checkTime) {
460
if (gRunInfo.verbose) {
461
fprintf(stderr, "Main: suspending all threads\n");
463
umtx_lock(&gMutex); // Block the worker threads at the top of their loop
464
gRunInfo.stopFlag = TRUE;
465
while (gRunInfo.runningThreads > 0) { ThreadFuncs::yield(); }
467
gRunInfo.fTest->check();
468
if (gRunInfo.quiet == false && gRunInfo.verbose == false) {
472
if (gRunInfo.verbose) {
473
fprintf(stderr, "Main: starting all threads.\n");
475
gRunInfo.stopFlag = FALSE; // Unblock the worker threads.
476
umtx_unlock(&gMutex);
482
// Time's up, we are done. (We only get here if this was a timed run)
483
// Tell the threads to exit.
485
gRunInfo.exitFlag = true;
486
while (gRunInfo.runningThreads > 0) { ThreadFuncs::yield(); }
489
// Tally up the total number of cycles completed by each of the threads.
491
double totalCyclesCompleted = 0;
492
for (threadNum=0; threadNum < gRunInfo.numThreads; threadNum++) {
493
totalCyclesCompleted += gThreadInfo[threadNum].fCycles;
496
double cyclesPerMinute = totalCyclesCompleted / (double(gRunInfo.totalTime) / double(60));
497
printf("\n%8.1f cycles per minute.", cyclesPerMinute);
500
// Memory should be clean coming out
502
delete gRunInfo.fTest;
503
delete [] gThreadInfo;
504
umtx_destroy(&gMutex);