]> git.saurik.com Git - apple/icu.git/blame - icuSources/tools/toolutil/uperf.cpp
ICU-6.2.10.tar.gz
[apple/icu.git] / icuSources / tools / toolutil / uperf.cpp
CommitLineData
b75a7d8f
A
1/********************************************************************
2 * COPYRIGHT:
374ca955 3 * Copyright (c) 2002-2004, International Business Machines Corporation and
b75a7d8f
A
4 * others. All Rights Reserved.
5 ********************************************************************/
6
7#include "uperf.h"
8
9static const char delim = '/';
10static int32_t execCount = 0;
11UPerfTest* UPerfTest::gTest = NULL;
374ca955
A
12static const int MAXLINES = 40000;
13const char UPerfTest::gUsageString[] =
14 "Usage: %s [OPTIONS] [FILES]\n"
15 "\tReads the input file and prints out time taken in seconds\n"
16 "Options:\n"
17 "\t-h or -? or --help this usage text\n"
18 "\t-v or --verbose print extra information when processing files\n"
19 "\t-s or --sourcedir source directory for files followed by path\n"
20 "\t followed by path\n"
21 "\t-e or --encoding encoding of source files\n"
22 "\t-u or --uselen perform timing analysis on non-null terminated buffer using length\n"
23 "\t-f or --file-name file to be used as input data\n"
24 "\t-p or --passes Number of passes to be performed. Requires Numeric argument. Cannot be used with --time\n"
25 "\t-i or --iterations Number of iterations to be performed. Requires Numeric argument\n"
26 "\t-t or --time Threshold time for looping until in seconds. Requires Numeric argument.Cannot be used with --iterations\n"
27 "\t-l or --line-mode The data file should be processed in line mode\n"
28 "\t-b or --bulk-mode The data file should be processed in file based. Cannot be used with --line-mode\n"
29 "\t-L or --locale Locale for the test\n";
30
b75a7d8f
A
31enum
32{
33 HELP1,
34 HELP2,
35 VERBOSE,
36 SOURCEDIR,
37 ENCODING,
38 USELEN,
39 FILE_NAME,
40 PASSES,
41 ITERATIONS,
42 TIME,
43 LINE_MODE,
44 BULK_MODE,
45 LOCALE
46};
47
48
49static UOption options[]={
374ca955
A
50 UOPTION_HELP_H,
51 UOPTION_HELP_QUESTION_MARK,
52 UOPTION_VERBOSE,
53 UOPTION_SOURCEDIR,
54 UOPTION_ENCODING,
55 UOPTION_DEF( "uselen", 'u', UOPT_NO_ARG),
56 UOPTION_DEF( "file-name", 'f', UOPT_REQUIRES_ARG),
57 UOPTION_DEF( "passes", 'p', UOPT_REQUIRES_ARG),
58 UOPTION_DEF( "iterations", 'i', UOPT_REQUIRES_ARG),
59 UOPTION_DEF( "time", 't', UOPT_REQUIRES_ARG),
60 UOPTION_DEF( "line-mode", 'l', UOPT_NO_ARG),
61 UOPTION_DEF( "bulk-mode", 'b', UOPT_NO_ARG),
62 UOPTION_DEF( "locale", 'L', UOPT_REQUIRES_ARG)
63};
b75a7d8f
A
64
65UPerfTest::UPerfTest(int32_t argc, const char* argv[], UErrorCode& status){
66
67 _argc = argc;
68 _argv = argv;
69 ucharBuf = NULL;
70 encoding = "";
71 uselen = FALSE;
72 fileName = NULL;
73 sourceDir = ".";
74 lines = NULL;
75 numLines = 0;
76 line_mode = TRUE;
77 buffer = NULL;
78 bufferLen = 0;
79 verbose = FALSE;
80 bulk_mode = FALSE;
81 passes = iterations = time = 0;
82 locale = NULL;
83
84 //initialize the argument list
85 U_MAIN_INIT_ARGS(argc, argv);
86 //parse the arguments
87 _remainingArgc = u_parseArgs(argc, (char**)argv, (int32_t)(sizeof(options)/sizeof(options[0])), options);
88
89 // Now setup the arguments
90 if(argc==1 || options[HELP1].doesOccur || options[HELP2].doesOccur) {
91 status = U_ILLEGAL_ARGUMENT_ERROR;
92 return;
93 }
94
95 if(options[VERBOSE].doesOccur) {
96 verbose = TRUE;
97 }
98
99 if(options[SOURCEDIR].doesOccur) {
100 sourceDir = options[SOURCEDIR].value;
101 }
102
103 if(options[ENCODING].doesOccur) {
104 encoding = options[ENCODING].value;
105 }
106
107 if(options[USELEN].doesOccur) {
108 uselen = TRUE;
109 }
110
111 if(options[FILE_NAME].doesOccur){
112 fileName = options[FILE_NAME].value;
113 }
114
115 if(options[PASSES].doesOccur) {
116 passes = atoi(options[PASSES].value);
117 }
118 if(options[ITERATIONS].doesOccur) {
119 iterations = atoi(options[ITERATIONS].value);
120 }
121
122 if(options[TIME].doesOccur) {
123 time = atoi(options[TIME].value);
124 }
125
126 if(options[LINE_MODE].doesOccur) {
127 line_mode = TRUE;
128 bulk_mode = FALSE;
129 }
130
131 if(options[BULK_MODE].doesOccur) {
132 bulk_mode = TRUE;
133 line_mode = FALSE;
134 }
135
136 if(options[LOCALE].doesOccur) {
137 locale = options[LOCALE].value;
138 }
139
140 if(time > 0 && iterations >0){
141 status = U_ILLEGAL_ARGUMENT_ERROR;
142 return;
143 }
144
145 int32_t len = 0;
146 resolvedFileName = NULL;
147 if(fileName!=NULL){
148 //pre-flight
149 ucbuf_resolveFileName(sourceDir, fileName,resolvedFileName,&len, &status);
150 resolvedFileName = (char*) uprv_malloc(len);
151 if(fileName==NULL){
152 status= U_MEMORY_ALLOCATION_ERROR;
153 return;
154 }
155 if(status == U_BUFFER_OVERFLOW_ERROR){
156 status = U_ZERO_ERROR;
157 }
158 ucbuf_resolveFileName(sourceDir, fileName, resolvedFileName, &len, &status);
159 ucharBuf = ucbuf_open(resolvedFileName,&encoding,TRUE,FALSE,&status);
160
161 if(U_FAILURE(status)){
162 printf("Could not open the input file %s. Error: %s\n", fileName, u_errorName(status));
163 return;
164 }
165 }
166}
167
168ULine* UPerfTest::getLines(UErrorCode& status){
169 lines = new ULine[MAXLINES];
170 int maxLines = MAXLINES;
171 numLines=0;
172 const UChar* line=NULL;
173 int32_t len =0;
174 for (;;) {
374ca955
A
175 line = ucbuf_readline(ucharBuf,&len,&status);
176 if(line == NULL || U_FAILURE(status)){
177 break;
178 }
179 lines[numLines].name = new UChar[len];
180 lines[numLines].len = len;
181 memcpy(lines[numLines].name, line, len * U_SIZEOF_UCHAR);
182
183 numLines++;
184 len = 0;
185 if (numLines >= maxLines) {
186 maxLines += MAXLINES;
187 ULine *newLines = new ULine[maxLines];
188 if(newLines == NULL) {
189 fprintf(stderr, "Out of memory reading line %d.\n", (int)numLines);
190 status= U_MEMORY_ALLOCATION_ERROR;
b75a7d8f 191 delete lines;
374ca955 192 return NULL;
b75a7d8f 193 }
374ca955
A
194
195 memcpy(newLines, lines, numLines*sizeof(ULine));
196 delete lines;
197 lines = newLines;
198 }
b75a7d8f
A
199 }
200 return lines;
201}
202const UChar* UPerfTest::getBuffer(int32_t& len, UErrorCode& status){
203 len = ucbuf_size(ucharBuf);
204 buffer = (UChar*) uprv_malloc(U_SIZEOF_UCHAR * (len+1));
205 u_strncpy(buffer,ucbuf_getBuffer(ucharBuf,&bufferLen,&status),len);
206 buffer[len]=0;
207 len = bufferLen;
208 return buffer;
209}
210UBool UPerfTest::run(){
211 if(_remainingArgc==1){
212 // Testing all methods
213 return runTest();
214 }
215 UBool res=FALSE;
216 // Test only the specified fucntion
217 for (int i = 1; i < _remainingArgc; ++i) {
218 if (_argv[i][0] != '-') {
219 char* name = (char*) _argv[i];
220 if(verbose==TRUE){
221 //fprintf(stdout, "\n=== Handling test: %s: ===\n", name);
222 //fprintf(stdout, "\n%s:\n", name);
223 }
224 char* parameter = strchr( name, '@' );
225 if (parameter) {
226 *parameter = 0;
227 parameter += 1;
228 }
229 execCount = 0;
230 res = runTest( name, parameter );
231 if (!res || (execCount <= 0)) {
232 fprintf(stdout, "\n---ERROR: Test doesn't exist: %s!\n", name);
233 return FALSE;
234 }
235 }
236 }
237 return res;
238}
239UBool UPerfTest::runTest(char* name, char* par ){
240 UBool rval;
241 char* pos = NULL;
242
243 if (name)
244 pos = strchr( name, delim ); // check if name contains path (by looking for '/')
245 if (pos) {
246 path = pos+1; // store subpath for calling subtest
247 *pos = 0; // split into two strings
248 }else{
249 path = NULL;
250 }
251
252 if (!name || (name[0] == 0) || (strcmp(name, "*") == 0)) {
253 rval = runTestLoop( NULL, NULL );
254
255 }else if (strcmp( name, "LIST" ) == 0) {
256 this->usage();
257 rval = TRUE;
258
259 }else{
260 rval = runTestLoop( name, par );
261 }
262
263 if (pos)
264 *pos = delim; // restore original value at pos
265 return rval;
266}
267
268
269void UPerfTest::setPath( char* pathVal )
270{
271 this->path = pathVal;
272}
273
274// call individual tests, to be overriden to call implementations
275UPerfFunction* UPerfTest::runIndexedTest( int32_t index, UBool exec, const char* &name, char* par )
276{
277 // to be overriden by a method like:
278 /*
279 switch (index) {
280 case 0: name = "First Test"; if (exec) FirstTest( par ); break;
281 case 1: name = "Second Test"; if (exec) SecondTest( par ); break;
282 default: name = ""; break;
283 }
284 */
285 fprintf(stderr,"*** runIndexedTest needs to be overriden! ***");
286 name = ""; exec = exec; index = index; par = par;
287 return NULL;
288}
289
290
291UBool UPerfTest::runTestLoop( char* testname, char* par )
292{
293 int32_t index = 0;
294 const char* name;
295 UBool run_this_test;
296 UBool rval = FALSE;
297 UErrorCode status = U_ZERO_ERROR;
298 UPerfTest* saveTest = gTest;
299 gTest = this;
300 int32_t loops = 0;
301 double t=0;
302 int32_t n = 1;
303 do {
304 this->runIndexedTest( index, FALSE, name );
305 if (!name || (name[0] == 0))
306 break;
307 if (!testname) {
308 run_this_test = TRUE;
309 }else{
310 run_this_test = (UBool) (strcmp( name, testname ) == 0);
311 }
312 if (run_this_test) {
313 UPerfFunction* testFunction = this->runIndexedTest( index, TRUE, name, par );
314 execCount++;
315 rval=TRUE;
316 if(testFunction==NULL){
317 fprintf(stderr,"%s function returned NULL", name);
318 return FALSE;
319 }
320 if (testFunction->getOperationsPerIteration() < 1) {
321 fprintf(stderr, "%s returned an illegal operations/iteration()\n", name);
322 return FALSE;
323 }
324 if(iterations == 0) {
374ca955
A
325 n = time;
326 // Run for specified duration in seconds
327 if(verbose==TRUE){
328 fprintf(stdout,"= %s calibrating %i seconds \n", name, (int)n);
329 }
330
331 //n *= 1000; // s => ms
332 //System.out.println("# " + meth.getName() + " " + n + " sec");
333 int32_t failsafe = 1; // last resort for very fast methods
334 t = 0;
335 while (t < (int)(n * 0.9)) { // 90% is close enough
336 if (loops == 0 || t == 0) {
337 loops = failsafe;
338 failsafe *= 10;
339 } else {
340 //System.out.println("# " + meth.getName() + " x " + loops + " = " + t);
341 loops = (int)((double)n / t * loops + 0.5);
342 if (loops == 0) {
343 fprintf(stderr,"Unable to converge on desired duration");
344 return FALSE;
345 }
346 }
347 //System.out.println("# " + meth.getName() + " x " + loops);
348 t = testFunction->time(loops,&status);
349 if(U_FAILURE(status)){
350 printf("Performance test failed with error: %s \n", u_errorName(status));
351 break;
352 }
353 }
b75a7d8f 354 } else {
374ca955 355 loops = iterations;
b75a7d8f
A
356 }
357
358 for(int32_t ps =0; ps < passes; ps++){
374ca955
A
359 long events = -1;
360 fprintf(stdout,"= %s begin " ,name);
361 if(verbose==TRUE){
362 if(iterations > 0) {
363 fprintf(stdout, "%i\n", (int)loops);
364 } else {
365 fprintf(stdout, "%i\n", (int)n);
366 }
367 } else {
368 fprintf(stdout, "\n");
369 }
370 t = testFunction->time(loops, &status);
371 if(U_FAILURE(status)){
372 printf("Performance test failed with error: %s \n", u_errorName(status));
373 break;
374 }
375 events = testFunction->getEventsPerIteration();
376 //print info only in verbose mode
377 if(verbose==TRUE){
b75a7d8f 378/*
374ca955
A
379 if(events == -1){
380 fprintf(stdout,"= %s end %f %i %i\n",name , t , loops, testFunction->getOperationsPerIteration());
381 }else{
382 fprintf(stdout,"= %s end %f %i %i %i\n",name , t , loops, testFunction->getOperationsPerIteration(), events);
383 }
b75a7d8f 384*/
374ca955
A
385 if(events == -1){
386 fprintf(stdout, "= %s end: %f loops: %i operations: %li \n", name, t, (int)loops, testFunction->getOperationsPerIteration());
387 }else{
388 fprintf(stdout, "= %s end: %f loops: %i operations: %li events: %li\n", name, t, (int)loops, testFunction->getOperationsPerIteration(), events);
389 }
390 }else{
b75a7d8f 391/*
374ca955
A
392 if(events == -1){
393 fprintf(stdout,"= %f %i %i \n", t , loops, testFunction->getOperationsPerIteration());
394 }else{
395 fprintf(stdout,"= %f %i %i %i\n", t , loops, testFunction->getOperationsPerIteration(), events);
396 }
b75a7d8f 397*/
374ca955
A
398 if(events == -1){
399 fprintf(stdout,"= %s end %f %i %li\n", name, t, (int)loops, testFunction->getOperationsPerIteration());
400 }else{
401 fprintf(stdout,"= %s end %f %i %li %li\n", name, t, (int)loops, testFunction->getOperationsPerIteration(), events);
402 }
403 }
b75a7d8f
A
404 }
405 delete testFunction;
406 }
407 index++;
408 }while(name);
409
410 gTest = saveTest;
411 return rval;
412}
413
414/**
415* Print a usage message for this test class.
416*/
417void UPerfTest::usage( void )
418{
419 UBool save_verbose = verbose;
420 verbose = TRUE;
421 fprintf(stdout,"Test names:\n");
422 fprintf(stdout,"-----------\n");
423
424 int32_t index = 0;
425 const char* name = NULL;
426 do{
427 this->runIndexedTest( index, FALSE, name );
374ca955
A
428 if (!name)
429 break;
b75a7d8f
A
430 fprintf(stdout,name);
431 fprintf(stdout,"\n");
432 index++;
433 }while (name && (name[0] != 0));
434 verbose = save_verbose;
435}
436
437
438
439
440void UPerfTest::setCaller( UPerfTest* callingTest )
441{
442 caller = callingTest;
443 if (caller) {
444 verbose = caller->verbose;
445 }
446}
447
448UBool UPerfTest::callTest( UPerfTest& testToBeCalled, char* par )
449{
450 execCount--; // correct a previously assumed test-exec, as this only calls a subtest
451 testToBeCalled.setCaller( this );
452 return testToBeCalled.runTest( path, par );
453}
454
455UPerfTest::~UPerfTest(){
456 if(lines!=NULL){
457 delete[] lines;
458 }
459 if(buffer!=NULL){
460 uprv_free(buffer);
461 }
462 ucbuf_close(ucharBuf);
463}
464
465