]>
Commit | Line | Data |
---|---|---|
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 | ||
9 | static const char delim = '/'; | |
10 | static int32_t execCount = 0; | |
11 | UPerfTest* UPerfTest::gTest = NULL; | |
374ca955 A |
12 | static const int MAXLINES = 40000; |
13 | const 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 |
31 | enum |
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 | ||
49 | static 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 | |
65 | UPerfTest::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 | ||
168 | ULine* 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 | } | |
202 | const 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 | } | |
210 | UBool 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 | } | |
239 | UBool 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 | ||
269 | void UPerfTest::setPath( char* pathVal ) | |
270 | { | |
271 | this->path = pathVal; | |
272 | } | |
273 | ||
274 | // call individual tests, to be overriden to call implementations | |
275 | UPerfFunction* 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 | ||
291 | UBool 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 | */ | |
417 | void 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 | ||
440 | void UPerfTest::setCaller( UPerfTest* callingTest ) | |
441 | { | |
442 | caller = callingTest; | |
443 | if (caller) { | |
444 | verbose = caller->verbose; | |
445 | } | |
446 | } | |
447 | ||
448 | UBool 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 | ||
455 | UPerfTest::~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 |