Skip to content

Instantly share code, notes, and snippets.

@lpinca
Last active May 4, 2016 07:18
Show Gist options
  • Save lpinca/389b2fb022eee147d11a to your computer and use it in GitHub Desktop.
Save lpinca/389b2fb022eee147d11a to your computer and use it in GitHub Desktop.
Compare different WebSocket modules echoing big and small buffers
'use strict';
const deflate = require('permessage-deflate');
const Faye = require('faye-websocket');
const http = require('http');
exports.echo = opts => {
const messages = opts.messages;
const length = messages.length;
const extensions = [];
let count = 0;
let start;
if (opts.perMessageDeflate) extensions.push(deflate);
const server = http.createServer();
server.on('upgrade', (req, socket, head) => {
const ws = new Faye(req, socket, head, null, {
maxLength: Infinity,
extensions
});
ws.on('message', data => ws.send(data));
});
return new Promise(resolve => {
server.listen(() => {
const ws = new Faye.Client(`ws://localhost:${server.address().port}`, null, {
maxLength: Infinity,
extensions
});
ws.on('open', () => {
start = Date.now();
messages.forEach(message => ws.send(message));
});
ws.on('message', () => {
if (++count !== length) return;
const elapsed = (Date.now() - start) / 1000;
ws.close();
server.close(() => resolve({
rate: opts.size / elapsed,
time: elapsed
}));
});
});
});
};
'use strict';
const prettyBytes = require('pretty-bytes');
const crypto = require('crypto');
const faye = require('./faye');
const uws = require('./uws');
const ws = require('./ws');
const print = process.stderr.write.bind(process.stderr);
const size = 100 * 1024 * 1024;
const bigBufferOptions = { messages: [crypto.randomBytes(size)], size };
const smallBuffersOptions = { messages: [], size: 0 };
let i = 10000;
while (i--) {
const size = Math.floor(Math.random() * 1000) + 1;
smallBuffersOptions.messages.push(crypto.randomBytes(size));
smallBuffersOptions.size += size;
}
const benchmarks = [
{
opts: Object.assign({ perMessageDeflate: false }, bigBufferOptions),
name: 'big buffer (ws)',
fn: ws.echo
},
{
opts: Object.assign({ perMessageDeflate: false }, bigBufferOptions),
name: 'big buffer (faye)',
fn: faye.echo
},
{
opts: Object.assign({ perMessageDeflate: false }, bigBufferOptions),
name: 'big buffer (uws)',
fn: uws.echo
},
{
opts: Object.assign({ perMessageDeflate: false }, smallBuffersOptions),
name: 'small buffers (ws)',
fn: ws.echo
},
{
opts: Object.assign({ perMessageDeflate: false }, smallBuffersOptions),
name: 'small buffers (faye)',
fn: faye.echo
},
{
opts: Object.assign({ perMessageDeflate: false }, smallBuffersOptions),
name: 'small buffers (uws)',
fn: uws.echo
},
{
opts: Object.assign({ perMessageDeflate: true }, bigBufferOptions),
name: 'big buffer permessage-deflate (ws)',
fn: ws.echo
},
{
opts: Object.assign({ perMessageDeflate: true }, bigBufferOptions),
name: 'big buffer permessage-deflate (faye)',
fn: faye.echo
},
{
opts: Object.assign({ perMessageDeflate: true }, smallBuffersOptions),
name: 'small buffers permessage-deflate (ws)',
fn: ws.echo
},
{
opts: Object.assign({ perMessageDeflate: true }, smallBuffersOptions),
name: 'small buffers permessage-deflate (faye)',
fn: faye.echo
}
];
benchmarks.reduce((p, benchmark) => {
return p.then(data => {
if (data) print(`${data.time.toFixed(2)}s ${prettyBytes(data.rate)}/s\n`);
print(`${benchmark.name}: `);
return benchmark.fn.call(null, benchmark.opts);
});
}, Promise.resolve())
.then(data => print(`${data.time.toFixed(2)}s ${prettyBytes(data.rate)}/s\n`))
.catch(err => console.error(err.stack));
{
"name": "echo",
"version": "1.0.0",
"description": "Compare different WebSocket modules echoing big and small buffers",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "Luigi Pinca",
"license": "ISC",
"main": "index.js",
"dependencies": {
"bufferutil": "^1.2.1",
"faye-websocket": "^0.11.0",
"permessage-deflate": "^0.1.5",
"pretty-bytes": "^3.0.1",
"utf-8-validate": "^1.2.1",
"uws": "^0.3.0",
"ws": "^1.0.1"
}
}
'use strict';
const uws = require('uws').uws;
const ws = require('ws');
let port = 1023;
exports.echo = opts => {
const messages = opts.messages;
const length = messages.length;
let count = 0;
let start;
const server = new uws.Server(++port);
server.onMessage((socket, data, binary) => server.send(socket, data, binary));
return new Promise(resolve => {
const socket = new ws(`ws://localhost:${port}`, {
perMessageDeflate: opts.perMessageDeflate
});
socket.on('open', () => {
start = Date.now();
messages.forEach(message => socket.send(message));
});
socket.on('message', () => {
if (++count !== length) return;
const elapsed = (Date.now() - start) / 1000;
socket.close();
server.close();
resolve({
rate: opts.size / elapsed,
time: elapsed
});
});
});
};
'use strict';
const http = require('http');
const ws = require('ws');
exports.echo = opts => {
const server = http.createServer();
const messages = opts.messages;
const length = messages.length;
let count = 0;
let start;
const wss = new ws.Server({
perMessageDeflate: opts.perMessageDeflate,
clientTracking: false,
server
});
wss.on('connection', socket => {
socket.on('message', data => socket.send(data));
});
return new Promise(resolve => {
server.listen(() => {
const socket = new ws(`ws://localhost:${server.address().port}`, {
perMessageDeflate: opts.perMessageDeflate
});
socket.on('open', () => {
start = Date.now();
messages.forEach(message => socket.send(message));
});
socket.on('message', () => {
if (++count !== length) return;
const elapsed = (Date.now() - start) / 1000;
socket.close();
server.close(() => resolve({
rate: opts.size / elapsed,
time: elapsed
}));
});
});
});
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment