From f2cc56d2d7eb6615641a25637c69c08ba30ec43a Mon Sep 17 00:00:00 2001 From: Chenyu Yang Date: Tue, 7 Nov 2023 11:24:27 +0800 Subject: [PATCH 1/8] benchmark: add undici websocket benchmark Refs: https://github.com/nodejs/performance/issues/114 --- benchmark/websocket/simple.js | 65 +++++++++++++++++++++++++++++++++++ 1 file changed, 65 insertions(+) create mode 100644 benchmark/websocket/simple.js diff --git a/benchmark/websocket/simple.js b/benchmark/websocket/simple.js new file mode 100644 index 00000000000000..dc2a80e9c4c850 --- /dev/null +++ b/benchmark/websocket/simple.js @@ -0,0 +1,65 @@ +'use strict'; + +const common = require('../common.js'); +const http = require('http'); +const WebSocketServer = require('ws'); +const { WebSocket } = require('undici'); + +const port = 8181; +const path = ''; + +const configs = { + useBinary: ['true', 'false'], + roundtrips: [5000, 1000, 100, 1], + size: [64, 16 * 1024, 128 * 1024, 1024 * 1024], +}; + +const bench = common.createBenchmark(main, configs); + +function main(conf) { + const server = http.createServer(); + const wss = new WebSocketServer.Server({ + maxPayload: 600 * 1024 * 1024, + perMessageDeflate: false, + clientTracking: false, + server, + }); + + wss.on('connection', (ws) => { + ws.on('message', (data, isBinary) => { + ws.send(data, { binary: isBinary }); + }); + }); + + server.listen(path ? { path } : { port }); + const url = path ? `ws+unix://${path}` : `ws://localhost:${port}`; + const wsc = new WebSocket(url); + const data = Buffer.allocUnsafe(conf.size).fill('.'); // Pre-fill data for testing + + let roundtrip = 0; + + wsc.addEventListener('error', (err) => { + throw err; + }); + + bench.start(); + + wsc.addEventListener('open', () => { + wsc.send(data, { binary: conf.useBinary }); + }); + + wsc.addEventListener('close', () => { + wss.close(() => { + server.close(); + }); + }); + + wsc.addEventListener('message', () => { + if (++roundtrip !== conf.roundtrips) { + wsc.send(data, { binary: conf.useBinary }); + } else { + bench.end(conf.roundtrips); + wsc.close(); + } + }); +} From 8292e19cfc3d321be131665b7bec2d6f60167376 Mon Sep 17 00:00:00 2001 From: Chenyu Yang Date: Thu, 9 Nov 2023 18:17:52 +0800 Subject: [PATCH 2/8] benchmark: update websocket server --- benchmark/websocket/simple.js | 109 ++++++++++++++++++++++------------ 1 file changed, 72 insertions(+), 37 deletions(-) diff --git a/benchmark/websocket/simple.js b/benchmark/websocket/simple.js index dc2a80e9c4c850..9198c30242e876 100644 --- a/benchmark/websocket/simple.js +++ b/benchmark/websocket/simple.js @@ -1,65 +1,100 @@ 'use strict'; const common = require('../common.js'); +const crypto = require('crypto'); const http = require('http'); -const WebSocketServer = require('ws'); const { WebSocket } = require('undici'); -const port = 8181; -const path = ''; +const GUID = '258EAFA5-E914-47DA-95CA-C5AB0DC85B11'; const configs = { + size: [64, 16 * 1024, 128 * 1024, 1024 * 1024], useBinary: ['true', 'false'], roundtrips: [5000, 1000, 100, 1], - size: [64, 16 * 1024, 128 * 1024, 1024 * 1024], }; const bench = common.createBenchmark(main, configs); +function createFrame(data, opcode) { + let infoLength = 2; + let payloadLength = data.length; + + if (payloadLength >= 65536) { + infoLength += 8; + payloadLength = 127; + } else if (payloadLength > 125) { + infoLength += 2; + payloadLength = 126; + } + + const info = Buffer.alloc(infoLength); + + info[0] = opcode | 0x80; + info[1] = payloadLength; + + if (payloadLength === 126) { + info.writeUInt16BE(data.length, 2); + } else if (payloadLength === 127) { + info[2] = info[3] = 0; + info.writeUIntBE(data.length, 4, 6); + } + + return Buffer.concat([info, data]); +} + function main(conf) { + const frame = createFrame(Buffer.alloc(conf.size).fill('.'), 1); + const server = http.createServer(); - const wss = new WebSocketServer.Server({ - maxPayload: 600 * 1024 * 1024, - perMessageDeflate: false, - clientTracking: false, - server, - }); + server.on('upgrade', (req, socket) => { + const key = crypto + .createHash('sha1') + .update(req.headers['sec-websocket-key'] + GUID) + .digest('base64'); - wss.on('connection', (ws) => { - ws.on('message', (data, isBinary) => { - ws.send(data, { binary: isBinary }); - }); - }); + let bytesReceived = 0; + let roundtrip = 0; - server.listen(path ? { path } : { port }); - const url = path ? `ws+unix://${path}` : `ws://localhost:${port}`; - const wsc = new WebSocket(url); - const data = Buffer.allocUnsafe(conf.size).fill('.'); // Pre-fill data for testing + socket.on('data', function onData(chunk) { + bytesReceived += chunk.length; - let roundtrip = 0; + if (bytesReceived === frame.length + 4) { // +4 for the mask. + // Message completely received. + bytesReceived = 0; - wsc.addEventListener('error', (err) => { - throw err; - }); + if (++roundtrip === conf.roundtrips) { + socket.removeListener('data', onData); + socket.resume(); + socket.end(); + server.close(); - bench.start(); + bench.end(conf.roundtrips); + } else { + socket.write(frame); + } + } + }); + + socket.write( + [ + 'HTTP/1.1 101 Switching Protocols', + 'Upgrade: websocket', + 'Connection: Upgrade', + `Sec-WebSocket-Accept: ${key}`, + '\r\n', + ].join('\r\n'), + ); - wsc.addEventListener('open', () => { - wsc.send(data, { binary: conf.useBinary }); + socket.write(frame); }); - wsc.addEventListener('close', () => { - wss.close(() => { - server.close(); + server.listen(8080, () => { + const ws = new WebSocket('ws://localhost:8080'); + + ws.addEventListener('message', (event) => { + ws.send(event.data); }); }); - wsc.addEventListener('message', () => { - if (++roundtrip !== conf.roundtrips) { - wsc.send(data, { binary: conf.useBinary }); - } else { - bench.end(conf.roundtrips); - wsc.close(); - } - }); + bench.start(); } From 6a67c0289e8feb594a4a0cc26bdc542e18c20a31 Mon Sep 17 00:00:00 2001 From: Chenyu Yang Date: Fri, 10 Nov 2023 00:33:17 +0800 Subject: [PATCH 3/8] benchmark: update undici benchmark --- benchmark/websocket/simple.js | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/benchmark/websocket/simple.js b/benchmark/websocket/simple.js index 9198c30242e876..b19e34a5d1aa88 100644 --- a/benchmark/websocket/simple.js +++ b/benchmark/websocket/simple.js @@ -43,8 +43,7 @@ function createFrame(data, opcode) { } function main(conf) { - const frame = createFrame(Buffer.alloc(conf.size).fill('.'), 1); - + const frame = createFrame(Buffer.alloc(conf.size).fill('.'), conf.useBinary === 'true'); const server = http.createServer(); server.on('upgrade', (req, socket) => { const key = crypto @@ -91,10 +90,14 @@ function main(conf) { server.listen(8080, () => { const ws = new WebSocket('ws://localhost:8080'); + ws.addEventListener('open', () => { + bench.start(); + }); + ws.addEventListener('message', (event) => { ws.send(event.data); }); }); - bench.start(); + } From d591842a0a957f1a81f7bd9c4ad94ed12fe4b04a Mon Sep 17 00:00:00 2001 From: Chenyu Yang Date: Fri, 10 Nov 2023 12:14:10 +0800 Subject: [PATCH 4/8] benchamrk: update undici websocket benchmark --- benchmark/websocket/simple.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/benchmark/websocket/simple.js b/benchmark/websocket/simple.js index b19e34a5d1aa88..7e00f34959c52f 100644 --- a/benchmark/websocket/simple.js +++ b/benchmark/websocket/simple.js @@ -43,7 +43,7 @@ function createFrame(data, opcode) { } function main(conf) { - const frame = createFrame(Buffer.alloc(conf.size).fill('.'), conf.useBinary === 'true'); + const frame = createFrame(Buffer.alloc(conf.size).fill('.'), conf.useBinary === 'true' ? 2 : 1); const server = http.createServer(); server.on('upgrade', (req, socket) => { const key = crypto @@ -98,6 +98,4 @@ function main(conf) { ws.send(event.data); }); }); - - } From 21ff7a0c8b605f1f860c50970267744458108772 Mon Sep 17 00:00:00 2001 From: Chenyu Yang Date: Mon, 13 Nov 2023 10:08:39 +0800 Subject: [PATCH 5/8] test: add test/benchmark/test-benchmark-websocket.js --- test/benchmark/test-benchmark-websocket.js | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 test/benchmark/test-benchmark-websocket.js diff --git a/test/benchmark/test-benchmark-websocket.js b/test/benchmark/test-benchmark-websocket.js new file mode 100644 index 00000000000000..ba19315b9d9c4b --- /dev/null +++ b/test/benchmark/test-benchmark-websocket.js @@ -0,0 +1,13 @@ +'use strict'; + +const common = require('../common'); +if (!common.enoughTestMem) + common.skip('Insufficient memory for Websocket benchmark test'); + +// Because the websocket benchmarks use hardcoded ports, this should be in sequential +// rather than parallel to make sure it does not conflict with tests that choose +// random available ports. + +const runBenchmark = require('../common/benchmark'); + +runBenchmark('websocket', { NODEJS_BENCHMARK_ZERO_ALLOWED: 1 }); From 84e0d3b925775bd83774a8c7461a36b46a07e5e4 Mon Sep 17 00:00:00 2001 From: Chenyu Yang Date: Tue, 14 Nov 2023 10:33:28 +0800 Subject: [PATCH 6/8] update undici websocket benchmark & test --- benchmark/websocket/simple.js | 8 +++----- test/benchmark/test-benchmark-websocket.js | 4 ---- 2 files changed, 3 insertions(+), 9 deletions(-) diff --git a/benchmark/websocket/simple.js b/benchmark/websocket/simple.js index 7e00f34959c52f..2101f345f4220b 100644 --- a/benchmark/websocket/simple.js +++ b/benchmark/websocket/simple.js @@ -10,8 +10,7 @@ const GUID = '258EAFA5-E914-47DA-95CA-C5AB0DC85B11'; const configs = { size: [64, 16 * 1024, 128 * 1024, 1024 * 1024], useBinary: ['true', 'false'], - roundtrips: [5000, 1000, 100, 1], -}; + roundtrips: [5000, 1000, 100],}; const bench = common.createBenchmark(main, configs); @@ -87,9 +86,8 @@ function main(conf) { socket.write(frame); }); - server.listen(8080, () => { - const ws = new WebSocket('ws://localhost:8080'); - + server.listen(0, () => { + const ws = new WebSocket(`ws://localhost:${server.address().port}`); ws.addEventListener('open', () => { bench.start(); }); diff --git a/test/benchmark/test-benchmark-websocket.js b/test/benchmark/test-benchmark-websocket.js index ba19315b9d9c4b..d02e46a76b4e9e 100644 --- a/test/benchmark/test-benchmark-websocket.js +++ b/test/benchmark/test-benchmark-websocket.js @@ -4,10 +4,6 @@ const common = require('../common'); if (!common.enoughTestMem) common.skip('Insufficient memory for Websocket benchmark test'); -// Because the websocket benchmarks use hardcoded ports, this should be in sequential -// rather than parallel to make sure it does not conflict with tests that choose -// random available ports. - const runBenchmark = require('../common/benchmark'); runBenchmark('websocket', { NODEJS_BENCHMARK_ZERO_ALLOWED: 1 }); From 406077c9d235ac174a5fef4a4bb42c2184decb1e Mon Sep 17 00:00:00 2001 From: Chenyu Yang Date: Tue, 14 Nov 2023 14:45:27 +0800 Subject: [PATCH 7/8] fix lint error --- benchmark/websocket/simple.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/benchmark/websocket/simple.js b/benchmark/websocket/simple.js index 2101f345f4220b..4494a76b6105f9 100644 --- a/benchmark/websocket/simple.js +++ b/benchmark/websocket/simple.js @@ -10,7 +10,8 @@ const GUID = '258EAFA5-E914-47DA-95CA-C5AB0DC85B11'; const configs = { size: [64, 16 * 1024, 128 * 1024, 1024 * 1024], useBinary: ['true', 'false'], - roundtrips: [5000, 1000, 100],}; + roundtrips: [5000, 1000, 100], +}; const bench = common.createBenchmark(main, configs); From 5da73e6190d7ebfe227f6d0e812921552b2d825c Mon Sep 17 00:00:00 2001 From: Chenyu Yang Date: Tue, 14 Nov 2023 17:22:27 +0800 Subject: [PATCH 8/8] update undici websocket benchmark --- benchmark/websocket/simple.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/benchmark/websocket/simple.js b/benchmark/websocket/simple.js index 4494a76b6105f9..1147602a7b1ea7 100644 --- a/benchmark/websocket/simple.js +++ b/benchmark/websocket/simple.js @@ -3,7 +3,7 @@ const common = require('../common.js'); const crypto = require('crypto'); const http = require('http'); -const { WebSocket } = require('undici'); +const { WebSocket } = require('../../deps/undici/undici'); const GUID = '258EAFA5-E914-47DA-95CA-C5AB0DC85B11';