benchmark.pl 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198
  1. #!/usr/bin/perl
  2. # Process the raw output from benchmark.sh into Javascript-ified HTML.
  3. use strict;
  4. use warnings;
  5. my @presets = ();
  6. my %presets = ();
  7. my $maxval = 0;
  8. while (<<>>) {
  9. chomp;
  10. if (/^(.*)(#.*): ([\d\.]+)$/) {
  11. push @presets, $1 unless defined $presets{$1};
  12. push @{$presets{$1}}, $3;
  13. $maxval = $3 if $maxval < $3;
  14. }
  15. }
  16. print <<EOF;
  17. <!DOCTYPE html>
  18. <html>
  19. <head>
  20. <meta http-equiv="Content-Type" content="text/html; charset=ASCII" />
  21. <title>Puzzle generation-time benchmarks</title>
  22. <script type="text/javascript">
  23. //<![CDATA[
  24. function choose_scale_ticks(scale) {
  25. var nscale = 1, j = 0, factors = [2,2.5,2];
  26. while (scale / nscale > 20) {
  27. nscale *= factors[j];
  28. j = (j+1) % factors.length;
  29. }
  30. return nscale;
  31. }
  32. function initPlots() {
  33. var canvases = document.getElementsByTagName('canvas');
  34. for (var i = 0; i < canvases.length; i++) {
  35. var canvas = canvases[i];
  36. var scale = eval(canvas.getAttribute("data-scale"));
  37. var add = 20.5, mult = (canvas.width - 2*add) / scale;
  38. var data = eval(canvas.getAttribute("data-points"));
  39. var ctx = canvas.getContext('2d');
  40. ctx.lineWidth = '1px';
  41. ctx.lineCap = 'round';
  42. ctx.lineJoin = 'round';
  43. ctx.strokeStyle = ctx.fillStyle = '#000000';
  44. if (data === "scale") {
  45. // Draw scale.
  46. ctx.font = "16px sans-serif";
  47. ctx.textAlign = "center";
  48. ctx.textBaseline = "alphabetic";
  49. var nscale = choose_scale_ticks(scale);
  50. for (var x = 0; x <= scale; x += nscale) {
  51. ctx.beginPath();
  52. ctx.moveTo(add+mult*x, canvas.height);
  53. ctx.lineTo(add+mult*x, canvas.height - 3);
  54. ctx.stroke();
  55. ctx.fillText(x + "s", add+mult*x, canvas.height - 6);
  56. }
  57. } else {
  58. // Draw a box plot.
  59. function quantile(x) {
  60. var n = (data.length * x) | 0;
  61. return (data[n-1] + data[n]) / 2;
  62. }
  63. var q1 = quantile(0.25), q2 = quantile(0.5), q3 = quantile(0.75);
  64. var iqr = q3 - q1;
  65. var top = 0.5, bot = canvas.height - 1.5, mid = (top+bot)/2;
  66. var wlo = null, whi = null; // whisker ends
  67. ctx.strokeStyle = '#bbbbbb';
  68. var nscale = choose_scale_ticks(scale);
  69. for (var x = 0; x <= scale; x += nscale) {
  70. ctx.beginPath();
  71. ctx.moveTo(add+mult*x, 0);
  72. ctx.lineTo(add+mult*x, canvas.height);
  73. ctx.stroke();
  74. }
  75. ctx.strokeStyle = '#000000';
  76. for (var j in data) {
  77. var x = data[j];
  78. if (x >= q1 - 1.5 * iqr && x <= q3 + 1.5 * iqr) {
  79. if (wlo === null || wlo > x)
  80. wlo = x;
  81. if (whi === null || whi < x)
  82. whi = x;
  83. } else {
  84. ctx.beginPath();
  85. ctx.arc(add+mult*x, mid, 2, 0, 2*Math.PI);
  86. ctx.stroke();
  87. if (x >= q1 - 3 * iqr && x <= q3 + 3 * iqr)
  88. ctx.fill();
  89. }
  90. }
  91. ctx.beginPath();
  92. // Box
  93. ctx.moveTo(add+mult*q1, top);
  94. ctx.lineTo(add+mult*q3, top);
  95. ctx.lineTo(add+mult*q3, bot);
  96. ctx.lineTo(add+mult*q1, bot);
  97. ctx.closePath();
  98. // Line at median
  99. ctx.moveTo(add+mult*q2, top);
  100. ctx.lineTo(add+mult*q2, bot);
  101. // Lower whisker
  102. ctx.moveTo(add+mult*q1, mid);
  103. ctx.lineTo(add+mult*wlo, mid);
  104. ctx.moveTo(add+mult*wlo, top);
  105. ctx.lineTo(add+mult*wlo, bot);
  106. // Upper whisker
  107. ctx.moveTo(add+mult*q3, mid);
  108. ctx.lineTo(add+mult*whi, mid);
  109. ctx.moveTo(add+mult*whi, top);
  110. ctx.lineTo(add+mult*whi, bot);
  111. ctx.stroke();
  112. }
  113. }
  114. document.getElementById('sort_orig').onclick = function() {
  115. sort(function(e) {
  116. return parseFloat(e.getAttribute("data-index"));
  117. });
  118. };
  119. document.getElementById('sort_median').onclick = function() {
  120. sort(function(e) {
  121. return -parseFloat(e.getAttribute("data-median"));
  122. });
  123. };
  124. document.getElementById('sort_mean').onclick = function() {
  125. sort(function(e) {
  126. return -parseFloat(e.getAttribute("data-mean"));
  127. });
  128. };
  129. }
  130. function sort(keyfn) {
  131. var rows = document.getElementsByTagName("tr");
  132. var trs = [];
  133. for (var i = 0; i < rows.length; i++)
  134. trs.push(rows[i]);
  135. trs.sort(function(a,b) {
  136. var akey = keyfn(a);
  137. var bkey = keyfn(b);
  138. return akey < bkey ? -1 : akey > bkey ? +1 : 0;
  139. });
  140. var parent = trs[0].parentElement;
  141. for (var i = 0; i < trs.length; i++)
  142. parent.removeChild(trs[i]);
  143. for (var i = 0; i < trs.length; i++)
  144. parent.appendChild(trs[i]);
  145. }
  146. //]]>
  147. </script>
  148. </head>
  149. <body onLoad="initPlots();">
  150. <h1 align=center>Puzzle generation-time benchmarks</h1>
  151. <p>Sort order:
  152. <button id="sort_orig">Original</button>
  153. <button id="sort_median">Median</button>
  154. <button id="sort_mean">Mean</button>
  155. <table>
  156. <tr><th>Preset</th><td><canvas width=700 height=30 data-points='"scale"' data-scale="$maxval"></td></tr>
  157. EOF
  158. my $index = 0;
  159. for my $preset (@presets) {
  160. my @data = sort { $a <=> $b } @{$presets{$preset}};
  161. my $median = ($#data % 2 ?
  162. ($data[($#data-1)/2]+$data[($#data+1)/2])/2 :
  163. $data[$#data/2]);
  164. my $mean = 0; map { $mean += $_ } @data; $mean /= @data;
  165. print "<tr data-index=\"$index\" data-mean=\"$mean\" data-median=\"$median\"><td>", &escape($preset), "</td><td><canvas width=700 height=15 data-points=\"[";
  166. print join ",", @data;
  167. print "]\" data-scale=\"$maxval\"></td></tr>\n";
  168. $index++;
  169. }
  170. print <<EOF;
  171. </body>
  172. </html>
  173. EOF
  174. sub escape {
  175. my ($text) = @_;
  176. $text =~ s/&/&amp;/g;
  177. $text =~ s/</&lt;/g;
  178. $text =~ s/>/&gt;/g;
  179. return $text;
  180. }