ref: e6aa7ab6dd219d92b332c3662de95c28f7bd6b8f
dir: /benchmark.pl/
#!/usr/bin/perl # Process the raw output from benchmark.sh into Javascript-ified HTML. use strict; use warnings; my @presets = (); my %presets = (); my $maxval = 0; while (<<>>) { chomp; if (/^(.*)(#.*): ([\d\.]+)$/) { push @presets, $1 unless defined $presets{$1}; push @{$presets{$1}}, $3; $maxval = $3 if $maxval < $3; } } print <<EOF; <!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=ASCII" /> <title>Puzzle generation-time benchmarks</title> <script type="text/javascript"> //<![CDATA[ function choose_scale_ticks(scale) { var nscale = 1, j = 0, factors = [2,2.5,2]; while (scale / nscale > 20) { nscale *= factors[j]; j = (j+1) % factors.length; } return nscale; } function initPlots() { var canvases = document.getElementsByTagName('canvas'); for (var i = 0; i < canvases.length; i++) { var canvas = canvases[i]; var scale = eval(canvas.getAttribute("data-scale")); var add = 20.5, mult = (canvas.width - 2*add) / scale; var data = eval(canvas.getAttribute("data-points")); var ctx = canvas.getContext('2d'); ctx.lineWidth = '1px'; ctx.lineCap = 'round'; ctx.lineJoin = 'round'; ctx.strokeStyle = ctx.fillStyle = '#000000'; if (data === "scale") { // Draw scale. ctx.font = "16px sans-serif"; ctx.textAlign = "center"; ctx.textBaseline = "alphabetic"; var nscale = choose_scale_ticks(scale); for (var x = 0; x <= scale; x += nscale) { ctx.beginPath(); ctx.moveTo(add+mult*x, canvas.height); ctx.lineTo(add+mult*x, canvas.height - 3); ctx.stroke(); ctx.fillText(x + "s", add+mult*x, canvas.height - 6); } } else { // Draw a box plot. function quantile(x) { var n = (data.length * x) | 0; return (data[n-1] + data[n]) / 2; } var q1 = quantile(0.25), q2 = quantile(0.5), q3 = quantile(0.75); var iqr = q3 - q1; var top = 0.5, bot = canvas.height - 1.5, mid = (top+bot)/2; var wlo = null, whi = null; // whisker ends ctx.strokeStyle = '#bbbbbb'; var nscale = choose_scale_ticks(scale); for (var x = 0; x <= scale; x += nscale) { ctx.beginPath(); ctx.moveTo(add+mult*x, 0); ctx.lineTo(add+mult*x, canvas.height); ctx.stroke(); } ctx.strokeStyle = '#000000'; for (var j in data) { var x = data[j]; if (x >= q1 - 1.5 * iqr && x <= q3 + 1.5 * iqr) { if (wlo === null || wlo > x) wlo = x; if (whi === null || whi < x) whi = x; } else { ctx.beginPath(); ctx.arc(add+mult*x, mid, 2, 0, 2*Math.PI); ctx.stroke(); if (x >= q1 - 3 * iqr && x <= q3 + 3 * iqr) ctx.fill(); } } ctx.beginPath(); // Box ctx.moveTo(add+mult*q1, top); ctx.lineTo(add+mult*q3, top); ctx.lineTo(add+mult*q3, bot); ctx.lineTo(add+mult*q1, bot); ctx.closePath(); // Line at median ctx.moveTo(add+mult*q2, top); ctx.lineTo(add+mult*q2, bot); // Lower whisker ctx.moveTo(add+mult*q1, mid); ctx.lineTo(add+mult*wlo, mid); ctx.moveTo(add+mult*wlo, top); ctx.lineTo(add+mult*wlo, bot); // Upper whisker ctx.moveTo(add+mult*q3, mid); ctx.lineTo(add+mult*whi, mid); ctx.moveTo(add+mult*whi, top); ctx.lineTo(add+mult*whi, bot); ctx.stroke(); } } document.getElementById('sort_orig').onclick = function() { sort(function(e) { return parseFloat(e.getAttribute("data-index")); }); }; document.getElementById('sort_median').onclick = function() { sort(function(e) { return -parseFloat(e.getAttribute("data-median")); }); }; document.getElementById('sort_mean').onclick = function() { sort(function(e) { return -parseFloat(e.getAttribute("data-mean")); }); }; } function sort(keyfn) { var rows = document.getElementsByTagName("tr"); var trs = []; for (var i = 0; i < rows.length; i++) trs.push(rows[i]); trs.sort(function(a,b) { var akey = keyfn(a); var bkey = keyfn(b); return akey < bkey ? -1 : akey > bkey ? +1 : 0; }); var parent = trs[0].parentElement; for (var i = 0; i < trs.length; i++) parent.removeChild(trs[i]); for (var i = 0; i < trs.length; i++) parent.appendChild(trs[i]); } //]]> </script> </head> <body onLoad="initPlots();"> <h1 align=center>Puzzle generation-time benchmarks</h1> <p>Sort order: <button id="sort_orig">Original</button> <button id="sort_median">Median</button> <button id="sort_mean">Mean</button> <table> <tr><th>Preset</th><td><canvas width=700 height=30 data-points='"scale"' data-scale="$maxval"></td></tr> EOF my $index = 0; for my $preset (@presets) { my @data = sort { $a <=> $b } @{$presets{$preset}}; my $median = ($#data % 2 ? ($data[($#data-1)/2]+$data[($#data+1)/2])/2 : $data[$#data/2]); my $mean = 0; map { $mean += $_ } @data; $mean /= @data; print "<tr data-index=\"$index\" data-mean=\"$mean\" data-median=\"$median\"><td>", &escape($preset), "</td><td><canvas width=700 height=15 data-points=\"["; print join ",", @data; print "]\" data-scale=\"$maxval\"></td></tr>\n"; $index++; } print <<EOF; </body> </html> EOF sub escape { my ($text) = @_; $text =~ s/&/&/g; $text =~ s/</</g; $text =~ s/>/>/g; return $text; }