From 8a946c2ee7aba1722aab9773bbf8534d063870e4 Mon Sep 17 00:00:00 2001 From: isaacs Date: Sat, 23 Jun 2012 10:03:12 -0700 Subject: [PATCH] benchmark: Backport improvements made in master Ported to v0.6 for easier comparison in the 0.8.0 blog post. --- benchmark/fs-readfile.js | 72 +++++++++++++++++++++++++++++++ benchmark/http.sh | 12 ++++++ benchmark/http_simple.js | 109 ++++++++++++++++++++++++++++++----------------- benchmark/io.js | 4 +- 4 files changed, 156 insertions(+), 41 deletions(-) create mode 100644 benchmark/fs-readfile.js create mode 100755 benchmark/http.sh diff --git a/benchmark/fs-readfile.js b/benchmark/fs-readfile.js new file mode 100644 index 0000000..c2d9bd3 --- /dev/null +++ b/benchmark/fs-readfile.js @@ -0,0 +1,72 @@ +// Call fs.readFile over and over again really fast. +// Then see how many times it got called. +// Yes, this is a silly benchmark. Most benchmarks are silly. + +var path = require('path'); +var filename = path.resolve(__dirname, 'http.sh'); +var fs = require('fs'); +var count = 0; +var go = true; +var len = -1; +var assert = require('assert'); + +var concurrency = 1; +var encoding = null; +var time = 10; + +for (var i = 2; i < process.argv.length; i++) { + var arg = process.argv[i]; + if (arg.match(/^-e$/)) { + encoding = process.argv[++i] || null; + } else if (arg.match(/^-c$/)) { + concurrency = ~~process.argv[++i]; + if (concurrency < 1) concurrency = 1; + } else if (arg === '-t') { + time = ~~process.argv[++i]; + if (time < 1) time = 1; + } +} + + +setTimeout(function() { + go = false; +}, time * 1000); + +function round(n) { + return Math.floor(n * 100) / 100; +} + +var start = Date.now(); +while (concurrency--) readFile(); + +function readFile() { + if (!go) { + process.stdout.write('\n'); + console.log('read the file %d times (higher is better)', count); + var end = Date.now(); + var elapsed = (end - start) / 1000; + var ns = elapsed * 1E9; + var nsper = round(ns / count); + console.log('%d ns per read (lower is better)', nsper); + var readsper = round(count / (ns / 1E9)); + console.log('%d reads per sec (higher is better)', readsper); + process.exit(0); + return; + } + + if (!(count % 1000)) { + process.stdout.write('.'); + } + + if (encoding) fs.readFile(filename, encoding, then); + else fs.readFile(filename, then); + + function then(er, data) { + assert.ifError(er); + count++; + // basic sanity test: we should get the same number of bytes each time. + if (count === 1) len = data.length; + else assert(len === data.length); + readFile(); + } +} diff --git a/benchmark/http.sh b/benchmark/http.sh new file mode 100755 index 0000000..40d0c71 --- /dev/null +++ b/benchmark/http.sh @@ -0,0 +1,12 @@ +#!/bin/bash +cd "$(dirname "$(dirname $0)")" +sudo sysctl -w net.inet.ip.portrange.first=12000 +sudo sysctl -w net.inet.tcp.msl=1000 +sudo sysctl -w kern.maxfiles=1000000 kern.maxfilesperproc=1000000 +ulimit -n 100000 + +./node benchmark/http_simple.js || exit 1 & +sleep 1 + +ab -n 30000 -c 100 http://127.0.0.1:8000/${TYPE:-bytes}/${LENGTH:-1024} | grep Req +killall node diff --git a/benchmark/http_simple.js b/benchmark/http_simple.js index 74ba4d7..1b3cee7 100644 --- a/benchmark/http_simple.js +++ b/benchmark/http_simple.js @@ -1,75 +1,99 @@ -path = require("path"); -exec = require("child_process").exec; -http = require("http"); +var path = require('path'), + exec = require('child_process').exec, + http = require('http'); -port = parseInt(process.env.PORT || 8000); +var port = parseInt(process.env.PORT || 8000); console.log('pid ' + process.pid); -fixed = "" -for (var i = 0; i < 20*1024; i++) { - fixed += "C"; +var fixed = makeString(20 * 1024, 'C'), + storedBytes = {}, + storedBuffer = {}, + storedUnicode = {}; + +var useDomains = process.env.NODE_USE_DOMAINS; + +// set up one global domain. +if (useDomains) { + var domain = require('domain'); + var gdom = domain.create(); + gdom.on('error', function(er) { + console.log('Error on global domain', er); + throw er; + }); + gdom.enter(); } -stored = {}; -storedBuffer = {}; - var server = http.createServer(function (req, res) { - var commands = req.url.split("/"); + if (useDomains) { + var dom = domain.create(); + dom.add(req); + dom.add(res); + } + + var commands = req.url.split('/'); var command = commands[1]; - var body = ""; + var body = ''; var arg = commands[2]; var n_chunks = parseInt(commands[3], 10); var status = 200; - if (command == "bytes") { - var n = parseInt(arg, 10) + if (command == 'bytes') { + var n = ~~arg; if (n <= 0) - throw "bytes called with n <= 0" - if (stored[n] === undefined) { - console.log("create stored[n]"); - stored[n] = ""; - for (var i = 0; i < n; i++) { - stored[n] += "C" - } + throw new Error('bytes called with n <= 0') + if (storedBytes[n] === undefined) { + console.log('create storedBytes[n]'); + storedBytes[n] = makeString(n, 'C'); } - body = stored[n]; + body = storedBytes[n]; - } else if (command == "buffer") { - var n = parseInt(arg, 10) - if (n <= 0) throw new Error("bytes called with n <= 0"); + } else if (command == 'buffer') { + var n = ~~arg; + if (n <= 0) + throw new Error('buffer called with n <= 0'); if (storedBuffer[n] === undefined) { - console.log("create storedBuffer[n]"); + console.log('create storedBuffer[n]'); storedBuffer[n] = new Buffer(n); for (var i = 0; i < n; i++) { - storedBuffer[n][i] = "C".charCodeAt(0); + storedBuffer[n][i] = 'C'.charCodeAt(0); } } body = storedBuffer[n]; - } else if (command == "quit") { + } else if (command == 'unicode') { + var n = ~~arg; + if (n <= 0) + throw new Error('unicode called with n <= 0'); + if (storedUnicode[n] === undefined) { + console.log('create storedUnicode[n]'); + storedUnicode[n] = makeString(n, '\u263A'); + } + body = storedUnicode[n]; + + } else if (command == 'quit') { res.connection.server.close(); - body = "quitting"; + body = 'quitting'; - } else if (command == "fixed") { + } else if (command == 'fixed') { body = fixed; - } else if (command == "echo") { - res.writeHead(200, { "Content-Type": "text/plain", - "Transfer-Encoding": "chunked" }); + } else if (command == 'echo') { + res.writeHead(200, { 'Content-Type': 'text/plain', + 'Transfer-Encoding': 'chunked' }); req.pipe(res); return; } else { status = 404; - body = "not found\n"; + body = 'not found\n'; } // example: http://localhost:port/bytes/512/4 // sends a 512 byte body in 4 chunks of 128 bytes if (n_chunks > 0) { - res.writeHead(status, { "Content-Type": "text/plain", - "Transfer-Encoding": "chunked" }); + res.writeHead(status, { 'Content-Type': 'text/plain', + 'Transfer-Encoding': 'chunked' }); // send body in chunks var len = body.length; var step = ~~(len / n_chunks) || len; @@ -82,13 +106,20 @@ var server = http.createServer(function (req, res) { } else { var content_length = body.length.toString(); - res.writeHead(status, { "Content-Type": "text/plain", - "Content-Length": content_length }); + res.writeHead(status, { 'Content-Type': 'text/plain', + 'Content-Length': content_length }); res.end(body); } - }); +function makeString(size, c) { + var s = ''; + while (s.length < size) { + s += c; + } + return s; +} + server.listen(port, function () { console.log('Listening at http://127.0.0.1:'+port+'/'); }); diff --git a/benchmark/io.js b/benchmark/io.js index 505d8d0..1c18e05 100644 --- a/benchmark/io.js +++ b/benchmark/io.js @@ -62,7 +62,7 @@ function readtest(size, bsize) { function wt(tsize, bsize, done) { var start = Date.now(); - s = writetest(tsize, bsizes[0]); + s = writetest(tsize, bsize); s.addListener('close', function() { var end = Date.now(); var diff = end - start; @@ -73,7 +73,7 @@ function wt(tsize, bsize, done) { function rt(tsize, bsize, done) { var start = Date.now(); - s = readtest(tsize, bsizes[0]); + s = readtest(tsize, bsize); s.addListener('close', function() { var end = Date.now(); var diff = end - start; -- 2.7.4