1 var assert = require('assert');
2 var path = require('path');
3 var silent = +process.env.NODE_BENCH_SILENT;
5 exports.PORT = process.env.PORT || 12346;
7 // If this is the main module, then run the benchmarks
8 if (module === require.main) {
9 var type = process.argv[2];
11 console.error('usage:\n ./node benchmark/common.js <type>');
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;
23 function runBenchmarks() {
24 var test = tests.shift();
28 if (test.match(/^[\._]/))
29 return process.nextTick(runBenchmarks);
31 console.error(type + '/' + test);
32 test = path.resolve(dir, test);
34 var a = (process.execArgv || []).concat(test);
35 var child = spawn(process.execPath, a, { stdio: 'inherit' });
36 child.on('close', function(code) {
46 exports.createBenchmark = function(fn, options) {
47 return new Benchmark(fn, options);
50 function Benchmark(fn, options) {
52 this.options = options;
53 this.config = parseOpts(options);
54 this._name = require.main.filename.split(/benchmark[\/\\]/).pop();
56 this._started = false;
58 process.nextTick(function() {
63 // benchmark an http server.
64 Benchmark.prototype.http = function(p, args, cb) {
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;
71 args = args.concat(url);
74 var child = spawn(wrk, args);
76 child.stdout.setEncoding('utf8');
78 child.stdout.on('data', function(chunk) {
82 child.on('close', function(code) {
87 console.error('wrk failed with ' + code);
90 var m = out.match(regexp);
93 console.error('%j', out);
94 console.error('wrk produced strange output');
101 Benchmark.prototype._run = function() {
103 return this.fn(this.config);
105 // one more more options weren't set.
106 // run with all combinations
107 var main = require.main.filename;
110 var options = this.options;
112 var queue = Object.keys(options).reduce(function(set, key) {
113 var vals = options[key];
114 assert(Array.isArray(vals));
116 // match each item in the set with each item in the list
117 var newSet = new Array(set.length * vals.length);
119 set.forEach(function(s) {
120 vals.forEach(function(val) {
121 newSet[j++] = s.concat(key + '=' + val);
127 var spawn = require('child_process').spawn;
128 var node = process.execPath;
131 var argv = queue[i++];
134 var child = spawn(node, argv, { stdio: 'inherit' });
135 child.on('close', function(code, signal) {
137 console.error('child process exited with code ' + code);
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;
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]])
156 conf[m[1]] = isFinite(m[2]) ? +m[2] : m[2]
160 // still go ahead and set whatever WAS set, if it was.
162 Object.keys(conf).forEach(function(k) {
163 options[k] = [conf[k]];
166 return num === 0 ? conf : null;
169 Benchmark.prototype.start = function() {
171 throw new Error('Called start more than once in a single benchmark');
172 this._started = true;
173 this._start = process.hrtime();
176 Benchmark.prototype.end = function(operations) {
177 var elapsed = process.hrtime(this._start);
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;
187 Benchmark.prototype.report = function(value) {
188 var heading = this.getHeading();
190 console.log('%s: %s', heading, value.toPrecision(5));
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];