1 var assert = require('assert');
2 var fs = require('fs');
3 var path = require('path');
4 var spawn = require('child_process').spawn;
6 var silent = +process.env.NODE_BENCH_SILENT;
8 exports.PORT = process.env.PORT || 12346;
10 // If this is the main module, then run the benchmarks
11 if (module === require.main) {
12 var type = process.argv[2];
13 var testFilter = process.argv[3];
15 console.error('usage:\n ./iojs benchmark/common.js <type> [testFilter]');
19 var dir = path.join(__dirname, type);
20 var tests = fs.readdirSync(dir);
23 var filteredTests = tests.filter(function(item){
24 if (item.lastIndexOf(testFilter) >= 0) {
29 if (filteredTests.length === 0) {
30 console.error('%s is not found in \n %j', testFilter, tests);
33 tests = filteredTests;
39 function runBenchmarks() {
40 var test = tests.shift();
44 if (test.match(/^[\._]/))
45 return process.nextTick(runBenchmarks);
47 console.error(type + '/' + test);
48 test = path.resolve(dir, test);
50 var a = (process.execArgv || []).concat(test);
51 var child = spawn(process.execPath, a, { stdio: 'inherit' });
52 child.on('close', function(code) {
62 exports.createBenchmark = function(fn, options) {
63 return new Benchmark(fn, options);
66 function Benchmark(fn, options) {
68 this.options = options;
69 this.config = parseOpts(options);
70 this._name = require.main.filename.split(/benchmark[\/\\]/).pop();
72 this._started = false;
74 process.nextTick(function() {
79 // benchmark an http server.
80 Benchmark.prototype.http = function(p, args, cb) {
82 var wrk = path.resolve(__dirname, '..', 'tools', 'wrk', 'wrk');
83 var regexp = /Requests\/sec:[ \t]+([0-9\.]+)/;
84 var url = 'http://127.0.0.1:' + exports.PORT + p;
86 args = args.concat(url);
89 var child = spawn(wrk, args);
91 child.stdout.setEncoding('utf8');
93 child.stdout.on('data', function(chunk) {
97 child.on('close', function(code) {
102 console.error('wrk failed with ' + code);
105 var match = out.match(regexp);
106 var qps = match && +match[1];
108 console.error('%j', out);
109 console.error('wrk produced strange output');
116 Benchmark.prototype._run = function() {
118 return this.fn(this.config);
120 // one more more options weren't set.
121 // run with all combinations
122 var main = require.main.filename;
125 var options = this.options;
127 var queue = Object.keys(options).reduce(function(set, key) {
128 var vals = options[key];
129 assert(Array.isArray(vals));
131 // match each item in the set with each item in the list
132 var newSet = new Array(set.length * vals.length);
134 set.forEach(function(s) {
135 vals.forEach(function(val) {
136 newSet[j++] = s.concat(key + '=' + val);
142 var node = process.execPath;
145 var argv = queue[i++];
148 argv = process.execArgv.concat(argv);
149 var child = spawn(node, argv, { stdio: 'inherit' });
150 child.on('close', function(code, signal) {
152 console.error('child process exited with code ' + code);
160 function parseOpts(options) {
161 // verify that there's an option provided for each of the options
162 // if they're not *all* specified, then we return null.
163 var keys = Object.keys(options);
164 var num = keys.length;
166 for (var i = 2; i < process.argv.length; i++) {
167 var match = process.argv[i].match(/^(.+)=(.+)$/);
168 if (!match || !match[1] || !match[2] || !options[match[1]]) {
171 conf[match[1]] = isFinite(match[2]) ? +match[2] : match[2]
175 // still go ahead and set whatever WAS set, if it was.
177 Object.keys(conf).forEach(function(k) {
178 options[k] = [conf[k]];
181 return num === 0 ? conf : null;
184 Benchmark.prototype.start = function() {
186 throw new Error('Called start more than once in a single benchmark');
188 this._started = true;
189 this._start = process.hrtime();
192 Benchmark.prototype.end = function(operations) {
193 var elapsed = process.hrtime(this._start);
196 throw new Error('called end without start');
197 if (typeof operations !== 'number')
198 throw new Error('called end() without specifying operation count');
200 var time = elapsed[0] + elapsed[1]/1e9;
201 var rate = operations/time;
205 Benchmark.prototype.report = function(value) {
206 var heading = this.getHeading();
208 console.log('%s: %s', heading, value.toFixed(5));
213 Benchmark.prototype.getHeading = function() {
214 var conf = this.config;
215 return this._name + ' ' + Object.keys(conf).map(function(key) {
216 return key + '=' + conf[key];