Optimize storage, GC, and upload hot paths

This commit is contained in:
DioCrafts
2026-07-22 02:06:04 +02:00
parent 67fe944c2a
commit d66956824c
68 changed files with 16500 additions and 108 deletions
@@ -0,0 +1,798 @@
#!/usr/bin/env node
import { createServer } from "node:http";
import { mkdir, writeFile } from "node:fs/promises";
import { dirname, resolve } from "node:path";
import { performance } from "node:perf_hooks";
import { parseArgs } from "node:util";
import os from "node:os";
const MAX_DEDUP_HASHES = 10_000;
const UPLOAD_BATCH_BYTES = 8 * 1024 * 1024;
const CURSOR_COMPACT_AT = 4_096;
let blackhole = 0;
const { values } = parseArgs({
options: {
suite: { type: "string", default: "all" },
warmup: { type: "string", default: "3" },
samples: { type: "string", default: "15" },
"queue-counts": { type: "string", default: "64,256,1024,10000,50000" },
"progress-cases": {
type: "string",
default: "1:100,10:500,100:5000,1000:10000,10000:5000",
},
"hash-counts": { type: "string", default: "1000,10000,10001,25000" },
"dedup-batch-size": { type: "string", default: "10000" },
"dedup-concurrency": { type: "string", default: "4" },
"server-latency-ms": { type: "string", default: "0" },
"modeled-file-bytes": { type: "string", default: "65536" },
output: { type: "string" },
},
strict: true,
allowPositionals: false,
});
function positiveInteger(name, raw, allowZero = false) {
const value = Number(raw);
const lowerBound = allowZero ? 0 : 1;
if (!Number.isInteger(value) || value < lowerBound) {
throw new Error(
name + " must be an integer >= " + lowerBound + "; received " + raw,
);
}
return value;
}
function numberList(name, raw) {
const parsed = raw
.split(",")
.filter(Boolean)
.map((part) => positiveInteger(name, part));
if (parsed.length === 0) throw new Error(name + " must not be empty");
return parsed;
}
function progressCases(raw) {
const parsed = raw
.split(",")
.filter(Boolean)
.map((entry) => {
const parts = entry.split(":");
if (parts.length !== 2)
throw new Error("Invalid progress case: " + entry);
return {
items: positiveInteger("progress items", parts[0]),
updates: positiveInteger("progress updates", parts[1]),
};
});
if (parsed.length === 0) throw new Error("progress-cases must not be empty");
return parsed;
}
const config = {
suite: values.suite,
warmup: positiveInteger("warmup", values.warmup, true),
samples: positiveInteger("samples", values.samples),
queueCounts: numberList("queue-counts", values["queue-counts"]),
progressCases: progressCases(values["progress-cases"]),
hashCounts: numberList("hash-counts", values["hash-counts"]),
dedupBatchSize: positiveInteger(
"dedup-batch-size",
values["dedup-batch-size"],
),
dedupConcurrency: positiveInteger(
"dedup-concurrency",
values["dedup-concurrency"],
),
serverLatencyMs: positiveInteger(
"server-latency-ms",
values["server-latency-ms"],
true,
),
modeledFileBytes: positiveInteger(
"modeled-file-bytes",
values["modeled-file-bytes"],
),
};
if (!["all", "queue", "progress", "dedup"].includes(config.suite)) {
throw new Error("suite must be all, queue, progress, or dedup");
}
if (config.dedupBatchSize > MAX_DEDUP_HASHES) {
throw new Error(
"dedup-batch-size must be <= the server limit of " + MAX_DEDUP_HASHES,
);
}
function median(sorted) {
const middle = Math.floor(sorted.length / 2);
return sorted.length % 2 === 0
? (sorted[middle - 1] + sorted[middle]) / 2
: sorted[middle];
}
function summarize(samples) {
const times = samples.map((sample) => sample.ms).sort((a, b) => a - b);
const heaps = samples
.map((sample) => sample.heapDeltaBytes)
.sort((a, b) => a - b);
const rss = samples
.map((sample) => sample.rssDeltaBytes)
.sort((a, b) => a - b);
const p95Index = Math.max(0, Math.ceil(times.length * 0.95) - 1);
return {
sampleCount: samples.length,
medianMs: median(times),
p95Ms: times[p95Index],
minMs: times[0],
maxMs: times[times.length - 1],
medianHeapDeltaBytes: median(heaps),
medianRssDeltaBytes: median(rss),
};
}
function consume(result) {
const token = Number(
result.checksum ??
result.ownedCount ??
result.chunkCount ??
result.lastPercent ??
0,
);
blackhole = (blackhole ^ (token >>> 0)) >>> 0;
}
async function measureOne(fn) {
if (global.gc) global.gc();
const before = process.memoryUsage();
const started = performance.now();
const result = await fn();
const ms = performance.now() - started;
const after = process.memoryUsage();
consume(result);
return {
sample: {
ms,
heapDeltaBytes: after.heapUsed - before.heapUsed,
rssDeltaBytes: after.rss - before.rss,
},
result,
};
}
async function benchmarkPair(currentFn, candidateFn, verify) {
const checkedCurrent = await currentFn();
const checkedCandidate = await candidateFn();
verify(checkedCurrent, checkedCandidate);
for (let i = 0; i < config.warmup; i++) {
if (i % 2 === 0) {
consume(await currentFn());
consume(await candidateFn());
} else {
consume(await candidateFn());
consume(await currentFn());
}
}
const currentSamples = [];
const candidateSamples = [];
let currentResult = checkedCurrent;
let candidateResult = checkedCandidate;
for (let i = 0; i < config.samples; i++) {
const order =
i % 2 === 0
? [
["current", currentFn],
["candidate", candidateFn],
]
: [
["candidate", candidateFn],
["current", currentFn],
];
for (const [kind, fn] of order) {
const measured = await measureOne(fn);
if (kind === "current") {
currentSamples.push(measured.sample);
currentResult = measured.result;
} else {
candidateSamples.push(measured.sample);
candidateResult = measured.result;
}
}
}
const current = summarize(currentSamples);
const candidate = summarize(candidateSamples);
return {
current,
candidate,
speedup: current.medianMs / candidate.medianMs,
representative: {
current: currentResult,
candidate: candidateResult,
},
};
}
function makeChunks(count) {
const chunks = new Array(count);
let offset = 0;
for (let i = 0; i < count; i++) {
const size =
(1 + ((Math.imul(i + 1, 2_654_435_761) >>> 28) & 7)) * 32 * 1024;
chunks[i] = { h: "chunk-" + i, s: size, offset };
offset += size;
}
return chunks;
}
function foldBatch(batch, checksum) {
let next = checksum;
for (const chunk of batch) {
next = Math.imul(next ^ chunk.s ^ (chunk.offset >>> 0), 16_777_619) >>> 0;
}
return next;
}
function drainWithShift(source) {
const uploadQueue = source.slice();
let checksum = 2_166_136_261;
let chunkCount = 0;
let totalBytes = 0;
let batchCount = 0;
while (uploadQueue.length > 0) {
const batch = [];
let bytes = 0;
while (uploadQueue.length > 0 && bytes < UPLOAD_BATCH_BYTES) {
const chunk = uploadQueue.shift();
batch.push(chunk);
bytes += chunk.s;
}
checksum = foldBatch(batch, checksum);
chunkCount += batch.length;
totalBytes += bytes;
batchCount++;
}
return { checksum, chunkCount, totalBytes, batchCount };
}
function drainWithCursor(source) {
const uploadQueue = source.slice();
let head = 0;
let checksum = 2_166_136_261;
let chunkCount = 0;
let totalBytes = 0;
let batchCount = 0;
let compactions = 0;
while (head < uploadQueue.length) {
const batch = [];
let bytes = 0;
while (head < uploadQueue.length && bytes < UPLOAD_BATCH_BYTES) {
const chunk = uploadQueue[head];
uploadQueue[head] = undefined;
head++;
batch.push(chunk);
bytes += chunk.s;
}
checksum = foldBatch(batch, checksum);
chunkCount += batch.length;
totalBytes += bytes;
batchCount++;
if (head === uploadQueue.length) {
uploadQueue.length = 0;
head = 0;
} else if (head >= CURSOR_COMPACT_AT && head * 2 >= uploadQueue.length) {
uploadQueue.copyWithin(0, head);
uploadQueue.length -= head;
head = 0;
compactions++;
}
}
return { checksum, chunkCount, totalBytes, batchCount, compactions };
}
function verifyQueue(current, candidate) {
for (const key of ["checksum", "chunkCount", "totalBytes", "batchCount"]) {
if (current[key] !== candidate[key]) {
throw new Error(
"Queue candidate changed " +
key +
": " +
current[key] +
" vs " +
candidate[key],
);
}
}
}
function makeProgressEvents(items, updateCount) {
const indices = new Uint32Array(updateCount);
const values = new Float64Array(updateCount);
let state = 0x9e3779b9;
for (let i = 0; i < updateCount; i++) {
state ^= state << 13;
state ^= state >>> 17;
state ^= state << 5;
state >>>= 0;
indices[i] = state % items;
values[i] = (state & 1023) / 1024;
}
return { indices, values };
}
function recordProgress(checksum, sum, total) {
const percent = Math.round((sum / total) * 100);
const done = Math.round(sum);
return {
checksum: (checksum + Math.imul(percent + 1, done + 1)) >>> 0,
percent,
};
}
function progressWithFullScan(items, events) {
const fractions = new Array(items).fill(0);
let checksum = 0;
let lastPercent = 0;
let finalSum = 0;
for (let update = 0; update < events.indices.length; update++) {
fractions[events.indices[update]] = Math.min(1, events.values[update]);
let sum = 0;
for (const fraction of fractions) sum += fraction;
const recorded = recordProgress(checksum, sum, items);
checksum = recorded.checksum;
lastPercent = recorded.percent;
finalSum = sum;
}
return { checksum, lastPercent, finalSum };
}
function progressWithAccumulator(items, events) {
const fractions = new Array(items).fill(0);
let sum = 0;
let checksum = 0;
let lastPercent = 0;
for (let update = 0; update < events.indices.length; update++) {
const index = events.indices[update];
const next = Math.min(1, events.values[update]);
sum += next - fractions[index];
fractions[index] = next;
const recorded = recordProgress(checksum, sum, items);
checksum = recorded.checksum;
lastPercent = recorded.percent;
}
return { checksum, lastPercent, finalSum: sum };
}
function verifyProgress(current, candidate) {
if (
current.checksum !== candidate.checksum ||
current.lastPercent !== candidate.lastPercent
) {
throw new Error("Progress candidate changed user-visible progress values");
}
if (Math.abs(current.finalSum - candidate.finalSum) > Number.EPSILON * 8) {
throw new Error("Progress candidate changed final sum");
}
}
function makeHashes(count) {
const hashes = new Array(count);
for (let i = 0; i < count; i++) hashes[i] = i.toString(16).padStart(64, "0");
return hashes;
}
function isOwnedHash(hash) {
return (Number.parseInt(hash.at(-1), 16) & 1) === 0;
}
function emptyServerStats() {
return {
requests: 0,
acceptedRequests: 0,
rejectedRequests: 0,
requestBytes: 0,
responseBytes: 0,
maxBatchHashes: 0,
};
}
async function startDedupServer() {
let activeStats = emptyServerStats();
const server = createServer(async (request, response) => {
const parts = [];
for await (const part of request) parts.push(part);
const body = Buffer.concat(parts);
const parsed = JSON.parse(body.toString("utf8"));
const hashes = Array.isArray(parsed.hashes) ? parsed.hashes : [];
activeStats.requests++;
activeStats.requestBytes += body.byteLength;
activeStats.maxBatchHashes = Math.max(
activeStats.maxBatchHashes,
hashes.length,
);
if (config.serverLatencyMs > 0) {
await new Promise((resolveDelay) =>
setTimeout(resolveDelay, config.serverLatencyMs),
);
}
let status;
let responseBody;
if (hashes.length > MAX_DEDUP_HASHES) {
status = 400;
activeStats.rejectedRequests++;
responseBody = JSON.stringify({ error: "Too many hashes" });
} else {
status = 200;
activeStats.acceptedRequests++;
responseBody = JSON.stringify({ owned: hashes.filter(isOwnedHash) });
}
activeStats.responseBytes += Buffer.byteLength(responseBody);
response.writeHead(status, { "content-type": "application/json" });
response.end(responseBody);
});
await new Promise((resolveListen, rejectListen) => {
server.once("error", rejectListen);
server.listen(0, "127.0.0.1", resolveListen);
});
const address = server.address();
if (!address || typeof address === "string")
throw new Error("Could not determine mock server address");
return {
url: "http://127.0.0.1:" + address.port + "/api/dedup/check-batch",
resetStats() {
activeStats = emptyServerStats();
return activeStats;
},
async close() {
await new Promise((resolveClose, rejectClose) => {
server.close((error) => (error ? rejectClose(error) : resolveClose()));
});
},
};
}
async function postHashes(url, hashes) {
const response = await fetch(url, {
method: "POST",
headers: { "content-type": "application/json" },
body: JSON.stringify({ hashes }),
});
if (!response.ok) return new Set();
const data = await response.json().catch(() => null);
return new Set(data?.owned ?? []);
}
async function dedupCurrent(url, hashes) {
return postHashes(url, hashes);
}
async function dedupBatched(url, hashes) {
// Production keeps the former one-request path exact for the overwhelmingly
// common valid case: no slice, batching array, or Promise pool below the cap.
if (hashes.length <= MAX_DEDUP_HASHES) return postHashes(url, hashes);
const batches = [];
for (let start = 0; start < hashes.length; start += config.dedupBatchSize) {
batches.push(hashes.slice(start, start + config.dedupBatchSize));
}
const owned = new Set();
let next = 0;
const worker = async () => {
while (next < batches.length) {
const index = next++;
const batchOwned = await postHashes(url, batches[index]);
for (const hash of batchOwned) owned.add(hash);
}
};
await Promise.all(
Array.from(
{ length: Math.min(config.dedupConcurrency, batches.length) },
worker,
),
);
return owned;
}
function dedupRun(server, hashes, implementation) {
return async () => {
const stats = server.resetStats();
const owned = await implementation(server.url, hashes);
let checksum = 0;
for (const hash of owned)
checksum = (checksum + Number.parseInt(hash.slice(-8), 16)) >>> 0;
return {
checksum,
ownedCount: owned.size,
contentBytesAvoided: owned.size * config.modeledFileBytes,
...stats,
};
};
}
function verifyDedup(current, candidate, hashCount) {
const expectedOwned = Math.ceil(hashCount / 2);
if (hashCount <= MAX_DEDUP_HASHES) {
if (
current.ownedCount !== expectedOwned ||
candidate.ownedCount !== expectedOwned ||
current.checksum !== candidate.checksum
) {
throw new Error("Dedup fast path changed the ownership result");
}
if (
current.requests !== 1 ||
candidate.requests !== 1 ||
current.rejectedRequests !== 0 ||
candidate.rejectedRequests !== 0
) {
throw new Error("Dedup fast path must remain one accepted request");
}
return;
}
if (current.ownedCount !== 0 || current.rejectedRequests !== 1) {
throw new Error(
"Current >10k control did not reproduce the expected rejection",
);
}
if (candidate.ownedCount !== expectedOwned) {
throw new Error(
"Batched candidate found " +
candidate.ownedCount +
" owned hashes; expected " +
expectedOwned,
);
}
if (
candidate.rejectedRequests !== 0 ||
candidate.maxBatchHashes > MAX_DEDUP_HASHES
) {
throw new Error("Batched candidate exceeded the server request limit");
}
}
function repeatQueueDrain(fn, repetitions) {
let checksum = 0;
let chunkCount = 0;
let totalBytes = 0;
let batchCount = 0;
for (let iteration = 0; iteration < repetitions; iteration++) {
const result = fn();
checksum = (checksum + result.checksum) >>> 0;
chunkCount += result.chunkCount;
totalBytes += result.totalBytes;
batchCount += result.batchCount;
}
return { checksum, chunkCount, totalBytes, batchCount };
}
function repeatProgress(fn, repetitions) {
let checksum = 0;
let lastPercent = 0;
let finalSum = 0;
for (let iteration = 0; iteration < repetitions; iteration++) {
const result = fn();
checksum = (checksum + result.checksum) >>> 0;
lastPercent = result.lastPercent;
finalSum += result.finalSum;
}
return { checksum, lastPercent, finalSum };
}
function formatMs(value) {
if (value >= 100) return value.toFixed(1);
if (value >= 10) return value.toFixed(2);
return value.toFixed(3);
}
function formatBytes(value) {
const absolute = Math.abs(value);
const sign = value < 0 ? "-" : "";
if (absolute >= 1024 * 1024 * 1024)
return sign + (absolute / (1024 * 1024 * 1024)).toFixed(2) + " GiB";
if (absolute >= 1024 * 1024)
return sign + (absolute / (1024 * 1024)).toFixed(2) + " MiB";
if (absolute >= 1024) return sign + (absolute / 1024).toFixed(2) + " KiB";
return sign + absolute.toFixed(0) + " B";
}
function printPair(label, result) {
console.log(label);
console.log(
" current median " +
formatMs(result.current.medianMs) +
" ms; p95 " +
formatMs(result.current.p95Ms) +
" ms; heap delta " +
formatBytes(result.current.medianHeapDeltaBytes),
);
console.log(
" candidate median " +
formatMs(result.candidate.medianMs) +
" ms; p95 " +
formatMs(result.candidate.p95Ms) +
" ms; heap delta " +
formatBytes(result.candidate.medianHeapDeltaBytes),
);
console.log(" median speedup " + result.speedup.toFixed(2) + "x");
}
async function runQueueSuite(output) {
output.queue = [];
for (const count of config.queueCounts) {
const source = makeChunks(count);
const repetitions = count <= 1024 ? Math.ceil(200_000 / count) : 1;
const result = await benchmarkPair(
() => repeatQueueDrain(() => drainWithShift(source), repetitions),
() => repeatQueueDrain(() => drainWithCursor(source), repetitions),
verifyQueue,
);
output.queue.push({
chunkCount: count,
repetitions,
normalizedMedianUsPerDrain: {
current: (result.current.medianMs * 1000) / repetitions,
candidate: (result.candidate.medianMs * 1000) / repetitions,
},
...result,
});
printPair(
"A queue drain, " +
count.toLocaleString("en-US") +
" chunks x " +
repetitions.toLocaleString("en-US"),
result,
);
}
}
async function runProgressSuite(output) {
output.progress = [];
for (const scenario of config.progressCases) {
const events = makeProgressEvents(scenario.items, scenario.updates);
const repetitions =
scenario.items <= 100 ? Math.ceil(100_000 / scenario.updates) : 1;
const result = await benchmarkPair(
() =>
repeatProgress(
() => progressWithFullScan(scenario.items, events),
repetitions,
),
() =>
repeatProgress(
() => progressWithAccumulator(scenario.items, events),
repetitions,
),
verifyProgress,
);
output.progress.push({
...scenario,
repetitions,
normalizedMedianUsPerRun: {
current: (result.current.medianMs * 1000) / repetitions,
candidate: (result.candidate.medianMs * 1000) / repetitions,
},
...result,
});
printPair(
"B aggregate progress, " +
scenario.items.toLocaleString("en-US") +
" files x " +
scenario.updates.toLocaleString("en-US") +
" updates",
result,
);
}
}
async function runDedupSuite(output) {
output.dedup = [];
const server = await startDedupServer();
try {
for (const hashCount of config.hashCounts) {
const hashes = makeHashes(hashCount);
const result = await benchmarkPair(
dedupRun(server, hashes, dedupCurrent),
dedupRun(server, hashes, dedupBatched),
(current, candidate) => verifyDedup(current, candidate, hashCount),
);
output.dedup.push({ hashCount, ...result });
printPair(
"C dedup HTTP probe, " + hashCount.toLocaleString("en-US") + " hashes",
result,
);
if (hashCount <= MAX_DEDUP_HASHES) {
console.log(
" both paths used one accepted request and found " +
result.representative.current.ownedCount +
" owned hashes",
);
} else {
console.log(
" current rejected " +
result.representative.current.rejectedRequests +
" request and found " +
result.representative.current.ownedCount +
" owned hashes",
);
}
console.log(
" candidate used " +
result.representative.candidate.requests +
" accepted batches, found " +
result.representative.candidate.ownedCount +
", and avoided " +
formatBytes(result.representative.candidate.contentBytesAvoided) +
" of modeled content upload",
);
}
} finally {
await server.close();
}
}
const output = {
schemaVersion: 1,
generatedAt: new Date().toISOString(),
environment: {
node: process.version,
platform: process.platform,
release: os.release(),
arch: process.arch,
cpu: os.cpus()[0]?.model ?? "unknown",
logicalCpus: os.cpus().length,
gcExposed: Boolean(global.gc),
},
config,
notes: {
heap: "Median heap delta is indicative only; timing is the primary microbenchmark metric.",
dedup:
"The current >10k path is faster only because it is rejected and returns no owned hashes.",
},
suites: {},
};
if (!global.gc) {
console.warn("Warning: run with --expose-gc for less noisy heap deltas.");
}
console.log(
"Node " +
process.version +
"; warmup " +
config.warmup +
"; samples " +
config.samples +
"; GC exposed " +
Boolean(global.gc),
);
if (config.suite === "all" || config.suite === "queue")
await runQueueSuite(output.suites);
if (config.suite === "all" || config.suite === "progress")
await runProgressSuite(output.suites);
if (config.suite === "all" || config.suite === "dedup")
await runDedupSuite(output.suites);
output.blackhole = blackhole;
if (values.output) {
const destination = resolve(values.output);
await mkdir(dirname(destination), { recursive: true });
await writeFile(destination, JSON.stringify(output, null, 2) + "\n");
console.log("Wrote JSON result to " + destination);
}