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