src: move debug agent from deps/ to src/
[platform/upstream/nodejs.git] / benchmark / common.js
1 var assert = require('assert');
2 var path = require('path');
3 var silent = +process.env.NODE_BENCH_SILENT;
4
5 exports.PORT = process.env.PORT || 12346;
6
7 // If this is the main module, then run the benchmarks
8 if (module === require.main) {
9   var type = process.argv[2];
10   if (!type) {
11     console.error('usage:\n ./node benchmark/common.js <type>');
12     process.exit(1);
13   }
14
15   var fs = require('fs');
16   var dir = path.join(__dirname, type);
17   var tests = fs.readdirSync(dir);
18   var spawn = require('child_process').spawn;
19
20   runBenchmarks();
21 }
22
23 function runBenchmarks() {
24   var test = tests.shift();
25   if (!test)
26     return;
27
28   if (test.match(/^[\._]/))
29     return process.nextTick(runBenchmarks);
30
31   console.error(type + '/' + test);
32   test = path.resolve(dir, test);
33
34   var a = (process.execArgv || []).concat(test);
35   var child = spawn(process.execPath, a, { stdio: 'inherit' });
36   child.on('close', function(code) {
37     if (code)
38       process.exit(code);
39     else {
40       console.log('');
41       runBenchmarks();
42     }
43   });
44 }
45
46 exports.createBenchmark = function(fn, options) {
47   return new Benchmark(fn, options);
48 };
49
50 function Benchmark(fn, options) {
51   this.fn = fn;
52   this.options = options;
53   this.config = parseOpts(options);
54   this._name = require.main.filename.split(/benchmark[\/\\]/).pop();
55   this._start = [0,0];
56   this._started = false;
57   var self = this;
58   process.nextTick(function() {
59     self._run();
60   });
61 }
62
63 // benchmark an http server.
64 Benchmark.prototype.http = function(p, args, cb) {
65   var self = this;
66   var wrk = path.resolve(__dirname, '..', 'tools', 'wrk', 'wrk');
67   var regexp = /Requests\/sec:[ \t]+([0-9\.]+)/;
68   var spawn = require('child_process').spawn;
69   var url = 'http://127.0.0.1:' + exports.PORT + p;
70
71   args = args.concat(url);
72
73   var out = '';
74   var child = spawn(wrk, args);
75
76   child.stdout.setEncoding('utf8');
77
78   child.stdout.on('data', function(chunk) {
79     out += chunk;
80   });
81
82   child.on('close', function(code) {
83     if (cb)
84       cb(code);
85
86     if (code) {
87       console.error('wrk failed with ' + code);
88       process.exit(code)
89     }
90     var m = out.match(regexp);
91     var qps = m && +m[1];
92     if (!qps) {
93       console.error('%j', out);
94       console.error('wrk produced strange output');
95       process.exit(1);
96     }
97     self.report(+qps);
98   });
99 };
100
101 Benchmark.prototype._run = function() {
102   if (this.config)
103     return this.fn(this.config);
104
105   // one more more options weren't set.
106   // run with all combinations
107   var main = require.main.filename;
108   var settings = [];
109   var queueLen = 1;
110   var options = this.options;
111
112   var queue = Object.keys(options).reduce(function(set, key) {
113     var vals = options[key];
114     assert(Array.isArray(vals));
115
116     // match each item in the set with each item in the list
117     var newSet = new Array(set.length * vals.length);
118     var j = 0;
119     set.forEach(function(s) {
120       vals.forEach(function(val) {
121         newSet[j++] = s.concat(key + '=' + val);
122       });
123     });
124     return newSet;
125   }, [[main]]);
126
127   var spawn = require('child_process').spawn;
128   var node = process.execPath;
129   var i = 0;
130   function run() {
131     var argv = queue[i++];
132     if (!argv)
133       return;
134     var child = spawn(node, argv, { stdio: 'inherit' });
135     child.on('close', function(code, signal) {
136       if (code)
137         console.error('child process exited with code ' + code);
138       else
139         run();
140     });
141   }
142   run();
143 };
144
145 function parseOpts(options) {
146   // verify that there's an option provided for each of the options
147   // if they're not *all* specified, then we return null.
148   var keys = Object.keys(options);
149   var num = keys.length;
150   var conf = {};
151   for (var i = 2; i < process.argv.length; i++) {
152     var m = process.argv[i].match(/^(.+)=(.+)$/);
153     if (!m || !m[1] || !m[2] || !options[m[1]])
154       return null;
155     else {
156       conf[m[1]] = isFinite(m[2]) ? +m[2] : m[2]
157       num--;
158     }
159   }
160   // still go ahead and set whatever WAS set, if it was.
161   if (num !== 0) {
162     Object.keys(conf).forEach(function(k) {
163       options[k] = [conf[k]];
164     });
165   }
166   return num === 0 ? conf : null;
167 };
168
169 Benchmark.prototype.start = function() {
170   if (this._started)
171     throw new Error('Called start more than once in a single benchmark');
172   this._started = true;
173   this._start = process.hrtime();
174 };
175
176 Benchmark.prototype.end = function(operations) {
177   var elapsed = process.hrtime(this._start);
178   if (!this._started)
179     throw new Error('called end without start');
180   if (typeof operations !== 'number')
181     throw new Error('called end() without specifying operation count');
182   var time = elapsed[0] + elapsed[1]/1e9;
183   var rate = operations/time;
184   this.report(rate);
185 };
186
187 Benchmark.prototype.report = function(value) {
188   var heading = this.getHeading();
189   if (!silent)
190     console.log('%s: %s', heading, value.toPrecision(5));
191   process.exit(0);
192 };
193
194 Benchmark.prototype.getHeading = function() {
195   var conf = this.config;
196   return this._name + ' ' + Object.keys(conf).map(function(key) {
197     return key + '=' + conf[key];
198   }).join(' ');
199 }