From e82f97401f9d7c54155b52b310f1893e45205c46 Mon Sep 17 00:00:00 2001 From: isaacs Date: Thu, 7 Feb 2013 19:13:26 -0800 Subject: bench: net benchmarks using common script --- benchmark/net/net-c2s.js | 112 +++++++++++++++++++++++++++++++ benchmark/net/net-pipe.js | 131 +++++++++++++++++++------------------ benchmark/net/net-s2c.js | 112 +++++++++++++++++++++++++++++++ benchmark/net/tcp-raw-c2s.js | 136 ++++++++++++++++++++++++++++++++++++++ benchmark/net/tcp-raw-pipe.js | 149 ++++++++++++++++++++++++++++++++++++++++++ benchmark/net/tcp-raw-s2c.js | 136 ++++++++++++++++++++++++++++++++++++++ 6 files changed, 711 insertions(+), 65 deletions(-) create mode 100644 benchmark/net/net-c2s.js create mode 100644 benchmark/net/net-s2c.js create mode 100644 benchmark/net/tcp-raw-c2s.js create mode 100644 benchmark/net/tcp-raw-pipe.js create mode 100644 benchmark/net/tcp-raw-s2c.js (limited to 'benchmark/net') diff --git a/benchmark/net/net-c2s.js b/benchmark/net/net-c2s.js new file mode 100644 index 0000000000..0467643f3a --- /dev/null +++ b/benchmark/net/net-c2s.js @@ -0,0 +1,112 @@ +// test the speed of .pipe() with sockets + +var common = require('../common.js'); +var PORT = common.PORT; + +var bench = common.createBenchmark(main, { + len: [102400, 1024 * 1024 * 16], + type: ['utf', 'asc', 'buf'], + dur: [1, 3], +}); + +var dur; +var len; +var type; +var chunk; +var encoding; + +function main(conf) { + dur = +conf.dur; + len = +conf.len; + type = conf.type; + + switch (type) { + case 'buf': + chunk = new Buffer(len); + chunk.fill('x'); + break; + case 'utf': + encoding = 'utf8'; + chunk = new Array(len / 2 + 1).join('ü'); + break; + case 'asc': + encoding = 'ascii'; + chunk = new Array(len + 1).join('x'); + break; + default: + throw new Error('invalid type: ' + type); + break; + } + + server(); +} + +var net = require('net'); + +function Writer() { + this.received = 0; + this.writable = true; +} + +Writer.prototype.write = function(chunk, encoding, cb) { + this.received += chunk.length; + + if (typeof encoding === 'function') + encoding(); + else if (typeof cb === 'function') + cb(); + + return true; +}; + +// doesn't matter, never emits anything. +Writer.prototype.on = function() {}; +Writer.prototype.once = function() {}; +Writer.prototype.emit = function() {}; + + +function Reader() { + this.flow = this.flow.bind(this); + this.readable = true; +} + +Reader.prototype.pipe = function(dest) { + this.dest = dest; + this.flow(); + return dest; +}; + +Reader.prototype.flow = function() { + var dest = this.dest; + var res = dest.write(chunk, encoding); + if (!res) + dest.once('drain', this.flow); + else + process.nextTick(this.flow); +}; + + +function server() { + var reader = new Reader(); + var writer = new Writer(); + + // the actual benchmark. + var server = net.createServer(function(socket) { + socket.pipe(writer); + }); + + server.listen(PORT, function() { + var socket = net.connect(PORT); + socket.on('connect', function() { + bench.start(); + + reader.pipe(socket); + + setTimeout(function() { + var bytes = writer.received; + var gbits = (bytes * 8) / (1024 * 1024 * 1024); + bench.end(gbits); + }, dur * 1000); + }); + }); +} diff --git a/benchmark/net/net-pipe.js b/benchmark/net/net-pipe.js index e981cc3b4e..d3908e8439 100644 --- a/benchmark/net/net-pipe.js +++ b/benchmark/net/net-pipe.js @@ -1,21 +1,54 @@ // test the speed of .pipe() with sockets +var common = require('../common.js'); +var PORT = common.PORT; + +var bench = common.createBenchmark(main, { + len: [102400, 1024 * 1024 * 16], + type: ['utf', 'asc', 'buf'], + dur: [1, 3], +}); + +var dur; +var len; +var type; +var chunk; +var encoding; + +function main(conf) { + dur = +conf.dur; + len = +conf.len; + type = conf.type; + + switch (type) { + case 'buf': + chunk = new Buffer(len); + chunk.fill('x'); + break; + case 'utf': + encoding = 'utf8'; + chunk = new Array(len / 2 + 1).join('ü'); + break; + case 'asc': + encoding = 'ascii'; + chunk = new Array(len + 1).join('x'); + break; + default: + throw new Error('invalid type: ' + type); + break; + } + + server(); +} + var net = require('net'); -var N = parseInt(process.argv[2]) || 100; -var start; function Writer() { - this.start = null; this.received = 0; this.writable = true; - this.printStats = this.printStats.bind(this); - this.interval = setInterval(this.printStats, 1000); } Writer.prototype.write = function(chunk, encoding, cb) { - if (!this.start) - this.start = process.hrtime(); - this.received += chunk.length; if (typeof encoding === 'function') @@ -31,49 +64,6 @@ Writer.prototype.on = function() {}; Writer.prototype.once = function() {}; Writer.prototype.emit = function() {}; -var rates = []; -var statCounter = 0; -Writer.prototype.printStats = function() { - if (!this.start || !this.received) - return; - var elapsed = process.hrtime(this.start); - elapsed = elapsed[0] * 1E9 + elapsed[1]; - var bits = this.received * 8; - var gbits = bits / (1024 * 1024 * 1024); - var rate = gbits / elapsed * 1E9; - rates.push(rate); - console.log('%s Gbits/sec (%d bits / %d ns)', rate.toFixed(4), bits, elapsed); - - // reset to keep getting instant time. - this.start = process.hrtime(); - this.received = 0; - - if (++statCounter === N) { - report(); - process.exit(0); - } -}; - -function report() { - rates.sort(); - var min = rates[0]; - var max = rates[rates.length - 1]; - var median = rates[rates.length >> 1]; - var avg = 0; - rates.forEach(function(rate) { avg += rate }); - avg /= rates.length; - console.error('min:%s avg:%s max:%s median:%s', - min.toFixed(2), - avg.toFixed(2), - max.toFixed(2), - median.toFixed(2)); -} - -var len = process.env.LENGTH || 16 * 1024 * 1024; -var chunk = new Buffer(len); -for (var i = 0; i < len; i++) { - chunk[i] = i % 256; -} function Reader() { this.flow = this.flow.bind(this); @@ -88,7 +78,7 @@ Reader.prototype.pipe = function(dest) { Reader.prototype.flow = function() { var dest = this.dest; - var res = dest.write(chunk); + var res = dest.write(chunk, encoding); if (!res) dest.once('drain', this.flow); else @@ -96,19 +86,30 @@ Reader.prototype.flow = function() { }; -var reader = new Reader(); -var writer = new Writer(); +function server() { + var reader = new Reader(); + var writer = new Writer(); -// the actual benchmark. -var server = net.createServer(function(socket) { - socket.pipe(socket); -}); - -server.listen(1337, function() { - var socket = net.connect(1337); - socket.on('connect', function() { - reader.pipe(socket); - socket.pipe(writer); + // the actual benchmark. + var server = net.createServer(function(socket) { + socket.pipe(socket); }); -}); + server.listen(PORT, function() { + var socket = net.connect(PORT); + socket.on('connect', function() { + bench.start(); + + reader.pipe(socket); + socket.pipe(writer); + + setTimeout(function() { + // multiply by 2 since we're sending it first one way + // then then back again. + var bytes = writer.received * 2; + var gbits = (bytes * 8) / (1024 * 1024 * 1024); + bench.end(gbits); + }, dur * 1000); + }); + }); +} diff --git a/benchmark/net/net-s2c.js b/benchmark/net/net-s2c.js new file mode 100644 index 0000000000..96cb67d242 --- /dev/null +++ b/benchmark/net/net-s2c.js @@ -0,0 +1,112 @@ +// test the speed of .pipe() with sockets + +var common = require('../common.js'); +var PORT = common.PORT; + +var bench = common.createBenchmark(main, { + len: [102400, 1024 * 1024 * 16], + type: ['utf', 'asc', 'buf'], + dur: [1, 3], +}); + +var dur; +var len; +var type; +var chunk; +var encoding; + +function main(conf) { + dur = +conf.dur; + len = +conf.len; + type = conf.type; + + switch (type) { + case 'buf': + chunk = new Buffer(len); + chunk.fill('x'); + break; + case 'utf': + encoding = 'utf8'; + chunk = new Array(len / 2 + 1).join('ü'); + break; + case 'asc': + encoding = 'ascii'; + chunk = new Array(len + 1).join('x'); + break; + default: + throw new Error('invalid type: ' + type); + break; + } + + server(); +} + +var net = require('net'); + +function Writer() { + this.received = 0; + this.writable = true; +} + +Writer.prototype.write = function(chunk, encoding, cb) { + this.received += chunk.length; + + if (typeof encoding === 'function') + encoding(); + else if (typeof cb === 'function') + cb(); + + return true; +}; + +// doesn't matter, never emits anything. +Writer.prototype.on = function() {}; +Writer.prototype.once = function() {}; +Writer.prototype.emit = function() {}; + + +function Reader() { + this.flow = this.flow.bind(this); + this.readable = true; +} + +Reader.prototype.pipe = function(dest) { + this.dest = dest; + this.flow(); + return dest; +}; + +Reader.prototype.flow = function() { + var dest = this.dest; + var res = dest.write(chunk, encoding); + if (!res) + dest.once('drain', this.flow); + else + process.nextTick(this.flow); +}; + + +function server() { + var reader = new Reader(); + var writer = new Writer(); + + // the actual benchmark. + var server = net.createServer(function(socket) { + reader.pipe(socket); + }); + + server.listen(PORT, function() { + var socket = net.connect(PORT); + socket.on('connect', function() { + bench.start(); + + socket.pipe(writer); + + setTimeout(function() { + var bytes = writer.received; + var gbits = (bytes * 8) / (1024 * 1024 * 1024); + bench.end(gbits); + }, dur * 1000); + }); + }); +} diff --git a/benchmark/net/tcp-raw-c2s.js b/benchmark/net/tcp-raw-c2s.js new file mode 100644 index 0000000000..2664e25fe0 --- /dev/null +++ b/benchmark/net/tcp-raw-c2s.js @@ -0,0 +1,136 @@ +// In this benchmark, we connect a client to the server, and write +// as many bytes as we can in the specified time (default = 10s) + +var common = require('../common.js'); + +// if there are --dur=N and --len=N args, then +// run the function with those settings. +// if not, then queue up a bunch of child processes. +var bench = common.createBenchmark(main, { + len: [102400, 1024 * 1024 * 16], + type: ['utf', 'asc', 'buf'], + dur: [1, 3], +}); + +var TCP = process.binding('tcp_wrap').TCP; +var PORT = common.PORT; + +var dur; +var len; +var type; + +function main(conf) { + dur = +conf.dur; + len = +conf.len; + type = conf.type; + server(); +} + + +function fail(syscall) { + var e = new Error(syscall + ' ' + errno); + e.errno = e.code = errno; + e.syscall = syscall; + throw e; +} + +function server() { + var serverHandle = new TCP(); + var r = serverHandle.bind('127.0.0.1', PORT); + if (r) + fail('bind'); + + var r = serverHandle.listen(511); + if (r) + fail('listen'); + + serverHandle.onconnection = function(clientHandle) { + if (!clientHandle) + fail('connect'); + + // the meat of the benchmark is right here: + bench.start(); + var bytes = 0; + + setTimeout(function() { + // report in Gb/sec + bench.end((bytes * 8) / (1024 * 1024 * 1024)); + }, dur * 1000); + + clientHandle.onread = function(buffer, offset, length) { + // we're not expecting to ever get an EOF from the client. + // just lots of data forever. + if (!buffer) + fail('read'); + + // don't slice the buffer. the point of this is to isolate, not + // simulate real traffic. + // var chunk = buffer.slice(offset, offset + length); + bytes += length; + }; + + clientHandle.readStart(); + }; + + client(); +} + +function client() { + var chunk; + switch (type) { + case 'buf': + chunk = new Buffer(len); + chunk.fill('x'); + break; + case 'utf': + chunk = new Array(len / 2 + 1).join('ü'); + break; + case 'asc': + chunk = new Array(len + 1).join('x'); + break; + default: + throw new Error('invalid type: ' + type); + break; + } + + var clientHandle = new TCP(); + var connectReq = clientHandle.connect('127.0.0.1', PORT); + + if (!connectReq) + fail('connect'); + + clientHandle.readStart(); + + connectReq.oncomplete = function() { + while (clientHandle.writeQueueSize === 0) + write(); + }; + + function write() { + var writeReq + switch (type) { + case 'buf': + writeReq = clientHandle.writeBuffer(chunk); + break; + case 'utf': + writeReq = clientHandle.writeUtf8String(chunk); + break; + case 'asc': + writeReq = clientHandle.writeAsciiString(chunk); + break; + } + + if (!writeReq) + fail('write'); + + writeReq.oncomplete = afterWrite; + } + + function afterWrite(status, handle, req) { + if (status) + fail('write'); + + while (clientHandle.writeQueueSize === 0) + write(); + } +} diff --git a/benchmark/net/tcp-raw-pipe.js b/benchmark/net/tcp-raw-pipe.js new file mode 100644 index 0000000000..d55c2c5d7e --- /dev/null +++ b/benchmark/net/tcp-raw-pipe.js @@ -0,0 +1,149 @@ +// In this benchmark, we connect a client to the server, and write +// as many bytes as we can in the specified time (default = 10s) + +var common = require('../common.js'); + +// if there are --dur=N and --len=N args, then +// run the function with those settings. +// if not, then queue up a bunch of child processes. +var bench = common.createBenchmark(main, { + len: [102400, 1024 * 1024 * 16], + type: ['utf', 'asc', 'buf'], + dur: [1, 3], +}); + +var TCP = process.binding('tcp_wrap').TCP; +var PORT = common.PORT; + +var dur; +var len; +var type; + +function main(conf) { + dur = +conf.dur; + len = +conf.len; + type = conf.type; + server(); +} + + +function fail(syscall) { + var e = new Error(syscall + ' ' + errno); + e.errno = e.code = errno; + e.syscall = syscall; + throw e; +} + +function server() { + var serverHandle = new TCP(); + var r = serverHandle.bind('127.0.0.1', PORT); + if (r) + fail('bind'); + + var r = serverHandle.listen(511); + if (r) + fail('listen'); + + serverHandle.onconnection = function(clientHandle) { + if (!clientHandle) + fail('connect'); + + clientHandle.onread = function(buffer, offset, length) { + // we're not expecting to ever get an EOF from the client. + // just lots of data forever. + if (!buffer) + fail('read'); + + var chunk = buffer.slice(offset, offset + length); + var writeReq = clientHandle.writeBuffer(chunk); + + if (!writeReq) + fail('write'); + + writeReq.oncomplete = function(status, handle, req) { + if (status) + fail('write'); + }; + }; + + clientHandle.readStart(); + }; + + client(); +} + +function client() { + var chunk; + switch (type) { + case 'buf': + chunk = new Buffer(len); + chunk.fill('x'); + break; + case 'utf': + chunk = new Array(len / 2 + 1).join('ü'); + break; + case 'asc': + chunk = new Array(len + 1).join('x'); + break; + default: + throw new Error('invalid type: ' + type); + break; + } + + var clientHandle = new TCP(); + var connectReq = clientHandle.connect('127.0.0.1', PORT); + var bytes = 0; + + if (!connectReq) + fail('connect'); + + clientHandle.readStart(); + + clientHandle.onread = function(buffer, start, length) { + if (!buffer) + fail('read'); + + bytes += length; + }; + + connectReq.oncomplete = function() { + bench.start(); + + setTimeout(function() { + // multiply by 2 since we're sending it first one way + // then then back again. + bench.end(2 * (bytes * 8) / (1024 * 1024 * 1024)); + }, dur * 1000); + + while (clientHandle.writeQueueSize === 0) + write(); + }; + + function write() { + var writeReq + switch (type) { + case 'buf': + writeReq = clientHandle.writeBuffer(chunk); + break; + case 'utf': + writeReq = clientHandle.writeUtf8String(chunk); + break; + case 'asc': + writeReq = clientHandle.writeAsciiString(chunk); + break; + } + + if (!writeReq) + fail('write'); + + writeReq.oncomplete = afterWrite; + } + + function afterWrite(status, handle, req) { + if (status) + fail('write'); + + while (clientHandle.writeQueueSize === 0) + write(); + } +} diff --git a/benchmark/net/tcp-raw-s2c.js b/benchmark/net/tcp-raw-s2c.js new file mode 100644 index 0000000000..94a90f29de --- /dev/null +++ b/benchmark/net/tcp-raw-s2c.js @@ -0,0 +1,136 @@ +// In this benchmark, we connect a client to the server, and write +// as many bytes as we can in the specified time (default = 10s) + +var common = require('../common.js'); + +// if there are dur=N and len=N args, then +// run the function with those settings. +// if not, then queue up a bunch of child processes. +var bench = common.createBenchmark(main, { + len: [102400, 1024 * 1024 * 16], + type: ['utf', 'asc', 'buf'], + dur: [1, 3], +}); + +var TCP = process.binding('tcp_wrap').TCP; +var PORT = common.PORT; + +var dur; +var len; +var type; + +function main(conf) { + dur = +conf.dur; + len = +conf.len; + type = conf.type; + server(); +} + + +function fail(syscall) { + var e = new Error(syscall + ' ' + errno); + e.errno = e.code = errno; + e.syscall = syscall; + throw e; +} + +function server() { + var serverHandle = new TCP(); + var r = serverHandle.bind('127.0.0.1', PORT); + if (r) + fail('bind'); + + var r = serverHandle.listen(511); + if (r) + fail('listen'); + + serverHandle.onconnection = function(clientHandle) { + if (!clientHandle) + fail('connect'); + + var chunk; + switch (type) { + case 'buf': + chunk = new Buffer(len); + chunk.fill('x'); + break; + case 'utf': + chunk = new Array(len / 2 + 1).join('ü'); + break; + case 'asc': + chunk = new Array(len + 1).join('x'); + break; + default: + throw new Error('invalid type: ' + type); + break; + } + + clientHandle.readStart(); + + while (clientHandle.writeQueueSize === 0) + write(); + + function write() { + var writeReq + switch (type) { + case 'buf': + writeReq = clientHandle.writeBuffer(chunk); + break; + case 'utf': + writeReq = clientHandle.writeUtf8String(chunk); + break; + case 'asc': + writeReq = clientHandle.writeAsciiString(chunk); + break; + } + + if (!writeReq) + fail('write'); + + writeReq.oncomplete = afterWrite; + } + + function afterWrite(status, handle, req) { + if (status) + fail('write'); + + while (clientHandle.writeQueueSize === 0) + write(); + } + }; + + client(); +} + +function client() { + var clientHandle = new TCP(); + var connectReq = clientHandle.connect('127.0.0.1', PORT); + + if (!connectReq) + fail('connect'); + + connectReq.oncomplete = function() { + var bytes = 0; + clientHandle.onread = function(buffer, offset, length) { + // we're not expecting to ever get an EOF from the client. + // just lots of data forever. + if (!buffer) + fail('read'); + + // don't slice the buffer. the point of this is to isolate, not + // simulate real traffic. + // var chunk = buffer.slice(offset, offset + length); + bytes += length; + }; + + clientHandle.readStart(); + + // the meat of the benchmark is right here: + bench.start(); + + setTimeout(function() { + // report in Gb/sec + bench.end((bytes * 8) / (1024 * 1024 * 1024)); + }, dur * 1000); + }; +} -- cgit v1.2.3