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