Skip to content

Instantly share code, notes, and snippets.

@puzpuzpuz
Last active September 9, 2020 17:00
Show Gist options
  • Save puzpuzpuz/b91aefae5ec089b22cb2e8e9bad4a73e to your computer and use it in GitHub Desktop.
Save puzpuzpuz/b91aefae5ec089b22cb2e8e9bad4a73e to your computer and use it in GitHub Desktop.
Another non-scientific, synthetic benchmark for net.Socket.write()
'use strict';
const crypto = require('crypto');
const net = require('net');
const writeCount = 10000000;
const batchSize = 100;
const chunkSize = 128;
const chunks = [];
const state = { writes: 0 };
for (let i = 0; i < batchSize; i++) {
chunks[i] = crypto.randomBytes(chunkSize);
}
function benchmark(writeFn, done) {
let serverSocket;
const ackBuf = Buffer.from([0x1]);
const server = net.createServer((socket) => {
socket.on('data', () => {
socket.write(ackBuf);
});
serverSocket = socket;
}).on('error', (err) => {
console.error('Server error', err);
process.exit(1);
});
server.listen({ host: 'localhost', port: 8080 });
function startWriting(socket) {
writeFn(socket, state);
if (state.writes >= writeCount) {
done();
socket.unref();
serverSocket.unref();
server.close();
}
}
const socket = net.createConnection({ port: 8080 }, () => {
startWriting(socket);
});
socket.on('drain', () => {
if (state.writes < writeCount) {
startWriting(socket);
}
});
socket.on('data', () => {
// no-op
});
}
function writeDirect(socket, state) {
let keepWriting = true;
while (keepWriting && state.writes < writeCount) {
for (let i = 0; i < batchSize; i++) {
state.writes++;
keepWriting = socket.write(chunks[i]);
}
}
}
function writeCoalesced(socket, state) {
let keepWriting = true;
while (keepWriting && state.writes < writeCount) {
// coalesce buffers each time to have a fair comparison
const batchChunks = chunks.slice();
const coalesced = Buffer.concat(batchChunks, batchSize * chunkSize);
state.writes += batchSize;
keepWriting = socket.write(coalesced);
}
}
function writeCorked(socket, state) {
let keepWriting = true;
while (keepWriting && state.writes < writeCount) {
socket.cork();
state.writes += batchSize;
for (let i = 0; i < batchSize; i++) {
keepWriting = socket.write(chunks[i]);
}
socket.uncork();
}
}
const typeToFn = {
'direct': writeDirect,
'coalesced': writeCoalesced,
'corked': writeCorked
};
const type = process.argv.slice(2)[0];
const writeFn = typeToFn[type];
if (writeFn === undefined) {
console.error('Please specify type of benchmark: "direct", "coalesced", or "corked"');
process.exit(1);
}
const start = process.hrtime();
benchmark(writeFn, () => {
console.log('Benchmark finished');
const time = process.hrtime(start);
const tookSec = time[0] + time[1] * 1e-9;
console.log(`Took ${tookSec} seconds for ${writeCount} requests`);
console.log(`Ops/s: ${writeCount / tookSec}`);
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment