Skip to content

Commit

Permalink
Merge branch 'feature/batch'
Browse files Browse the repository at this point in the history
* feature/batch: (25 commits)
  update travis to run node v0.10
  add support for `before` and `run`
  handle comparisons in the CLI
  add simple test for the comparison class
  update comparison examples
  seperate features designed for making comparions into a seperate class
  pull out the lambda
  setImmediate instead of nextTick for node v0.10.x
  add --reporters flag to cli
  add support for loading implementations from the cli
  rm fixed widths in table reporter
  add suport for loading several implementations in one benchmark with batch.load()
  add request suite example
  stop catching load bench load errors
  improve number formating in table reporter
  add support for passing args to the bench process
  add a cli for running batches
  add basic title to table reporters output
  clean up example
  ensure child processes are cleaned up
  ...
  • Loading branch information
jkroso committed May 14, 2013
2 parents ac97096 + d52e151 commit 8c21b9c
Show file tree
Hide file tree
Showing 35 changed files with 1,100 additions and 77 deletions.
2 changes: 1 addition & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
language: node_js
node_js:
- 0.8
- 0.10
1 change: 1 addition & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ REPORTER = dot
test:
@NODE_ENV=test ./node_modules/.bin/mocha \
--reporter $(REPORTER) \
--bail \
$(TESTS)

.PHONY: test
153 changes: 153 additions & 0 deletions bin/bench
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
#!/usr/bin/env node

var program = require('commander')
, path = require('path')
, join = path.join
, basename = path.basename
, resolve = path.resolve
, fs = require('fs')
, Batch = require('../lib/batch')
, Comparison = require('../lib/comparison')
, Promise = require('laissez-faire/full')

program.version(require('../package').version)
.usage('[options] [files]')
.option('-n, --name <name>', 'benchmark title')
.option('-r, --recursive', 'include files in sub directories')
.option('-R, --reporter <name>', 'specify the reporter to use [table]', 'table')
.option('-c, --cycles <number>', 'times to execute each benchmark [1000]', 1000)
.option('-i, --implementations <files...>', 'modules to load into each benchmark', list)
.option('-k, --key <name>', 'global variable where benchmarks expect to find an implementation', 'implementation')
.option('--reporters', 'list the available reporters')

program.on('--help', function () {
write(' Examples: \n')
write('\n')
write(' # batch of all files in a directory\n')
write(' $ bench examples/file-benches\n')
write('\n')
})

program.on('reporters', function(){
var path = resolve(__dirname, '../lib/reporters')
write('\n')
fs.readdirSync(path).forEach(function(name){
write(' ' + name.replace(/\.js$/, '') + '\n')
})
write('\n')
process.exit()
})

// guess the current projects name

function project(){
var cwd = process.cwd()
if (fs.existsSync(cwd+'/.git')) return basename(cwd)
return ''
}

function list(args){
return args.split(',')
}

function write(txt){
process.stdout.write(txt)
}

program.parse(process.argv)

var args = program.args

// default search path to bench/*.js

if (!args.length) args.push('bench')

// absolutize

args = args.map(function(name){ return resolve(name) })

// match files

var files = args.reduce(function(files, path){
return files.concat(lookupFiles(path, program.recursive))
}, [])

if (!files.length) throw new Error('no files found')

// Lookup file names at the given `path`.

function lookupFiles(path, recursive) {
var files = []

if (!fs.existsSync(path)) path += '.js'
var stat = fs.statSync(path)
if (stat.isFile()) return path

fs.readdirSync(path)
.filter(function(name){
return name[0] != '.'
})
.forEach(function(file){
file = join(path, file)
var stat = fs.statSync(file)
if (stat.isDirectory()) {
if (recursive) files = files.concat(lookupFiles(file, recursive))
} else if (stat.isFile()) {
if (/\.js$/.test(file)) files.push(file)
}
})

return files
}

// --name

if (!program.name) {
if (files.length == 1) program.name = basename(files[0])
else program.name = project()
}

var imps = program.implementations

// comparison
if (imps) {
// expand paths
imps = imps.map(function(name){ return resolve(name) })
// look for existing files
imps = imps.reduce(function(files, path){
return files.concat(lookupFiles(path, false))
}, [])
if (!imps.length) throw new Error('no implementations found')

// sequence all benchmarks
files.reduce(function(job, next){
return job.then(function(){
var name = basename(next).replace(/\.js/, '')
var batch = new Comparison(name, next)

// --key
batch.as(program.key)

// --reporter
batch.reporter(program.reporter)

imps.forEach(function(file){
batch.addFile(file)
})

return batch.run(program.cycles)
})
}, Promise.fulfilled())
}
// plain batch
else {
var batch = new Batch(program.name)

files.forEach(function(path){
batch.addFile(path)
})

batch.reporter(program.reporter)

batch.run(program.cycles)
}
4 changes: 4 additions & 0 deletions examples/compare/bench.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@

module.exports = function(i, done){
defer(done)
}
5 changes: 5 additions & 0 deletions examples/compare/implementations/process.nextTick.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
var nt = process.nextTick

module.exports = function(done){
nt(done)
}
4 changes: 4 additions & 0 deletions examples/compare/implementations/setImmediate.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@

module.exports = function(done){
setImmediate(done)
}
4 changes: 4 additions & 0 deletions examples/compare/implementations/setTimeout.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@

module.exports = function(done){
setTimeout(done, 0)
}
27 changes: 27 additions & 0 deletions examples/compare/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@

/**
* this benchmark can also be run with the following command
* though you can't set the name of a comparison benchmark
* from the CLI
*
* $ bench examples/compare/bench.js \
* -i examples/compare/implementations \
* -k defer
*/

var Comparison = require('../../lib/comparison')
, fs = require('fs')

var file = __dirname + '/bench.js'
var imps = fs.readdirSync(__dirname+'/implementations')

var batch = new Comparison('defer execution', file)
.reporter('table')
.as('defer')

imps.forEach(function(name){
var path = __dirname + '/implementations/' + name
batch.addFile(path)
})

batch.run(1000)
4 changes: 4 additions & 0 deletions examples/file-benches/async.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@

module.exports = function(i, done){
setTimeout(done, 10)
}
5 changes: 5 additions & 0 deletions examples/file-benches/sync.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@

module.exports = function(i){
var start = Date.now()
while (Date.now() - start < 10);
}
34 changes: 31 additions & 3 deletions examples/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,42 @@ var b = require('../');
* Synchronous
*/

b('Synchronous benchmark').run(100, function() {
b('Synchronous benchmark', function() {
for (var i = 0, len = 1000000; ++i < len;) {}
});
}).run(100);

/**
* Asynchronous
*/

b('Asynchronous benchmark').run(10, function(i, done) {
b('Asynchronous benchmark', function(i, done) {
setTimeout(done, 10);
})
.run(10)
.then(function(){
return batch.run(10);
})
.then(function(){
return files.run(10);
})
.then(function(){
require('./compare');
});

/**
* in process batch
*/

var batch = b('same process batch')
.add('sync', require('./file-benches/sync'))
.add('async', require('./file-benches/async'));

var dir = __dirname + '/file-benches';

/**
* seperate process batch
*/

var files = b('seperate process batch')
.add('sync', dir + '/sync.js')
.add('async', dir + '/async.js');
11 changes: 11 additions & 0 deletions examples/suite/implementations/.cert.pem
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
-----BEGIN CERTIFICATE-----
MIIBhDCCAS4CCQC1Ju2HL3ek5DANBgkqhkiG9w0BAQUFADBJMQswCQYDVQQGEwJB
VTENMAsGA1UECBMERkFLRTENMAsGA1UEBxMERkFLRTENMAsGA1UEChMERkFLRTEN
MAsGA1UEAxMERkFLRTAeFw0xMzA1MDgwMTU0MzhaFw00MDA5MjIwMTU0MzhaMEkx
CzAJBgNVBAYTAkFVMQ0wCwYDVQQIEwRGQUtFMQ0wCwYDVQQHEwRGQUtFMQ0wCwYD
VQQKEwRGQUtFMQ0wCwYDVQQDEwRGQUtFMFwwDQYJKoZIhvcNAQEBBQADSwAwSAJB
AJ2xKCDLQPhBxuyJm3YJu2xZTyjtm0v/zXIR/Ne5U+Qsm5gP1uJ/npWTVWUHWj5N
E7uipBze/Tq4vBw0v18QjWECAwEAATANBgkqhkiG9w0BAQUFAANBAAFTrpQ2XZBE
os5mec3y+v4CT/s5m8iHRGw9q9Dkmw0+ruMJ0J5txe28hYJzQ5LOXttxubVLSmQr
cs7O65on/1w=
-----END CERTIFICATE-----
9 changes: 9 additions & 0 deletions examples/suite/implementations/.key.pem
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
-----BEGIN RSA PRIVATE KEY-----
MIIBOQIBAAJBAJ2xKCDLQPhBxuyJm3YJu2xZTyjtm0v/zXIR/Ne5U+Qsm5gP1uJ/
npWTVWUHWj5NE7uipBze/Tq4vBw0v18QjWECAwEAAQJAV6RGcTOGAHROYth4FrqB
+E4KuOyWCz84p9VneV3/SijBJDaju0WVnqF1ZoYooSqsgKIf9YSPtut3dHaNLnSN
oQIhANHlvu8yrkrdhQiNHlhH5MkHpXAXV8qrUecU9Kia/buTAiEAwFP4H55vNIou
bvkdeRyP5EqEevtuiI//cVbE1Bok87sCIBDyFm8jTVT3+2SMWBXSgBMGzgF1sP3I
xQz98R6nnLKHAiALEQnW7+vgLw9K7WSnwl/5N9x1oyASFY8SO3bp6XM03wIgbjCL
Q5XnTuOodgrYmOmb5keq4pdIDaqetKdMODqAxxc=
-----END RSA PRIVATE KEY-----
12 changes: 12 additions & 0 deletions examples/suite/implementations/http.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@

var http = require('http')
, fs = require('fs')
, resolve = require('path').resolve

var file = resolve(__dirname, '../../../Readme.md')

http.createServer(function(req, res){
fs.createReadStream(file).pipe(res)
}).listen(3001)

module.exports = http.request
15 changes: 15 additions & 0 deletions examples/suite/implementations/https.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@

var https = require('https')
, fs = require('fs')
, resolve = require('path').resolve

var file = resolve(__dirname, '../../../Readme.md')

https.createServer({
key: fs.readFileSync(__dirname+'/.key.pem'),
cert: fs.readFileSync(__dirname+'/.cert.pem')
}, function(req, res){
fs.createReadStream(file).pipe(res)
}).listen(4001)

module.exports = https.request
18 changes: 18 additions & 0 deletions examples/suite/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@

/**
* This batch is equivilent to the cli command
*
* $ bench examples/suite/request.js \
* --key request \
* --implementations examples/suite/implementations \
* --cycles 100
*/

var Comparison = require('../../lib/comparison')

var batch = new Comparison('requests', __dirname + '/request.js')
.as('request')
.addFile(__dirname + '/implementations/http.js')
.addFile(__dirname + '/implementations/https.js')
.reporter('table')
.run(1e2)
31 changes: 31 additions & 0 deletions examples/suite/request.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
var http = require('http')
, https = require('https')

var request = global.request

var port = request === http.request
? 3001
: 4001

/**
* how long does it take to download and buffer
* the same request using https vs http
*/

module.exports = function(i, done){
request({
hostname: 'localhost',
port: port,
method: 'GET',
agent:false,
rejectUnauthorized: false
}, function(res) {
res.setEncoding('utf8')
res.on('readable', function () {
res.read()
})
res.on('end', done)
}).on('error', function(e) {
throw e
}).end()
}
Loading

0 comments on commit 8c21b9c

Please sign in to comment.