1 /********************************************************************
3 * Copyright (c) 2002-2006, International Business Machines Corporation and
4 * others. All Rights Reserved.
5 ********************************************************************/
7 #include "unicode/uperf.h"
13 #if !UCONFIG_NO_CONVERSION
14 static const char delim
= '/';
15 static int32_t execCount
= 0;
16 UPerfTest
* UPerfTest::gTest
= NULL
;
17 static const int MAXLINES
= 40000;
18 const char UPerfTest::gUsageString
[] =
19 "Usage: %s [OPTIONS] [FILES]\n"
20 "\tReads the input file and prints out time taken in seconds\n"
22 "\t-h or -? or --help this usage text\n"
23 "\t-v or --verbose print extra information when processing files\n"
24 "\t-s or --sourcedir source directory for files followed by path\n"
25 "\t followed by path\n"
26 "\t-e or --encoding encoding of source files\n"
27 "\t-u or --uselen perform timing analysis on non-null terminated buffer using length\n"
28 "\t-f or --file-name file to be used as input data\n"
29 "\t-p or --passes Number of passes to be performed. Requires Numeric argument. Cannot be used with --time\n"
30 "\t-i or --iterations Number of iterations to be performed. Requires Numeric argument\n"
31 "\t-t or --time Threshold time for looping until in seconds. Requires Numeric argument.Cannot be used with --iterations\n"
32 "\t-l or --line-mode The data file should be processed in line mode\n"
33 "\t-b or --bulk-mode The data file should be processed in file based. Cannot be used with --line-mode\n"
34 "\t-L or --locale Locale for the test\n";
54 static UOption options
[]={
56 UOPTION_HELP_QUESTION_MARK
,
60 UOPTION_DEF( "uselen", 'u', UOPT_NO_ARG
),
61 UOPTION_DEF( "file-name", 'f', UOPT_REQUIRES_ARG
),
62 UOPTION_DEF( "passes", 'p', UOPT_REQUIRES_ARG
),
63 UOPTION_DEF( "iterations", 'i', UOPT_REQUIRES_ARG
),
64 UOPTION_DEF( "time", 't', UOPT_REQUIRES_ARG
),
65 UOPTION_DEF( "line-mode", 'l', UOPT_NO_ARG
),
66 UOPTION_DEF( "bulk-mode", 'b', UOPT_NO_ARG
),
67 UOPTION_DEF( "locale", 'L', UOPT_REQUIRES_ARG
)
70 UPerfTest::UPerfTest(int32_t argc
, const char* argv
[], UErrorCode
& status
){
86 passes
= iterations
= time
= 0;
89 //initialize the argument list
90 U_MAIN_INIT_ARGS(argc
, argv
);
92 _remainingArgc
= u_parseArgs(argc
, (char**)argv
, (int32_t)(sizeof(options
)/sizeof(options
[0])), options
);
94 // Now setup the arguments
95 if(argc
==1 || options
[HELP1
].doesOccur
|| options
[HELP2
].doesOccur
) {
96 status
= U_ILLEGAL_ARGUMENT_ERROR
;
100 if(options
[VERBOSE
].doesOccur
) {
104 if(options
[SOURCEDIR
].doesOccur
) {
105 sourceDir
= options
[SOURCEDIR
].value
;
108 if(options
[ENCODING
].doesOccur
) {
109 encoding
= options
[ENCODING
].value
;
112 if(options
[USELEN
].doesOccur
) {
116 if(options
[FILE_NAME
].doesOccur
){
117 fileName
= options
[FILE_NAME
].value
;
120 if(options
[PASSES
].doesOccur
) {
121 passes
= atoi(options
[PASSES
].value
);
123 if(options
[ITERATIONS
].doesOccur
) {
124 iterations
= atoi(options
[ITERATIONS
].value
);
127 if(options
[TIME
].doesOccur
) {
128 time
= atoi(options
[TIME
].value
);
131 if(options
[LINE_MODE
].doesOccur
) {
136 if(options
[BULK_MODE
].doesOccur
) {
141 if(options
[LOCALE
].doesOccur
) {
142 locale
= options
[LOCALE
].value
;
145 if(time
> 0 && iterations
>0){
146 status
= U_ILLEGAL_ARGUMENT_ERROR
;
151 resolvedFileName
= NULL
;
154 ucbuf_resolveFileName(sourceDir
, fileName
, NULL
, &len
, &status
);
155 resolvedFileName
= (char*) uprv_malloc(len
);
156 if(resolvedFileName
==NULL
){
157 status
= U_MEMORY_ALLOCATION_ERROR
;
160 if(status
== U_BUFFER_OVERFLOW_ERROR
){
161 status
= U_ZERO_ERROR
;
163 ucbuf_resolveFileName(sourceDir
, fileName
, resolvedFileName
, &len
, &status
);
164 ucharBuf
= ucbuf_open(resolvedFileName
,&encoding
,TRUE
,FALSE
,&status
);
166 if(U_FAILURE(status
)){
167 printf("Could not open the input file %s. Error: %s\n", fileName
, u_errorName(status
));
173 ULine
* UPerfTest::getLines(UErrorCode
& status
){
174 lines
= new ULine
[MAXLINES
];
175 int maxLines
= MAXLINES
;
177 const UChar
* line
=NULL
;
180 line
= ucbuf_readline(ucharBuf
,&len
,&status
);
181 if(line
== NULL
|| U_FAILURE(status
)){
184 lines
[numLines
].name
= new UChar
[len
];
185 lines
[numLines
].len
= len
;
186 memcpy(lines
[numLines
].name
, line
, len
* U_SIZEOF_UCHAR
);
190 if (numLines
>= maxLines
) {
191 maxLines
+= MAXLINES
;
192 ULine
*newLines
= new ULine
[maxLines
];
193 if(newLines
== NULL
) {
194 fprintf(stderr
, "Out of memory reading line %d.\n", (int)numLines
);
195 status
= U_MEMORY_ALLOCATION_ERROR
;
200 memcpy(newLines
, lines
, numLines
*sizeof(ULine
));
207 const UChar
* UPerfTest::getBuffer(int32_t& len
, UErrorCode
& status
){
208 len
= ucbuf_size(ucharBuf
);
209 buffer
= (UChar
*) uprv_malloc(U_SIZEOF_UCHAR
* (len
+1));
210 u_strncpy(buffer
,ucbuf_getBuffer(ucharBuf
,&bufferLen
,&status
),len
);
215 UBool
UPerfTest::run(){
216 if(_remainingArgc
==1){
217 // Testing all methods
221 // Test only the specified fucntion
222 for (int i
= 1; i
< _remainingArgc
; ++i
) {
223 if (_argv
[i
][0] != '-') {
224 char* name
= (char*) _argv
[i
];
226 //fprintf(stdout, "\n=== Handling test: %s: ===\n", name);
227 //fprintf(stdout, "\n%s:\n", name);
229 char* parameter
= strchr( name
, '@' );
235 res
= runTest( name
, parameter
);
236 if (!res
|| (execCount
<= 0)) {
237 fprintf(stdout
, "\n---ERROR: Test doesn't exist: %s!\n", name
);
244 UBool
UPerfTest::runTest(char* name
, char* par
){
249 pos
= strchr( name
, delim
); // check if name contains path (by looking for '/')
251 path
= pos
+1; // store subpath for calling subtest
252 *pos
= 0; // split into two strings
257 if (!name
|| (name
[0] == 0) || (strcmp(name
, "*") == 0)) {
258 rval
= runTestLoop( NULL
, NULL
);
260 }else if (strcmp( name
, "LIST" ) == 0) {
265 rval
= runTestLoop( name
, par
);
269 *pos
= delim
; // restore original value at pos
274 void UPerfTest::setPath( char* pathVal
)
276 this->path
= pathVal
;
279 // call individual tests, to be overriden to call implementations
280 UPerfFunction
* UPerfTest::runIndexedTest( int32_t index
, UBool exec
, const char* &name
, char* par
)
282 // to be overriden by a method like:
285 case 0: name = "First Test"; if (exec) FirstTest( par ); break;
286 case 1: name = "Second Test"; if (exec) SecondTest( par ); break;
287 default: name = ""; break;
290 fprintf(stderr
,"*** runIndexedTest needs to be overriden! ***");
291 name
= ""; exec
= exec
; index
= index
; par
= par
;
296 UBool
UPerfTest::runTestLoop( char* testname
, char* par
)
302 UErrorCode status
= U_ZERO_ERROR
;
303 UPerfTest
* saveTest
= gTest
;
309 this->runIndexedTest( index
, FALSE
, name
);
310 if (!name
|| (name
[0] == 0))
313 run_this_test
= TRUE
;
315 run_this_test
= (UBool
) (strcmp( name
, testname
) == 0);
318 UPerfFunction
* testFunction
= this->runIndexedTest( index
, TRUE
, name
, par
);
321 if(testFunction
==NULL
){
322 fprintf(stderr
,"%s function returned NULL", name
);
325 if (testFunction
->getOperationsPerIteration() < 1) {
326 fprintf(stderr
, "%s returned an illegal operations/iteration()\n", name
);
329 if(iterations
== 0) {
331 // Run for specified duration in seconds
333 fprintf(stdout
,"= %s calibrating %i seconds \n", name
, (int)n
);
336 //n *= 1000; // s => ms
337 //System.out.println("# " + meth.getName() + " " + n + " sec");
338 int32_t failsafe
= 1; // last resort for very fast methods
340 while (t
< (int)(n
* 0.9)) { // 90% is close enough
341 if (loops
== 0 || t
== 0) {
345 //System.out.println("# " + meth.getName() + " x " + loops + " = " + t);
346 loops
= (int)((double)n
/ t
* loops
+ 0.5);
348 fprintf(stderr
,"Unable to converge on desired duration");
352 //System.out.println("# " + meth.getName() + " x " + loops);
353 t
= testFunction
->time(loops
,&status
);
354 if(U_FAILURE(status
)){
355 printf("Performance test failed with error: %s \n", u_errorName(status
));
363 for(int32_t ps
=0; ps
< passes
; ps
++){
365 fprintf(stdout
,"= %s begin " ,name
);
368 fprintf(stdout
, "%i\n", (int)loops
);
370 fprintf(stdout
, "%i\n", (int)n
);
373 fprintf(stdout
, "\n");
375 t
= testFunction
->time(loops
, &status
);
376 if(U_FAILURE(status
)){
377 printf("Performance test failed with error: %s \n", u_errorName(status
));
380 events
= testFunction
->getEventsPerIteration();
381 //print info only in verbose mode
385 fprintf(stdout,"= %s end %f %i %i\n",name , t , loops, testFunction->getOperationsPerIteration());
387 fprintf(stdout,"= %s end %f %i %i %i\n",name , t , loops, testFunction->getOperationsPerIteration(), events);
391 fprintf(stdout
, "= %s end: %f loops: %i operations: %li \n", name
, t
, (int)loops
, testFunction
->getOperationsPerIteration());
393 fprintf(stdout
, "= %s end: %f loops: %i operations: %li events: %li\n", name
, t
, (int)loops
, testFunction
->getOperationsPerIteration(), events
);
398 fprintf(stdout,"= %f %i %i \n", t , loops, testFunction->getOperationsPerIteration());
400 fprintf(stdout,"= %f %i %i %i\n", t , loops, testFunction->getOperationsPerIteration(), events);
404 fprintf(stdout
,"= %s end %f %i %li\n", name
, t
, (int)loops
, testFunction
->getOperationsPerIteration());
406 fprintf(stdout
,"= %s end %f %i %li %li\n", name
, t
, (int)loops
, testFunction
->getOperationsPerIteration(), events
);
420 * Print a usage message for this test class.
422 void UPerfTest::usage( void )
424 UBool save_verbose
= verbose
;
426 fprintf(stdout
,"Test names:\n");
427 fprintf(stdout
,"-----------\n");
430 const char* name
= NULL
;
432 this->runIndexedTest( index
, FALSE
, name
);
435 fprintf(stdout
,name
);
436 fprintf(stdout
,"\n");
438 }while (name
&& (name
[0] != 0));
439 verbose
= save_verbose
;
445 void UPerfTest::setCaller( UPerfTest
* callingTest
)
447 caller
= callingTest
;
449 verbose
= caller
->verbose
;
453 UBool
UPerfTest::callTest( UPerfTest
& testToBeCalled
, char* par
)
455 execCount
--; // correct a previously assumed test-exec, as this only calls a subtest
456 testToBeCalled
.setCaller( this );
457 return testToBeCalled
.runTest( path
, par
);
460 UPerfTest::~UPerfTest(){
467 if(resolvedFileName
!=NULL
){
468 uprv_free(resolvedFileName
);
470 ucbuf_close(ucharBuf
);