intl/icu/source/tools/ctestfw/uperf.cpp

Wed, 31 Dec 2014 07:22:50 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 07:22:50 +0100
branch
TOR_BUG_3246
changeset 4
fc2d59ddac77
permissions
-rw-r--r--

Correct previous dual key logic pending first delivery installment.

     1 /********************************************************************
     2  * COPYRIGHT:
     3  * Copyright (c) 2002-2012, International Business Machines Corporation and
     4  * others. All Rights Reserved.
     5  ********************************************************************/
     7 // Defines _XOPEN_SOURCE for access to POSIX functions.
     8 // Must be before any other #includes.
     9 #include "uposixdefs.h"
    11 #include "unicode/uperf.h"
    12 #include "uoptions.h"
    13 #include "cmemory.h"
    14 #include <stdio.h>
    15 #include <stdlib.h>
    17 #if !UCONFIG_NO_CONVERSION
    19 UPerfFunction::~UPerfFunction() {}
    21 static const char delim = '/';
    22 static int32_t execCount = 0;
    23 UPerfTest* UPerfTest::gTest = NULL;
    24 static const int MAXLINES = 40000;
    25 const char UPerfTest::gUsageString[] =
    26     "Usage: %s [OPTIONS] [FILES]\n"
    27     "\tReads the input file and prints out time taken in seconds\n"
    28     "Options:\n"
    29     "\t-h or -? or --help   this usage text\n"
    30     "\t-v or --verbose      print extra information when processing files\n"
    31     "\t-s or --sourcedir    source directory for files followed by path\n"
    32     "\t                     followed by path\n"
    33     "\t-e or --encoding     encoding of source files\n"
    34     "\t-u or --uselen       perform timing analysis on non-null terminated buffer using length\n"
    35     "\t-f or --file-name    file to be used as input data\n"
    36     "\t-p or --passes       Number of passes to be performed. Requires Numeric argument.\n"
    37     "\t                     Cannot be used with --time\n"
    38     "\t-i or --iterations   Number of iterations to be performed. Requires Numeric argument\n"
    39     "\t-t or --time         Threshold time for looping until in seconds. Requires Numeric argument.\n"
    40     "\t                     Cannot be used with --iterations\n"
    41     "\t-l or --line-mode    The data file should be processed in line mode\n"
    42     "\t-b or --bulk-mode    The data file should be processed in file based.\n"
    43     "\t                     Cannot be used with --line-mode\n"
    44     "\t-L or --locale       Locale for the test\n";
    46 enum
    47 {
    48     HELP1,
    49     HELP2,
    50     VERBOSE,
    51     SOURCEDIR,
    52     ENCODING,
    53     USELEN,
    54     FILE_NAME,
    55     PASSES,
    56     ITERATIONS,
    57     TIME,
    58     LINE_MODE,
    59     BULK_MODE,
    60     LOCALE,
    61     OPTIONS_COUNT
    62 };
    65 static UOption options[OPTIONS_COUNT+20]={
    66     UOPTION_HELP_H,
    67     UOPTION_HELP_QUESTION_MARK,
    68     UOPTION_VERBOSE,
    69     UOPTION_SOURCEDIR,
    70     UOPTION_ENCODING,
    71     UOPTION_DEF( "uselen",        'u', UOPT_NO_ARG),
    72     UOPTION_DEF( "file-name",     'f', UOPT_REQUIRES_ARG),
    73     UOPTION_DEF( "passes",        'p', UOPT_REQUIRES_ARG),
    74     UOPTION_DEF( "iterations",    'i', UOPT_REQUIRES_ARG),
    75     UOPTION_DEF( "time",          't', UOPT_REQUIRES_ARG),
    76     UOPTION_DEF( "line-mode",     'l', UOPT_NO_ARG),
    77     UOPTION_DEF( "bulk-mode",     'b', UOPT_NO_ARG),
    78     UOPTION_DEF( "locale",        'L', UOPT_REQUIRES_ARG)
    79 };
    81 UPerfTest::UPerfTest(int32_t argc, const char* argv[], UErrorCode& status)
    82         : _argc(argc), _argv(argv), _addUsage(NULL),
    83           ucharBuf(NULL), encoding(""),
    84           uselen(FALSE),
    85           fileName(NULL), sourceDir("."),
    86           lines(NULL), numLines(0), line_mode(TRUE),
    87           buffer(NULL), bufferLen(0),
    88           verbose(FALSE), bulk_mode(FALSE),
    89           passes(1), iterations(0), time(0),
    90           locale(NULL) {
    91     init(NULL, 0, status);
    92 }
    94 UPerfTest::UPerfTest(int32_t argc, const char* argv[],
    95                      UOption addOptions[], int32_t addOptionsCount,
    96                      const char *addUsage,
    97                      UErrorCode& status)
    98         : _argc(argc), _argv(argv), _addUsage(addUsage),
    99           ucharBuf(NULL), encoding(""),
   100           uselen(FALSE),
   101           fileName(NULL), sourceDir("."),
   102           lines(NULL), numLines(0), line_mode(TRUE),
   103           buffer(NULL), bufferLen(0),
   104           verbose(FALSE), bulk_mode(FALSE),
   105           passes(1), iterations(0), time(0),
   106           locale(NULL) {
   107     init(addOptions, addOptionsCount, status);
   108 }
   110 void UPerfTest::init(UOption addOptions[], int32_t addOptionsCount,
   111                      UErrorCode& status) {
   112     //initialize the argument list
   113     U_MAIN_INIT_ARGS(_argc, _argv);
   115     resolvedFileName = NULL;
   117     // add specific options
   118     int32_t optionsCount = OPTIONS_COUNT;
   119     if (addOptionsCount > 0) {
   120         memcpy(options+optionsCount, addOptions, addOptionsCount*sizeof(UOption));
   121         optionsCount += addOptionsCount;
   122     }
   124     //parse the arguments
   125     _remainingArgc = u_parseArgs(_argc, (char**)_argv, optionsCount, options);
   127     // copy back values for additional options
   128     if (addOptionsCount > 0) {
   129         memcpy(addOptions, options+OPTIONS_COUNT, addOptionsCount*sizeof(UOption));
   130     }
   132     // Now setup the arguments
   133     if(_argc==1 || options[HELP1].doesOccur || options[HELP2].doesOccur) {
   134         status = U_ILLEGAL_ARGUMENT_ERROR;
   135         return;
   136     }
   138     if(options[VERBOSE].doesOccur) {
   139         verbose = TRUE;
   140     }
   142     if(options[SOURCEDIR].doesOccur) {
   143         sourceDir = options[SOURCEDIR].value;
   144     }
   146     if(options[ENCODING].doesOccur) {
   147         encoding = options[ENCODING].value;
   148     }
   150     if(options[USELEN].doesOccur) {
   151         uselen = TRUE;
   152     }
   154     if(options[FILE_NAME].doesOccur){
   155         fileName = options[FILE_NAME].value;
   156     }
   158     if(options[PASSES].doesOccur) {
   159         passes = atoi(options[PASSES].value);
   160     }
   161     if(options[ITERATIONS].doesOccur) {
   162         iterations = atoi(options[ITERATIONS].value);
   163         if(options[TIME].doesOccur) {
   164             status = U_ILLEGAL_ARGUMENT_ERROR;
   165             return;
   166         }
   167     } else if(options[TIME].doesOccur) {
   168         time = atoi(options[TIME].value);
   169     } else {
   170         iterations = 1000; // some default
   171     }
   173     if(options[LINE_MODE].doesOccur) {
   174         line_mode = TRUE;
   175         bulk_mode = FALSE;
   176     }
   178     if(options[BULK_MODE].doesOccur) {
   179         bulk_mode = TRUE;
   180         line_mode = FALSE;
   181     }
   183     if(options[LOCALE].doesOccur) {
   184         locale = options[LOCALE].value;
   185     }
   187     int32_t len = 0;
   188     if(fileName!=NULL){
   189         //pre-flight
   190         ucbuf_resolveFileName(sourceDir, fileName, NULL, &len, &status);
   191         resolvedFileName = (char*) uprv_malloc(len);
   192         if(resolvedFileName==NULL){
   193             status= U_MEMORY_ALLOCATION_ERROR;
   194             return;
   195         }
   196         if(status == U_BUFFER_OVERFLOW_ERROR){
   197             status = U_ZERO_ERROR;
   198         }
   199         ucbuf_resolveFileName(sourceDir, fileName, resolvedFileName, &len, &status);
   200         ucharBuf = ucbuf_open(resolvedFileName,&encoding,TRUE,FALSE,&status);
   202         if(U_FAILURE(status)){
   203             printf("Could not open the input file %s. Error: %s\n", fileName, u_errorName(status));
   204             return;
   205         }
   206     }
   207 }
   209 ULine* UPerfTest::getLines(UErrorCode& status){
   210     if (U_FAILURE(status)) {
   211         return NULL;
   212     }
   213     if (lines != NULL) {
   214         return lines;  // don't do it again
   215     }
   216     lines     = new ULine[MAXLINES];
   217     int maxLines = MAXLINES;
   218     numLines=0;
   219     const UChar* line=NULL;
   220     int32_t len =0;
   221     for (;;) {
   222         line = ucbuf_readline(ucharBuf,&len,&status);
   223         if(line == NULL || U_FAILURE(status)){
   224             break;
   225         }
   226         lines[numLines].name  = new UChar[len];
   227         lines[numLines].len   = len;
   228         memcpy(lines[numLines].name, line, len * U_SIZEOF_UCHAR);
   230         numLines++;
   231         len = 0;
   232         if (numLines >= maxLines) {
   233             maxLines += MAXLINES;
   234             ULine *newLines = new ULine[maxLines];
   235             if(newLines == NULL) {
   236                 fprintf(stderr, "Out of memory reading line %d.\n", (int)numLines);
   237                 status= U_MEMORY_ALLOCATION_ERROR;
   238                 delete []lines;
   239                 return NULL;
   240             }
   242             memcpy(newLines, lines, numLines*sizeof(ULine));
   243             delete []lines;
   244             lines = newLines;
   245         }
   246     }
   247     return lines;
   248 }
   249 const UChar* UPerfTest::getBuffer(int32_t& len, UErrorCode& status){
   250     if (U_FAILURE(status)) {
   251         return NULL;
   252     }
   253     len = ucbuf_size(ucharBuf);
   254     buffer =  (UChar*) uprv_malloc(U_SIZEOF_UCHAR * (len+1));
   255     u_strncpy(buffer,ucbuf_getBuffer(ucharBuf,&bufferLen,&status),len);
   256     buffer[len]=0;
   257     len = bufferLen;
   258     return buffer;
   259 }
   260 UBool UPerfTest::run(){
   261     if(_remainingArgc==1){
   262         // Testing all methods
   263         return runTest();
   264     }
   265     UBool res=FALSE;
   266     // Test only the specified fucntion
   267     for (int i = 1; i < _remainingArgc; ++i) {
   268         if (_argv[i][0] != '-') {
   269             char* name = (char*) _argv[i];
   270             if(verbose==TRUE){
   271                 //fprintf(stdout, "\n=== Handling test: %s: ===\n", name);
   272                 //fprintf(stdout, "\n%s:\n", name);
   273             }
   274             char* parameter = strchr( name, '@' );
   275             if (parameter) {
   276                 *parameter = 0;
   277                 parameter += 1;
   278             }
   279             execCount = 0;
   280             res = runTest( name, parameter );
   281             if (!res || (execCount <= 0)) {
   282                 fprintf(stdout, "\n---ERROR: Test doesn't exist: %s!\n", name);
   283                 return FALSE;
   284             }
   285         }
   286     }
   287     return res;
   288 }
   289 UBool UPerfTest::runTest(char* name, char* par ){
   290     UBool rval;
   291     char* pos = NULL;
   293     if (name)
   294         pos = strchr( name, delim ); // check if name contains path (by looking for '/')
   295     if (pos) {
   296         path = pos+1;   // store subpath for calling subtest
   297         *pos = 0;       // split into two strings
   298     }else{
   299         path = NULL;
   300     }
   302     if (!name || (name[0] == 0) || (strcmp(name, "*") == 0)) {
   303         rval = runTestLoop( NULL, NULL );
   305     }else if (strcmp( name, "LIST" ) == 0) {
   306         this->usage();
   307         rval = TRUE;
   309     }else{
   310         rval = runTestLoop( name, par );
   311     }
   313     if (pos)
   314         *pos = delim;  // restore original value at pos
   315     return rval;
   316 }
   319 void UPerfTest::setPath( char* pathVal )
   320 {
   321     this->path = pathVal;
   322 }
   324 // call individual tests, to be overriden to call implementations
   325 UPerfFunction* UPerfTest::runIndexedTest( int32_t /*index*/, UBool /*exec*/, const char* & /*name*/, char* /*par*/ )
   326 {
   327     // to be overriden by a method like:
   328     /*
   329     switch (index) {
   330         case 0: name = "First Test"; if (exec) FirstTest( par ); break;
   331         case 1: name = "Second Test"; if (exec) SecondTest( par ); break;
   332         default: name = ""; break;
   333     }
   334     */
   335     fprintf(stderr,"*** runIndexedTest needs to be overriden! ***");
   336     return NULL;
   337 }
   340 UBool UPerfTest::runTestLoop( char* testname, char* par )
   341 {
   342     int32_t    index = 0;
   343     const char*   name;
   344     UBool  run_this_test;
   345     UBool  rval = FALSE;
   346     UErrorCode status = U_ZERO_ERROR;
   347     UPerfTest* saveTest = gTest;
   348     gTest = this;
   349     int32_t loops = 0;
   350     double t=0;
   351     int32_t n = 1;
   352     long ops;
   353     do {
   354         this->runIndexedTest( index, FALSE, name );
   355         if (!name || (name[0] == 0))
   356             break;
   357         if (!testname) {
   358             run_this_test = TRUE;
   359         }else{
   360             run_this_test = (UBool) (strcmp( name, testname ) == 0);
   361         }
   362         if (run_this_test) {
   363             UPerfFunction* testFunction = this->runIndexedTest( index, TRUE, name, par );
   364             execCount++;
   365             rval=TRUE;
   366             if(testFunction==NULL){
   367                 fprintf(stderr,"%s function returned NULL", name);
   368                 return FALSE;
   369             }
   370             ops = testFunction->getOperationsPerIteration();
   371             if (ops < 1) {
   372                 fprintf(stderr, "%s returned an illegal operations/iteration()\n", name);
   373                 return FALSE;
   374             }
   375             if(iterations == 0) {
   376                 n = time;
   377                 // Run for specified duration in seconds
   378                 if(verbose==TRUE){
   379                     fprintf(stdout,"= %s calibrating %i seconds \n", name, (int)n);
   380                 }
   382                 //n *=  1000; // s => ms
   383                 //System.out.println("# " + meth.getName() + " " + n + " sec");
   384                 int32_t failsafe = 1; // last resort for very fast methods
   385                 t = 0;
   386                 while (t < (int)(n * 0.9)) { // 90% is close enough
   387                     if (loops == 0 || t == 0) {
   388                         loops = failsafe;
   389                         failsafe *= 10;
   390                     } else {
   391                         //System.out.println("# " + meth.getName() + " x " + loops + " = " + t);                            
   392                         loops = (int)((double)n / t * loops + 0.5);
   393                         if (loops == 0) {
   394                             fprintf(stderr,"Unable to converge on desired duration");
   395                             return FALSE;
   396                         }
   397                     }
   398                     //System.out.println("# " + meth.getName() + " x " + loops);
   399                     t = testFunction->time(loops,&status);
   400                     if(U_FAILURE(status)){
   401                         printf("Performance test failed with error: %s \n", u_errorName(status));
   402                         break;
   403                     }
   404                 }
   405             } else {
   406                 loops = iterations;
   407             }
   409             double min_t=1000000.0, sum_t=0.0;
   410             long events = -1;
   412             for(int32_t ps =0; ps < passes; ps++){
   413                 fprintf(stdout,"= %s begin " ,name);
   414                 if(verbose==TRUE){
   415                     if(iterations > 0) {
   416                         fprintf(stdout, "%i\n", (int)loops);
   417                     } else {
   418                         fprintf(stdout, "%i\n", (int)n);
   419                     }
   420                 } else {
   421                     fprintf(stdout, "\n");
   422                 }
   423                 t = testFunction->time(loops, &status);
   424                 if(U_FAILURE(status)){
   425                     printf("Performance test failed with error: %s \n", u_errorName(status));
   426                     break;
   427                 }
   428                 sum_t+=t;
   429                 if(t<min_t) {
   430                     min_t=t;
   431                 }
   432                 events = testFunction->getEventsPerIteration();
   433                 //print info only in verbose mode
   434                 if(verbose==TRUE){
   435                     if(events == -1){
   436                         fprintf(stdout, "= %s end: %f loops: %i operations: %li \n", name, t, (int)loops, ops);
   437                     }else{
   438                         fprintf(stdout, "= %s end: %f loops: %i operations: %li events: %li\n", name, t, (int)loops, ops, events);
   439                     }
   440                 }else{
   441                     if(events == -1){
   442                         fprintf(stdout,"= %s end %f %i %li\n", name, t, (int)loops, ops);
   443                     }else{
   444                         fprintf(stdout,"= %s end %f %i %li %li\n", name, t, (int)loops, ops, events);
   445                     }
   446                 }
   447             }
   448             if(verbose && U_SUCCESS(status)) {
   449                 double avg_t = sum_t/passes;
   450                 if (loops == 0 || ops == 0) {
   451                     fprintf(stderr, "%s did not run\n", name);
   452                 }
   453                 else if(events == -1) {
   454                     fprintf(stdout, "%%= %s avg: %.4g loops: %i avg/op: %.4g ns\n",
   455                             name, avg_t, (int)loops, (avg_t*1E9)/(loops*ops));
   456                     fprintf(stdout, "_= %s min: %.4g loops: %i min/op: %.4g ns\n",
   457                             name, min_t, (int)loops, (min_t*1E9)/(loops*ops));
   458                 }
   459                 else {
   460                     fprintf(stdout, "%%= %s avg: %.4g loops: %i avg/op: %.4g ns avg/event: %.4g ns\n",
   461                             name, avg_t, (int)loops, (avg_t*1E9)/(loops*ops), (avg_t*1E9)/(loops*events));
   462                     fprintf(stdout, "_= %s min: %.4g loops: %i min/op: %.4g ns min/event: %.4g ns\n",
   463                             name, min_t, (int)loops, (min_t*1E9)/(loops*ops), (min_t*1E9)/(loops*events));
   464                 }
   465             }
   466             delete testFunction;
   467         }
   468         index++;
   469     }while(name);
   471     gTest = saveTest;
   472     return rval;
   473 }
   475 /**
   476 * Print a usage message for this test class.
   477 */
   478 void UPerfTest::usage( void )
   479 {
   480     puts(gUsageString);
   481     if (_addUsage != NULL) {
   482         puts(_addUsage);
   483     }
   485     UBool save_verbose = verbose;
   486     verbose = TRUE;
   487     fprintf(stdout,"Test names:\n");
   488     fprintf(stdout,"-----------\n");
   490     int32_t index = 0;
   491     const char* name = NULL;
   492     do{
   493         this->runIndexedTest( index, FALSE, name );
   494         if (!name)
   495             break;
   496         fprintf(stdout, "%s\n", name);
   497         index++;
   498     }while (name && (name[0] != 0));
   499     verbose = save_verbose;
   500 }
   505 void UPerfTest::setCaller( UPerfTest* callingTest )
   506 {
   507     caller = callingTest;
   508     if (caller) {
   509         verbose = caller->verbose;
   510     }
   511 }
   513 UBool UPerfTest::callTest( UPerfTest& testToBeCalled, char* par )
   514 {
   515     execCount--; // correct a previously assumed test-exec, as this only calls a subtest
   516     testToBeCalled.setCaller( this );
   517     return testToBeCalled.runTest( path, par );
   518 }
   520 UPerfTest::~UPerfTest(){
   521     if(lines!=NULL){
   522         delete[] lines;
   523     }
   524     if(buffer!=NULL){
   525         uprv_free(buffer);
   526     }
   527     if(resolvedFileName!=NULL){
   528         uprv_free(resolvedFileName);
   529     }
   530     ucbuf_close(ucharBuf);
   531 }
   533 #endif

mercurial