| 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
|
|
|
|
|