mirror of
https://github.com/vrtmrz/obsidian-livesync.git
synced 2026-07-17 18:16:01 +00:00
Add P2P signalling-only netem benchmark
This commit is contained in:
@@ -12,6 +12,15 @@ function readEnvString(name: string, fallback: string): string {
|
||||
return value && value.length > 0 ? value : fallback;
|
||||
}
|
||||
|
||||
function readEnvInteger(name: string, fallback: number): number {
|
||||
const value = readEnvString(name, String(fallback));
|
||||
const parsed = Number(value);
|
||||
if (!Number.isInteger(parsed) || parsed < 1) {
|
||||
throw new Error(`${name} must be a positive integer, got '${value}'`);
|
||||
}
|
||||
return parsed;
|
||||
}
|
||||
|
||||
function timestamp(): string {
|
||||
const d = new Date();
|
||||
const pad = (n: number) => String(n).padStart(2, "0");
|
||||
@@ -41,6 +50,7 @@ function buildCases(): BenchmarkCase[] {
|
||||
const tetheringVpnRtt = readEnvString("BENCH_TETHERING_VPN_RTT_MS", "120");
|
||||
const localTurnServers = readEnvString("BENCH_LOCAL_TURN_SERVERS", "turn:127.0.0.1:3478");
|
||||
const shimCouchdbUri = readEnvString("BENCH_SHIM_COUCHDB_URI", "http://couchdb-shim:5984");
|
||||
const signallingShimRelay = readEnvString("BENCH_SIGNAL_SHIM_RELAY", "ws://p2p-signalling-shim:7777/");
|
||||
|
||||
return [
|
||||
{
|
||||
@@ -136,6 +146,44 @@ function buildCases(): BenchmarkCase[] {
|
||||
"structural-placeholder-only; selected ICE pair may be collected, but the path is not shaped",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "p2p-signalling-netem-home-wifi",
|
||||
runner: "p2p",
|
||||
description:
|
||||
"Tier 2 P2P path with only the Nostr signalling relay accessed through the home-wifi netem shim.",
|
||||
dataPath: "Device A -> Device B over WebRTC DataChannel; Nostr signalling through netem shim",
|
||||
trustBoundary: "Nostr signalling metadata through constrained network shim; no TURN relay",
|
||||
env: {
|
||||
...base,
|
||||
BENCH_CASE: "p2p-signalling-netem-home-wifi",
|
||||
BENCH_RELAY: signallingShimRelay,
|
||||
BENCH_TURN_SERVERS: "",
|
||||
BENCH_SIMULATION_TIER: "2",
|
||||
BENCH_NETWORK_PROFILE: "home-wifi",
|
||||
BENCH_NETWORK_MODEL: "compose-netem-signalling-shim",
|
||||
BENCH_P2P_CANDIDATE_PATH_VERIFICATION:
|
||||
"selected ICE pair collected; only Nostr signalling path is shaped",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "p2p-signalling-netem-tethering-vpn",
|
||||
runner: "p2p",
|
||||
description:
|
||||
"Tier 2 P2P path with only the Nostr signalling relay accessed through the tethering-vpn netem shim.",
|
||||
dataPath: "Device A -> Device B over WebRTC DataChannel; Nostr signalling through netem shim",
|
||||
trustBoundary: "Nostr signalling metadata through constrained smartphone/VPN-like network shim; no TURN relay",
|
||||
env: {
|
||||
...base,
|
||||
BENCH_CASE: "p2p-signalling-netem-tethering-vpn",
|
||||
BENCH_RELAY: signallingShimRelay,
|
||||
BENCH_TURN_SERVERS: "",
|
||||
BENCH_SIMULATION_TIER: "2",
|
||||
BENCH_NETWORK_PROFILE: "tethering-vpn",
|
||||
BENCH_NETWORK_MODEL: "compose-netem-signalling-shim",
|
||||
BENCH_P2P_CANDIDATE_PATH_VERIFICATION:
|
||||
"selected ICE pair collected; only Nostr signalling path is shaped",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "p2p-user-turn",
|
||||
runner: "p2p",
|
||||
@@ -156,16 +204,25 @@ function buildCases(): BenchmarkCase[] {
|
||||
];
|
||||
}
|
||||
|
||||
async function runCase(testCase: BenchmarkCase, outputDir: string): Promise<Record<string, unknown>> {
|
||||
const resultPath = `${outputDir}/${testCase.name}.json`;
|
||||
async function runCase(
|
||||
testCase: BenchmarkCase,
|
||||
outputDir: string,
|
||||
repeatIndex: number,
|
||||
repeatCount: number
|
||||
): Promise<Record<string, unknown>> {
|
||||
const suffix = repeatCount > 1 ? `-r${String(repeatIndex).padStart(2, "0")}` : "";
|
||||
const resultPath = `${outputDir}/${testCase.name}${suffix}.json`;
|
||||
const taskName = testCase.runner === "p2p" ? "bench:p2p" : "bench:couchdb";
|
||||
const env = {
|
||||
...Deno.env.toObject(),
|
||||
...testCase.env,
|
||||
BENCH_RESULT_JSON: resultPath,
|
||||
BENCH_REPEAT_INDEX: String(repeatIndex),
|
||||
BENCH_REPEAT_COUNT: String(repeatCount),
|
||||
};
|
||||
|
||||
console.log(`[bench-cases] running ${testCase.name}: ${testCase.description}`);
|
||||
const repeatLabel = repeatCount > 1 ? ` (${repeatIndex}/${repeatCount})` : "";
|
||||
console.log(`[bench-cases] running ${testCase.name}${repeatLabel}: ${testCase.description}`);
|
||||
const command = new Deno.Command("deno", {
|
||||
args: ["task", taskName],
|
||||
cwd: import.meta.dirname,
|
||||
@@ -184,6 +241,9 @@ async function runCase(testCase: BenchmarkCase, outputDir: string): Promise<Reco
|
||||
const result = JSON.parse(await Deno.readTextFile(resultPath)) as Record<string, unknown>;
|
||||
return {
|
||||
...testCase,
|
||||
repeatIndex,
|
||||
repeatCount,
|
||||
resultPath,
|
||||
result,
|
||||
};
|
||||
}
|
||||
@@ -211,11 +271,13 @@ async function main(): Promise<void> {
|
||||
|
||||
const allCases = buildCases();
|
||||
const cases = selectCases(allCases);
|
||||
const repeatCount = readEnvInteger("BENCH_REPEAT_COUNT", 1);
|
||||
await Deno.writeTextFile(
|
||||
`${outputDir}/case-manifest.json`,
|
||||
JSON.stringify(
|
||||
{
|
||||
generatedAt: new Date().toISOString(),
|
||||
repeatCount,
|
||||
selectedCases: cases,
|
||||
availableCases: allCases,
|
||||
},
|
||||
@@ -226,12 +288,15 @@ async function main(): Promise<void> {
|
||||
|
||||
const results: Record<string, unknown>[] = [];
|
||||
for (const testCase of cases) {
|
||||
results.push(await runCase(testCase, outputDir));
|
||||
for (let repeatIndex = 1; repeatIndex <= repeatCount; repeatIndex++) {
|
||||
results.push(await runCase(testCase, outputDir, repeatIndex, repeatCount));
|
||||
}
|
||||
}
|
||||
|
||||
const summary = {
|
||||
generatedAt: new Date().toISOString(),
|
||||
outputDir,
|
||||
repeatCount,
|
||||
results,
|
||||
};
|
||||
await Deno.writeTextFile(`${outputDir}/summary.json`, JSON.stringify(summary, null, 2));
|
||||
|
||||
Reference in New Issue
Block a user