~ubuntu-branches/ubuntu/gutsy/icu/gutsy-updates

« back to all changes in this revision

Viewing changes to source/test/threadtest/threadtest.cpp

  • Committer: Package Import Robot
  • Author(s): Jay Berkenbilt
  • Date: 2005-11-19 11:29:31 UTC
  • mfrom: (1.1.2)
  • Revision ID: package-import@ubuntu.com-20051119112931-vcizkrp10tli4enw
Tags: 3.4-3
Explicitly build with g++ 3.4.  The current ICU fails its test suite
with 4.0 but not with 3.4.  Future versions should work properly with
4.0.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
//
2
 
//********************************************************************
3
 
//   Copyright (C) 2002, International Business Machines
4
 
//   Corporation and others.  All Rights Reserved.
5
 
//********************************************************************
6
 
//
7
 
// File threadtest.cpp
8
 
//
9
 
 
10
 
#include <stdlib.h>
11
 
#include <stdio.h>
12
 
#include <string.h>
13
 
 
14
 
#include "unicode/utypes.h"
15
 
#include "unicode/uclean.h"
16
 
#include "umutex.h"
17
 
#include "threadtest.h"
18
 
 
19
 
 
20
 
//------------------------------------------------------------------------------
21
 
//
22
 
//   Factory functions for creating different test types.
23
 
//
24
 
//------------------------------------------------------------------------------
25
 
extern  AbstractThreadTest *createStringTest();
26
 
extern  AbstractThreadTest *createConvertTest();
27
 
 
28
 
 
29
 
 
30
 
//------------------------------------------------------------------------------
31
 
//
32
 
//   Windows specific code for starting threads
33
 
//
34
 
//------------------------------------------------------------------------------
35
 
#ifdef WIN32
36
 
 
37
 
#include "Windows.h"
38
 
#include "process.h"
39
 
 
40
 
 
41
 
 
42
 
typedef void (*ThreadFunc)(void *);
43
 
 
44
 
class ThreadFuncs           // This class isolates OS dependent threading
45
 
{                           //   functions from the rest of ThreadTest program.
46
 
public:
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);};
51
 
};
52
 
 
53
 
void ThreadFuncs::startThread(ThreadFunc func, void *param)
54
 
{
55
 
    unsigned long x;
56
 
    x = _beginthread(func, 0x10000, param);
57
 
    if (x == -1)
58
 
    {
59
 
        fprintf(stderr, "Error starting thread.  Errno = %d\n", errno);
60
 
        exit(-1);
61
 
    }
62
 
}
63
 
 
64
 
unsigned long ThreadFuncs::getCurrentMillis()
65
 
{
66
 
    return (unsigned long)::GetTickCount();
67
 
}
68
 
 
69
 
 
70
 
 
71
 
 
72
 
// #elif defined (POSIX) 
73
 
#else
74
 
 
75
 
//------------------------------------------------------------------------------
76
 
//
77
 
//   UNIX specific code for starting threads
78
 
//
79
 
//------------------------------------------------------------------------------
80
 
#include <pthread.h>
81
 
#include <unistd.h>
82
 
#include <errno.h>
83
 
#include <sched.h>
84
 
#include <sys/timeb.h>
85
 
 
86
 
 
87
 
extern "C" {
88
 
 
89
 
 
90
 
typedef void (*ThreadFunc)(void *);
91
 
typedef void *(*pthreadfunc)(void *);
92
 
 
93
 
class ThreadFuncs           // This class isolates OS dependent threading
94
 
{                           //   functions from the rest of ThreadTest program.
95
 
public:
96
 
    static void            Sleep(int millis);
97
 
    static void            startThread(ThreadFunc, void *param);
98
 
    static unsigned long   getCurrentMillis();
99
 
    static void            yield() {sched_yield();};
100
 
};
101
 
 
102
 
void ThreadFuncs::Sleep(int millis)
103
 
{
104
 
   int seconds = millis/1000;
105
 
   if (seconds <= 0) seconds = 1;
106
 
   ::sleep(seconds);
107
 
}
108
 
 
109
 
 
110
 
void ThreadFuncs::startThread(ThreadFunc func, void *param)
111
 
{
112
 
    unsigned long x;
113
 
 
114
 
    pthread_t tId;
115
 
    //thread_t tId;
116
 
#if defined(_HP_UX) && defined(XML_USE_DCE)
117
 
    x = pthread_create( &tId, pthread_attr_default,  (pthreadfunc)func,  param);
118
 
#else
119
 
    pthread_attr_t attr;
120
 
    pthread_attr_init(&attr);
121
 
    x = pthread_create( &tId, &attr,  (pthreadfunc)func,  param);
122
 
#endif
123
 
    if (x == -1)
124
 
    {
125
 
        fprintf(stderr, "Error starting thread.  Errno = %d\n", errno);
126
 
        exit(-1);
127
 
    }
128
 
}
129
 
 
130
 
unsigned long ThreadFuncs::getCurrentMillis() {
131
 
    timeb aTime;
132
 
    ftime(&aTime);
133
 
    return (unsigned long)(aTime.time*1000 + aTime.millitm);
134
 
}
135
 
}
136
 
 
137
 
 
138
 
// #else
139
 
// #error This platform is not supported
140
 
#endif
141
 
 
142
 
 
143
 
 
144
 
//------------------------------------------------------------------------------
145
 
//
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.
151
 
//
152
 
//------------------------------------------------------------------------------
153
 
const int MAXINFILES = 25;
154
 
struct RunInfo
155
 
{
156
 
    bool                quiet;
157
 
    bool                verbose;
158
 
    int                 numThreads;
159
 
    int                 totalTime;
160
 
    int                 checkTime;
161
 
    AbstractThreadTest *fTest;
162
 
    bool                stopFlag;
163
 
    bool                exitFlag;
164
 
    int32_t             runningThreads;
165
 
};
166
 
 
167
 
 
168
 
//------------------------------------------------------------------------------
169
 
//
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.
174
 
//
175
 
//------------------------------------------------------------------------------
176
 
struct ThreadInfo
177
 
{
178
 
    bool    fHeartBeat;            // Set true by the thread each time it finishes
179
 
                                   //   parsing a file.
180
 
    unsigned int     fCycles;      // Number of cycles completed.
181
 
    int              fThreadNum;   // Identifying number for this thread.
182
 
    ThreadInfo() {
183
 
        fHeartBeat = false;
184
 
        fCycles = 0;
185
 
        fThreadNum = -1;
186
 
    }
187
 
};
188
 
 
189
 
 
190
 
//
191
 
//------------------------------------------------------------------------------
192
 
//
193
 
//  Global Data
194
 
//
195
 
//------------------------------------------------------------------------------
196
 
RunInfo         gRunInfo;
197
 
ThreadInfo      *gThreadInfo;
198
 
UMTX            gMutex;
199
 
 
200
 
 
201
 
//----------------------------------------------------------------------
202
 
//
203
 
//   parseCommandLine   Read through the command line, and save all
204
 
//                      of the options in the gRunInfo struct.
205
 
//
206
 
//                      Display the usage message if the command line
207
 
//                      is no good.
208
 
//
209
 
//                      Probably ought to be a member function of RunInfo.
210
 
//
211
 
//----------------------------------------------------------------------
212
 
 
213
 
void parseCommandLine(int argc, char **argv)
214
 
{
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;
220
 
 
221
 
    try             // Use exceptions for command line syntax errors.
222
 
    {
223
 
        int argnum = 1;
224
 
        while (argnum < argc)
225
 
        {
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; }
232
 
                
233
 
            else if (strcmp(argv[argnum], "-threads") == 0)
234
 
            {
235
 
                ++argnum;
236
 
                if (argnum >= argc)
237
 
                    throw 1;
238
 
                gRunInfo.numThreads = atoi(argv[argnum]);
239
 
                if (gRunInfo.numThreads < 0)
240
 
                    throw 1;
241
 
            }
242
 
            else if (strcmp(argv[argnum], "-time") == 0)
243
 
            {
244
 
                ++argnum;
245
 
                if (argnum >= argc)
246
 
                    throw 1;
247
 
                gRunInfo.totalTime = atoi(argv[argnum]);
248
 
                if (gRunInfo.totalTime < 1)
249
 
                    throw 1;
250
 
            }
251
 
            else if (strcmp(argv[argnum], "-ctime") == 0)
252
 
            {
253
 
                ++argnum;
254
 
                if (argnum >= argc)
255
 
                    throw 1;
256
 
                gRunInfo.checkTime = atoi(argv[argnum]);
257
 
                if (gRunInfo.checkTime < 1)
258
 
                    throw 1;
259
 
            }
260
 
            else if (strcmp(argv[argnum], "string") == 0)
261
 
            {
262
 
                gRunInfo.fTest = createStringTest();
263
 
            }
264
 
            else if (strcmp(argv[argnum], "convert") == 0)
265
 
            {
266
 
                gRunInfo.fTest = createConvertTest();
267
 
            }
268
 
           else  
269
 
            {
270
 
                fprintf(stderr, "Unrecognized command line option.  Scanning \"%s\"\n",
271
 
                    argv[argnum]);
272
 
                throw 1;
273
 
            }
274
 
            argnum++;
275
 
        }
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");
280
 
            throw 1;
281
 
        }
282
 
 
283
 
    }
284
 
    catch (int)
285
 
    {
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"
293
 
            );
294
 
        exit(1);
295
 
    }
296
 
}
297
 
 
298
 
 
299
 
 
300
 
 
301
 
 
302
 
//----------------------------------------------------------------------
303
 
//
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.
306
 
//
307
 
//
308
 
//----------------------------------------------------------------------
309
 
 
310
 
extern "C" {
311
 
 
312
 
void threadMain (void *param)
313
 
{
314
 
    ThreadInfo   *thInfo = (ThreadInfo *)param;
315
 
 
316
 
    if (gRunInfo.verbose)
317
 
        printf("Thread #%d: starting\n", thInfo->fThreadNum);
318
 
    umtx_atomic_inc(&gRunInfo.runningThreads);
319
 
 
320
 
    //
321
 
    //
322
 
    while (true)
323
 
    {
324
 
        if (gRunInfo.verbose )
325
 
            printf("Thread #%d: starting loop\n", thInfo->fThreadNum);
326
 
 
327
 
        //
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.
330
 
        // 
331
 
        if (gRunInfo.stopFlag) {
332
 
            if (gRunInfo.verbose) {
333
 
                fprintf(stderr, "Thread #%d: suspending\n", thInfo->fThreadNum);
334
 
            }
335
 
            umtx_atomic_dec(&gRunInfo.runningThreads);
336
 
            while (gRunInfo.stopFlag) {
337
 
                umtx_lock(&gMutex);
338
 
                umtx_unlock(&gMutex);
339
 
            }
340
 
            umtx_atomic_inc(&gRunInfo.runningThreads);
341
 
            if (gRunInfo.verbose) {
342
 
                fprintf(stderr, "Thread #%d: restarting\n", thInfo->fThreadNum);
343
 
            }
344
 
        }
345
 
 
346
 
        //
347
 
        // The real work of the test happens here.
348
 
        //
349
 
        gRunInfo.fTest->runOnce();
350
 
 
351
 
        thInfo->fHeartBeat = true;
352
 
        thInfo->fCycles++;
353
 
 
354
 
        //
355
 
        // If main thread says it's time to exit, break out of the loop.
356
 
        //
357
 
        if (gRunInfo.exitFlag) {
358
 
            break;
359
 
        }
360
 
    }
361
 
            
362
 
    umtx_atomic_dec(&gRunInfo.runningThreads);
363
 
 
364
 
    // Returning will kill the thread.
365
 
    return;
366
 
}
367
 
 
368
 
}
369
 
 
370
 
 
371
 
 
372
 
 
373
 
//----------------------------------------------------------------------
374
 
//
375
 
//   main
376
 
//
377
 
//----------------------------------------------------------------------
378
 
 
379
 
int main (int argc, char **argv)
380
 
{
381
 
    //
382
 
    //  Parse the command line options, and create the specified kind of test.
383
 
    //
384
 
    parseCommandLine(argc, argv);
385
 
 
386
 
 
387
 
    //
388
 
    //  Fire off the requested number of parallel threads
389
 
    //
390
 
 
391
 
    if (gRunInfo.numThreads == 0)
392
 
        exit(0);
393
 
 
394
 
    gRunInfo.exitFlag = FALSE;
395
 
    gRunInfo.stopFlag = TRUE;      // Will cause the new threads to block 
396
 
    umtx_lock(&gMutex);
397
 
 
398
 
    gThreadInfo = new ThreadInfo[gRunInfo.numThreads];
399
 
    int threadNum;
400
 
    for (threadNum=0; threadNum < gRunInfo.numThreads; threadNum++)
401
 
    {
402
 
        gThreadInfo[threadNum].fThreadNum = threadNum;
403
 
        ThreadFuncs::startThread(threadMain, &gThreadInfo[threadNum]);
404
 
    }
405
 
 
406
 
 
407
 
    unsigned long startTime = ThreadFuncs::getCurrentMillis();
408
 
    int elapsedSeconds = 0;
409
 
    int timeSinceCheck = 0;
410
 
 
411
 
    //
412
 
    // Unblock the threads.
413
 
    //
414
 
    gRunInfo.stopFlag = FALSE;       // Unblocks the worker threads.
415
 
    umtx_unlock(&gMutex);      
416
 
 
417
 
    //
418
 
    //  Loop, watching the heartbeat of the worker threads.
419
 
    //    Each second,
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.
425
 
    //
426
 
    while (gRunInfo.totalTime == 0 || gRunInfo.totalTime > elapsedSeconds)
427
 
    {
428
 
        ThreadFuncs::Sleep(1000);      // We sleep while threads do their work ...
429
 
 
430
 
        if (gRunInfo.quiet == false && gRunInfo.verbose == false)
431
 
        {
432
 
            char c = '+';
433
 
            int threadNum;
434
 
            for (threadNum=0; threadNum < gRunInfo.numThreads; threadNum++)
435
 
            {
436
 
                if (gThreadInfo[threadNum].fHeartBeat == false)
437
 
                {
438
 
                    c = '.';
439
 
                    break;
440
 
                };
441
 
            }
442
 
            fputc(c, stdout);
443
 
            fflush(stdout);
444
 
            if (c == '+')
445
 
                for (threadNum=0; threadNum < gRunInfo.numThreads; threadNum++)
446
 
                    gThreadInfo[threadNum].fHeartBeat = false;
447
 
        }
448
 
 
449
 
        //
450
 
        // Update running times.
451
 
        //
452
 
        timeSinceCheck -= elapsedSeconds;
453
 
        elapsedSeconds = (ThreadFuncs::getCurrentMillis() - startTime) / 1000;
454
 
        timeSinceCheck += elapsedSeconds;
455
 
 
456
 
        //
457
 
        //  Call back to the test to let it check its internal validity
458
 
        //
459
 
        if (timeSinceCheck >= gRunInfo.checkTime) {
460
 
            if (gRunInfo.verbose) {
461
 
                fprintf(stderr, "Main: suspending all threads\n");
462
 
            }
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(); }
466
 
            
467
 
            gRunInfo.fTest->check();
468
 
            if (gRunInfo.quiet == false && gRunInfo.verbose == false) {
469
 
                fputc('C', stdout);
470
 
            }
471
 
 
472
 
            if (gRunInfo.verbose) {
473
 
                fprintf(stderr, "Main: starting all threads.\n");
474
 
            }
475
 
            gRunInfo.stopFlag = FALSE;       // Unblock the worker threads.
476
 
            umtx_unlock(&gMutex);      
477
 
            timeSinceCheck = 0;
478
 
        }
479
 
    };
480
 
 
481
 
    //
482
 
    //  Time's up, we are done.  (We only get here if this was a timed run)
483
 
    //  Tell the threads to exit.
484
 
    //
485
 
    gRunInfo.exitFlag = true;
486
 
    while (gRunInfo.runningThreads > 0) { ThreadFuncs::yield(); }
487
 
 
488
 
    //
489
 
    //  Tally up the total number of cycles completed by each of the threads.
490
 
    //
491
 
    double totalCyclesCompleted = 0;
492
 
    for (threadNum=0; threadNum < gRunInfo.numThreads; threadNum++) {
493
 
        totalCyclesCompleted += gThreadInfo[threadNum].fCycles;
494
 
    }
495
 
 
496
 
    double cyclesPerMinute = totalCyclesCompleted / (double(gRunInfo.totalTime) / double(60));
497
 
    printf("\n%8.1f cycles per minute.", cyclesPerMinute);
498
 
 
499
 
    //
500
 
    //  Memory should be clean coming out
501
 
    //
502
 
    delete gRunInfo.fTest;
503
 
    delete [] gThreadInfo;
504
 
    umtx_destroy(&gMutex);
505
 
    u_cleanup();
506
 
 
507
 
    return 0;
508
 
}
509
 
 
510