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