]> git.saurik.com Git - apple/icu.git/blobdiff - icuSources/tools/ctestfw/uperf.cpp
ICU-59117.0.1.tar.gz
[apple/icu.git] / icuSources / tools / ctestfw / uperf.cpp
index 72b5a6d8adb358bab6689e210ef2b7a245ab6dec..0735f8a8eff4cbe917505225473d5c96142a07b8 100644 (file)
@@ -1,9 +1,15 @@
+// © 2016 and later: Unicode, Inc. and others.
+// License & terms of use: http://www.unicode.org/copyright.html
 /********************************************************************
  * COPYRIGHT:
- * Copyright (c) 2002-2006, International Business Machines Corporation and
+ * Copyright (c) 2002-2012, International Business Machines Corporation and
  * others. All Rights Reserved.
  ********************************************************************/
 
+// Defines _XOPEN_SOURCE for access to POSIX functions.
+// Must be before any other #includes.
+#include "uposixdefs.h"
+
 #include "unicode/uperf.h"
 #include "uoptions.h"
 #include "cmemory.h"
@@ -11,6 +17,9 @@
 #include <stdlib.h>
 
 #if !UCONFIG_NO_CONVERSION
+
+UPerfFunction::~UPerfFunction() {}
+
 static const char delim = '/';
 static int32_t execCount = 0;
 UPerfTest* UPerfTest::gTest = NULL;
@@ -26,11 +35,14 @@ const char UPerfTest::gUsageString[] =
     "\t-e or --encoding     encoding of source files\n"
     "\t-u or --uselen       perform timing analysis on non-null terminated buffer using length\n"
     "\t-f or --file-name    file to be used as input data\n"
-    "\t-p or --passes       Number of passes to be performed. Requires Numeric argument. Cannot be used with --time\n"
+    "\t-p or --passes       Number of passes to be performed. Requires Numeric argument.\n"
+    "\t                     Cannot be used with --time\n"
     "\t-i or --iterations   Number of iterations to be performed. Requires Numeric argument\n"
-    "\t-t or --time         Threshold time for looping until in seconds. Requires Numeric argument.Cannot be used with --iterations\n"
+    "\t-t or --time         Threshold time for looping until in seconds. Requires Numeric argument.\n"
+    "\t                     Cannot be used with --iterations\n"
     "\t-l or --line-mode    The data file should be processed in line mode\n"
-    "\t-b or --bulk-mode    The data file should be processed in file based. Cannot be used with --line-mode\n"
+    "\t-b or --bulk-mode    The data file should be processed in file based.\n"
+    "\t                     Cannot be used with --line-mode\n"
     "\t-L or --locale       Locale for the test\n";
 
 enum
@@ -47,11 +59,12 @@ enum
     TIME,
     LINE_MODE,
     BULK_MODE,
-    LOCALE
+    LOCALE,
+    OPTIONS_COUNT
 };
 
 
-static UOption options[]={
+static UOption options[OPTIONS_COUNT+20]={
     UOPTION_HELP_H,
     UOPTION_HELP_QUESTION_MARK,
     UOPTION_VERBOSE,
@@ -67,32 +80,59 @@ static UOption options[]={
     UOPTION_DEF( "locale",        'L', UOPT_REQUIRES_ARG)
 };
 
-UPerfTest::UPerfTest(int32_t argc, const char* argv[], UErrorCode& status){
-    
-    _argc = argc;
-    _argv = argv;
-    ucharBuf = NULL;
-    encoding = "";
-    uselen = FALSE;
-    fileName = NULL;
-    sourceDir = ".";
-    lines = NULL;
-    numLines = 0;
-    line_mode = TRUE;
-    buffer = NULL;
-    bufferLen = 0;
-    verbose = FALSE;
-    bulk_mode = FALSE;
-    passes = iterations = time = 0;
-    locale = NULL;
-    
+UPerfTest::UPerfTest(int32_t argc, const char* argv[], UErrorCode& status)
+        : _argc(argc), _argv(argv), _addUsage(NULL),
+          ucharBuf(NULL), encoding(""),
+          uselen(FALSE),
+          fileName(NULL), sourceDir("."),
+          lines(NULL), numLines(0), line_mode(TRUE),
+          buffer(NULL), bufferLen(0),
+          verbose(FALSE), bulk_mode(FALSE),
+          passes(1), iterations(0), time(0),
+          locale(NULL) {
+    init(NULL, 0, status);
+}
+
+UPerfTest::UPerfTest(int32_t argc, const char* argv[],
+                     UOption addOptions[], int32_t addOptionsCount,
+                     const char *addUsage,
+                     UErrorCode& status)
+        : _argc(argc), _argv(argv), _addUsage(addUsage),
+          ucharBuf(NULL), encoding(""),
+          uselen(FALSE),
+          fileName(NULL), sourceDir("."),
+          lines(NULL), numLines(0), line_mode(TRUE),
+          buffer(NULL), bufferLen(0),
+          verbose(FALSE), bulk_mode(FALSE),
+          passes(1), iterations(0), time(0),
+          locale(NULL) {
+    init(addOptions, addOptionsCount, status);
+}
+
+void UPerfTest::init(UOption addOptions[], int32_t addOptionsCount,
+                     UErrorCode& status) {
     //initialize the argument list
-    U_MAIN_INIT_ARGS(argc, argv);
+    U_MAIN_INIT_ARGS(_argc, _argv);
+
+    resolvedFileName = NULL;
+
+    // add specific options
+    int32_t optionsCount = OPTIONS_COUNT;
+    if (addOptionsCount > 0) {
+        memcpy(options+optionsCount, addOptions, addOptionsCount*sizeof(UOption));
+        optionsCount += addOptionsCount;
+    }
+
     //parse the arguments
-    _remainingArgc = u_parseArgs(argc, (char**)argv, (int32_t)(sizeof(options)/sizeof(options[0])), options);
+    _remainingArgc = u_parseArgs(_argc, (char**)_argv, optionsCount, options);
+
+    // copy back values for additional options
+    if (addOptionsCount > 0) {
+        memcpy(addOptions, options+OPTIONS_COUNT, addOptionsCount*sizeof(UOption));
+    }
 
     // Now setup the arguments
-    if(argc==1 || options[HELP1].doesOccur || options[HELP2].doesOccur) {
+    if(_argc==1 || options[HELP1].doesOccur || options[HELP2].doesOccur) {
         status = U_ILLEGAL_ARGUMENT_ERROR;
         return;
     }
@@ -122,12 +162,16 @@ UPerfTest::UPerfTest(int32_t argc, const char* argv[], UErrorCode& status){
     }
     if(options[ITERATIONS].doesOccur) {
         iterations = atoi(options[ITERATIONS].value);
-    }
-    if(options[TIME].doesOccur) {
+        if(options[TIME].doesOccur) {
+            status = U_ILLEGAL_ARGUMENT_ERROR;
+            return;
+        }
+    } else if(options[TIME].doesOccur) {
         time = atoi(options[TIME].value);
+    } else {
+        iterations = 1000; // some default
     }
-    
+
     if(options[LINE_MODE].doesOccur) {
         line_mode = TRUE;
         bulk_mode = FALSE;
@@ -139,16 +183,10 @@ UPerfTest::UPerfTest(int32_t argc, const char* argv[], UErrorCode& status){
     }
     
     if(options[LOCALE].doesOccur) {
-      locale = options[LOCALE].value;
-    }
-
-    if(time > 0 && iterations >0){
-        status = U_ILLEGAL_ARGUMENT_ERROR;
-        return;
+        locale = options[LOCALE].value;
     }
 
     int32_t len = 0;
-    resolvedFileName = NULL;
     if(fileName!=NULL){
         //pre-flight
         ucbuf_resolveFileName(sourceDir, fileName, NULL, &len, &status);
@@ -171,6 +209,12 @@ UPerfTest::UPerfTest(int32_t argc, const char* argv[], UErrorCode& status){
 }
 
 ULine* UPerfTest::getLines(UErrorCode& status){
+    if (U_FAILURE(status)) {
+        return NULL;
+    }
+    if (lines != NULL) {
+        return lines;  // don't do it again
+    }
     lines     = new ULine[MAXLINES];
     int maxLines = MAXLINES;
     numLines=0;
@@ -205,6 +249,9 @@ ULine* UPerfTest::getLines(UErrorCode& status){
     return lines;
 }
 const UChar* UPerfTest::getBuffer(int32_t& len, UErrorCode& status){
+    if (U_FAILURE(status)) {
+        return NULL;
+    }
     len = ucbuf_size(ucharBuf);
     buffer =  (UChar*) uprv_malloc(U_SIZEOF_UCHAR * (len+1));
     u_strncpy(buffer,ucbuf_getBuffer(ucharBuf,&bufferLen,&status),len);
@@ -277,7 +324,7 @@ void UPerfTest::setPath( char* pathVal )
 }
 
 // call individual tests, to be overriden to call implementations
-UPerfFunction* UPerfTest::runIndexedTest( int32_t index, UBool exec, const char* &name, char* par )
+UPerfFunction* UPerfTest::runIndexedTest( int32_t /*index*/, UBool /*exec*/, const char* & /*name*/, char* /*par*/ )
 {
     // to be overriden by a method like:
     /*
@@ -288,7 +335,6 @@ UPerfFunction* UPerfTest::runIndexedTest( int32_t index, UBool exec, const char*
     }
     */
     fprintf(stderr,"*** runIndexedTest needs to be overriden! ***");
-    name = ""; exec = exec; index = index; par = par;
     return NULL;
 }
 
@@ -305,6 +351,7 @@ UBool UPerfTest::runTestLoop( char* testname, char* par )
     int32_t loops = 0;
     double t=0;
     int32_t n = 1;
+    long ops;
     do {
         this->runIndexedTest( index, FALSE, name );
         if (!name || (name[0] == 0))
@@ -322,7 +369,8 @@ UBool UPerfTest::runTestLoop( char* testname, char* par )
                 fprintf(stderr,"%s function returned NULL", name);
                 return FALSE;
             }
-            if (testFunction->getOperationsPerIteration() < 1) {
+            ops = testFunction->getOperationsPerIteration();
+            if (ops < 1) {
                 fprintf(stderr, "%s returned an illegal operations/iteration()\n", name);
                 return FALSE;
             }
@@ -360,8 +408,10 @@ UBool UPerfTest::runTestLoop( char* testname, char* par )
                 loops = iterations;
             }
 
+            double min_t=1000000.0, sum_t=0.0;
+            long events = -1;
+
             for(int32_t ps =0; ps < passes; ps++){
-                long events = -1;
                 fprintf(stdout,"= %s begin " ,name);
                 if(verbose==TRUE){
                     if(iterations > 0) {
@@ -377,36 +427,44 @@ UBool UPerfTest::runTestLoop( char* testname, char* par )
                     printf("Performance test failed with error: %s \n", u_errorName(status));
                     break;
                 }
+                sum_t+=t;
+                if(t<min_t) {
+                    min_t=t;
+                }
                 events = testFunction->getEventsPerIteration();
                 //print info only in verbose mode
                 if(verbose==TRUE){
-/*
-                    if(events == -1){
-                        fprintf(stdout,"= %s end %f %i %i\n",name , t , loops, testFunction->getOperationsPerIteration());
-                    }else{
-                        fprintf(stdout,"= %s end %f %i %i %i\n",name , t , loops, testFunction->getOperationsPerIteration(), events);
-                    }
-*/
                     if(events == -1){
-                        fprintf(stdout, "= %s end: %f loops: %i operations: %li \n", name, t, (int)loops, testFunction->getOperationsPerIteration());
+                        fprintf(stdout, "= %s end: %f loops: %i operations: %li \n", name, t, (int)loops, ops);
                     }else{
-                        fprintf(stdout, "= %s end: %f loops: %i operations: %li events: %li\n", name, t, (int)loops, testFunction->getOperationsPerIteration(), events);
+                        fprintf(stdout, "= %s end: %f loops: %i operations: %li events: %li\n", name, t, (int)loops, ops, events);
                     }
                 }else{
-/*
-                    if(events == -1){
-                        fprintf(stdout,"= %f %i %i \n", t , loops, testFunction->getOperationsPerIteration());
-                    }else{
-                        fprintf(stdout,"= %f %i %i %i\n", t , loops, testFunction->getOperationsPerIteration(), events);
-                    }
-*/
                     if(events == -1){
-                        fprintf(stdout,"= %s end %f %i %li\n", name, t, (int)loops, testFunction->getOperationsPerIteration());
+                        fprintf(stdout,"= %s end %f %i %li\n", name, t, (int)loops, ops);
                     }else{
-                        fprintf(stdout,"= %s end %f %i %li %li\n", name, t, (int)loops, testFunction->getOperationsPerIteration(), events);
+                        fprintf(stdout,"= %s end %f %i %li %li\n", name, t, (int)loops, ops, events);
                     }
                 }
             }
+            if(verbose && U_SUCCESS(status)) {
+                double avg_t = sum_t/passes;
+                if (loops == 0 || ops == 0) {
+                    fprintf(stderr, "%s did not run\n", name);
+                }
+                else if(events == -1) {
+                    fprintf(stdout, "%%= %s avg: %.4g loops: %i avg/op: %.4g ns\n",
+                            name, avg_t, (int)loops, (avg_t*1E9)/(loops*ops));
+                    fprintf(stdout, "_= %s min: %.4g loops: %i min/op: %.4g ns\n",
+                            name, min_t, (int)loops, (min_t*1E9)/(loops*ops));
+                }
+                else {
+                    fprintf(stdout, "%%= %s avg: %.4g loops: %i avg/op: %.4g ns avg/event: %.4g ns\n",
+                            name, avg_t, (int)loops, (avg_t*1E9)/(loops*ops), (avg_t*1E9)/(loops*events));
+                    fprintf(stdout, "_= %s min: %.4g loops: %i min/op: %.4g ns min/event: %.4g ns\n",
+                            name, min_t, (int)loops, (min_t*1E9)/(loops*ops), (min_t*1E9)/(loops*events));
+                }
+            }
             delete testFunction;
         }
         index++;
@@ -421,6 +479,11 @@ UBool UPerfTest::runTestLoop( char* testname, char* par )
 */
 void UPerfTest::usage( void )
 {
+    puts(gUsageString);
+    if (_addUsage != NULL) {
+        puts(_addUsage);
+    }
+
     UBool save_verbose = verbose;
     verbose = TRUE;
     fprintf(stdout,"Test names:\n");
@@ -432,8 +495,7 @@ void UPerfTest::usage( void )
         this->runIndexedTest( index, FALSE, name );
         if (!name)
             break;
-        fprintf(stdout,name);
-        fprintf(stdout,"\n");
+        fprintf(stdout, "%s\n", name);
         index++;
     }while (name && (name[0] != 0));
     verbose = save_verbose;