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