-
-
Save felixge/1267712 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
.DS_Store | |
node_modules |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
var options = require('commander'); | |
var transports = { | |
'xhr-polling': require('./transport/xhr_polling'), | |
}; | |
options | |
.option('-p, --port [port]', 'The port to connect to [3030]', 3030) | |
.option('-h, --host [host]', 'The host to connect to [localhost]', 'localhost') | |
.option('-c, --clients [clients]', 'The number of total clients', 10) | |
.option('-m, --messages [messages]', 'The number of messages to send per sec [0.1]', 0.1) | |
.option('-i, --interval [interval]', 'The interval in seconds to accumlate stats [10]', 10) | |
.option('-t, --transport [transport]', 'The transport type to use by the client [xhr-polling,websocket]', 'xhr-polling') | |
.option('-%, --percentile [percentile]', 'The percentile to calculate latency for [95]', 95) | |
.parse(process.argv); | |
function Benchmark() { | |
this.clients = []; | |
this.maxClients = null; | |
this.interval = null; | |
this.transport = null; | |
this.connectedCounter = 0; | |
this.percentile = null; | |
this.responseTimes = []; | |
} | |
Benchmark.create = function(options) { | |
var instance = new Benchmark(); | |
instance.maxClients = options.clients; | |
instance.host = options.host; | |
instance.port = options.port; | |
instance.interval = options.interval; | |
instance.transport = options.transport; | |
instance.percentile = options.percentile; | |
return instance; | |
}; | |
Benchmark.prototype.start = function() { | |
for (var i = 0; i < this.maxClients; i++) { | |
this.connectClient(); | |
} | |
}; | |
Benchmark.prototype.connectClient = function() { | |
var client = transports[this.transport].create(this.port, this.host); | |
client.connect(); | |
client | |
.on('connect', this.handleConnect.bind(this, client)) | |
.on('message', this.handleMessage.bind(this, client)) | |
.on('error', this.handleError.bind(this, client)); | |
this.clients.push(client); | |
}; | |
Benchmark.prototype.handleMessage = function(client, message) { | |
var time = message.args[0].time; | |
var latency = Date.now() - time; | |
this.responseTimes.push(latency); | |
if (this.responseTimes.length === this.clients.length) { | |
this.analyze(); | |
this.responseTimes = []; | |
} | |
}; | |
Benchmark.prototype.analyze = function() { | |
this.responseTimes.sort(function(a, b) { | |
if (a === b) return 0; | |
return (a < b) | |
? -1 | |
: 1; | |
}); | |
var index = Math.ceil(this.responseTimes.length * this.percentile / 100); | |
var responseTime = this.responseTimes[index]; | |
console.error( | |
'%s percentile response time for %d clients: %d', | |
this.percentile, | |
this.clients.length, | |
responseTime | |
); | |
}; | |
Benchmark.prototype.handleConnect = function(client, message) { | |
this.connectedCounter++; | |
}; | |
Benchmark.prototype.handleError = function(client, error) { | |
var index = this.clients.indexOf(client); | |
console.error('Error from client %d: %s', index, error); | |
}; | |
var benchmark = Benchmark.create(options); | |
benchmark.start(); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"author": "Robin Mehner <[email protected]>", | |
"name": "socketio-bench-server", | |
"description": "Small socket.io server bench", | |
"version": "0.0.0", | |
"repository": { | |
"url": "" | |
}, | |
"engines": { | |
"node": "~0.4.12" | |
}, | |
"dependencies": { | |
"socket.io": "~0.8.4", | |
"commander": "~0.2.0", | |
"socket.io-client": "~0.8.4" | |
}, | |
"devDependencies": {} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
var port = 3030; | |
var interval = 1000; | |
var duration = 10 * 1000; | |
var receivedCounter = 0; | |
var sockets = []; | |
var io = require('socket.io').listen(port); | |
io.configure(function() { | |
io.set('log level', 1); | |
}); | |
io.sockets.on('connection', function (socket) { | |
sockets.push(socket); | |
socket.on('chat.send', function(data) { | |
receivedCounter++; | |
}); | |
}); | |
setInterval(function() { | |
sockets.forEach(function(socket) { | |
socket.emit('chat.msg', { | |
msg: 'JavaScript motherfucker. Do you speak it!', | |
time: Date.now(), | |
}); | |
}); | |
}, interval); | |
setInterval(function() { | |
console.log('Received %d requests per second', receivedCounter / duration * 1000); | |
receivedCounter = 0; | |
}, duration); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
var program = require('commander'); | |
var io = require('socket.io-client') | |
program | |
.option('-p, --port [port]', 'The port to connect to [3030]', 3030) | |
.option('-h, --host [host]', 'The host to connect to [localhost]', 'localhost') | |
.option('-c, --clients [clients]', 'The number of total clients', 1000) | |
.option('-m, --messages [messages]', 'The number of messages to send per sec [0.1]', 0.1) | |
.parse(process.argv); | |
function WebsocketClient() { | |
this.connection = undefined; | |
} | |
WebsocketClient.prototype.connect = function() { | |
this.connection = io.connect('http://' + program.host + ':' + program.port); | |
} | |
WebsocketClient.prototype.sendMsg = function() { | |
if (this.connection.socket.connected) { | |
this.connection.emit('chat.send', {msg: 'Your mum'}); | |
} | |
} | |
WebsocketClient.prototype.sendMessages = function() { | |
var that = this; | |
setInterval(function() { | |
that.sendMsg(); | |
}, 1000 / program.messages); | |
} | |
for (var i = 0; i < program.clients; i++) { | |
var client = new WebsocketClient(); | |
client.connect(); | |
client.sendMessages(); | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
var http = require('http'); | |
var querystring = require('querystring'); | |
var clients = []; | |
var EventEmitter = require('events').EventEmitter; | |
var util = require('util'); | |
module.exports = XhrPolling; | |
util.inherits(XhrPolling, EventEmitter); | |
function XhrPolling() { | |
EventEmitter.call(this); | |
this.port = null; | |
this.host = null; | |
this.connecting = false; | |
this.connected = false; | |
this.sessionId = null; | |
this.transport = 'xhr-polling'; | |
this._request = null; | |
} | |
XhrPolling.create = function(port, host) { | |
var instance = new this(); | |
instance.port = port; | |
instance.host = host; | |
return instance; | |
}; | |
XhrPolling.prototype.connect = function() { | |
this.connecting = true; | |
this.handshake(); | |
}; | |
XhrPolling.prototype.handshake = function() { | |
var self = this; | |
this.request(function(err, response) { | |
if (err) return self.emit('error', err); | |
self.sessionId = response[0]; | |
self.poll(); | |
}); | |
}; | |
XhrPolling.prototype.poll = function() { | |
var self = this; | |
this.request(function(err, response) { | |
if (err) return self.emit('error', err); | |
if (response[0] === '7') { | |
self.emit('error', new Error('Error: ' + JSON.stringify(response))); | |
} | |
// Connected | |
if (response[0] === '1') { | |
self.connected = true; | |
self.connecting = false; | |
self.emit('connect'); | |
self.poll(); | |
return; | |
} | |
// Event | |
if (response[0] === '5') { | |
var message = JSON.parse(response[3]); | |
self.emit('message', message); | |
self.poll(); | |
return; | |
} | |
self.emit('error', new Error('Not implemented: ' + JSON.stringify(response))); | |
}); | |
}; | |
XhrPolling.prototype.request = function(endpoint, cb) { | |
if (typeof endpoint === 'function') { | |
cb = endpoint; | |
endpoint = ''; | |
} | |
if (endpoint) endpoint = '/' + endpoint; | |
var session = ''; | |
if (this.sessionId) { | |
session = this.transport + '/' + this.sessionId; | |
} | |
var path = '/socket.io/1/' + session + endpoint; | |
var options = { | |
host: this.host, | |
port: this.port, | |
path: path, | |
}; | |
var agent = http.getAgent(options.host, options.port) | |
agent.maxSockets = 1000; | |
this._request = http.get(options, this.handleResponse.bind(this, cb)); | |
var self = this; | |
this._request.on('error', function(err) { | |
self.emit('error', err); | |
}); | |
}; | |
XhrPolling.prototype.handleResponse = function(cb, res) { | |
var data = ''; | |
res.setEncoding('utf8'); | |
res | |
.on('data', function(chunk) { | |
data += chunk; | |
}) | |
.on('end', function() { | |
var message = []; | |
for (var i = 0; i < 3; i++) { | |
var end = data.indexOf(':'); | |
message[i] = data.substr(0, end); | |
data = data.substr(end + 1); | |
} | |
message[3] = data; | |
cb(null, message); | |
}); | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment