--- /dev/null
+#!/usr/local/bin/perl\r
+# *******************************************************************************\r
+# * Copyright (C) 2002-2012 International Business Machines Corporation and *\r
+# * others. All Rights Reserved. *\r
+# *******************************************************************************\r
+\r
+use XML::LibXML;\r
+\r
+# Assume we are running within the icu4j root directory\r
+use lib 'src/com/ibm/icu/dev/test/perf';\r
+use Dataset;\r
+my $CLASSPATH="../icu4j.jar:../tools/misc/out/lib/icu4j-tools.jar:out/bin";\r
+#---------------------------------------------------------------------\r
+\r
+# Methods to be tested. Each pair represents a test method and\r
+# a baseline method which is used for comparison.\r
+my @METHODS = (\r
+ ['TestJDKConstruction', 'TestICUConstruction'],\r
+ ['TestJDKParse', 'TestICUParse'],\r
+ ['TestJDKFormat', 'TestICUFormat']\r
+ );\r
+# Patterns which define the set of characters used for testing.\r
+my @OPTIONS = (\r
+# locale pattern date string\r
+ [ "en_US", "dddd MMM yyyy", "15 Jan 2007"],\r
+ [ "sw_KE", "dddd MMM yyyy", "15 Jan 2007"],\r
+ [ "en_US", "HH:mm", "13:13"],\r
+ [ "en_US", "HH:mm zzzz", "13:13 Pacific Standard Time"],\r
+ [ "en_US", "HH:mm z", "13:13 PST"],\r
+ [ "en_US", "HH:mm Z", "13:13 -0800"],\r
+ );\r
+\r
+my $THREADS; # number of threads (input from command-line args)\r
+my $CALIBRATE = 2; # duration in seconds for initial calibration\r
+my $DURATION = 10; # duration in seconds for each pass\r
+my $NUMPASSES = 4; # number of passes. If > 1 then the first pass\r
+ # is discarded as a JIT warm-up pass.\r
+\r
+my $TABLEATTR = 'BORDER="1" CELLPADDING="4" CELLSPACING="0"';\r
+\r
+my $PLUS_MINUS = "±";\r
+\r
+if ($NUMPASSES < 3) {\r
+ die "Need at least 3 passes. One is discarded (JIT warmup) and need two to have 1 degree of freedom (t distribution).";\r
+}\r
+\r
+\r
+# run all tests with the specified number of threads from command-line input\r
+# (if there is no arguments, use $THREADS = 1)\r
+foreach my $arg ($#ARGV >= 0 ? @ARGV : "1") {\r
+ $THREADS = $arg;\r
+ main();\r
+}\r
+\r
+\r
+#---------------------------------------------------------------------\r
+sub main {\r
+\r
+#-----------DATE FORMAT PERFORMANCE TESTS-----------------------------\r
+ my $testclass = 'com.ibm.icu.dev.test.perf.DateFormatPerformanceTest';\r
+ #my $threads = ($THREADS > 1) ? "($THREADS threads)" : "";\r
+ \r
+ my $doc = XML::LibXML::Document->new('1.0', 'utf-8');\r
+ my $root = $doc->createElement("perfTestResults");\r
+\r
+ # my $raw = "";\r
+ my @shortNames = ( "open" , "parse", "fmt");\r
+ my $index=0;\r
+\r
+ for my $methodPair (@METHODS) {\r
+\r
+ my $testMethod = $methodPair->[0];\r
+ my $baselineMethod = $methodPair->[1];\r
+ my $testname = $shortNames[$index];\r
+ $index++;\r
+\r
+ $OUT = '';\r
+ my $patternCounter=1;\r
+\r
+ for my $pat (@OPTIONS) { \r
+\r
+ # measure the test method\r
+ my $t = measure2($testclass, $testMethod, $pat, -$DURATION);\r
+ my $testResult = $t->getMean();\r
+ my $jdkElement = $doc->createElement("perfTestResult");\r
+ my $testName = "DateFmt-$testname-pat$patternCounter-JDK";\r
+ $jdkElement->setAttribute("test" => $testName);\r
+ $jdkElement->setAttribute("iterations" => 1);\r
+ $jdkElement->setAttribute("time" => $testResult);\r
+ $root->appendChild($jdkElement);\r
+\r
+ # measure baseline method\r
+ my $b = measure2($testclass, $baselineMethod, $pat, -$DURATION);\r
+ my $baseResult = $b->getMean();\r
+ my $icuElement = $doc->createElement("perfTestResult");\r
+ my $testName = "DateFmt-$testname-pat$patternCounter";\r
+ $patternCounter++;\r
+ $icuElement->setAttribute("test"=> $testName);\r
+ $icuElement->setAttribute("iterations" => 1); \r
+ $icuElement->setAttribute("time" => $baseResult);\r
+ $root->appendChild($icuElement);\r
+\r
+ }\r
+ }\r
+\r
+#------------------DECIMAL FORMAT TESTS---------------------------------\r
+\r
+ my $testclass = 'com.ibm.icu.dev.test.perf.DecimalFormatPerformanceTest';\r
+ my @OPTIONS = (\r
+# locale pattern date string\r
+ [ "en_US", "#,###.##", "1,234.56"],\r
+ [ "de_DE", "#,###.##", "1.234,56"],\r
+ );\r
+ my $index=0;\r
+ for my $methodPair (@METHODS) {\r
+\r
+ my $testMethod = $methodPair->[0];\r
+ my $baselineMethod = $methodPair->[1];\r
+ my $testname = $shortNames[$index];\r
+ $index++;\r
+ \r
+\r
+ for my $pat (@OPTIONS) {\r
+ my $pat0 = $pat->[0];\r
+ my $patternName = $pat0->[0]; \r
+\r
+ # measure the test method\r
+ my $t = measure2($testclass, $testMethod, $pat, -$DURATION);\r
+ my $testResult = $t->getMean();\r
+ my $jdkElement = $doc->createElement("perfTestResult");\r
+ my $testName = "NumFmt-$testname-$patternName-JDK";\r
+ $jdkElement->setAttribute("test" => $testName);\r
+ $jdkElement->setAttribute("iterations"=>1);\r
+ $jdkElement->setAttribute("time" => $testResult);\r
+ $root->appendChild($jdkElement);\r
+\r
+ # measure baseline method\r
+ my $b = measure2($testclass, $baselineMethod, $pat, -$DURATION);\r
+ my $baseResult = $b->getMean();\r
+ my $icuElement = $doc->createElement("perfTestResult");\r
+ my $testName = "NumFmt-$testname-$patternName";\r
+ $icuElement->setAttribute("test"=> $testName);\r
+ $icuElement->setAttribute("iterations"=>1);\r
+ $icuElement->setAttribute("time" => $baseResult);\r
+ $root->appendChild($icuElement);\r
+ }\r
+ }\r
+\r
+#----------------COLLATION PERFORMANCE TESTS--------------------------_\r
+\r
+ %dataFiles = (\r
+ "en_US", "TestNames_Latin.txt",\r
+ "da_DK", "TestNames_Latin.txt",\r
+ "de_DE", "TestNames_Latin.txt",\r
+ "de__PHONEBOOK", "TestNames_Latin.txt",\r
+ "fr_FR", "TestNames_Latin.txt",\r
+ "ja_JP", "TestNames_Latin.txt TestNames_Japanese_h.txt TestNames_Japanese_k.txt TestNames_Asian.txt",\r
+ "zh_CN", "TestNames_Latin.txt TestNames_Chinese.txt",\r
+ "zh_TW", "TestNames_Latin.txt TestNames_Chinese.txt",\r
+ "zh__PINYIN", "TestNames_Latin.txt TestNames_Chinese.txt",\r
+ "ru_RU", "TestNames_Latin.txt TestNames_Russian.txt",\r
+ "th", "TestNames_Latin.txt TestNames_Thai.txt",\r
+ "ko_KR", "TestNames_Latin.txt TestNames_Korean.txt",\r
+ );\r
+ \r
+ # Outer loop runs through the locales to test\r
+ # (Edit this list dirctly to make changes)\r
+ #\r
+ foreach $locale (\r
+ "en_US",\r
+ "da_DK",\r
+ "de_DE",\r
+ "de__PHONEBOOK",\r
+ "fr_FR",\r
+ "ja_JP",\r
+ "zh_CN",\r
+ "zh_TW",\r
+ "zh__PINYIN",\r
+ "ko_KR",\r
+ "ru_RU",\r
+ "th",\r
+ )\r
+ {\r
+ \r
+ \r
+ #\r
+ # Inner loop runs over the set of data files specified for each locale.\r
+ # (Edit the %datafiles initialization, above, to make changes.\r
+ #\r
+ $ff = $dataFiles{$locale};\r
+ @ff = split(/[\s]+/, $ff);\r
+ $counter = 1;\r
+ foreach $data (@ff) {\r
+ #\r
+ # Run ICU Test for this (locale, data file) pair.\r
+ #\r
+ $iStrCol = `java -classpath $CLASSPATH com.ibm.icu.dev.test.perf.CollationPerformanceTest -terse -file src/com/ibm/icu/dev/test/perf/data/collation/$data -locale $locale -loop 1000 -binsearch`;\r
+print "java -classpath $CLASSPATH com.ibm.icu.dev.test.perf.CollationPerformanceTest -terse -file src/com/ibm/icu/dev/test/perf/data/collation/$data -locale $locale -loop 1000 -binsearch\n";\r
+ $iStrCol =~s/[,\s]*//g; # whack off the leading " ," in the returned result.\r
+ doKeyTimes("java -classpath $CLASSPATH com.ibm.icu.dev.test.perf.CollationPerformanceTest -terse -file src/com/ibm/icu/dev/test/perf/data/collation/$data -locale $locale -loop 1000 -keygen",\r
+ my $iKeyGen, my $iKeyLen);\r
+\r
+ #\r
+ # Run Windows test for this (locale, data file) pair. Only do if\r
+ # we are not on Windows 98/ME and we hava a windows langID\r
+ # for the locale.\r
+ #\r
+ $wStrCol = $wKeyGen = $wKeyLen = 0;\r
+ my $wStrCol = `java -classpath $CLASSPATH com.ibm.icu.dev.test.perf.CollationPerformanceTest -terse -file src/com/ibm/icu/dev/test/perf/data/collation/$data -locale $locale -loop 1000 -binsearch -java`;\r
+ $wStrCol =~s/[,\s]*//g; # whack off the leading " ," in the returned result.\r
+ doKeyTimes("java -classpath $CLASSPATH com.ibm.icu.dev.test.perf.CollationPerformanceTest -terse -file src/com/ibm/icu/dev/test/perf/data/collation/$data -locale $locale -loop 1000 -keygen -java",\r
+ $wKeyGen, $wKeyLen);\r
+ \r
+ $collDiff = $keyGenDiff = $keyLenDiff = 0;\r
+ if ($wKeyLen > 0) {\r
+ $collDiff = (($wStrCol - $iStrCol) / $iStrCol) * 100;\r
+ $keyGenDiff = (($wKeyGen - $iKeyGen) / $iKeyGen) * 100;\r
+ $keyLenDiff = (($wKeyLen - $iKeyLen) / $iKeyLen) * 100;\r
+ }\r
+\r
+ my $ICU = $doc->createElement("perfTestResult");\r
+ my $testname = "Coll-$locale-data$counter-StrCol";\r
+ #write the results corresponding to this local,data pair\r
+ $ICU->setAttribute("test"=> $testname);\r
+ $ICU->setAttribute("iterations"=>1000);\r
+ $ICU->setAttribute("time"=> $iStrCol);\r
+ $root->appendChild($ICU);\r
+\r
+ my $Key = $doc->createElement("perfTestResult");\r
+ my $testname = "Coll-$locale-data$counter-keyGen";\r
+ $Key->setAttribute("test"=> $testname);\r
+ $Key->setAttribute("iterations"=>1000);\r
+ $Key->setAttribute("time"=>$iKeyGen);\r
+ $root->appendChild($Key);\r
+\r
+ my $JDK = $doc->createElement("perfTestResult");\r
+ my $testname = "Coll-$locale-data$counter-StrCol-JDK";\r
+ $JDK->setAttribute("test"=>$testname);\r
+ $JDK->setAttribute("iterations"=>1000);\r
+ $JDK->setAttribute("time"=>$wStrCol);\r
+ $root->appendChild($JDK);\r
+\r
+ my $Key = $doc->createElement("perfTestResult");\r
+ my $testname = "Coll-$locale-data$counter-keyGen-JDK";\r
+ $Key->setAttribute("test"=>$testname);\r
+ $Key->setAttribute("iterations"=>1000);\r
+ $Key->setAttribute("time"=>$wKeyGen);\r
+ $root->appendChild($Key);\r
+ $counter++;\r
+ }\r
+ }\r
+\r
+\r
+\r
+#----------WRITE RESULTS TO perf.xml-----------------------\r
+ $doc->setDocumentElement($root);\r
+ open my $out_fh, '>', "perf.xml";\r
+ print {$out_fh} $doc->toString;\r
+}\r
+\r
+\r
+#---------------------------------------------------------------------\r
+# Append text to the global variable $OUT\r
+sub out {\r
+ $OUT .= join('', @_);\r
+}\r
+\r
+\r
+#---------------------------------------------------------------------\r
+# Measure a given test method with a give test pattern using the\r
+# global run parameters.\r
+#\r
+# @param the method to run\r
+# @param the pattern defining characters to test\r
+# @param if >0 then the number of iterations per pass. If <0 then\r
+# (negative of) the number of seconds per pass.\r
+#\r
+# @return a Dataset object, scaled by iterations per pass and\r
+# events per iteration, to give time per event\r
+#\r
+sub measure2 {\r
+ my @data = measure1(@_);\r
+ my $iterPerPass = shift(@data);\r
+ my $eventPerIter = shift(@data);\r
+\r
+ shift(@data) if (@data > 1); # discard first run\r
+\r
+ my $ds = Dataset->new(@data);\r
+ $ds->setScale(1.0e-3 / ($iterPerPass * $eventPerIter));\r
+ $ds;\r
+}\r
+\r
+#---------------------------------------------------------------------\r
+# Measure a given test method with a give test pattern using the\r
+# global run parameters.\r
+#\r
+# @param the method to run\r
+# @param the pattern defining characters to test\r
+# @param if >0 then the number of iterations per pass. If <0 then\r
+# (negative of) the number of seconds per pass.\r
+#\r
+# @return array of:\r
+# [0] iterations per pass\r
+# [1] events per iteration\r
+# [2..] ms reported for each pass, in order\r
+#\r
+sub measure1 {\r
+ my $testclass = shift;\r
+ my $method = shift;\r
+ my $pat = shift;\r
+ my $iterCount = shift; # actually might be -seconds/pass\r
+\r
+ # is $iterCount actually -seconds/pass?\r
+ if ($iterCount < 0) {\r
+\r
+ # calibrate: estimate ms/iteration\r
+ print "Calibrating...";\r
+ my @t = callJava($testclass, $method, $pat, -$CALIBRATE, 1);\r
+ print "done.\n";\r
+\r
+ my @data = split(/\s+/, $t[0]->[2]);\r
+ $data[0] *= 1.0e+3;\r
+\r
+ my $timePerIter = 1.0e-3 * $data[0] / $data[1];\r
+ \r
+ # determine iterations/pass\r
+ $iterCount = int(-$iterCount / $timePerIter + 0.5);\r
+ }\r
+ \r
+ # run passes\r
+ print "Measuring $iterCount iterations x $NUMPASSES passes...";\r
+ my @t = callJava($testclass, $method, $pat, $iterCount, $NUMPASSES);\r
+ print "done.\n";\r
+ my @ms = ();\r
+ my @b; # scratch\r
+ for my $a (@t) {\r
+ # $a->[0]: method name, corresponds to $method\r
+ # $a->[1]: 'begin' data, == $iterCount\r
+ # $a->[2]: 'end' data, of the form <ms> <loops> <eventsPerIter>\r
+ # $a->[3...]: gc messages from JVM during pass\r
+ @b = split(/\s+/, $a->[2]);\r
+ push(@ms, $b[0] * 1.0e+3);\r
+ }\r
+ my $eventsPerIter = $b[2];\r
+\r
+ my @ms_str = @ms;\r
+ $ms_str[0] .= " (discarded)" if (@ms_str > 1);\r
+\r
+ ($iterCount, $eventsPerIter, @ms);\r
+}\r
+\r
+#---------------------------------------------------------------------\r
+# Invoke java to run $TESTCLASS, passing it the given parameters.\r
+#\r
+# @param the method to run\r
+# @param the number of iterations, or if negative, the duration\r
+# in seconds. If more than on pass is desired, pass in\r
+# a string, e.g., "100 100 100".\r
+# @param the pattern defining characters to test\r
+#\r
+# @return an array of results. Each result is an array REF\r
+# describing one pass. The array REF contains:\r
+# ->[0]: The method name as reported\r
+# ->[1]: The params on the '= <meth> begin ...' line\r
+# ->[2]: The params on the '= <meth> end ...' line\r
+# ->[3..]: GC messages from the JVM, if any\r
+#\r
+sub callJava {\r
+ my $testclass = shift;\r
+ my $method = shift;\r
+ my $pat = shift;\r
+ my $n = shift;\r
+ my $passes = shift;\r
+ \r
+ my $n = ($n < 0) ? "-t ".(-$n) : "-i ".$n;\r
+ \r
+ my $cmd = "java -classpath $CLASSPATH $testclass $method $n -p $passes -L @$pat[0] \"@$pat[1]\" \"@$pat[2]\" -r $THREADS";\r
+ print "[$cmd]\n"; # for debugging\r
+ open(PIPE, "$cmd|") or die "Can't run \"$cmd\"";\r
+ my @out;\r
+ while (<PIPE>) {\r
+ push(@out, $_);\r
+ }\r
+ close(PIPE) or die "Java failed: \"$cmd\"";\r
+\r
+ @out = grep(!/^\#/, @out); # filter out comments\r
+\r
+ #print "[", join("\n", @out), "]\n";\r
+\r
+ my @results;\r
+ my $method = '';\r
+ my $data = [];\r
+ foreach (@out) {\r
+ next unless (/\S/);\r
+\r
+ if (/^=\s*(\w+)\s*(\w+)\s*(.*)/) {\r
+ my ($m, $state, $d) = ($1, $2, $3);\r
+ #print "$_ => [[$m $state $data]]\n";\r
+ if ($state eq 'begin') {\r
+ die "$method was begun but not finished" if ($method);\r
+ $method = $m;\r
+ push(@$data, $d);\r
+ push(@$data, ''); # placeholder for end data\r
+ } elsif ($state eq 'end') {\r
+ if ($m ne $method) {\r
+ die "$method end does not match: $_";\r
+ }\r
+ $data->[1] = $d; # insert end data at [1]\r
+ #print "#$method:", join(";",@$data), "\n";\r
+ unshift(@$data, $method); # add method to start\r
+\r
+ push(@results, $data);\r
+ $method = '';\r
+ $data = [];\r
+ } else {\r
+ die "Can't parse: $_";\r
+ }\r
+ }\r
+ elsif (/^\[/) {\r
+ if ($method) {\r
+ push(@$data, $_);\r
+ } else {\r
+ # ignore extraneous GC notices\r
+ }\r
+ }\r
+ else {\r
+ die "Can't parse: $_";\r
+ }\r
+ }\r
+\r
+ die "$method was begun but not finished" if ($method);\r
+\r
+ @results;\r
+}\r
+\r
+#-----------------------------------------------------------------------------------\r
+# doKeyGenTimes($Command_to_run, $time, $key_length)\r
+# Do a key-generation test and return the time and key length/char values.\r
+#\r
+sub doKeyTimes($$$) {\r
+ # print "$_[0]\n";\r
+ local($x) = `$_[0]`; # execute the collperf command.\r
+ ($_[1], $_[2]) = split(/\,/, $x); # collperf returns "time, keylength" string.\r
+}\r
+\r
+\r
+#eof\r