@peerbit/stream 5.0.1 → 5.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/benchmark/chunk-transfer.d.ts +2 -0
- package/dist/benchmark/chunk-transfer.d.ts.map +1 -0
- package/dist/benchmark/chunk-transfer.js +221 -0
- package/dist/benchmark/chunk-transfer.js.map +1 -0
- package/dist/benchmark/index.d.ts +1 -0
- package/dist/benchmark/index.d.ts.map +1 -1
- package/dist/benchmark/index.js +8 -2
- package/dist/benchmark/index.js.map +1 -1
- package/dist/benchmark/transfer.js +233 -72
- package/dist/benchmark/transfer.js.map +1 -1
- package/dist/src/index.d.ts +3 -1
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +48 -37
- package/dist/src/index.js.map +1 -1
- package/package.json +7 -4
- package/src/index.ts +90 -70
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chunk-transfer.d.ts","sourceRoot":"","sources":["../../benchmark/chunk-transfer.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
import { tcp } from "@libp2p/tcp";
|
|
2
|
+
import { TestSession } from "@peerbit/libp2p-test-utils";
|
|
3
|
+
import { AcknowledgeDelivery } from "@peerbit/stream-interface";
|
|
4
|
+
import { waitForResolved } from "@peerbit/time";
|
|
5
|
+
import { DirectStream, waitForNeighbour, } from "../src/index.js";
|
|
6
|
+
const modes = ["silent", "ack"];
|
|
7
|
+
const envInt = (name, fallback) => {
|
|
8
|
+
const value = process.env[name];
|
|
9
|
+
if (value == null) {
|
|
10
|
+
return fallback;
|
|
11
|
+
}
|
|
12
|
+
const parsed = Number.parseInt(value, 10);
|
|
13
|
+
return Number.isFinite(parsed) ? parsed : fallback;
|
|
14
|
+
};
|
|
15
|
+
const chunkBytes = Math.max(1, envInt("CHUNK_TRANSFER_CHUNK_BYTES", 262144));
|
|
16
|
+
const chunkCount = Math.max(1, envInt("CHUNK_TRANSFER_CHUNKS", 24));
|
|
17
|
+
const warmupIterations = Math.max(0, envInt("CHUNK_TRANSFER_WARMUP", 1));
|
|
18
|
+
const iterations = Math.max(1, envInt("CHUNK_TRANSFER_ITERATIONS", 3));
|
|
19
|
+
const timeoutMs = Math.max(1_000, envInt("CHUNK_TRANSFER_TIMEOUT_MS", 30_000));
|
|
20
|
+
class TestStreamImpl extends DirectStream {
|
|
21
|
+
constructor(components) {
|
|
22
|
+
super(components, ["bench/0.0.0"], {
|
|
23
|
+
canRelayMessage: true,
|
|
24
|
+
connectionManager: false,
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
const round = (value, digits = 3) => Number.isFinite(value) ? Number(value.toFixed(digits)) : value;
|
|
29
|
+
const average = (values) => values.reduce((sum, value) => sum + value, 0) / values.length;
|
|
30
|
+
const summarizeTask = (name, values) => {
|
|
31
|
+
const meanMs = average(values);
|
|
32
|
+
return {
|
|
33
|
+
name,
|
|
34
|
+
hz: round(1000 / meanMs, 6),
|
|
35
|
+
mean_ms: round(meanMs, 6),
|
|
36
|
+
rme: null,
|
|
37
|
+
samples: values.length,
|
|
38
|
+
};
|
|
39
|
+
};
|
|
40
|
+
const makePayload = (size, sequence) => {
|
|
41
|
+
const payload = new Uint8Array(size);
|
|
42
|
+
payload.fill(sequence % 251);
|
|
43
|
+
if (size >= 8) {
|
|
44
|
+
const view = Buffer.from(payload.buffer, payload.byteOffset, payload.byteLength);
|
|
45
|
+
view.writeUInt32BE(sequence >>> 0, 0);
|
|
46
|
+
view.writeUInt32BE((sequence ^ 0x9e3779b9) >>> 0, 4);
|
|
47
|
+
}
|
|
48
|
+
return payload;
|
|
49
|
+
};
|
|
50
|
+
const readSequence = (data) => {
|
|
51
|
+
if (data.byteLength < 8) {
|
|
52
|
+
return null;
|
|
53
|
+
}
|
|
54
|
+
const view = Buffer.from(data.buffer, data.byteOffset, data.byteLength);
|
|
55
|
+
return view.readUInt32BE(0);
|
|
56
|
+
};
|
|
57
|
+
const waitForPayloadBatch = (receiver, startSequence, count, timeout) => new Promise((resolve, reject) => {
|
|
58
|
+
const pending = new Set();
|
|
59
|
+
for (let i = 0; i < count; i++) {
|
|
60
|
+
pending.add(startSequence + i);
|
|
61
|
+
}
|
|
62
|
+
const timer = setTimeout(() => {
|
|
63
|
+
cleanup();
|
|
64
|
+
reject(new Error(`Timed out waiting for payload batch start=${startSequence} count=${count} pending=${pending.size}`));
|
|
65
|
+
}, timeout);
|
|
66
|
+
const onData = (event) => {
|
|
67
|
+
const data = event.detail.data;
|
|
68
|
+
const sequence = readSequence(data);
|
|
69
|
+
if (sequence == null || !pending.has(sequence)) {
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
pending.delete(sequence);
|
|
73
|
+
if (pending.size === 0) {
|
|
74
|
+
cleanup();
|
|
75
|
+
resolve();
|
|
76
|
+
}
|
|
77
|
+
};
|
|
78
|
+
const cleanup = () => {
|
|
79
|
+
clearTimeout(timer);
|
|
80
|
+
receiver.removeEventListener("data", onData);
|
|
81
|
+
};
|
|
82
|
+
receiver.addEventListener("data", onData);
|
|
83
|
+
});
|
|
84
|
+
const modeOptions = (mode, receiver) => mode === "ack"
|
|
85
|
+
? {
|
|
86
|
+
mode: new AcknowledgeDelivery({
|
|
87
|
+
redundancy: 1,
|
|
88
|
+
to: [receiver.publicKey],
|
|
89
|
+
}),
|
|
90
|
+
}
|
|
91
|
+
: {
|
|
92
|
+
to: [receiver.publicKey],
|
|
93
|
+
};
|
|
94
|
+
const runIteration = async (sender, receiver, mode, startSequence) => {
|
|
95
|
+
const payloads = Array.from({ length: chunkCount }, (_, index) => makePayload(chunkBytes, startSequence + index));
|
|
96
|
+
const startedAt = performance.now();
|
|
97
|
+
let receiverCompleteMs = 0;
|
|
98
|
+
const receivePromise = waitForPayloadBatch(receiver, startSequence, payloads.length, timeoutMs).then(() => {
|
|
99
|
+
receiverCompleteMs = performance.now() - startedAt;
|
|
100
|
+
});
|
|
101
|
+
for (const payload of payloads) {
|
|
102
|
+
await sender.publish(payload, modeOptions(mode, receiver));
|
|
103
|
+
}
|
|
104
|
+
const senderCompleteMs = performance.now() - startedAt;
|
|
105
|
+
await receivePromise;
|
|
106
|
+
return {
|
|
107
|
+
senderCompleteMs,
|
|
108
|
+
receiverCompleteMs,
|
|
109
|
+
senderAfterReceiverMs: Math.max(0, senderCompleteMs - receiverCompleteMs),
|
|
110
|
+
receiverAfterSenderMs: Math.max(0, receiverCompleteMs - senderCompleteMs),
|
|
111
|
+
};
|
|
112
|
+
};
|
|
113
|
+
const prepareSession = async () => {
|
|
114
|
+
const session = await TestSession.disconnected(4, {
|
|
115
|
+
transports: [tcp()],
|
|
116
|
+
services: { directstream: (c) => new TestStreamImpl(c) },
|
|
117
|
+
});
|
|
118
|
+
await session.connect([
|
|
119
|
+
[session.peers[0], session.peers[1]],
|
|
120
|
+
[session.peers[1], session.peers[2]],
|
|
121
|
+
[session.peers[2], session.peers[3]],
|
|
122
|
+
]);
|
|
123
|
+
const stream = (i) => session.peers[i].services.directstream;
|
|
124
|
+
await waitForNeighbour(stream(0), stream(1));
|
|
125
|
+
await waitForNeighbour(stream(1), stream(2));
|
|
126
|
+
await waitForNeighbour(stream(2), stream(3));
|
|
127
|
+
await stream(0).publish(new Uint8Array([1, 2, 3, 4]), {
|
|
128
|
+
mode: new AcknowledgeDelivery({
|
|
129
|
+
redundancy: 1,
|
|
130
|
+
to: [stream(3).publicKey],
|
|
131
|
+
}),
|
|
132
|
+
});
|
|
133
|
+
await waitForResolved(() => stream(0).routes.isReachable(stream(0).publicKeyHash, stream(3).publicKeyHash));
|
|
134
|
+
return {
|
|
135
|
+
session,
|
|
136
|
+
sender: stream(0),
|
|
137
|
+
receiver: stream(3),
|
|
138
|
+
};
|
|
139
|
+
};
|
|
140
|
+
const runMode = async (mode) => {
|
|
141
|
+
let sequence = 1_000;
|
|
142
|
+
const { session, sender, receiver } = await prepareSession();
|
|
143
|
+
const samples = [];
|
|
144
|
+
try {
|
|
145
|
+
for (let i = 0; i < warmupIterations; i++) {
|
|
146
|
+
await runIteration(sender, receiver, mode, sequence);
|
|
147
|
+
sequence += chunkCount;
|
|
148
|
+
}
|
|
149
|
+
for (let i = 0; i < iterations; i++) {
|
|
150
|
+
samples.push(await runIteration(sender, receiver, mode, sequence));
|
|
151
|
+
sequence += chunkCount;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
finally {
|
|
155
|
+
await session.stop();
|
|
156
|
+
}
|
|
157
|
+
return samples;
|
|
158
|
+
};
|
|
159
|
+
const results = await Promise.all(modes.map(async (mode) => ({
|
|
160
|
+
mode,
|
|
161
|
+
samples: await runMode(mode),
|
|
162
|
+
})));
|
|
163
|
+
const totalBytes = chunkBytes * chunkCount;
|
|
164
|
+
const totalMb = totalBytes / (1024 * 1024);
|
|
165
|
+
const tasks = [];
|
|
166
|
+
for (const result of results) {
|
|
167
|
+
tasks.push(summarizeTask(`${result.mode}: sender-complete`, result.samples.map((sample) => sample.senderCompleteMs)));
|
|
168
|
+
tasks.push(summarizeTask(`${result.mode}: receiver-complete`, result.samples.map((sample) => sample.receiverCompleteMs)));
|
|
169
|
+
tasks.push(summarizeTask(`${result.mode}: sender-after-receiver`, result.samples.map((sample) => sample.senderAfterReceiverMs)));
|
|
170
|
+
tasks.push(summarizeTask(`${result.mode}: receiver-after-sender`, result.samples.map((sample) => sample.receiverAfterSenderMs)));
|
|
171
|
+
}
|
|
172
|
+
const output = {
|
|
173
|
+
name: "chunk-transfer",
|
|
174
|
+
tasks,
|
|
175
|
+
meta: {
|
|
176
|
+
chunkBytes,
|
|
177
|
+
chunkCount,
|
|
178
|
+
totalBytes,
|
|
179
|
+
totalMb: round(totalMb, 3),
|
|
180
|
+
hops: 3,
|
|
181
|
+
warmupIterations,
|
|
182
|
+
iterations,
|
|
183
|
+
timeoutMs,
|
|
184
|
+
results: results.map((result) => ({
|
|
185
|
+
mode: result.mode,
|
|
186
|
+
senderCompleteMsAvg: round(average(result.samples.map((sample) => sample.senderCompleteMs))),
|
|
187
|
+
receiverCompleteMsAvg: round(average(result.samples.map((sample) => sample.receiverCompleteMs))),
|
|
188
|
+
senderAfterReceiverMsAvg: round(average(result.samples.map((sample) => sample.senderAfterReceiverMs))),
|
|
189
|
+
receiverAfterSenderMsAvg: round(average(result.samples.map((sample) => sample.receiverAfterSenderMs))),
|
|
190
|
+
senderMbPerSecondAvg: round(average(result.samples.map((sample) => totalMb / (sample.senderCompleteMs / 1000)))),
|
|
191
|
+
receiverMbPerSecondAvg: round(average(result.samples.map((sample) => totalMb / (sample.receiverCompleteMs / 1000)))),
|
|
192
|
+
samples: result.samples.map((sample) => ({
|
|
193
|
+
senderCompleteMs: round(sample.senderCompleteMs),
|
|
194
|
+
receiverCompleteMs: round(sample.receiverCompleteMs),
|
|
195
|
+
senderAfterReceiverMs: round(sample.senderAfterReceiverMs),
|
|
196
|
+
receiverAfterSenderMs: round(sample.receiverAfterSenderMs),
|
|
197
|
+
})),
|
|
198
|
+
})),
|
|
199
|
+
},
|
|
200
|
+
};
|
|
201
|
+
if (process.env.BENCH_JSON === "1") {
|
|
202
|
+
await new Promise((resolve, reject) => {
|
|
203
|
+
process.stdout.write(JSON.stringify(output, null, 2), (error) => {
|
|
204
|
+
if (error) {
|
|
205
|
+
reject(error);
|
|
206
|
+
return;
|
|
207
|
+
}
|
|
208
|
+
resolve();
|
|
209
|
+
});
|
|
210
|
+
});
|
|
211
|
+
}
|
|
212
|
+
else {
|
|
213
|
+
console.table(tasks.map((task) => ({
|
|
214
|
+
task: task.name,
|
|
215
|
+
mean_ms: task.mean_ms,
|
|
216
|
+
ops_s: round(task.hz, 3),
|
|
217
|
+
samples: task.samples,
|
|
218
|
+
})));
|
|
219
|
+
}
|
|
220
|
+
process.exit(0);
|
|
221
|
+
//# sourceMappingURL=chunk-transfer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chunk-transfer.js","sourceRoot":"","sources":["../../benchmark/chunk-transfer.ts"],"names":[],"mappings":"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"}
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
* pnpm -C packages/transport/stream run bench -- directstream-sim --nodes 500 --degree 6
|
|
6
6
|
* pnpm -C packages/transport/stream run bench -- topology-sim --nodes 2000 --degree 4
|
|
7
7
|
* pnpm -C packages/transport/stream run bench -- transfer
|
|
8
|
+
* pnpm -C packages/transport/stream run bench -- chunk-transfer
|
|
8
9
|
*/
|
|
9
10
|
export {};
|
|
10
11
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../benchmark/index.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../benchmark/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG"}
|
package/dist/benchmark/index.js
CHANGED
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
* pnpm -C packages/transport/stream run bench -- directstream-sim --nodes 500 --degree 6
|
|
6
6
|
* pnpm -C packages/transport/stream run bench -- topology-sim --nodes 2000 --degree 4
|
|
7
7
|
* pnpm -C packages/transport/stream run bench -- transfer
|
|
8
|
+
* pnpm -C packages/transport/stream run bench -- chunk-transfer
|
|
8
9
|
*/
|
|
9
10
|
const argv = process.argv.slice(2);
|
|
10
11
|
const bench = argv[0] === "--" ? argv[1] : argv[0];
|
|
@@ -18,12 +19,14 @@ const usage = () => {
|
|
|
18
19
|
"Benchmarks:",
|
|
19
20
|
" directstream-sim in-memory DirectStream network sim",
|
|
20
21
|
" topology-sim discrete-event topology/routing sim",
|
|
21
|
-
" transfer
|
|
22
|
+
" transfer real-libp2p transfer throughput bench",
|
|
23
|
+
" chunk-transfer chunked multi-hop transfer bench",
|
|
22
24
|
"",
|
|
23
25
|
"Examples:",
|
|
24
26
|
" pnpm -C packages/transport/stream run bench -- directstream-sim --nodes 500 --degree 6",
|
|
25
27
|
" pnpm -C packages/transport/stream run bench -- topology-sim --nodes 2000 --degree 4",
|
|
26
|
-
" pnpm -C packages/transport/stream run bench -- transfer",
|
|
28
|
+
" pnpm -C packages/transport/stream run bench -- transfer --sizes 262144,1048576 --mode both",
|
|
29
|
+
" pnpm -C packages/transport/stream run bench -- chunk-transfer",
|
|
27
30
|
].join("\n"));
|
|
28
31
|
};
|
|
29
32
|
if (!bench || bench === "--help" || bench === "-h") {
|
|
@@ -40,6 +43,9 @@ switch (bench) {
|
|
|
40
43
|
case "transfer":
|
|
41
44
|
await import("./transfer.js");
|
|
42
45
|
break;
|
|
46
|
+
case "chunk-transfer":
|
|
47
|
+
await import("./chunk-transfer.js");
|
|
48
|
+
break;
|
|
43
49
|
default:
|
|
44
50
|
usage();
|
|
45
51
|
process.exit(1);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../benchmark/index.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../benchmark/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AACnC,MAAM,KAAK,GAAG,IAAI,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAEnD,MAAM,KAAK,GAAG,GAAG,EAAE;IAClB,OAAO,CAAC,GAAG,CACV;QACC,4BAA4B;QAC5B,EAAE;QACF,QAAQ;QACR,qEAAqE;QACrE,EAAE;QACF,aAAa;QACb,wDAAwD;QACxD,yDAAyD;QACzD,2DAA2D;QAC3D,sDAAsD;QACtD,EAAE;QACF,WAAW;QACX,0FAA0F;QAC1F,uFAAuF;QACvF,8FAA8F;QAC9F,iEAAiE;KACjE,CAAC,IAAI,CAAC,IAAI,CAAC,CACZ,CAAC;AACH,CAAC,CAAC;AAEF,IAAI,CAAC,KAAK,IAAI,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,EAAE,CAAC;IACpD,KAAK,EAAE,CAAC;IACR,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AACjB,CAAC;AAED,QAAQ,KAAK,EAAE,CAAC;IACf,KAAK,kBAAkB;QACtB,MAAM,MAAM,CAAC,uBAAuB,CAAC,CAAC;QACtC,MAAM;IACP,KAAK,cAAc;QAClB,MAAM,MAAM,CAAC,mBAAmB,CAAC,CAAC;QAClC,MAAM;IACP,KAAK,UAAU;QACd,MAAM,MAAM,CAAC,eAAe,CAAC,CAAC;QAC9B,MAAM;IACP,KAAK,gBAAgB;QACpB,MAAM,MAAM,CAAC,qBAAqB,CAAC,CAAC;QACpC,MAAM;IACP;QACC,KAAK,EAAE,CAAC;QACR,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC"}
|
|
@@ -2,13 +2,10 @@ import { tcp } from "@libp2p/tcp";
|
|
|
2
2
|
import { TestSession } from "@peerbit/libp2p-test-utils";
|
|
3
3
|
import { AcknowledgeDelivery } from "@peerbit/stream-interface";
|
|
4
4
|
import { waitForResolved } from "@peerbit/time";
|
|
5
|
-
import B from "benchmark";
|
|
6
5
|
import crypto from "crypto";
|
|
6
|
+
import fs from "node:fs/promises";
|
|
7
|
+
import path from "node:path";
|
|
7
8
|
import { DirectStream, waitForNeighbour, } from "../src/index.js";
|
|
8
|
-
// Run with "node --loader ts-node/esm ./benchmark/transfer.ts"
|
|
9
|
-
// size: 100byte x 1,727 ops/sec ±2.61% (83 runs sampled)
|
|
10
|
-
// size: 1kb x 1,727 ops/sec ±2.61% (83 runs sampled)
|
|
11
|
-
// size: 1000kb x 104 ops/sec ±2.46% (83 runs sampled)
|
|
12
9
|
class TestStreamImpl extends DirectStream {
|
|
13
10
|
constructor(c) {
|
|
14
11
|
super(c, ["bench/0.0.0"], {
|
|
@@ -17,74 +14,238 @@ class TestStreamImpl extends DirectStream {
|
|
|
17
14
|
});
|
|
18
15
|
}
|
|
19
16
|
}
|
|
20
|
-
const
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
17
|
+
const parseArgs = (argv) => {
|
|
18
|
+
const get = (key) => {
|
|
19
|
+
const idx = argv.indexOf(key);
|
|
20
|
+
if (idx === -1)
|
|
21
|
+
return undefined;
|
|
22
|
+
return argv[idx + 1];
|
|
23
|
+
};
|
|
24
|
+
if (argv.includes("--help") || argv.includes("-h")) {
|
|
25
|
+
console.log([
|
|
26
|
+
"transfer.ts",
|
|
27
|
+
"",
|
|
28
|
+
"Real libp2p direct-stream transfer benchmark.",
|
|
29
|
+
"",
|
|
30
|
+
"Args:",
|
|
31
|
+
" --sizes BYTES[,BYTES...] payload sizes (default: 262144,1048576)",
|
|
32
|
+
" --iterations N measured iterations per run (default: 10)",
|
|
33
|
+
" --warmup N warmup iterations per run (default: 2)",
|
|
34
|
+
" --runs N repeated runs per case (default: 3)",
|
|
35
|
+
" --timeoutMs N per-iteration timeout (default: 30000)",
|
|
36
|
+
" --mode silent|ack|both delivery mode (default: both)",
|
|
37
|
+
" --json PATH write JSON results to file",
|
|
38
|
+
"",
|
|
39
|
+
"Examples:",
|
|
40
|
+
" pnpm -C packages/transport/stream run bench -- transfer",
|
|
41
|
+
" pnpm -C packages/transport/stream run bench -- transfer --sizes 1048576 --mode ack --runs 5",
|
|
42
|
+
].join("\n"));
|
|
43
|
+
process.exit(0);
|
|
44
|
+
}
|
|
45
|
+
const sizes = (get("--sizes") ?? "262144,1048576")
|
|
46
|
+
.split(",")
|
|
47
|
+
.map((value) => Number(value.trim()))
|
|
48
|
+
.filter((value) => Number.isFinite(value) && value > 0);
|
|
49
|
+
if (sizes.length === 0) {
|
|
50
|
+
throw new Error("Expected at least one positive size in --sizes");
|
|
51
|
+
}
|
|
52
|
+
const mode = (get("--mode") ?? "both");
|
|
53
|
+
if (!["silent", "ack", "both"].includes(mode)) {
|
|
54
|
+
throw new Error(`Unsupported --mode "${mode}"`);
|
|
55
|
+
}
|
|
56
|
+
return {
|
|
57
|
+
sizes,
|
|
58
|
+
iterations: Number(get("--iterations") ?? 10),
|
|
59
|
+
warmup: Number(get("--warmup") ?? 2),
|
|
60
|
+
runs: Number(get("--runs") ?? 3),
|
|
61
|
+
timeoutMs: Number(get("--timeoutMs") ?? 30_000),
|
|
62
|
+
mode,
|
|
63
|
+
json: get("--json"),
|
|
64
|
+
};
|
|
65
|
+
};
|
|
66
|
+
const average = (values) => values.reduce((sum, value) => sum + value, 0) / values.length;
|
|
67
|
+
const percentile = (values, p) => {
|
|
68
|
+
const sorted = [...values].sort((a, b) => a - b);
|
|
69
|
+
const idx = Math.min(sorted.length - 1, Math.max(0, Math.ceil(sorted.length * p) - 1));
|
|
70
|
+
return sorted[idx];
|
|
71
|
+
};
|
|
72
|
+
const round = (value, digits = 2) => Number(value.toFixed(digits));
|
|
73
|
+
const makePayload = (size, sequence) => {
|
|
74
|
+
const payload = crypto.randomBytes(size);
|
|
75
|
+
if (size >= 8) {
|
|
76
|
+
payload.writeUInt32BE(sequence >>> 0, 0);
|
|
77
|
+
payload.writeUInt32BE((sequence ^ 0x9e3779b9) >>> 0, 4);
|
|
78
|
+
}
|
|
79
|
+
return payload;
|
|
80
|
+
};
|
|
81
|
+
const matchesPayload = (data, sequence) => {
|
|
82
|
+
if (data.byteLength < 8) {
|
|
83
|
+
return true;
|
|
84
|
+
}
|
|
85
|
+
const view = Buffer.from(data.buffer, data.byteOffset, data.byteLength);
|
|
86
|
+
return (view.readUInt32BE(0) === (sequence >>> 0) &&
|
|
87
|
+
view.readUInt32BE(4) === ((sequence ^ 0x9e3779b9) >>> 0));
|
|
88
|
+
};
|
|
89
|
+
const waitForPayload = (receiver, sequence, timeoutMs) => new Promise((resolve, reject) => {
|
|
90
|
+
const timer = setTimeout(() => {
|
|
91
|
+
cleanup();
|
|
92
|
+
reject(new Error(`Timed out waiting for payload sequence=${sequence}`));
|
|
93
|
+
}, timeoutMs);
|
|
94
|
+
const onData = (event) => {
|
|
95
|
+
const data = event.detail.data;
|
|
96
|
+
if (!matchesPayload(data, sequence)) {
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
cleanup();
|
|
100
|
+
resolve();
|
|
101
|
+
};
|
|
102
|
+
const cleanup = () => {
|
|
103
|
+
clearTimeout(timer);
|
|
104
|
+
receiver.removeEventListener("data", onData);
|
|
105
|
+
};
|
|
106
|
+
receiver.addEventListener("data", onData);
|
|
53
107
|
});
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
108
|
+
const modeOptions = (mode, receiver) => mode === "ack"
|
|
109
|
+
? {
|
|
110
|
+
mode: new AcknowledgeDelivery({
|
|
111
|
+
redundancy: 1,
|
|
112
|
+
to: [receiver.publicKey],
|
|
113
|
+
}),
|
|
114
|
+
}
|
|
115
|
+
: {
|
|
116
|
+
to: [receiver.publicKey],
|
|
117
|
+
};
|
|
118
|
+
const summarize = (mode, sizeBytes, iterations, warmup, runs, iterationResults) => {
|
|
119
|
+
const publishResolved = iterationResults.map((result) => result.publishResolvedMs);
|
|
120
|
+
const receiverObserved = iterationResults.map((result) => result.receiverObservedMs);
|
|
121
|
+
const publisherTail = iterationResults.map((result) => result.publisherTailMs);
|
|
122
|
+
const complete = iterationResults.map((result) => result.completeMs);
|
|
123
|
+
const elapsedSeconds = complete.reduce((sum, value) => sum + value, 0) / 1_000;
|
|
124
|
+
const totalMb = (sizeBytes * iterationResults.length) / (1024 * 1024);
|
|
125
|
+
return {
|
|
126
|
+
mode,
|
|
127
|
+
sizeBytes,
|
|
128
|
+
iterations,
|
|
129
|
+
warmup,
|
|
130
|
+
runs,
|
|
131
|
+
metrics: {
|
|
132
|
+
publishResolvedMsAvg: round(average(publishResolved)),
|
|
133
|
+
receiverObservedMsAvg: round(average(receiverObserved)),
|
|
134
|
+
publisherTailMsAvg: round(average(publisherTail)),
|
|
135
|
+
publisherTailMsMedian: round(percentile(publisherTail, 0.5)),
|
|
136
|
+
publisherTailMsP95: round(percentile(publisherTail, 0.95)),
|
|
137
|
+
completeMsAvg: round(average(complete)),
|
|
138
|
+
completeMsMedian: round(percentile(complete, 0.5)),
|
|
139
|
+
completeMsP95: round(percentile(complete, 0.95)),
|
|
140
|
+
opsPerSecond: round(iterationResults.length / elapsedSeconds),
|
|
141
|
+
mbPerSecond: round(totalMb / elapsedSeconds),
|
|
79
142
|
},
|
|
143
|
+
iterationResults,
|
|
144
|
+
};
|
|
145
|
+
};
|
|
146
|
+
const main = async () => {
|
|
147
|
+
const options = parseArgs(process.argv.slice(2));
|
|
148
|
+
const session = await TestSession.disconnected(4, {
|
|
149
|
+
transports: [tcp()],
|
|
150
|
+
services: { directstream: (c) => new TestStreamImpl(c) },
|
|
80
151
|
});
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
152
|
+
try {
|
|
153
|
+
await session.connect([
|
|
154
|
+
[session.peers[0], session.peers[1]],
|
|
155
|
+
[session.peers[1], session.peers[2]],
|
|
156
|
+
[session.peers[2], session.peers[3]],
|
|
157
|
+
]);
|
|
158
|
+
const stream = (i) => session.peers[i].services.directstream;
|
|
159
|
+
await waitForNeighbour(stream(0), stream(1));
|
|
160
|
+
await waitForNeighbour(stream(1), stream(2));
|
|
161
|
+
await waitForNeighbour(stream(2), stream(3));
|
|
162
|
+
await stream(0).publish(new Uint8Array([123]), {
|
|
163
|
+
mode: new AcknowledgeDelivery({
|
|
164
|
+
redundancy: 1,
|
|
165
|
+
to: [stream(session.peers.length - 1).publicKey],
|
|
166
|
+
}),
|
|
167
|
+
});
|
|
168
|
+
await waitForResolved(() => stream(0).routes.isReachable(stream(0).publicKeyHash, stream(3).publicKeyHash));
|
|
169
|
+
const sender = stream(0);
|
|
170
|
+
const receiver = stream(3);
|
|
171
|
+
const modes = options.mode === "both" ? ["silent", "ack"] : [options.mode];
|
|
172
|
+
const results = [];
|
|
173
|
+
let sequence = 0;
|
|
174
|
+
for (const mode of modes) {
|
|
175
|
+
for (const sizeBytes of options.sizes) {
|
|
176
|
+
console.log(`Running transfer benchmark mode=${mode} sizeBytes=${sizeBytes} runs=${options.runs} iterations=${options.iterations} warmup=${options.warmup}`);
|
|
177
|
+
const iterationResults = [];
|
|
178
|
+
for (let run = 0; run < options.runs; run++) {
|
|
179
|
+
for (let warmupIteration = 0; warmupIteration < options.warmup; warmupIteration++) {
|
|
180
|
+
sequence++;
|
|
181
|
+
const payload = makePayload(sizeBytes, sequence);
|
|
182
|
+
const receivePromise = waitForPayload(receiver, sequence, options.timeoutMs);
|
|
183
|
+
await Promise.all([
|
|
184
|
+
sender.publish(payload, modeOptions(mode, receiver)),
|
|
185
|
+
receivePromise,
|
|
186
|
+
]);
|
|
187
|
+
}
|
|
188
|
+
for (let measuredIteration = 0; measuredIteration < options.iterations; measuredIteration++) {
|
|
189
|
+
sequence++;
|
|
190
|
+
const payload = makePayload(sizeBytes, sequence);
|
|
191
|
+
let publishResolvedMs = 0;
|
|
192
|
+
let receiverObservedMs = 0;
|
|
193
|
+
const startedAt = performance.now();
|
|
194
|
+
const receivePromise = waitForPayload(receiver, sequence, options.timeoutMs).then(() => {
|
|
195
|
+
receiverObservedMs = performance.now() - startedAt;
|
|
196
|
+
});
|
|
197
|
+
const publishPromise = sender
|
|
198
|
+
.publish(payload, modeOptions(mode, receiver))
|
|
199
|
+
.then(() => {
|
|
200
|
+
publishResolvedMs = performance.now() - startedAt;
|
|
201
|
+
});
|
|
202
|
+
await Promise.all([publishPromise, receivePromise]);
|
|
203
|
+
const publisherTailMs = Math.max(0, publishResolvedMs - receiverObservedMs);
|
|
204
|
+
iterationResults.push({
|
|
205
|
+
iteration: run * options.iterations + measuredIteration + 1,
|
|
206
|
+
publishResolvedMs: round(publishResolvedMs, 3),
|
|
207
|
+
receiverObservedMs: round(receiverObservedMs, 3),
|
|
208
|
+
publisherTailMs: round(publisherTailMs, 3),
|
|
209
|
+
completeMs: round(Math.max(publishResolvedMs, receiverObservedMs), 3),
|
|
210
|
+
});
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
results.push(summarize(mode, sizeBytes, options.iterations, options.warmup, options.runs, iterationResults));
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
console.table(results.map((result) => ({
|
|
217
|
+
mode: result.mode,
|
|
218
|
+
sizeBytes: result.sizeBytes,
|
|
219
|
+
runs: result.runs,
|
|
220
|
+
iterationsPerRun: result.iterations,
|
|
221
|
+
completeMsAvg: result.metrics.completeMsAvg,
|
|
222
|
+
completeMsMedian: result.metrics.completeMsMedian,
|
|
223
|
+
completeMsP95: result.metrics.completeMsP95,
|
|
224
|
+
publishResolvedMsAvg: result.metrics.publishResolvedMsAvg,
|
|
225
|
+
receiverObservedMsAvg: result.metrics.receiverObservedMsAvg,
|
|
226
|
+
publisherTailMsAvg: result.metrics.publisherTailMsAvg,
|
|
227
|
+
publisherTailMsMedian: result.metrics.publisherTailMsMedian,
|
|
228
|
+
publisherTailMsP95: result.metrics.publisherTailMsP95,
|
|
229
|
+
opsPerSecond: result.metrics.opsPerSecond,
|
|
230
|
+
mbPerSecond: result.metrics.mbPerSecond,
|
|
231
|
+
})));
|
|
232
|
+
const output = {
|
|
233
|
+
options,
|
|
234
|
+
results,
|
|
235
|
+
};
|
|
236
|
+
if (options.json) {
|
|
237
|
+
const outPath = path.resolve(options.json);
|
|
238
|
+
await fs.mkdir(path.dirname(outPath), { recursive: true });
|
|
239
|
+
await fs.writeFile(outPath, `${JSON.stringify(output, null, 2)}\n`);
|
|
240
|
+
}
|
|
241
|
+
console.log(JSON.stringify(output, null, 2));
|
|
242
|
+
}
|
|
243
|
+
finally {
|
|
244
|
+
await session.stop();
|
|
245
|
+
}
|
|
246
|
+
};
|
|
247
|
+
main().catch((error) => {
|
|
248
|
+
console.error(error);
|
|
249
|
+
process.exitCode = 1;
|
|
250
|
+
});
|
|
90
251
|
//# sourceMappingURL=transfer.js.map
|