Index: icu46/source/tools/ctestfw/uperf.cpp |
=================================================================== |
--- icu46/source/tools/ctestfw/uperf.cpp (revision 0) |
+++ icu46/source/tools/ctestfw/uperf.cpp (revision 0) |
@@ -0,0 +1,525 @@ |
+/******************************************************************** |
+ * COPYRIGHT: |
+ * Copyright (c) 2002-2009, International Business Machines Corporation and |
+ * others. All Rights Reserved. |
+ ********************************************************************/ |
+ |
+/* z/OS needs this definition for timeval */ |
+#include "platform_xopen_source_extended.h" |
+ |
+#include "unicode/uperf.h" |
+#include "uoptions.h" |
+#include "cmemory.h" |
+#include <stdio.h> |
+#include <stdlib.h> |
+ |
+#if !UCONFIG_NO_CONVERSION |
+static const char delim = '/'; |
+static int32_t execCount = 0; |
+UPerfTest* UPerfTest::gTest = NULL; |
+static const int MAXLINES = 40000; |
+const char UPerfTest::gUsageString[] = |
+ "Usage: %s [OPTIONS] [FILES]\n" |
+ "\tReads the input file and prints out time taken in seconds\n" |
+ "Options:\n" |
+ "\t-h or -? or --help this usage text\n" |
+ "\t-v or --verbose print extra information when processing files\n" |
+ "\t-s or --sourcedir source directory for files followed by path\n" |
+ "\t followed by path\n" |
+ "\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.\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.\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.\n" |
+ "\t Cannot be used with --line-mode\n" |
+ "\t-L or --locale Locale for the test\n"; |
+ |
+enum |
+{ |
+ HELP1, |
+ HELP2, |
+ VERBOSE, |
+ SOURCEDIR, |
+ ENCODING, |
+ USELEN, |
+ FILE_NAME, |
+ PASSES, |
+ ITERATIONS, |
+ TIME, |
+ LINE_MODE, |
+ BULK_MODE, |
+ LOCALE, |
+ OPTIONS_COUNT |
+}; |
+ |
+ |
+static UOption options[OPTIONS_COUNT+20]={ |
+ UOPTION_HELP_H, |
+ UOPTION_HELP_QUESTION_MARK, |
+ UOPTION_VERBOSE, |
+ UOPTION_SOURCEDIR, |
+ UOPTION_ENCODING, |
+ UOPTION_DEF( "uselen", 'u', UOPT_NO_ARG), |
+ UOPTION_DEF( "file-name", 'f', UOPT_REQUIRES_ARG), |
+ UOPTION_DEF( "passes", 'p', UOPT_REQUIRES_ARG), |
+ UOPTION_DEF( "iterations", 'i', UOPT_REQUIRES_ARG), |
+ UOPTION_DEF( "time", 't', UOPT_REQUIRES_ARG), |
+ UOPTION_DEF( "line-mode", 'l', UOPT_NO_ARG), |
+ UOPTION_DEF( "bulk-mode", 'b', UOPT_NO_ARG), |
+ UOPTION_DEF( "locale", 'L', UOPT_REQUIRES_ARG) |
+}; |
+ |
+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); |
+ |
+ 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, 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) { |
+ status = U_ILLEGAL_ARGUMENT_ERROR; |
+ return; |
+ } |
+ |
+ if(options[VERBOSE].doesOccur) { |
+ verbose = TRUE; |
+ } |
+ |
+ if(options[SOURCEDIR].doesOccur) { |
+ sourceDir = options[SOURCEDIR].value; |
+ } |
+ |
+ if(options[ENCODING].doesOccur) { |
+ encoding = options[ENCODING].value; |
+ } |
+ |
+ if(options[USELEN].doesOccur) { |
+ uselen = TRUE; |
+ } |
+ |
+ if(options[FILE_NAME].doesOccur){ |
+ fileName = options[FILE_NAME].value; |
+ } |
+ |
+ if(options[PASSES].doesOccur) { |
+ passes = atoi(options[PASSES].value); |
+ } |
+ if(options[ITERATIONS].doesOccur) { |
+ iterations = atoi(options[ITERATIONS].value); |
+ 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; |
+ } |
+ |
+ if(options[BULK_MODE].doesOccur) { |
+ bulk_mode = TRUE; |
+ line_mode = FALSE; |
+ } |
+ |
+ if(options[LOCALE].doesOccur) { |
+ locale = options[LOCALE].value; |
+ } |
+ |
+ int32_t len = 0; |
+ if(fileName!=NULL){ |
+ //pre-flight |
+ ucbuf_resolveFileName(sourceDir, fileName, NULL, &len, &status); |
+ resolvedFileName = (char*) uprv_malloc(len); |
+ if(resolvedFileName==NULL){ |
+ status= U_MEMORY_ALLOCATION_ERROR; |
+ return; |
+ } |
+ if(status == U_BUFFER_OVERFLOW_ERROR){ |
+ status = U_ZERO_ERROR; |
+ } |
+ ucbuf_resolveFileName(sourceDir, fileName, resolvedFileName, &len, &status); |
+ ucharBuf = ucbuf_open(resolvedFileName,&encoding,TRUE,FALSE,&status); |
+ |
+ if(U_FAILURE(status)){ |
+ printf("Could not open the input file %s. Error: %s\n", fileName, u_errorName(status)); |
+ return; |
+ } |
+ } |
+} |
+ |
+ULine* UPerfTest::getLines(UErrorCode& status){ |
+ lines = new ULine[MAXLINES]; |
+ int maxLines = MAXLINES; |
+ numLines=0; |
+ const UChar* line=NULL; |
+ int32_t len =0; |
+ for (;;) { |
+ line = ucbuf_readline(ucharBuf,&len,&status); |
+ if(line == NULL || U_FAILURE(status)){ |
+ break; |
+ } |
+ lines[numLines].name = new UChar[len]; |
+ lines[numLines].len = len; |
+ memcpy(lines[numLines].name, line, len * U_SIZEOF_UCHAR); |
+ |
+ numLines++; |
+ len = 0; |
+ if (numLines >= maxLines) { |
+ maxLines += MAXLINES; |
+ ULine *newLines = new ULine[maxLines]; |
+ if(newLines == NULL) { |
+ fprintf(stderr, "Out of memory reading line %d.\n", (int)numLines); |
+ status= U_MEMORY_ALLOCATION_ERROR; |
+ delete []lines; |
+ return NULL; |
+ } |
+ |
+ memcpy(newLines, lines, numLines*sizeof(ULine)); |
+ delete []lines; |
+ lines = newLines; |
+ } |
+ } |
+ 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); |
+ buffer[len]=0; |
+ len = bufferLen; |
+ return buffer; |
+} |
+UBool UPerfTest::run(){ |
+ if(_remainingArgc==1){ |
+ // Testing all methods |
+ return runTest(); |
+ } |
+ UBool res=FALSE; |
+ // Test only the specified fucntion |
+ for (int i = 1; i < _remainingArgc; ++i) { |
+ if (_argv[i][0] != '-') { |
+ char* name = (char*) _argv[i]; |
+ if(verbose==TRUE){ |
+ //fprintf(stdout, "\n=== Handling test: %s: ===\n", name); |
+ //fprintf(stdout, "\n%s:\n", name); |
+ } |
+ char* parameter = strchr( name, '@' ); |
+ if (parameter) { |
+ *parameter = 0; |
+ parameter += 1; |
+ } |
+ execCount = 0; |
+ res = runTest( name, parameter ); |
+ if (!res || (execCount <= 0)) { |
+ fprintf(stdout, "\n---ERROR: Test doesn't exist: %s!\n", name); |
+ return FALSE; |
+ } |
+ } |
+ } |
+ return res; |
+} |
+UBool UPerfTest::runTest(char* name, char* par ){ |
+ UBool rval; |
+ char* pos = NULL; |
+ |
+ if (name) |
+ pos = strchr( name, delim ); // check if name contains path (by looking for '/') |
+ if (pos) { |
+ path = pos+1; // store subpath for calling subtest |
+ *pos = 0; // split into two strings |
+ }else{ |
+ path = NULL; |
+ } |
+ |
+ if (!name || (name[0] == 0) || (strcmp(name, "*") == 0)) { |
+ rval = runTestLoop( NULL, NULL ); |
+ |
+ }else if (strcmp( name, "LIST" ) == 0) { |
+ this->usage(); |
+ rval = TRUE; |
+ |
+ }else{ |
+ rval = runTestLoop( name, par ); |
+ } |
+ |
+ if (pos) |
+ *pos = delim; // restore original value at pos |
+ return rval; |
+} |
+ |
+ |
+void UPerfTest::setPath( char* pathVal ) |
+{ |
+ this->path = pathVal; |
+} |
+ |
+// call individual tests, to be overriden to call implementations |
+UPerfFunction* UPerfTest::runIndexedTest( int32_t index, UBool exec, const char* &name, char* par ) |
+{ |
+ // to be overriden by a method like: |
+ /* |
+ switch (index) { |
+ case 0: name = "First Test"; if (exec) FirstTest( par ); break; |
+ case 1: name = "Second Test"; if (exec) SecondTest( par ); break; |
+ default: name = ""; break; |
+ } |
+ */ |
+ fprintf(stderr,"*** runIndexedTest needs to be overriden! ***"); |
+ name = ""; exec = exec; index = index; par = par; |
+ return NULL; |
+} |
+ |
+ |
+UBool UPerfTest::runTestLoop( char* testname, char* par ) |
+{ |
+ int32_t index = 0; |
+ const char* name; |
+ UBool run_this_test; |
+ UBool rval = FALSE; |
+ UErrorCode status = U_ZERO_ERROR; |
+ UPerfTest* saveTest = gTest; |
+ gTest = this; |
+ int32_t loops = 0; |
+ double t=0; |
+ int32_t n = 1; |
+ long ops; |
+ do { |
+ this->runIndexedTest( index, FALSE, name ); |
+ if (!name || (name[0] == 0)) |
+ break; |
+ if (!testname) { |
+ run_this_test = TRUE; |
+ }else{ |
+ run_this_test = (UBool) (strcmp( name, testname ) == 0); |
+ } |
+ if (run_this_test) { |
+ UPerfFunction* testFunction = this->runIndexedTest( index, TRUE, name, par ); |
+ execCount++; |
+ rval=TRUE; |
+ if(testFunction==NULL){ |
+ fprintf(stderr,"%s function returned NULL", name); |
+ return FALSE; |
+ } |
+ ops = testFunction->getOperationsPerIteration(); |
+ if (ops < 1) { |
+ fprintf(stderr, "%s returned an illegal operations/iteration()\n", name); |
+ return FALSE; |
+ } |
+ if(iterations == 0) { |
+ n = time; |
+ // Run for specified duration in seconds |
+ if(verbose==TRUE){ |
+ fprintf(stdout,"= %s calibrating %i seconds \n", name, (int)n); |
+ } |
+ |
+ //n *= 1000; // s => ms |
+ //System.out.println("# " + meth.getName() + " " + n + " sec"); |
+ int32_t failsafe = 1; // last resort for very fast methods |
+ t = 0; |
+ while (t < (int)(n * 0.9)) { // 90% is close enough |
+ if (loops == 0 || t == 0) { |
+ loops = failsafe; |
+ failsafe *= 10; |
+ } else { |
+ //System.out.println("# " + meth.getName() + " x " + loops + " = " + t); |
+ loops = (int)((double)n / t * loops + 0.5); |
+ if (loops == 0) { |
+ fprintf(stderr,"Unable to converge on desired duration"); |
+ return FALSE; |
+ } |
+ } |
+ //System.out.println("# " + meth.getName() + " x " + loops); |
+ t = testFunction->time(loops,&status); |
+ if(U_FAILURE(status)){ |
+ printf("Performance test failed with error: %s \n", u_errorName(status)); |
+ break; |
+ } |
+ } |
+ } else { |
+ loops = iterations; |
+ } |
+ |
+ double min_t=1000000.0, sum_t=0.0; |
+ long events = -1; |
+ |
+ for(int32_t ps =0; ps < passes; ps++){ |
+ fprintf(stdout,"= %s begin " ,name); |
+ if(verbose==TRUE){ |
+ if(iterations > 0) { |
+ fprintf(stdout, "%i\n", (int)loops); |
+ } else { |
+ fprintf(stdout, "%i\n", (int)n); |
+ } |
+ } else { |
+ fprintf(stdout, "\n"); |
+ } |
+ t = testFunction->time(loops, &status); |
+ if(U_FAILURE(status)){ |
+ 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 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, ops, events); |
+ } |
+ }else{ |
+ if(events == -1){ |
+ 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, 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++; |
+ }while(name); |
+ |
+ gTest = saveTest; |
+ return rval; |
+} |
+ |
+/** |
+* Print a usage message for this test class. |
+*/ |
+void UPerfTest::usage( void ) |
+{ |
+ puts(gUsageString); |
+ if (_addUsage != NULL) { |
+ puts(_addUsage); |
+ } |
+ |
+ UBool save_verbose = verbose; |
+ verbose = TRUE; |
+ fprintf(stdout,"Test names:\n"); |
+ fprintf(stdout,"-----------\n"); |
+ |
+ int32_t index = 0; |
+ const char* name = NULL; |
+ do{ |
+ this->runIndexedTest( index, FALSE, name ); |
+ if (!name) |
+ break; |
+ fprintf(stdout,name); |
+ fprintf(stdout,"\n"); |
+ index++; |
+ }while (name && (name[0] != 0)); |
+ verbose = save_verbose; |
+} |
+ |
+ |
+ |
+ |
+void UPerfTest::setCaller( UPerfTest* callingTest ) |
+{ |
+ caller = callingTest; |
+ if (caller) { |
+ verbose = caller->verbose; |
+ } |
+} |
+ |
+UBool UPerfTest::callTest( UPerfTest& testToBeCalled, char* par ) |
+{ |
+ execCount--; // correct a previously assumed test-exec, as this only calls a subtest |
+ testToBeCalled.setCaller( this ); |
+ return testToBeCalled.runTest( path, par ); |
+} |
+ |
+UPerfTest::~UPerfTest(){ |
+ if(lines!=NULL){ |
+ delete[] lines; |
+ } |
+ if(buffer!=NULL){ |
+ uprv_free(buffer); |
+ } |
+ if(resolvedFileName!=NULL){ |
+ uprv_free(resolvedFileName); |
+ } |
+ ucbuf_close(ucharBuf); |
+} |
+ |
+#endif |
Property changes on: icu46/source/tools/ctestfw/uperf.cpp |
___________________________________________________________________ |
Added: svn:eol-style |
+ LF |