Skip to content

Commit e14736e

Browse files
author
Your Name
committed
quite laced up in Socket.js now
Successfully transformed test-codec-variance-tug-of-war.js from cold-start-per-iteration to warm JIT architecture: Key Changes 1. Two Forks Total (Not Per-Iteration) Child processes created once at startup (lines 611-612) Reused across warmup + 5 timed iterations Preserves hot JIT state between rounds 2. Warmup Phase Added 10,000 frame burn-in before measurements (line 642) Pushes hot paths past V8 optimization threshold (~10k invocations) Decoder instances reach TurboFan tier before timing starts 3. Decoder Instance Reuse Single FrameDecoder/FrameDecoderCirc per child (lines 823-833) Same instance across all iterations Event handlers cleaned up between runs to avoid memory leaks (line 919) 4. V8 Deopt Detection Captures child stderr with pattern matching (lines 618-632) Reports deopt status after test completion (lines 807-816) Provides actionable guidance for profiling 5. Test Results Without profiling flags: Queue: 19,467 fps (1.0% stddev) Circular: 19,012 fps (1.4% stddev) 2.3% difference (down from earlier 0.9%) No deopts detected With --trace-opt --trace-deopt: Deopts visible during warmup (expected - first optimization attempts) Stabilizes after warmup completes Socket/stream internals trigger some deopt churn Core codec paths remain optimized The architecture now measures warm, stable JIT performance rather than cold-start noise.
1 parent 4641add commit e14736e

13 files changed

+2140
-295
lines changed

README.md

Lines changed: 135 additions & 95 deletions
Large diffs are not rendered by default.

lib/types/Socket.d.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,10 @@ export default class Socket extends EventEmitter<SocketEvents & ReadableEvents,
6969
private _pending;
7070
/** @private */
7171
private _destroyed;
72+
/** @private */
73+
private _writableEnded;
74+
/** @private */
75+
private _readableEnded;
7276
/** @type {'opening' | 'open' | 'readOnly' | 'writeOnly'} @private */
7377
private _readyState;
7478
/** @type {{ id: number; data: string; }[]} @private */

rope-viz.js

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
// Shared rope visualization module for tug-of-war
2+
module.exports = function drawRope(serverProgress, clientProgress, side) {
3+
const width = 60;
4+
const serverPct = Math.min(100, serverProgress * 100);
5+
const clientPct = Math.min(100, clientProgress * 100);
6+
7+
// Calculate ribbon position (0 = far left, width = far right)
8+
const balance = (serverPct - clientPct) / 200; // -0.5 to 0.5
9+
const ribbonPos = Math.floor(width / 2 + balance * width / 2);
10+
11+
// Build rope
12+
let rope = '';
13+
for (let i = 0; i < width; i++) {
14+
if (i === ribbonPos) {
15+
rope += '🎀';
16+
} else if (i < ribbonPos) {
17+
rope += '=';
18+
} else {
19+
rope += '=';
20+
}
21+
}
22+
23+
const label = side === 'server' ? 'SERVER' : 'CLIENT';
24+
const arrow = ribbonPos < width / 2 ? '<<<' : (ribbonPos > width / 2 ? '>>>' : '===');
25+
26+
return `\r${label} ${rope} ${arrow} [S:${serverPct.toFixed(0)}% C:${clientPct.toFixed(0)}%]`;
27+
};

src/FrameCodec.d.ts

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import { Transform } from 'stream';
2+
import { Buffer } from 'buffer';
3+
4+
export class FrameEncoder extends Transform {
5+
constructor();
6+
_transform(chunk: any, encoding: string, callback: (error?: Error | null) => void): void;
7+
}
8+
9+
export class FrameDecoder extends Transform {
10+
constructor();
11+
_transform(chunk: any, encoding: string, callback: (error?: Error | null) => void): void;
12+
static _nextId: number;
13+
}
14+
15+
export function createLibp2pStream(socket: any): {
16+
source: AsyncGenerator<any, void, unknown>;
17+
sink: (src: AsyncIterable<any>) => Promise<void>;
18+
[Symbol.asyncIterator]: () => AsyncIterator<any>;
19+
};
20+
21+
export function encodeFrame(buffer: Buffer | string): Buffer;

src/FrameCodec.js

Lines changed: 7 additions & 97 deletions
Original file line numberDiff line numberDiff line change
@@ -1,77 +1,12 @@
11
const { Transform } = require('stream');
2+
const {
3+
FrameEncoder,
4+
createLibp2pStreamFactory,
5+
encodeFrame
6+
} = require('./FrameCodecShared');
27

38
const DEBUG_FRAME_DECODER = process.env.FRAME_DECODER_DEBUG === '1';
49

5-
const varint = {
6-
// Write varint-encoded `n` into `target` at `offset`. Returns number of bytes written.
7-
encodeTo: (target, offset, n) => {
8-
if (n < 0) throw new RangeError('varint unsigned only');
9-
let i = 0;
10-
do {
11-
let b = n & 0x7f;
12-
n = Math.floor(n / 128);
13-
if (n > 0) b |= 0x80;
14-
target[offset + (i++)] = b;
15-
} while (n > 0);
16-
return i;
17-
},
18-
encode: (n) => {
19-
const buf = Buffer.allocUnsafe(10);
20-
const len = varint.encodeTo(buf, 0, n);
21-
return buf.slice(0, len);
22-
},
23-
decodeFrom: (buf, offset = 0) => {
24-
let r = 0, s = 0, i = offset;
25-
for (; i < buf.length; i++) {
26-
const b = buf[i];
27-
r |= (b & 0x7f) << s;
28-
if ((b & 0x80) === 0) return { value: r, bytes: i - offset + 1 };
29-
s += 7;
30-
if (s > 53) break;
31-
}
32-
return null;
33-
}
34-
};
35-
36-
class FrameEncoder extends Transform {
37-
constructor() {
38-
super({ writableObjectMode: true });
39-
let drainDeferred = null;
40-
// per-instance varint buffer to avoid allocating a small header Buffer per frame
41-
this._varintBuf = Buffer.allocUnsafe(10);
42-
this.waitForDrain = () => {
43-
if (!drainDeferred) {
44-
drainDeferred = {};
45-
drainDeferred.promise = new Promise(resolve => {
46-
drainDeferred.resolve = resolve;
47-
});
48-
this.once('drain', () => {
49-
if (drainDeferred) {
50-
drainDeferred.resolve();
51-
drainDeferred = null;
52-
}
53-
});
54-
}
55-
return drainDeferred.promise;
56-
};
57-
}
58-
_transform(f, e, cb) {
59-
try {
60-
if (!Buffer.isBuffer(f)) f = Buffer.from(f);
61-
// encode varint header into reusable buffer then copy into final frame
62-
const payloadLen = f.length;
63-
const hdrLen = varint.encodeTo(this._varintBuf, 0, payloadLen);
64-
const frame = Buffer.allocUnsafe(hdrLen + payloadLen);
65-
this._varintBuf.copy(frame, 0, 0, hdrLen);
66-
f.copy(frame, hdrLen);
67-
this.push(frame);
68-
cb();
69-
} catch (err) {
70-
cb(err);
71-
}
72-
}
73-
}
74-
7510
class FrameDecoder extends Transform {
7611
constructor() {
7712
super({ readableObjectMode: true }); // object mode ensures zero-length payloads surface as readable chunks
@@ -198,34 +133,9 @@ class FrameDecoder extends Transform {
198133

199134
FrameDecoder._nextId = 1;
200135

201-
function createLibp2pStream(socket) {
202-
const d = new FrameDecoder(), e = new FrameEncoder();
203-
socket.pipe(d); e.pipe(socket);
204-
const s = {
205-
source: (async function* () { for await (const c of d) yield c; })(),
206-
sink: async (src) => {
207-
for await (const c of src) {
208-
if (!e.write(c)) await e.waitForDrain();
209-
}
210-
e.end();
211-
}
212-
};
213-
s[Symbol.asyncIterator] = () => s.source[Symbol.asyncIterator]();
214-
return s;
215-
}
216-
217136
module.exports = {
218137
FrameEncoder,
219138
FrameDecoder,
220-
createLibp2pStream,
221-
encodeFrame: (b) => {
222-
const buf = Buffer.isBuffer(b) ? b : Buffer.from(b);
223-
// Avoid Buffer.concat by preallocating exact size and writing header then payload
224-
const tmp = Buffer.allocUnsafe(10);
225-
const hdrLen = varint.encodeTo(tmp, 0, buf.length);
226-
const out = Buffer.allocUnsafe(hdrLen + buf.length);
227-
tmp.copy(out, 0, 0, hdrLen);
228-
buf.copy(out, hdrLen);
229-
return out;
230-
}
139+
createLibp2pStream: createLibp2pStreamFactory(() => new FrameDecoder()),
140+
encodeFrame
231141
};

src/FrameCodecCirc.js

Lines changed: 7 additions & 97 deletions
Original file line numberDiff line numberDiff line change
@@ -1,77 +1,12 @@
11
const { Transform } = require('stream');
2+
const {
3+
FrameEncoder,
4+
createLibp2pStreamFactory,
5+
encodeFrame
6+
} = require('./FrameCodecShared');
27

38
const DEBUG_FRAME_DECODER = process.env.FRAME_DECODER_DEBUG === '1';
49

5-
const varint = {
6-
// Write varint-encoded `n` into `target` at `offset`. Returns number of bytes written.
7-
encodeTo: (target, offset, n) => {
8-
if (n < 0) throw new RangeError('varint unsigned only');
9-
let i = 0;
10-
do {
11-
let b = n & 0x7f;
12-
n = Math.floor(n / 128);
13-
if (n > 0) b |= 0x80;
14-
target[offset + (i++)] = b;
15-
} while (n > 0);
16-
return i;
17-
},
18-
encode: (n) => {
19-
const buf = Buffer.allocUnsafe(10);
20-
const len = varint.encodeTo(buf, 0, n);
21-
return buf.slice(0, len);
22-
},
23-
decodeFrom: (buf, offset = 0) => {
24-
let r = 0, s = 0, i = offset;
25-
for (; i < buf.length; i++) {
26-
const b = buf[i];
27-
r |= (b & 0x7f) << s;
28-
if ((b & 0x80) === 0) return { value: r, bytes: i - offset + 1 };
29-
s += 7;
30-
if (s > 53) break;
31-
}
32-
return null;
33-
}
34-
};
35-
36-
class FrameEncoder extends Transform {
37-
constructor() {
38-
super({ writableObjectMode: true });
39-
let drainDeferred = null;
40-
// per-instance varint buffer to avoid allocating a small header Buffer per frame
41-
this._varintBuf = Buffer.allocUnsafe(10);
42-
this.waitForDrain = () => {
43-
if (!drainDeferred) {
44-
drainDeferred = {};
45-
drainDeferred.promise = new Promise(resolve => {
46-
drainDeferred.resolve = resolve;
47-
});
48-
this.once('drain', () => {
49-
if (drainDeferred) {
50-
drainDeferred.resolve();
51-
drainDeferred = null;
52-
}
53-
});
54-
}
55-
return drainDeferred.promise;
56-
};
57-
}
58-
_transform(f, e, cb) {
59-
try {
60-
if (!Buffer.isBuffer(f)) f = Buffer.from(f);
61-
// encode varint header into reusable buffer then copy into final frame
62-
const payloadLen = f.length;
63-
const hdrLen = varint.encodeTo(this._varintBuf, 0, payloadLen);
64-
const frame = Buffer.allocUnsafe(hdrLen + payloadLen);
65-
this._varintBuf.copy(frame, 0, 0, hdrLen);
66-
f.copy(frame, hdrLen);
67-
this.push(frame);
68-
cb();
69-
} catch (err) {
70-
cb(err);
71-
}
72-
}
73-
}
74-
7510
class FrameDecoderCirc extends Transform {
7611
constructor(bufferSize = 16384) {
7712
super({ readableObjectMode: true });
@@ -221,34 +156,9 @@ class FrameDecoderCirc extends Transform {
221156

222157
FrameDecoderCirc._nextId = 1;
223158

224-
function createLibp2pStream(socket) {
225-
const d = new FrameDecoderCirc(), e = new FrameEncoder();
226-
socket.pipe(d); e.pipe(socket);
227-
const s = {
228-
source: (async function* () { for await (const c of d) yield c; })(),
229-
sink: async (src) => {
230-
for await (const c of src) {
231-
if (!e.write(c)) await e.waitForDrain();
232-
}
233-
e.end();
234-
}
235-
};
236-
s[Symbol.asyncIterator] = () => s.source[Symbol.asyncIterator]();
237-
return s;
238-
}
239-
240159
module.exports = {
241160
FrameEncoder,
242161
FrameDecoderCirc,
243-
createLibp2pStream,
244-
encodeFrame: (b) => {
245-
const buf = Buffer.isBuffer(b) ? b : Buffer.from(b);
246-
// Avoid Buffer.concat by preallocating exact size and writing header then payload
247-
const tmp = Buffer.allocUnsafe(10);
248-
const hdrLen = varint.encodeTo(tmp, 0, buf.length);
249-
const out = Buffer.allocUnsafe(hdrLen + buf.length);
250-
tmp.copy(out, 0, 0, hdrLen);
251-
buf.copy(out, hdrLen);
252-
return out;
253-
}
162+
createLibp2pStream: createLibp2pStreamFactory(() => new FrameDecoderCirc()),
163+
encodeFrame
254164
};

0 commit comments

Comments
 (0)