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 = {}; |
Trevor Norris | 31314b6 | 2013-03-20 08:58:11 | [diff] [blame] | 51 | var toggle = 1; |
| 52 | var r = (+process.env.NODE_BENCH_RUNS || 1) * 2; |
isaacs | aa2edd4 | 2013-02-12 07:28:48 | [diff] [blame] | 53 | |
| 54 | run(); |
isaacs | aa2edd4 | 2013-02-12 07:28:48 | [diff] [blame] | 55 | function run() { |
Trevor Norris | 31314b6 | 2013-03-20 08:58:11 | [diff] [blame] | 56 | if (--r < 0) |
isaacs | db5d58e | 2013-03-06 20:32:59 | [diff] [blame] | 57 | return compare(); |
Trevor Norris | 31314b6 | 2013-03-20 08:58:11 | [diff] [blame] | 58 | toggle = ++toggle % 2; |
isaacs | aa2edd4 | 2013-02-12 07:28:48 | [diff] [blame] | 59 | |
Trevor Norris | 31314b6 | 2013-03-20 08:58:11 | [diff] [blame] | 60 | var node = nodes[toggle]; |
isaacs | aa2edd4 | 2013-02-12 07:28:48 | [diff] [blame] | 61 | console.error('running %s', node); |
isaacs | db5d58e | 2013-03-06 20:32:59 | [diff] [blame] | 62 | var env = {}; |
isaacs | aa2edd4 | 2013-02-12 07:28:48 | [diff] [blame] | 63 | for (var i in process.env) |
| 64 | env[i] = process.env[i]; |
| 65 | env.NODE = node; |
isaacs | aa2edd4 | 2013-02-12 07:28:48 | [diff] [blame] | 66 | |
isaacs | db5d58e | 2013-03-06 20:32:59 | [diff] [blame] | 67 | var out = ''; |
Trevor Norris | 31314b6 | 2013-03-20 08:58:11 | [diff] [blame] | 68 | var child = spawn('make', [runBench], { env: env }); |
isaacs | db5d58e | 2013-03-06 20:32:59 | [diff] [blame] | 69 | child.stdout.setEncoding('utf8'); |
| 70 | child.stdout.on('data', function(c) { |
| 71 | out += c; |
| 72 | }); |
isaacs | aa2edd4 | 2013-02-12 07:28:48 | [diff] [blame] | 73 | |
| 74 | child.stderr.pipe(process.stderr); |
| 75 | |
isaacs | db5d58e | 2013-03-06 20:32:59 | [diff] [blame] | 76 | child.on('close', function(code) { |
| 77 | if (code) { |
| 78 | console.error('%s exited with code=%d', node, code); |
| 79 | process.exit(code); |
| 80 | } else { |
| 81 | out.trim().split(/\r?\n/).forEach(function(line) { |
isaacs | aa2edd4 | 2013-02-12 07:28:48 | [diff] [blame] | 82 | line = line.trim(); |
| 83 | if (!line) |
| 84 | return; |
| 85 | |
isaacs | db5d58e | 2013-03-06 20:32:59 | [diff] [blame] | 86 | var s = line.split(':'); |
| 87 | var num = +s.pop(); |
| 88 | if (!num && num !== 0) |
| 89 | return; |
isaacs | aa2edd4 | 2013-02-12 07:28:48 | [diff] [blame] | 90 | |
isaacs | db5d58e | 2013-03-06 20:32:59 | [diff] [blame] | 91 | line = s.join(':'); |
| 92 | var res = results[line] = results[line] || {}; |
| 93 | res[node] = res[node] || []; |
| 94 | res[node].push(num); |
| 95 | }); |
isaacs | aa2edd4 | 2013-02-12 07:28:48 | [diff] [blame] | 96 | |
isaacs | db5d58e | 2013-03-06 20:32:59 | [diff] [blame] | 97 | run(); |
| 98 | } |
| 99 | }); |
isaacs | aa2edd4 | 2013-02-12 07:28:48 | [diff] [blame] | 100 | } |
| 101 | |
| 102 | function compare() { |
isaacs | db5d58e | 2013-03-06 20:32:59 | [diff] [blame] | 103 | // each result is an object with {"foo.js arg=bar":12345,...} |
| 104 | // compare each thing, and show which node did the best. |
isaacs | aa2edd4 | 2013-02-12 07:28:48 | [diff] [blame] | 105 | // node[0] is shown in green, node[1] shown in red. |
isaacs | aa2edd4 | 2013-02-12 07:28:48 | [diff] [blame] | 106 | var maxLen = -Infinity; |
| 107 | var util = require('util'); |
isaacs | 087c437 | 2013-02-13 18:47:29 | [diff] [blame] | 108 | console.log(start); |
| 109 | |
isaacs | db5d58e | 2013-03-06 20:32:59 | [diff] [blame] | 110 | Object.keys(results).map(function(bench) { |
isaacs | aa2edd4 | 2013-02-12 07:28:48 | [diff] [blame] | 111 | var res = results[bench]; |
isaacs | db5d58e | 2013-03-06 20:32:59 | [diff] [blame] | 112 | var n0 = avg(res[nodes[0]]); |
| 113 | var n1 = avg(res[nodes[1]]); |
isaacs | aa2edd4 | 2013-02-12 07:28:48 | [diff] [blame] | 114 | |
isaacs | 035aa6b | 2013-02-13 18:48:55 | [diff] [blame] | 115 | var pct = ((n0 - n1) / n1 * 100).toFixed(2); |
isaacs | aa2edd4 | 2013-02-12 07:28:48 | [diff] [blame] | 116 | |
| 117 | var g = n0 > n1 ? green : ''; |
| 118 | var r = n0 > n1 ? '' : red; |
| 119 | var c = r || g; |
| 120 | |
| 121 | if (show === 'green' && !g || show === 'red' && !r) |
| 122 | return; |
| 123 | |
isaacs | e7b8bad | 2013-03-07 19:56:53 | [diff] [blame] | 124 | var r0 = util.format('%s%s: %d%s', g, nodes[0], n0.toPrecision(5), g ? reset : ''); |
| 125 | var r1 = util.format('%s%s: %d%s', r, nodes[1], n1.toPrecision(5), r ? reset : ''); |
isaacs | aa2edd4 | 2013-02-12 07:28:48 | [diff] [blame] | 126 | var pct = c + pct + '%' + reset; |
| 127 | var l = util.format('%s: %s %s', bench, r0, r1); |
| 128 | maxLen = Math.max(l.length + pct.length, maxLen); |
| 129 | return [l, pct]; |
| 130 | }).filter(function(l) { |
| 131 | return l; |
| 132 | }).forEach(function(line) { |
| 133 | var l = line[0]; |
| 134 | var pct = line[1]; |
| 135 | var dotLen = maxLen - l.length - pct.length + 2; |
| 136 | var dots = ' ' + new Array(Math.max(0, dotLen)).join('.') + ' '; |
| 137 | console.log(l + dots + pct); |
| 138 | }); |
isaacs | 087c437 | 2013-02-13 18:47:29 | [diff] [blame] | 139 | console.log(end); |
isaacs | aa2edd4 | 2013-02-12 07:28:48 | [diff] [blame] | 140 | } |
isaacs | db5d58e | 2013-03-06 20:32:59 | [diff] [blame] | 141 | |
| 142 | function avg(list) { |
| 143 | if (list.length >= 3) { |
| 144 | list = list.sort(); |
| 145 | var q = Math.floor(list.length / 4) || 1; |
| 146 | list = list.slice(q, -q); |
| 147 | } |
isaacs | e7b8bad | 2013-03-07 19:56:53 | [diff] [blame] | 148 | return list.reduce(function(a, b) { |
isaacs | db5d58e | 2013-03-06 20:32:59 | [diff] [blame] | 149 | return a + b; |
isaacs | e7b8bad | 2013-03-07 19:56:53 | [diff] [blame] | 150 | }, 0) / list.length; |
isaacs | db5d58e | 2013-03-06 20:32:59 | [diff] [blame] | 151 | } |