Last active
September 9, 2020 17:00
-
-
Save puzpuzpuz/b91aefae5ec089b22cb2e8e9bad4a73e to your computer and use it in GitHub Desktop.
Another non-scientific, synthetic benchmark for net.Socket.write()
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
'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