isaacs | db5d58e | 2013-03-06 20:32:59 | [diff] [blame^] | 1 | var usage = 'node benchmark/compare.js ' + |
| 2 | '<node-binary1> <node-binary2> ' + |
| 3 | '[--html] [--red|-r] [--green|-g]'; |
isaacs | aa2edd4 | 2013-02-12 07:28:48 | [diff] [blame] | 4 | |
| 5 | var show = 'both'; |
| 6 | var nodes = []; |
isaacs | 087c437 | 2013-02-13 18:47:29 | [diff] [blame] | 7 | var html = false; |
| 8 | |
isaacs | aa2edd4 | 2013-02-12 07:28:48 | [diff] [blame] | 9 | for (var i = 2; i < process.argv.length; i++) { |
| 10 | var arg = process.argv[i]; |
| 11 | switch (arg) { |
| 12 | case '--red': case '-r': |
| 13 | show = show === 'green' ? 'both' : 'red'; |
| 14 | break; |
| 15 | case '--green': case '-g': |
| 16 | show = show === 'red' ? 'both' : 'green'; |
| 17 | break; |
isaacs | 087c437 | 2013-02-13 18:47:29 | [diff] [blame] | 18 | case '--html': |
| 19 | html = true; |
| 20 | break; |
| 21 | case '-h': case '-?': case '--help': |
| 22 | console.log(usage); |
| 23 | process.exit(0); |
isaacs | aa2edd4 | 2013-02-12 07:28:48 | [diff] [blame] | 24 | default: |
| 25 | nodes.push(arg); |
| 26 | break; |
| 27 | } |
| 28 | } |
| 29 | |
isaacs | 087c437 | 2013-02-13 18:47:29 | [diff] [blame] | 30 | if (!html) { |
| 31 | var start = ''; |
| 32 | var green = '\033[1;32m'; |
| 33 | var red = '\033[1;31m'; |
| 34 | var reset = '\033[m'; |
| 35 | var end = ''; |
| 36 | } else { |
| 37 | var start = '<pre style="background-color:#333;color:#eee">'; |
| 38 | var green = '<span style="background-color:#0f0;color:#000">'; |
isaacs | 053e02e | 2013-02-20 17:17:29 | [diff] [blame] | 39 | var red = '<span style="background-color:#f00;color:#fff">'; |
isaacs | 087c437 | 2013-02-13 18:47:29 | [diff] [blame] | 40 | var reset = '</span>'; |
| 41 | var end = '</pre>'; |
| 42 | } |
| 43 | |
isaacs | aa2edd4 | 2013-02-12 07:28:48 | [diff] [blame] | 44 | var runBench = process.env.NODE_BENCH || 'bench'; |
| 45 | |
| 46 | if (nodes.length !== 2) |
isaacs | db5d58e | 2013-03-06 20:32:59 | [diff] [blame^] | 47 | return console.error('usage:\n %s', usage); |
isaacs | aa2edd4 | 2013-02-12 07:28:48 | [diff] [blame] | 48 | |
| 49 | var spawn = require('child_process').spawn; |
| 50 | var results = {}; |
isaacs | db5d58e | 2013-03-06 20:32:59 | [diff] [blame^] | 51 | var n = 1; |
isaacs | aa2edd4 | 2013-02-12 07:28:48 | [diff] [blame] | 52 | |
| 53 | run(); |
| 54 | |
isaacs | db5d58e | 2013-03-06 20:32:59 | [diff] [blame^] | 55 | var RUNS = +process.env.NODE_BENCH_RUNS || 1; |
| 56 | var r = RUNS; |
isaacs | aa2edd4 | 2013-02-12 07:28:48 | [diff] [blame] | 57 | function run() { |
isaacs | db5d58e | 2013-03-06 20:32:59 | [diff] [blame^] | 58 | // Flip back and forth between the two binaries. |
| 59 | if (n === 1) { |
| 60 | n--; |
| 61 | } else { |
| 62 | r--; |
| 63 | if (r === 0) |
| 64 | return compare(); |
| 65 | else |
| 66 | n++; |
| 67 | } |
isaacs | aa2edd4 | 2013-02-12 07:28:48 | [diff] [blame] | 68 | |
isaacs | db5d58e | 2013-03-06 20:32:59 | [diff] [blame^] | 69 | if (n === -1) |
| 70 | return compare(); |
isaacs | aa2edd4 | 2013-02-12 07:28:48 | [diff] [blame] | 71 | |
isaacs | db5d58e | 2013-03-06 20:32:59 | [diff] [blame^] | 72 | var node = nodes[n]; |
isaacs | aa2edd4 | 2013-02-12 07:28:48 | [diff] [blame] | 73 | console.error('running %s', node); |
isaacs | db5d58e | 2013-03-06 20:32:59 | [diff] [blame^] | 74 | var env = {}; |
isaacs | aa2edd4 | 2013-02-12 07:28:48 | [diff] [blame] | 75 | for (var i in process.env) |
| 76 | env[i] = process.env[i]; |
| 77 | env.NODE = node; |
isaacs | db5d58e | 2013-03-06 20:32:59 | [diff] [blame^] | 78 | var child = spawn('make', [runBench], { env: env }); |
isaacs | aa2edd4 | 2013-02-12 07:28:48 | [diff] [blame] | 79 | |
isaacs | db5d58e | 2013-03-06 20:32:59 | [diff] [blame^] | 80 | var out = ''; |
| 81 | child.stdout.setEncoding('utf8'); |
| 82 | child.stdout.on('data', function(c) { |
| 83 | out += c; |
| 84 | }); |
isaacs | aa2edd4 | 2013-02-12 07:28:48 | [diff] [blame] | 85 | |
| 86 | child.stderr.pipe(process.stderr); |
| 87 | |
isaacs | db5d58e | 2013-03-06 20:32:59 | [diff] [blame^] | 88 | child.on('close', function(code) { |
| 89 | if (code) { |
| 90 | console.error('%s exited with code=%d', node, code); |
| 91 | process.exit(code); |
| 92 | } else { |
| 93 | out.trim().split(/\r?\n/).forEach(function(line) { |
isaacs | aa2edd4 | 2013-02-12 07:28:48 | [diff] [blame] | 94 | line = line.trim(); |
| 95 | if (!line) |
| 96 | return; |
| 97 | |
isaacs | db5d58e | 2013-03-06 20:32:59 | [diff] [blame^] | 98 | var s = line.split(':'); |
| 99 | var num = +s.pop(); |
| 100 | if (!num && num !== 0) |
| 101 | return; |
isaacs | aa2edd4 | 2013-02-12 07:28:48 | [diff] [blame] | 102 | |
isaacs | db5d58e | 2013-03-06 20:32:59 | [diff] [blame^] | 103 | line = s.join(':'); |
| 104 | var res = results[line] = results[line] || {}; |
| 105 | res[node] = res[node] || []; |
| 106 | res[node].push(num); |
| 107 | }); |
isaacs | aa2edd4 | 2013-02-12 07:28:48 | [diff] [blame] | 108 | |
isaacs | db5d58e | 2013-03-06 20:32:59 | [diff] [blame^] | 109 | run(); |
| 110 | } |
| 111 | }); |
isaacs | aa2edd4 | 2013-02-12 07:28:48 | [diff] [blame] | 112 | } |
| 113 | |
| 114 | function compare() { |
isaacs | db5d58e | 2013-03-06 20:32:59 | [diff] [blame^] | 115 | // each result is an object with {"foo.js arg=bar":12345,...} |
| 116 | // compare each thing, and show which node did the best. |
isaacs | aa2edd4 | 2013-02-12 07:28:48 | [diff] [blame] | 117 | // node[0] is shown in green, node[1] shown in red. |
isaacs | aa2edd4 | 2013-02-12 07:28:48 | [diff] [blame] | 118 | var maxLen = -Infinity; |
| 119 | var util = require('util'); |
isaacs | 087c437 | 2013-02-13 18:47:29 | [diff] [blame] | 120 | console.log(start); |
| 121 | |
isaacs | db5d58e | 2013-03-06 20:32:59 | [diff] [blame^] | 122 | Object.keys(results).map(function(bench) { |
isaacs | aa2edd4 | 2013-02-12 07:28:48 | [diff] [blame] | 123 | var res = results[bench]; |
isaacs | db5d58e | 2013-03-06 20:32:59 | [diff] [blame^] | 124 | var n0 = avg(res[nodes[0]]); |
| 125 | var n1 = avg(res[nodes[1]]); |
isaacs | aa2edd4 | 2013-02-12 07:28:48 | [diff] [blame] | 126 | |
isaacs | 035aa6b | 2013-02-13 18:48:55 | [diff] [blame] | 127 | var pct = ((n0 - n1) / n1 * 100).toFixed(2); |
isaacs | aa2edd4 | 2013-02-12 07:28:48 | [diff] [blame] | 128 | |
| 129 | var g = n0 > n1 ? green : ''; |
| 130 | var r = n0 > n1 ? '' : red; |
| 131 | var c = r || g; |
| 132 | |
| 133 | if (show === 'green' && !g || show === 'red' && !r) |
| 134 | return; |
| 135 | |
isaacs | db5d58e | 2013-03-06 20:32:59 | [diff] [blame^] | 136 | var r0 = util.format('%s%s: %d%s', g, nodes[0], n0, g ? reset : ''); |
| 137 | var r1 = util.format('%s%s: %d%s', r, nodes[1], n1, r ? reset : ''); |
isaacs | aa2edd4 | 2013-02-12 07:28:48 | [diff] [blame] | 138 | var pct = c + pct + '%' + reset; |
| 139 | var l = util.format('%s: %s %s', bench, r0, r1); |
| 140 | maxLen = Math.max(l.length + pct.length, maxLen); |
| 141 | return [l, pct]; |
| 142 | }).filter(function(l) { |
| 143 | return l; |
| 144 | }).forEach(function(line) { |
| 145 | var l = line[0]; |
| 146 | var pct = line[1]; |
| 147 | var dotLen = maxLen - l.length - pct.length + 2; |
| 148 | var dots = ' ' + new Array(Math.max(0, dotLen)).join('.') + ' '; |
| 149 | console.log(l + dots + pct); |
| 150 | }); |
isaacs | 087c437 | 2013-02-13 18:47:29 | [diff] [blame] | 151 | console.log(end); |
isaacs | aa2edd4 | 2013-02-12 07:28:48 | [diff] [blame] | 152 | } |
isaacs | db5d58e | 2013-03-06 20:32:59 | [diff] [blame^] | 153 | |
| 154 | function avg(list) { |
| 155 | if (list.length >= 3) { |
| 156 | list = list.sort(); |
| 157 | var q = Math.floor(list.length / 4) || 1; |
| 158 | list = list.slice(q, -q); |
| 159 | } |
| 160 | return (list.reduce(function(a, b) { |
| 161 | return a + b; |
| 162 | }, 0) / list.length).toPrecision(5); |
| 163 | } |