1 /******************************************************************** 
   3  * Copyright (c) 2002-2009, International Business Machines Corporation and 
   4  * others. All Rights Reserved. 
   5  ********************************************************************/ 
   7 /* z/OS needs this definition for timeval */ 
   8 #include "platform_xopen_source_extended.h" 
  10 #include "unicode/uperf.h" 
  16 #if !UCONFIG_NO_CONVERSION 
  17 static const char delim 
= '/'; 
  18 static int32_t execCount 
= 0; 
  19 UPerfTest
* UPerfTest::gTest 
= NULL
; 
  20 static const int MAXLINES 
= 40000; 
  21 const char UPerfTest::gUsageString
[] = 
  22     "Usage: %s [OPTIONS] [FILES]\n" 
  23     "\tReads the input file and prints out time taken in seconds\n" 
  25     "\t-h or -? or --help   this usage text\n" 
  26     "\t-v or --verbose      print extra information when processing files\n" 
  27     "\t-s or --sourcedir    source directory for files followed by path\n" 
  28     "\t                     followed by path\n" 
  29     "\t-e or --encoding     encoding of source files\n" 
  30     "\t-u or --uselen       perform timing analysis on non-null terminated buffer using length\n" 
  31     "\t-f or --file-name    file to be used as input data\n" 
  32     "\t-p or --passes       Number of passes to be performed. Requires Numeric argument.\n" 
  33     "\t                     Cannot be used with --time\n" 
  34     "\t-i or --iterations   Number of iterations to be performed. Requires Numeric argument\n" 
  35     "\t-t or --time         Threshold time for looping until in seconds. Requires Numeric argument.\n" 
  36     "\t                     Cannot be used with --iterations\n" 
  37     "\t-l or --line-mode    The data file should be processed in line mode\n" 
  38     "\t-b or --bulk-mode    The data file should be processed in file based.\n" 
  39     "\t                     Cannot be used with --line-mode\n" 
  40     "\t-L or --locale       Locale for the test\n"; 
  61 static UOption options
[OPTIONS_COUNT
+20]={ 
  63     UOPTION_HELP_QUESTION_MARK
, 
  67     UOPTION_DEF( "uselen",        'u', UOPT_NO_ARG
), 
  68     UOPTION_DEF( "file-name",     'f', UOPT_REQUIRES_ARG
), 
  69     UOPTION_DEF( "passes",        'p', UOPT_REQUIRES_ARG
), 
  70     UOPTION_DEF( "iterations",    'i', UOPT_REQUIRES_ARG
), 
  71     UOPTION_DEF( "time",          't', UOPT_REQUIRES_ARG
), 
  72     UOPTION_DEF( "line-mode",     'l', UOPT_NO_ARG
), 
  73     UOPTION_DEF( "bulk-mode",     'b', UOPT_NO_ARG
), 
  74     UOPTION_DEF( "locale",        'L', UOPT_REQUIRES_ARG
) 
  77 UPerfTest::UPerfTest(int32_t argc
, const char* argv
[], UErrorCode
& status
) 
  78         : _argc(argc
), _argv(argv
), _addUsage(NULL
), 
  79           ucharBuf(NULL
), encoding(""), 
  81           fileName(NULL
), sourceDir("."), 
  82           lines(NULL
), numLines(0), line_mode(TRUE
), 
  83           buffer(NULL
), bufferLen(0), 
  84           verbose(FALSE
), bulk_mode(FALSE
), 
  85           passes(1), iterations(0), time(0), 
  87     init(NULL
, 0, status
); 
  90 UPerfTest::UPerfTest(int32_t argc
, const char* argv
[], 
  91                      UOption addOptions
[], int32_t addOptionsCount
, 
  94         : _argc(argc
), _argv(argv
), _addUsage(addUsage
), 
  95           ucharBuf(NULL
), encoding(""), 
  97           fileName(NULL
), sourceDir("."), 
  98           lines(NULL
), numLines(0), line_mode(TRUE
), 
  99           buffer(NULL
), bufferLen(0), 
 100           verbose(FALSE
), bulk_mode(FALSE
), 
 101           passes(1), iterations(0), time(0), 
 103     init(addOptions
, addOptionsCount
, status
); 
 106 void UPerfTest::init(UOption addOptions
[], int32_t addOptionsCount
, 
 107                      UErrorCode
& status
) { 
 108     //initialize the argument list 
 109     U_MAIN_INIT_ARGS(_argc
, _argv
); 
 111     resolvedFileName 
= NULL
; 
 113     // add specific options 
 114     int32_t optionsCount 
= OPTIONS_COUNT
; 
 115     if (addOptionsCount 
> 0) { 
 116         memcpy(options
+optionsCount
, addOptions
, addOptionsCount
*sizeof(UOption
)); 
 117         optionsCount 
+= addOptionsCount
; 
 120     //parse the arguments 
 121     _remainingArgc 
= u_parseArgs(_argc
, (char**)_argv
, optionsCount
, options
); 
 123     // copy back values for additional options 
 124     if (addOptionsCount 
> 0) { 
 125         memcpy(addOptions
, options
+OPTIONS_COUNT
, addOptionsCount
*sizeof(UOption
)); 
 128     // Now setup the arguments 
 129     if(_argc
==1 || options
[HELP1
].doesOccur 
|| options
[HELP2
].doesOccur
) { 
 130         status 
= U_ILLEGAL_ARGUMENT_ERROR
; 
 134     if(options
[VERBOSE
].doesOccur
) { 
 138     if(options
[SOURCEDIR
].doesOccur
) { 
 139         sourceDir 
= options
[SOURCEDIR
].value
; 
 142     if(options
[ENCODING
].doesOccur
) { 
 143         encoding 
= options
[ENCODING
].value
; 
 146     if(options
[USELEN
].doesOccur
) { 
 150     if(options
[FILE_NAME
].doesOccur
){ 
 151         fileName 
= options
[FILE_NAME
].value
; 
 154     if(options
[PASSES
].doesOccur
) { 
 155         passes 
= atoi(options
[PASSES
].value
); 
 157     if(options
[ITERATIONS
].doesOccur
) { 
 158         iterations 
= atoi(options
[ITERATIONS
].value
); 
 159         if(options
[TIME
].doesOccur
) { 
 160             status 
= U_ILLEGAL_ARGUMENT_ERROR
; 
 163     } else if(options
[TIME
].doesOccur
) { 
 164         time 
= atoi(options
[TIME
].value
); 
 166         iterations 
= 1000; // some default 
 169     if(options
[LINE_MODE
].doesOccur
) { 
 174     if(options
[BULK_MODE
].doesOccur
) { 
 179     if(options
[LOCALE
].doesOccur
) { 
 180         locale 
= options
[LOCALE
].value
; 
 186         ucbuf_resolveFileName(sourceDir
, fileName
, NULL
, &len
, &status
); 
 187         resolvedFileName 
= (char*) uprv_malloc(len
); 
 188         if(resolvedFileName
==NULL
){ 
 189             status
= U_MEMORY_ALLOCATION_ERROR
; 
 192         if(status 
== U_BUFFER_OVERFLOW_ERROR
){ 
 193             status 
= U_ZERO_ERROR
; 
 195         ucbuf_resolveFileName(sourceDir
, fileName
, resolvedFileName
, &len
, &status
); 
 196         ucharBuf 
= ucbuf_open(resolvedFileName
,&encoding
,TRUE
,FALSE
,&status
); 
 198         if(U_FAILURE(status
)){ 
 199             printf("Could not open the input file %s. Error: %s\n", fileName
, u_errorName(status
)); 
 205 ULine
* UPerfTest::getLines(UErrorCode
& status
){ 
 206     lines     
= new ULine
[MAXLINES
]; 
 207     int maxLines 
= MAXLINES
; 
 209     const UChar
* line
=NULL
; 
 212         line 
= ucbuf_readline(ucharBuf
,&len
,&status
); 
 213         if(line 
== NULL 
|| U_FAILURE(status
)){ 
 216         lines
[numLines
].name  
= new UChar
[len
]; 
 217         lines
[numLines
].len   
= len
; 
 218         memcpy(lines
[numLines
].name
, line
, len 
* U_SIZEOF_UCHAR
); 
 222         if (numLines 
>= maxLines
) { 
 223             maxLines 
+= MAXLINES
; 
 224             ULine 
*newLines 
= new ULine
[maxLines
]; 
 225             if(newLines 
== NULL
) { 
 226                 fprintf(stderr
, "Out of memory reading line %d.\n", (int)numLines
); 
 227                 status
= U_MEMORY_ALLOCATION_ERROR
; 
 232             memcpy(newLines
, lines
, numLines
*sizeof(ULine
)); 
 239 const UChar
* UPerfTest::getBuffer(int32_t& len
, UErrorCode
& status
){ 
 240     if (U_FAILURE(status
)) { 
 243     len 
= ucbuf_size(ucharBuf
); 
 244     buffer 
=  (UChar
*) uprv_malloc(U_SIZEOF_UCHAR 
* (len
+1)); 
 245     u_strncpy(buffer
,ucbuf_getBuffer(ucharBuf
,&bufferLen
,&status
),len
); 
 250 UBool 
UPerfTest::run(){ 
 251     if(_remainingArgc
==1){ 
 252         // Testing all methods 
 256     // Test only the specified fucntion 
 257     for (int i 
= 1; i 
< _remainingArgc
; ++i
) { 
 258         if (_argv
[i
][0] != '-') { 
 259             char* name 
= (char*) _argv
[i
]; 
 261                 //fprintf(stdout, "\n=== Handling test: %s: ===\n", name); 
 262                 //fprintf(stdout, "\n%s:\n", name); 
 264             char* parameter 
= strchr( name
, '@' ); 
 270             res 
= runTest( name
, parameter 
); 
 271             if (!res 
|| (execCount 
<= 0)) { 
 272                 fprintf(stdout
, "\n---ERROR: Test doesn't exist: %s!\n", name
); 
 279 UBool 
UPerfTest::runTest(char* name
, char* par 
){ 
 284         pos 
= strchr( name
, delim 
); // check if name contains path (by looking for '/') 
 286         path 
= pos
+1;   // store subpath for calling subtest 
 287         *pos 
= 0;       // split into two strings 
 292     if (!name 
|| (name
[0] == 0) || (strcmp(name
, "*") == 0)) { 
 293         rval 
= runTestLoop( NULL
, NULL 
); 
 295     }else if (strcmp( name
, "LIST" ) == 0) { 
 300         rval 
= runTestLoop( name
, par 
); 
 304         *pos 
= delim
;  // restore original value at pos 
 309 void UPerfTest::setPath( char* pathVal 
) 
 311     this->path 
= pathVal
; 
 314 // call individual tests, to be overriden to call implementations 
 315 UPerfFunction
* UPerfTest::runIndexedTest( int32_t index
, UBool exec
, const char* &name
, char* par 
) 
 317     // to be overriden by a method like: 
 320         case 0: name = "First Test"; if (exec) FirstTest( par ); break; 
 321         case 1: name = "Second Test"; if (exec) SecondTest( par ); break; 
 322         default: name = ""; break; 
 325     fprintf(stderr
,"*** runIndexedTest needs to be overriden! ***"); 
 326     name 
= ""; exec 
= exec
; index 
= index
; par 
= par
; 
 331 UBool 
UPerfTest::runTestLoop( char* testname
, char* par 
) 
 337     UErrorCode status 
= U_ZERO_ERROR
; 
 338     UPerfTest
* saveTest 
= gTest
; 
 345         this->runIndexedTest( index
, FALSE
, name 
); 
 346         if (!name 
|| (name
[0] == 0)) 
 349             run_this_test 
= TRUE
; 
 351             run_this_test 
= (UBool
) (strcmp( name
, testname 
) == 0); 
 354             UPerfFunction
* testFunction 
= this->runIndexedTest( index
, TRUE
, name
, par 
); 
 357             if(testFunction
==NULL
){ 
 358                 fprintf(stderr
,"%s function returned NULL", name
); 
 361             ops 
= testFunction
->getOperationsPerIteration(); 
 363                 fprintf(stderr
, "%s returned an illegal operations/iteration()\n", name
); 
 366             if(iterations 
== 0) { 
 368                 // Run for specified duration in seconds 
 370                     fprintf(stdout
,"= %s calibrating %i seconds \n", name
, (int)n
); 
 373                 //n *=  1000; // s => ms 
 374                 //System.out.println("# " + meth.getName() + " " + n + " sec"); 
 375                 int32_t failsafe 
= 1; // last resort for very fast methods 
 377                 while (t 
< (int)(n 
* 0.9)) { // 90% is close enough 
 378                     if (loops 
== 0 || t 
== 0) { 
 382                         //System.out.println("# " + meth.getName() + " x " + loops + " = " + t);                             
 383                         loops 
= (int)((double)n 
/ t 
* loops 
+ 0.5); 
 385                             fprintf(stderr
,"Unable to converge on desired duration"); 
 389                     //System.out.println("# " + meth.getName() + " x " + loops); 
 390                     t 
= testFunction
->time(loops
,&status
); 
 391                     if(U_FAILURE(status
)){ 
 392                         printf("Performance test failed with error: %s \n", u_errorName(status
)); 
 400             double min_t
=1000000.0, sum_t
=0.0; 
 403             for(int32_t ps 
=0; ps 
< passes
; ps
++){ 
 404                 fprintf(stdout
,"= %s begin " ,name
); 
 407                         fprintf(stdout
, "%i\n", (int)loops
); 
 409                         fprintf(stdout
, "%i\n", (int)n
); 
 412                     fprintf(stdout
, "\n"); 
 414                 t 
= testFunction
->time(loops
, &status
); 
 415                 if(U_FAILURE(status
)){ 
 416                     printf("Performance test failed with error: %s \n", u_errorName(status
)); 
 423                 events 
= testFunction
->getEventsPerIteration(); 
 424                 //print info only in verbose mode 
 427                         fprintf(stdout
, "= %s end: %f loops: %i operations: %li \n", name
, t
, (int)loops
, ops
); 
 429                         fprintf(stdout
, "= %s end: %f loops: %i operations: %li events: %li\n", name
, t
, (int)loops
, ops
, events
); 
 433                         fprintf(stdout
,"= %s end %f %i %li\n", name
, t
, (int)loops
, ops
); 
 435                         fprintf(stdout
,"= %s end %f %i %li %li\n", name
, t
, (int)loops
, ops
, events
); 
 439             if(verbose 
&& U_SUCCESS(status
)) { 
 440                 double avg_t 
= sum_t
/passes
; 
 441                 if (loops 
== 0 || ops 
== 0) { 
 442                     fprintf(stderr
, "%s did not run\n", name
); 
 444                 else if(events 
== -1) { 
 445                     fprintf(stdout
, "%%= %s avg: %.4g loops: %i avg/op: %.4g ns\n", 
 446                             name
, avg_t
, (int)loops
, (avg_t
*1E9
)/(loops
*ops
)); 
 447                     fprintf(stdout
, "_= %s min: %.4g loops: %i min/op: %.4g ns\n", 
 448                             name
, min_t
, (int)loops
, (min_t
*1E9
)/(loops
*ops
)); 
 451                     fprintf(stdout
, "%%= %s avg: %.4g loops: %i avg/op: %.4g ns avg/event: %.4g ns\n", 
 452                             name
, avg_t
, (int)loops
, (avg_t
*1E9
)/(loops
*ops
), (avg_t
*1E9
)/(loops
*events
)); 
 453                     fprintf(stdout
, "_= %s min: %.4g loops: %i min/op: %.4g ns min/event: %.4g ns\n", 
 454                             name
, min_t
, (int)loops
, (min_t
*1E9
)/(loops
*ops
), (min_t
*1E9
)/(loops
*events
)); 
 467 * Print a usage message for this test class. 
 469 void UPerfTest::usage( void ) 
 472     if (_addUsage 
!= NULL
) { 
 476     UBool save_verbose 
= verbose
; 
 478     fprintf(stdout
,"Test names:\n"); 
 479     fprintf(stdout
,"-----------\n"); 
 482     const char* name 
= NULL
; 
 484         this->runIndexedTest( index
, FALSE
, name 
); 
 487         fprintf(stdout
,name
); 
 488         fprintf(stdout
,"\n"); 
 490     }while (name 
&& (name
[0] != 0)); 
 491     verbose 
= save_verbose
; 
 497 void UPerfTest::setCaller( UPerfTest
* callingTest 
) 
 499     caller 
= callingTest
; 
 501         verbose 
= caller
->verbose
; 
 505 UBool 
UPerfTest::callTest( UPerfTest
& testToBeCalled
, char* par 
) 
 507     execCount
--; // correct a previously assumed test-exec, as this only calls a subtest 
 508     testToBeCalled
.setCaller( this ); 
 509     return testToBeCalled
.runTest( path
, par 
); 
 512 UPerfTest::~UPerfTest(){ 
 519     if(resolvedFileName
!=NULL
){ 
 520         uprv_free(resolvedFileName
); 
 522     ucbuf_close(ucharBuf
);