1 #!/usr/local/bin/perl 2 3 # ******************************************************************** 4 # * Copyright (C) 2016 and later: Unicode, Inc. and others. 5 # * License & terms of use: http://www.unicode.org/copyright.html#License 6 # ******************************************************************** 7 # ******************************************************************** 8 # * COPYRIGHT: 9 # * Copyright (c) 2002, International Business Machines Corporation and 10 # * others. All Rights Reserved. 11 # ******************************************************************** 12 13 14 use strict; 15 16 use Dataset; 17 18 my $TABLEATTR = 'BORDER="1" CELLPADDING="4" CELLSPACING="0"'; 19 my $outType = "HTML"; 20 my $html = "noName"; 21 my $inTable; 22 my @headers; 23 my @timetypes = ("mean per op", "error per op", "events", "per event"); 24 my %raw; 25 my $current = ""; 26 my $exp = 0; 27 my $mult = 1e9; #use nanoseconds 28 my $perc = 100; #for percent 29 my $printEvents = 0; 30 my $legend = "<a name=\"Legend\">\n<h2>Table legend</h2></a><ul>"; 31 my $legendDone = 0; 32 my %options; 33 my $operationIs = "operation"; 34 my $eventIs = "event"; 35 36 sub startTest { 37 $current = shift; 38 $exp = 0; 39 outputData($current); 40 } 41 42 sub printLeg { 43 if(!$legendDone) { 44 my $message; 45 foreach $message (@_) { 46 $legend .= "<li>".$message."</li>\n"; 47 } 48 } 49 } 50 51 sub outputDist { 52 my $value = shift; 53 my $percent = shift; 54 my $mean = $value->getMean; 55 my $error = $value->getError; 56 print HTML "<td class=\""; 57 if($mean > 0) { 58 print HTML "value"; 59 } else { 60 print HTML "worse"; 61 } 62 print HTML "\">"; 63 if($percent) { 64 print HTML formatPercent(2, $mean); 65 } else { 66 print HTML formatNumber(2, $mult, $mean); 67 } 68 print HTML "</td>\n"; 69 print HTML "<td class=\""; 70 if((($error*$mult < 10)&&!$percent) || (($error<10)&&$percent)) { 71 print HTML "error"; 72 } else { 73 print HTML "errorLarge"; 74 } 75 print HTML "\">±"; 76 if($percent) { 77 print HTML formatPercent(2, $error); 78 } else { 79 print HTML formatNumber(2, $mult, $error); 80 } 81 print HTML "</td>\n"; 82 } 83 84 sub outputValue { 85 my $value = shift; 86 print HTML "<td class=\"sepvalue\">"; 87 print HTML $value; 88 #print HTML formatNumber(2, 1, $value); 89 print HTML "</td>\n"; 90 } 91 92 sub startTable { 93 #my $printEvents = shift; 94 $inTable = 1; 95 my $i; 96 print HTML "<table $TABLEATTR>\n"; 97 print HTML "<tbody>\n"; 98 if($#headers >= 0) { 99 my ($header, $i); 100 print HTML "<tr>\n"; 101 print HTML "<th rowspan=\"2\" class=\"testNameHeader\"><a href=\"#TestName\">Test Name</a></th>\n"; 102 print HTML "<th rowspan=\"2\" class=\"testNameHeader\"><a href=\"#Ops\">Ops</a></th>\n"; 103 printLeg("<a name=\"Test Name\">TestName</a> - name of the test as set by the test writer\n", "<a name=\"Ops\">Ops</a> - number of ".$operationIs."s per iteration\n"); 104 if(!$printEvents) { 105 print HTML "<th colspan=".((4*($#headers+1))-2)." class=\"sourceType\">Per Operation</th>\n"; 106 } else { 107 print HTML "<th colspan=".((2*($#headers+1))-2)." class=\"sourceType\">Per Operation</th>\n"; 108 print HTML "<th colspan=".((5*($#headers+1))-2)." class=\"sourceType\">Per Event</th>\n"; 109 } 110 print HTML "</tr>\n<tr>\n"; 111 if(!$printEvents) { 112 foreach $header (@headers) { 113 print HTML "<th class=\"source\" colspan=2><a href=\"#meanop_$header\">$header<br>/op</a></th>\n"; 114 printLeg("<a name=\"meanop_$header\">$header /op</a> - mean time and error for $header per $operationIs"); 115 } 116 } 117 for $i (1 .. $#headers) { 118 print HTML "<th class=\"source\" colspan=2><a href=\"#mean_op_$i\">ratio $i<br>/op</a></th>\n"; 119 printLeg("<a name=\"mean_op_$i\">ratio $i /op</a> - ratio and error of per $operationIs time, calculated as: (($headers[0] - $headers[$i])/$headers[$i])*100%, mean value"); 120 } 121 if($printEvents) { 122 foreach $header (@headers) { 123 print HTML "<th class=\"source\"><a href=\"#events_$header\">$header<br>events</a></th>\n"; 124 printLeg("<a name=\"events_$header\">$header events</a> - number of ".$eventIs."s for $header per iteration"); 125 } 126 foreach $header (@headers) { 127 print HTML "<th class=\"source\" colspan=2><a href=\"#mean_ev_$header\">$header<br>/ev</a></th>\n"; 128 printLeg("<a name=\"mean_ev_$header\">$header /ev</a> - mean time and error for $header per $eventIs"); 129 } 130 for $i (1 .. $#headers) { 131 print HTML "<th class=\"source\" colspan=2><a href=\"#mean_ev_$i\">ratio $i<br>/ev</a></th>\n"; 132 printLeg("<a name=\"mean_ev_$i\">ratio $i /ev</a> - ratio and error of per $eventIs time, calculated as: (($headers[0] - $headers[$i])/$headers[$i])*100%, mean value"); 133 } 134 } 135 print HTML "</tr>\n"; 136 } 137 $legendDone = 1; 138 } 139 140 sub closeTable { 141 if($inTable) { 142 undef $inTable; 143 print HTML "</tr>\n"; 144 print HTML "</tbody>"; 145 print HTML "</table>\n"; 146 } 147 } 148 149 sub newRow { 150 if(!$inTable) { 151 startTable; 152 } else { 153 print HTML "</tr>\n"; 154 } 155 print HTML "<tr>"; 156 } 157 158 sub outputData { 159 if($inTable) { 160 my $msg = shift; 161 my $align = shift; 162 print HTML "<td"; 163 if($align) { 164 print HTML " align = $align>"; 165 } else { 166 print HTML ">"; 167 } 168 print HTML "$msg"; 169 print HTML "</td>"; 170 } else { 171 my $message; 172 foreach $message (@_) { 173 print HTML "$message"; 174 } 175 } 176 } 177 178 sub setupOutput { 179 my $date = localtime; 180 my $options = shift; 181 %options = %{ $options }; 182 my $title = $options{ "title" }; 183 my $headers = $options{ "headers" }; 184 if($options{ "operationIs" }) { 185 $operationIs = $options{ "operationIs" }; 186 } 187 if($options{ "eventIs" }) { 188 $eventIs = $options{ "eventIs" }; 189 } 190 @headers = split(/ /, $headers); 191 my ($t, $rest); 192 ($t, $rest) = split(/\.\w+/, $0); 193 $t =~ /^.*\W(\w+)$/; 194 $t = $1; 195 if($outType eq 'HTML') { 196 $html = $date; 197 $html =~ s/://g; # ':' illegal 198 $html =~ s/\s*\d+$//; # delete year 199 $html =~ s/^\w+\s*//; # delete dow 200 $html = "$t $html.html"; 201 if($options{ "outputDir" }) { 202 $html = $options{ "outputDir" }."/".$html; 203 } 204 $html =~ s/ /_/g; 205 206 open(HTML,">$html") or die "Can't write to $html: $!"; 207 208 #<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd"> 209 print HTML <<EOF; 210 <HTML> 211 <HEAD> 212 <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> 213 <TITLE>$title</TITLE> 214 <style> 215 <!-- 216 body { font-size: 10pt; font-family: sans-serif } 217 th { font-size: 10pt; border: 0 solid #000080; padding: 5 } 218 th.testNameHeader { border-width: 1 } 219 th.testName { text-align: left; border-left-width: 1; border-right-width: 1; 220 border-bottom-width: 1 } 221 th.source { border-right-width: 1; border-bottom-width: 1 } 222 th.sourceType { border-right-width: 1; border-top-width: 1; border-bottom-width: 1 } 223 td { font-size: 10pt; text-align: Right; border: 0 solid #000080; padding: 5 } 224 td.string { text-align: Left; border-bottom-width:1; border-right-width:1 } 225 td.sepvalue { border-bottom-width: 1; border-right-width: 1 } 226 td.value { border-bottom-width: 1 } 227 td.worse { color: #FF0000; font-weight: bold; border-bottom-width: 1 } 228 td.error { font-size: 75%; border-right-width: 1; border-bottom-width: 1 } 229 td.errorLarge { font-size: 75%; color: #FF0000; font-weight: bold; border-right-width: 1; 230 border-bottom-width: 1 } 231 A:link { color: black; font-weight: normal; text-decoration: none} /* unvisited links */ 232 A:visited { color: blue; font-weight: normal; text-decoration: none } /* visited links */ 233 A:hover { color: red; font-weight: normal; text-decoration: none } /* user hovers */ 234 A:active { color: lime; font-weight: normal; text-decoration: none } /* active links */ 235 --> 236 </style> 237 </HEAD> 238 <BODY bgcolor="#FFFFFF" LINK="#006666" VLINK="#000000"> 239 EOF 240 print HTML "<H1>$title</H1>\n"; 241 242 #print HTML "<H2>$TESTCLASS</H2>\n"; 243 } 244 } 245 246 sub closeOutput { 247 if($outType eq 'HTML') { 248 if($inTable) { 249 closeTable; 250 } 251 $legend .= "</ul>\n"; 252 print HTML $legend; 253 outputRaw(); 254 print HTML <<EOF; 255 </BODY> 256 </HTML> 257 EOF 258 close(HTML) or die "Can't close $html: $!"; 259 } 260 } 261 262 263 sub outputRaw { 264 print HTML "<h2>Raw data</h2>"; 265 my $key; 266 my $i; 267 my $j; 268 my $k; 269 print HTML "<table $TABLEATTR>\n"; 270 for $key (sort keys %raw) { 271 my $printkey = $key; 272 $printkey =~ s/\<br\>/ /g; 273 if($printEvents) { 274 if($key ne "") { 275 print HTML "<tr><th class=\"testNameHeader\" colspan = 7>$printkey</td></tr>\n"; # locale and data file 276 } 277 print HTML "<tr><th class=\"testName\">test name</th><th class=\"testName\">interesting arguments</th><th class=\"testName\">iterations</th><th class=\"testName\">operations</th><th class=\"testName\">mean time (ns)</th><th class=\"testName\">error (ns)</th><th class=\"testName\">events</th></tr>\n"; 278 } else { 279 if($key ne "") { 280 print HTML "<tr><th class=\"testName\" colspan = 6>$printkey</td></tr>\n"; # locale and data file 281 } 282 print HTML "<tr><th class=\"testName\">test name</th><th class=\"testName\">interesting arguments</th><th class=\"testName\">iterations</th><th class=\"testName\">operations</th><th class=\"testName\">mean time (ns)</th><th class=\"testName\">error (ns)</th></tr>\n"; 283 } 284 $printkey =~ s/[\<\>\/ ]//g; 285 286 my %done; 287 for $i ( $raw{$key} ) { 288 print HTML "<tr>"; 289 for $j ( @$i ) { 290 my ($test, $args); 291 ($test, $args) = split(/,/, shift(@$j)); 292 293 print HTML "<th class=\"testName\">"; 294 if(!$done{$test}) { 295 print HTML "<a name=\"".$printkey."_".$test."\">".$test."</a>"; 296 $done{$test} = 1; 297 } else { 298 print HTML $test; 299 } 300 print HTML "</th>"; 301 302 print HTML "<td class=\"string\">".$args."</td>"; 303 304 print HTML "<td class=\"sepvalue\">".shift(@$j)."</td>"; 305 print HTML "<td class=\"sepvalue\">".shift(@$j)."</td>"; 306 307 my @data = @{ shift(@$j) }; 308 my $ds = Dataset->new(@data); 309 print HTML "<td class=\"sepvalue\">".formatNumber(4, $mult, $ds->getMean)."</td><td class=\"sepvalue\">".formatNumber(4, $mult, $ds->getError)."</td>"; 310 if($#{ $j } >= 0) { 311 print HTML "<td class=\"sepvalue\">".shift(@$j)."</td>"; 312 } 313 print HTML "</tr>\n"; 314 } 315 } 316 } 317 } 318 319 sub store { 320 $raw{$current}[$exp++] = [@_]; 321 } 322 323 sub outputRow { 324 #$raw{$current}[$exp++] = [@_]; 325 my $testName = shift; 326 my @iterPerPass = @{shift(@_)}; 327 my @noopers = @{shift(@_)}; 328 my @timedata = @{shift(@_)}; 329 my @noevents; 330 if($#_ >= 0) { 331 @noevents = @{shift(@_)}; 332 } 333 if(!$inTable) { 334 if(@noevents) { 335 $printEvents = 1; 336 startTable; 337 } else { 338 startTable; 339 } 340 } 341 debug("No events: @noevents, $#noevents\n"); 342 343 my $j; 344 my $loc = $current; 345 $loc =~ s/\<br\>/ /g; 346 $loc =~ s/[\<\>\/ ]//g; 347 348 # Finished one row of results. Outputting 349 newRow; 350 #outputData($testName, "LEFT"); 351 print HTML "<th class=\"testName\"><a href=\"#".$loc."_".$testName."\">$testName</a></th>\n"; 352 #outputData($iterCount); 353 #outputData($noopers[0], "RIGHT"); 354 outputValue($noopers[0]); 355 356 if(!$printEvents) { 357 for $j ( 0 .. $#timedata ) { 358 my $perOperation = $timedata[$j]->divideByScalar($iterPerPass[$j]*$noopers[$j]); # time per operation 359 #debug("Time per operation: ".formatSeconds(4, $perOperation->getMean, $perOperation->getError)."\n"); 360 outputDist($perOperation); 361 } 362 } 363 my $baseLinePO = $timedata[0]->divideByScalar($iterPerPass[0]*$noopers[0]); 364 for $j ( 1 .. $#timedata ) { 365 my $perOperation = $timedata[$j]->divideByScalar($iterPerPass[$j]*$noopers[$j]); # time per operation 366 my $ratio = $baseLinePO->subtract($perOperation); 367 $ratio = $ratio->divide($perOperation); 368 outputDist($ratio, "%"); 369 } 370 if (@noevents) { 371 for $j ( 0 .. $#timedata ) { 372 #outputData($noevents[$j], "RIGHT"); 373 outputValue($noevents[$j]); 374 } 375 for $j ( 0 .. $#timedata ) { 376 my $perEvent = $timedata[$j]->divideByScalar($iterPerPass[$j]*$noevents[$j]); # time per event 377 #debug("Time per operation: ".formatSeconds(4, $perEvent->getMean, $perEvent->getError)."\n"); 378 outputDist($perEvent); 379 } 380 my $baseLinePO = $timedata[0]->divideByScalar($iterPerPass[0]*$noevents[0]); 381 for $j ( 1 .. $#timedata ) { 382 my $perOperation = $timedata[$j]->divideByScalar($iterPerPass[$j]*$noevents[$j]); # time per operation 383 my $ratio = $baseLinePO->subtract($perOperation); 384 $ratio = $ratio->divide($perOperation); 385 outputDist($ratio, "%"); 386 } 387 } 388 } 389 390 391 1; 392 393 #eof 394