1 /********************************************************************
3 * Copyright (c) 2002-2008, International Business Machines Corporation and
4 * others. All Rights Reserved.
5 ********************************************************************/
7 /* z/OS needs this definition for timeval */
8 #if !defined(_XOPEN_SOURCE_EXTENDED)
9 #define _XOPEN_SOURCE_EXTENDED 1
12 #include "unicode/uperf.h"
18 #if !UCONFIG_NO_CONVERSION
19 static const char delim
= '/';
20 static int32_t execCount
= 0;
21 UPerfTest
* UPerfTest::gTest
= NULL
;
22 static const int MAXLINES
= 40000;
23 const char UPerfTest::gUsageString
[] =
24 "Usage: %s [OPTIONS] [FILES]\n"
25 "\tReads the input file and prints out time taken in seconds\n"
27 "\t-h or -? or --help this usage text\n"
28 "\t-v or --verbose print extra information when processing files\n"
29 "\t-s or --sourcedir source directory for files followed by path\n"
30 "\t followed by path\n"
31 "\t-e or --encoding encoding of source files\n"
32 "\t-u or --uselen perform timing analysis on non-null terminated buffer using length\n"
33 "\t-f or --file-name file to be used as input data\n"
34 "\t-p or --passes Number of passes to be performed. Requires Numeric argument.\n"
35 "\t Cannot be used with --time\n"
36 "\t-i or --iterations Number of iterations to be performed. Requires Numeric argument\n"
37 "\t-t or --time Threshold time for looping until in seconds. Requires Numeric argument.\n"
38 "\t Cannot be used with --iterations\n"
39 "\t-l or --line-mode The data file should be processed in line mode\n"
40 "\t-b or --bulk-mode The data file should be processed in file based.\n"
41 "\t Cannot be used with --line-mode\n"
42 "\t-L or --locale Locale for the test\n";
63 static UOption options
[OPTIONS_COUNT
+20]={
65 UOPTION_HELP_QUESTION_MARK
,
69 UOPTION_DEF( "uselen", 'u', UOPT_NO_ARG
),
70 UOPTION_DEF( "file-name", 'f', UOPT_REQUIRES_ARG
),
71 UOPTION_DEF( "passes", 'p', UOPT_REQUIRES_ARG
),
72 UOPTION_DEF( "iterations", 'i', UOPT_REQUIRES_ARG
),
73 UOPTION_DEF( "time", 't', UOPT_REQUIRES_ARG
),
74 UOPTION_DEF( "line-mode", 'l', UOPT_NO_ARG
),
75 UOPTION_DEF( "bulk-mode", 'b', UOPT_NO_ARG
),
76 UOPTION_DEF( "locale", 'L', UOPT_REQUIRES_ARG
)
79 UPerfTest::UPerfTest(int32_t argc
, const char* argv
[], UErrorCode
& status
)
80 : _argc(argc
), _argv(argv
), _addUsage(NULL
),
81 ucharBuf(NULL
), encoding(""),
83 fileName(NULL
), sourceDir("."),
84 lines(NULL
), numLines(0), line_mode(TRUE
),
85 buffer(NULL
), bufferLen(0),
86 verbose(FALSE
), bulk_mode(FALSE
),
87 passes(1), iterations(0), time(0),
89 init(NULL
, 0, status
);
92 UPerfTest::UPerfTest(int32_t argc
, const char* argv
[],
93 UOption addOptions
[], int32_t addOptionsCount
,
96 : _argc(argc
), _argv(argv
), _addUsage(addUsage
),
97 ucharBuf(NULL
), encoding(""),
99 fileName(NULL
), sourceDir("."),
100 lines(NULL
), numLines(0), line_mode(TRUE
),
101 buffer(NULL
), bufferLen(0),
102 verbose(FALSE
), bulk_mode(FALSE
),
103 passes(1), iterations(0), time(0),
105 init(addOptions
, addOptionsCount
, status
);
108 void UPerfTest::init(UOption addOptions
[], int32_t addOptionsCount
,
109 UErrorCode
& status
) {
110 //initialize the argument list
111 U_MAIN_INIT_ARGS(_argc
, _argv
);
113 resolvedFileName
= NULL
;
115 // add specific options
116 int32_t optionsCount
= OPTIONS_COUNT
;
117 if (addOptionsCount
> 0) {
118 memcpy(options
+optionsCount
, addOptions
, addOptionsCount
*sizeof(UOption
));
119 optionsCount
+= addOptionsCount
;
122 //parse the arguments
123 _remainingArgc
= u_parseArgs(_argc
, (char**)_argv
, optionsCount
, options
);
125 // copy back values for additional options
126 if (addOptionsCount
> 0) {
127 memcpy(addOptions
, options
+OPTIONS_COUNT
, addOptionsCount
*sizeof(UOption
));
130 // Now setup the arguments
131 if(_argc
==1 || options
[HELP1
].doesOccur
|| options
[HELP2
].doesOccur
) {
132 status
= U_ILLEGAL_ARGUMENT_ERROR
;
136 if(options
[VERBOSE
].doesOccur
) {
140 if(options
[SOURCEDIR
].doesOccur
) {
141 sourceDir
= options
[SOURCEDIR
].value
;
144 if(options
[ENCODING
].doesOccur
) {
145 encoding
= options
[ENCODING
].value
;
148 if(options
[USELEN
].doesOccur
) {
152 if(options
[FILE_NAME
].doesOccur
){
153 fileName
= options
[FILE_NAME
].value
;
156 if(options
[PASSES
].doesOccur
) {
157 passes
= atoi(options
[PASSES
].value
);
159 if(options
[ITERATIONS
].doesOccur
) {
160 iterations
= atoi(options
[ITERATIONS
].value
);
161 if(options
[TIME
].doesOccur
) {
162 status
= U_ILLEGAL_ARGUMENT_ERROR
;
165 } else if(options
[TIME
].doesOccur
) {
166 time
= atoi(options
[TIME
].value
);
168 iterations
= 1000; // some default
171 if(options
[LINE_MODE
].doesOccur
) {
176 if(options
[BULK_MODE
].doesOccur
) {
181 if(options
[LOCALE
].doesOccur
) {
182 locale
= options
[LOCALE
].value
;
188 ucbuf_resolveFileName(sourceDir
, fileName
, NULL
, &len
, &status
);
189 resolvedFileName
= (char*) uprv_malloc(len
);
190 if(resolvedFileName
==NULL
){
191 status
= U_MEMORY_ALLOCATION_ERROR
;
194 if(status
== U_BUFFER_OVERFLOW_ERROR
){
195 status
= U_ZERO_ERROR
;
197 ucbuf_resolveFileName(sourceDir
, fileName
, resolvedFileName
, &len
, &status
);
198 ucharBuf
= ucbuf_open(resolvedFileName
,&encoding
,TRUE
,FALSE
,&status
);
200 if(U_FAILURE(status
)){
201 printf("Could not open the input file %s. Error: %s\n", fileName
, u_errorName(status
));
207 ULine
* UPerfTest::getLines(UErrorCode
& status
){
208 lines
= new ULine
[MAXLINES
];
209 int maxLines
= MAXLINES
;
211 const UChar
* line
=NULL
;
214 line
= ucbuf_readline(ucharBuf
,&len
,&status
);
215 if(line
== NULL
|| U_FAILURE(status
)){
218 lines
[numLines
].name
= new UChar
[len
];
219 lines
[numLines
].len
= len
;
220 memcpy(lines
[numLines
].name
, line
, len
* U_SIZEOF_UCHAR
);
224 if (numLines
>= maxLines
) {
225 maxLines
+= MAXLINES
;
226 ULine
*newLines
= new ULine
[maxLines
];
227 if(newLines
== NULL
) {
228 fprintf(stderr
, "Out of memory reading line %d.\n", (int)numLines
);
229 status
= U_MEMORY_ALLOCATION_ERROR
;
234 memcpy(newLines
, lines
, numLines
*sizeof(ULine
));
241 const UChar
* UPerfTest::getBuffer(int32_t& len
, UErrorCode
& status
){
242 if (U_FAILURE(status
)) {
245 len
= ucbuf_size(ucharBuf
);
246 buffer
= (UChar
*) uprv_malloc(U_SIZEOF_UCHAR
* (len
+1));
247 u_strncpy(buffer
,ucbuf_getBuffer(ucharBuf
,&bufferLen
,&status
),len
);
252 UBool
UPerfTest::run(){
253 if(_remainingArgc
==1){
254 // Testing all methods
258 // Test only the specified fucntion
259 for (int i
= 1; i
< _remainingArgc
; ++i
) {
260 if (_argv
[i
][0] != '-') {
261 char* name
= (char*) _argv
[i
];
263 //fprintf(stdout, "\n=== Handling test: %s: ===\n", name);
264 //fprintf(stdout, "\n%s:\n", name);
266 char* parameter
= strchr( name
, '@' );
272 res
= runTest( name
, parameter
);
273 if (!res
|| (execCount
<= 0)) {
274 fprintf(stdout
, "\n---ERROR: Test doesn't exist: %s!\n", name
);
281 UBool
UPerfTest::runTest(char* name
, char* par
){
286 pos
= strchr( name
, delim
); // check if name contains path (by looking for '/')
288 path
= pos
+1; // store subpath for calling subtest
289 *pos
= 0; // split into two strings
294 if (!name
|| (name
[0] == 0) || (strcmp(name
, "*") == 0)) {
295 rval
= runTestLoop( NULL
, NULL
);
297 }else if (strcmp( name
, "LIST" ) == 0) {
302 rval
= runTestLoop( name
, par
);
306 *pos
= delim
; // restore original value at pos
311 void UPerfTest::setPath( char* pathVal
)
313 this->path
= pathVal
;
316 // call individual tests, to be overriden to call implementations
317 UPerfFunction
* UPerfTest::runIndexedTest( int32_t index
, UBool exec
, const char* &name
, char* par
)
319 // to be overriden by a method like:
322 case 0: name = "First Test"; if (exec) FirstTest( par ); break;
323 case 1: name = "Second Test"; if (exec) SecondTest( par ); break;
324 default: name = ""; break;
327 fprintf(stderr
,"*** runIndexedTest needs to be overriden! ***");
328 name
= ""; exec
= exec
; index
= index
; par
= par
;
333 UBool
UPerfTest::runTestLoop( char* testname
, char* par
)
339 UErrorCode status
= U_ZERO_ERROR
;
340 UPerfTest
* saveTest
= gTest
;
347 this->runIndexedTest( index
, FALSE
, name
);
348 if (!name
|| (name
[0] == 0))
351 run_this_test
= TRUE
;
353 run_this_test
= (UBool
) (strcmp( name
, testname
) == 0);
356 UPerfFunction
* testFunction
= this->runIndexedTest( index
, TRUE
, name
, par
);
359 if(testFunction
==NULL
){
360 fprintf(stderr
,"%s function returned NULL", name
);
363 ops
= testFunction
->getOperationsPerIteration();
365 fprintf(stderr
, "%s returned an illegal operations/iteration()\n", name
);
368 if(iterations
== 0) {
370 // Run for specified duration in seconds
372 fprintf(stdout
,"= %s calibrating %i seconds \n", name
, (int)n
);
375 //n *= 1000; // s => ms
376 //System.out.println("# " + meth.getName() + " " + n + " sec");
377 int32_t failsafe
= 1; // last resort for very fast methods
379 while (t
< (int)(n
* 0.9)) { // 90% is close enough
380 if (loops
== 0 || t
== 0) {
384 //System.out.println("# " + meth.getName() + " x " + loops + " = " + t);
385 loops
= (int)((double)n
/ t
* loops
+ 0.5);
387 fprintf(stderr
,"Unable to converge on desired duration");
391 //System.out.println("# " + meth.getName() + " x " + loops);
392 t
= testFunction
->time(loops
,&status
);
393 if(U_FAILURE(status
)){
394 printf("Performance test failed with error: %s \n", u_errorName(status
));
402 double min_t
=1000000.0, sum_t
=0.0;
405 for(int32_t ps
=0; ps
< passes
; ps
++){
406 fprintf(stdout
,"= %s begin " ,name
);
409 fprintf(stdout
, "%i\n", (int)loops
);
411 fprintf(stdout
, "%i\n", (int)n
);
414 fprintf(stdout
, "\n");
416 t
= testFunction
->time(loops
, &status
);
417 if(U_FAILURE(status
)){
418 printf("Performance test failed with error: %s \n", u_errorName(status
));
425 events
= testFunction
->getEventsPerIteration();
426 //print info only in verbose mode
429 fprintf(stdout
, "= %s end: %f loops: %i operations: %li \n", name
, t
, (int)loops
, ops
);
431 fprintf(stdout
, "= %s end: %f loops: %i operations: %li events: %li\n", name
, t
, (int)loops
, ops
, events
);
435 fprintf(stdout
,"= %s end %f %i %li\n", name
, t
, (int)loops
, ops
);
437 fprintf(stdout
,"= %s end %f %i %li %li\n", name
, t
, (int)loops
, ops
, events
);
441 if(verbose
&& U_SUCCESS(status
)) {
442 double avg_t
= sum_t
/passes
;
443 if (loops
== 0 || ops
== 0) {
444 fprintf(stderr
, "%s did not run\n", name
);
446 else if(events
== -1) {
447 fprintf(stdout
, "%%= %s avg: %.4g loops: %i avg/op: %.4g ns\n",
448 name
, avg_t
, (int)loops
, (avg_t
*1E9
)/(loops
*ops
));
449 fprintf(stdout
, "_= %s min: %.4g loops: %i min/op: %.4g ns\n",
450 name
, min_t
, (int)loops
, (min_t
*1E9
)/(loops
*ops
));
453 fprintf(stdout
, "%%= %s avg: %.4g loops: %i avg/op: %.4g ns avg/event: %.4g ns\n",
454 name
, avg_t
, (int)loops
, (avg_t
*1E9
)/(loops
*ops
), (avg_t
*1E9
)/(loops
*events
));
455 fprintf(stdout
, "_= %s min: %.4g loops: %i min/op: %.4g ns min/event: %.4g ns\n",
456 name
, min_t
, (int)loops
, (min_t
*1E9
)/(loops
*ops
), (min_t
*1E9
)/(loops
*events
));
469 * Print a usage message for this test class.
471 void UPerfTest::usage( void )
474 if (_addUsage
!= NULL
) {
478 UBool save_verbose
= verbose
;
480 fprintf(stdout
,"Test names:\n");
481 fprintf(stdout
,"-----------\n");
484 const char* name
= NULL
;
486 this->runIndexedTest( index
, FALSE
, name
);
489 fprintf(stdout
,name
);
490 fprintf(stdout
,"\n");
492 }while (name
&& (name
[0] != 0));
493 verbose
= save_verbose
;
499 void UPerfTest::setCaller( UPerfTest
* callingTest
)
501 caller
= callingTest
;
503 verbose
= caller
->verbose
;
507 UBool
UPerfTest::callTest( UPerfTest
& testToBeCalled
, char* par
)
509 execCount
--; // correct a previously assumed test-exec, as this only calls a subtest
510 testToBeCalled
.setCaller( this );
511 return testToBeCalled
.runTest( path
, par
);
514 UPerfTest::~UPerfTest(){
521 if(resolvedFileName
!=NULL
){
522 uprv_free(resolvedFileName
);
524 ucbuf_close(ucharBuf
);