2 # *******************************************************************************
3 # * Copyright (C) 2002-2012 International Business Machines Corporation and *
4 # * others. All Rights Reserved. *
5 # *******************************************************************************
9 # Assume we are running within the icu4j root directory
10 use lib 'src/com/ibm/icu/dev/test/perf';
15 if ($OS eq "linux" || $OS eq "darwin") {
16 $CLASSPATH="../icu4j.jar:../tools/misc/out/lib/icu4j-tools.jar:out/bin";
18 $CLASSPATH="../icu4j.jar;../tools/misc/out/lib/icu4j-tools.jar;out/bin";
20 #---------------------------------------------------------------------
22 # Methods to be tested. Each pair represents a test method and
23 # a baseline method which is used for comparison.
25 ['TestJDKConstruction', 'TestICUConstruction'],
26 ['TestJDKParse', 'TestICUParse'],
27 ['TestJDKFormat', 'TestICUFormat']
29 # Patterns which define the set of characters used for testing.
31 # locale pattern date string
32 [ "en_US", "dddd MMM yyyy", "15 Jan 2007"],
33 [ "sw_KE", "dddd MMM yyyy", "15 Jan 2007"],
34 [ "en_US", "HH:mm", "13:13"],
35 [ "en_US", "HH:mm zzzz", "13:13 Pacific Standard Time"],
36 [ "en_US", "HH:mm z", "13:13 PST"],
37 [ "en_US", "HH:mm Z", "13:13 -0800"],
40 my $THREADS; # number of threads (input from command-line args)
41 my $CALIBRATE = 2; # duration in seconds for initial calibration
42 my $DURATION = 10; # duration in seconds for each pass
43 my $NUMPASSES = 4; # number of passes. If > 1 then the first pass
44 # is discarded as a JIT warm-up pass.
46 my $TABLEATTR = 'BORDER="1" CELLPADDING="4" CELLSPACING="0"';
48 my $PLUS_MINUS = "±";
51 die "Need at least 3 passes. One is discarded (JIT warmup) and need two to have 1 degree of freedom (t distribution).";
55 # run all tests with the specified number of threads from command-line input
56 # (if there is no arguments, use $THREADS = 1)
57 foreach my $arg ($#ARGV >= 0 ? @ARGV : "1") {
63 #---------------------------------------------------------------------
66 #-----------DATE FORMAT PERFORMANCE TESTS-----------------------------
67 my $testclass = 'com.ibm.icu.dev.test.perf.DateFormatPerformanceTest';
68 #my $threads = ($THREADS > 1) ? "($THREADS threads)" : "";
70 my $doc = XML::LibXML::Document->new('1.0', 'utf-8');
71 my $root = $doc->createElement("perfTestResults");
74 my @shortNames = ( "open" , "parse", "fmt");
77 for my $methodPair (@METHODS) {
79 my $testMethod = $methodPair->[0];
80 my $baselineMethod = $methodPair->[1];
81 my $testname = $shortNames[$index];
87 for my $pat (@OPTIONS) {
89 # measure the test method
90 my $t = measure2($testclass, $testMethod, $pat, -$DURATION);
91 my $testResult = $t->getMean();
92 my $jdkElement = $doc->createElement("perfTestResult");
93 my $testName = "DateFmt-$testname-pat$patternCounter-JDK";
94 $jdkElement->setAttribute("test" => $testName);
95 $jdkElement->setAttribute("iterations" => 1);
96 $jdkElement->setAttribute("time" => $testResult);
97 $root->appendChild($jdkElement);
99 # measure baseline method
100 my $b = measure2($testclass, $baselineMethod, $pat, -$DURATION);
101 my $baseResult = $b->getMean();
102 my $icuElement = $doc->createElement("perfTestResult");
103 my $testName = "DateFmt-$testname-pat$patternCounter";
105 $icuElement->setAttribute("test"=> $testName);
106 $icuElement->setAttribute("iterations" => 1);
107 $icuElement->setAttribute("time" => $baseResult);
108 $root->appendChild($icuElement);
113 #------------------DECIMAL FORMAT TESTS---------------------------------
115 my $testclass = 'com.ibm.icu.dev.test.perf.DecimalFormatPerformanceTest';
117 # locale pattern date string
118 [ "en_US", "#,###.##", "1,234.56"],
119 [ "de_DE", "#,###.##", "1.234,56"],
122 for my $methodPair (@METHODS) {
124 my $testMethod = $methodPair->[0];
125 my $baselineMethod = $methodPair->[1];
126 my $testname = $shortNames[$index];
130 for my $pat (@OPTIONS) {
131 my $patternName = $pat->[0];
133 # measure the test method
134 my $t = measure2($testclass, $testMethod, $pat, -$DURATION);
135 my $testResult = $t->getMean();
136 my $jdkElement = $doc->createElement("perfTestResult");
137 my $testName = "NumFmt-$testname-$patternName-JDK";
138 $jdkElement->setAttribute("test" => $testName);
139 $jdkElement->setAttribute("iterations"=>1);
140 $jdkElement->setAttribute("time" => $testResult);
141 $root->appendChild($jdkElement);
143 # measure baseline method
144 my $b = measure2($testclass, $baselineMethod, $pat, -$DURATION);
145 my $baseResult = $b->getMean();
146 my $icuElement = $doc->createElement("perfTestResult");
147 my $testName = "NumFmt-$testname-$patternName";
148 $icuElement->setAttribute("test"=> $testName);
149 $icuElement->setAttribute("iterations"=>1);
150 $icuElement->setAttribute("time" => $baseResult);
151 $root->appendChild($icuElement);
155 #----------------COLLATION PERFORMANCE TESTS--------------------------_
158 "en_US", "TestNames_Latin.txt",
159 "da_DK", "TestNames_Latin.txt",
160 "de_DE", "TestNames_Latin.txt",
161 "de__PHONEBOOK", "TestNames_Latin.txt",
162 "fr_FR", "TestNames_Latin.txt",
163 "ja_JP", "TestNames_Latin.txt TestNames_Japanese_h.txt TestNames_Japanese_k.txt TestNames_Asian.txt",
164 "zh_CN", "TestNames_Latin.txt TestNames_Chinese.txt",
165 "zh_TW", "TestNames_Latin.txt TestNames_Chinese.txt",
166 "zh__PINYIN", "TestNames_Latin.txt TestNames_Chinese.txt",
167 "ru_RU", "TestNames_Latin.txt TestNames_Russian.txt",
168 "th", "TestNames_Latin.txt TestNames_Thai.txt",
169 "ko_KR", "TestNames_Latin.txt TestNames_Korean.txt",
172 # Outer loop runs through the locales to test
173 # (Edit this list dirctly to make changes)
193 # Inner loop runs over the set of data files specified for each locale.
194 # (Edit the %datafiles initialization, above, to make changes.
196 $ff = $dataFiles{$locale};
197 @ff = split(/[\s]+/, $ff);
199 foreach $data (@ff) {
201 # Run ICU Test for this (locale, data file) pair.
203 $iStrCol = `java -classpath $CLASSPATH com.ibm.icu.dev.test.perf.CollationPerformanceTest -terse -file data/collation/$data -locale $locale -loop 1000 -binsearch`;
204 print "java -classpath $CLASSPATH com.ibm.icu.dev.test.perf.CollationPerformanceTest -terse -file data/collation/$data -locale $locale -loop 1000 -binsearch\n";
205 $iStrCol =~s/[,\s]*//g; # whack off the leading " ," in the returned result.
206 doKeyTimes("java -classpath $CLASSPATH com.ibm.icu.dev.test.perf.CollationPerformanceTest -terse -file data/collation/$data -locale $locale -loop 1000 -keygen",
207 my $iKeyGen, my $iKeyLen);
210 # Run Windows test for this (locale, data file) pair. Only do if
211 # we are not on Windows 98/ME and we hava a windows langID
214 $wStrCol = $wKeyGen = $wKeyLen = 0;
215 my $wStrCol = `java -classpath $CLASSPATH com.ibm.icu.dev.test.perf.CollationPerformanceTest -terse -file data/collation/$data -locale $locale -loop 1000 -binsearch -java`;
216 $wStrCol =~s/[,\s]*//g; # whack off the leading " ," in the returned result.
217 doKeyTimes("java -classpath $CLASSPATH com.ibm.icu.dev.test.perf.CollationPerformanceTest -terse -file data/collation/$data -locale $locale -loop 1000 -keygen -java",
220 $collDiff = $keyGenDiff = $keyLenDiff = 0;
222 $collDiff = (($wStrCol - $iStrCol) / $iStrCol) * 100;
223 $keyGenDiff = (($wKeyGen - $iKeyGen) / $iKeyGen) * 100;
224 $keyLenDiff = (($wKeyLen - $iKeyLen) / $iKeyLen) * 100;
227 my $ICU = $doc->createElement("perfTestResult");
228 my $testname = "Coll-$locale-data$counter-StrCol";
229 #write the results corresponding to this local,data pair
230 $ICU->setAttribute("test"=> $testname);
231 $ICU->setAttribute("iterations"=>1000);
232 $ICU->setAttribute("time"=> $iStrCol);
233 $root->appendChild($ICU);
235 my $Key = $doc->createElement("perfTestResult");
236 my $testname = "Coll-$locale-data$counter-keyGen";
237 $Key->setAttribute("test"=> $testname);
238 $Key->setAttribute("iterations"=>1000);
239 $Key->setAttribute("time"=>$iKeyGen);
240 $root->appendChild($Key);
242 my $JDK = $doc->createElement("perfTestResult");
243 my $testname = "Coll-$locale-data$counter-StrCol-JDK";
244 $JDK->setAttribute("test"=>$testname);
245 $JDK->setAttribute("iterations"=>1000);
246 $JDK->setAttribute("time"=>$wStrCol);
247 $root->appendChild($JDK);
249 my $Key = $doc->createElement("perfTestResult");
250 my $testname = "Coll-$locale-data$counter-keyGen-JDK";
251 $Key->setAttribute("test"=>$testname);
252 $Key->setAttribute("iterations"=>1000);
253 $Key->setAttribute("time"=>$wKeyGen);
254 $root->appendChild($Key);
261 #----------WRITE RESULTS TO perf.xml-----------------------
262 $doc->setDocumentElement($root);
263 open my $out_fh, '>', "perf.xml";
264 print {$out_fh} $doc->toString;
268 #---------------------------------------------------------------------
269 # Append text to the global variable $OUT
271 $OUT .= join('', @_);
275 #---------------------------------------------------------------------
276 # Measure a given test method with a give test pattern using the
277 # global run parameters.
279 # @param the method to run
280 # @param the pattern defining characters to test
281 # @param if >0 then the number of iterations per pass. If <0 then
282 # (negative of) the number of seconds per pass.
284 # @return a Dataset object, scaled by iterations per pass and
285 # events per iteration, to give time per event
288 my @data = measure1(@_);
289 my $iterPerPass = shift(@data);
290 my $eventPerIter = shift(@data);
292 shift(@data) if (@data > 1); # discard first run
294 my $ds = Dataset->new(@data);
295 $ds->setScale(1.0e-3 / ($iterPerPass * $eventPerIter));
299 #---------------------------------------------------------------------
300 # Measure a given test method with a give test pattern using the
301 # global run parameters.
303 # @param the method to run
304 # @param the pattern defining characters to test
305 # @param if >0 then the number of iterations per pass. If <0 then
306 # (negative of) the number of seconds per pass.
309 # [0] iterations per pass
310 # [1] events per iteration
311 # [2..] ms reported for each pass, in order
314 my $testclass = shift;
317 my $iterCount = shift; # actually might be -seconds/pass
319 # is $iterCount actually -seconds/pass?
320 if ($iterCount < 0) {
322 # calibrate: estimate ms/iteration
323 print "Calibrating...";
324 my @t = callJava($testclass, $method, $pat, -$CALIBRATE, 1);
327 my @data = split(/\s+/, $t[0]->[2]);
330 my $timePerIter = 1.0e-3 * $data[0] / $data[1];
332 # determine iterations/pass
333 $iterCount = int(-$iterCount / $timePerIter + 0.5);
337 print "Measuring $iterCount iterations x $NUMPASSES passes...";
338 my @t = callJava($testclass, $method, $pat, $iterCount, $NUMPASSES);
343 # $a->[0]: method name, corresponds to $method
344 # $a->[1]: 'begin' data, == $iterCount
345 # $a->[2]: 'end' data, of the form <ms> <loops> <eventsPerIter>
346 # $a->[3...]: gc messages from JVM during pass
347 @b = split(/\s+/, $a->[2]);
348 push(@ms, $b[0] * 1.0e+3);
350 my $eventsPerIter = $b[2];
353 $ms_str[0] .= " (discarded)" if (@ms_str > 1);
355 ($iterCount, $eventsPerIter, @ms);
358 #---------------------------------------------------------------------
359 # Invoke java to run $TESTCLASS, passing it the given parameters.
361 # @param the method to run
362 # @param the number of iterations, or if negative, the duration
363 # in seconds. If more than on pass is desired, pass in
364 # a string, e.g., "100 100 100".
365 # @param the pattern defining characters to test
367 # @return an array of results. Each result is an array REF
368 # describing one pass. The array REF contains:
369 # ->[0]: The method name as reported
370 # ->[1]: The params on the '= <meth> begin ...' line
371 # ->[2]: The params on the '= <meth> end ...' line
372 # ->[3..]: GC messages from the JVM, if any
375 my $testclass = shift;
381 my $n = ($n < 0) ? "-t ".(-$n) : "-i ".$n;
383 my $cmd = "java -classpath $CLASSPATH $testclass $method $n -p $passes -L @$pat[0] \"@$pat[1]\" \"@$pat[2]\" -r $THREADS";
384 print "[$cmd]\n"; # for debugging
385 open(PIPE, "$cmd|") or die "Can't run \"$cmd\"";
390 close(PIPE) or die "Java failed: \"$cmd\"";
392 @out = grep(!/^\#/, @out); # filter out comments
394 #print "[", join("\n", @out), "]\n";
402 if (/^=\s*(\w+)\s*(\w+)\s*(.*)/) {
403 my ($m, $state, $d) = ($1, $2, $3);
404 #print "$_ => [[$m $state $data]]\n";
405 if ($state eq 'begin') {
406 die "$method was begun but not finished" if ($method);
409 push(@$data, ''); # placeholder for end data
410 } elsif ($state eq 'end') {
412 die "$method end does not match: $_";
414 $data->[1] = $d; # insert end data at [1]
415 #print "#$method:", join(";",@$data), "\n";
416 unshift(@$data, $method); # add method to start
418 push(@results, $data);
422 die "Can't parse: $_";
429 # ignore extraneous GC notices
433 die "Can't parse: $_";
437 die "$method was begun but not finished" if ($method);
442 #-----------------------------------------------------------------------------------
443 # doKeyGenTimes($Command_to_run, $time, $key_length)
444 # Do a key-generation test and return the time and key length/char values.
446 sub doKeyTimes($$$) {
448 local($x) = `$_[0]`; # execute the collperf command.
449 ($_[1], $_[2]) = split(/\,/, $x); # collperf returns "time, keylength" string.