summaryrefslogtreecommitdiff
path: root/scripts/profile-multiworld.sh
diff options
context:
space:
mode:
authorSomhairle H. Marisol <[email protected]>2026-09-29 04:23:26 +0800
committerSomhairle H. Marisol <[email protected]>2026-09-29 04:23:26 +0800
commitf681867692f575b078f46afaf07060faed457461 (patch)
tree4ab11638357891257703e55f5aa790868e902e3c /scripts/profile-multiworld.sh
parent2d9e4d845019b6c8793633258a45b91e0358e0e9 (diff)
downloadliving-village-f681867692f575b078f46afaf07060faed457461.tar.gz
p59: Sim 多世界并存后台压测(内存/GC 增长曲线证据单,只读)
目标:量化「多世界并存 × 天数」的内存/GC 增长,收口 P49 范围外项。 口径:新增 Headless `--profile-multiworld <worlds> <days> <npcs> <sampleEveryDays> <seedBase>`, N 个 Sim 世界同时存活,每轮 Parallel.For 各推进 sampleEveryDays 天并采样一行 (worlds/events/rumors/annals/memory_entries/gc_live_mb/working_set_rss_mb/elapsed_s, 行尾 flush);未改 Kernel/Sim 任何语义(Sim.initialWorldN / Sim.step 原样调用)。 标定:1 世界 × 2 天探针 = 34.2s(与 overnight-status 的 34.6s 一致),据此定 N=10 × 20 天。 运行:独立 systemd --user transient unit living-village-multiworld.service (scripts/profile-multiworld.sh,StandardOutput=append: + exec 2>&1,state.json 记 pid/unit/log/commit/参数/起止/exit)。主运行 wall=1024.4s(17.1min < 40min),exit=0。 结论(artifacts/perf-multiworld/20260928T195839Z/README.md): - 随世界数近似线性,未超线性:N=1 vs N=10(同日 D=20)annals/memory_entries 恰 10×、 rumors 9.67×、gc_live 8.81×(每世界 1.23MB,共享运行时开销摊薄)。 - RSS 有界无泄漏:N=10 39→峰值123(day8)→稳定104~112MB;每 2 天一轮墙钟恒 101~105s。 原因是历史集合有界(rumorRetentionDays=3 / rumorCapacity=16384 / maxAnnalEntries=128 / Mind.Memory 上限),约 day4 后进入稳态。 - 两轮世界0 digest 一致(2364CB74…)→ 并存+并行不改变单世界语义。 - 数字未越界 → 明确「不修」;只读本 slice 不修 Kernel/Sim。 回归:Desktop 304/304 + Kernel 119/119;--performance-baseline ×3 digest 953775FAEB2F… 不变,performance_determinism=PASS。未 push。
Diffstat (limited to 'scripts/profile-multiworld.sh')
-rwxr-xr-xscripts/profile-multiworld.sh80
1 files changed, 80 insertions, 0 deletions
diff --git a/scripts/profile-multiworld.sh b/scripts/profile-multiworld.sh
new file mode 100755
index 0000000..3ab099d
--- /dev/null
+++ b/scripts/profile-multiworld.sh
@@ -0,0 +1,80 @@
+#!/usr/bin/env bash
+# P59 多世界并存后台压测 MasterProcess(systemd --user transient unit 的 ExecStart)。
+#
+# 职责:
+# * 在 <PMW_DIR> 落 state.json(pid/unit/log/commit/参数/起止/exit);
+# * 以 2>&1 运行 Headless `--profile-multiworld N D npcs sampleEvery seedBase`,
+# 逐采样行流式打印并 flush;
+# * 退出时写回 ended_at/exit,并回传真实退出码。
+#
+# 环境变量(由 unit/transient 属性注入):
+# PMW_REPO / PMW_DIR / PMW_COMMIT / PMW_LOG
+# PMW_WORLDS(默认 10)/ PMW_DAYS(默认 20)/ PMW_NPCS(默认 30)
+# PMW_SAMPLE_EVERY(默认 2)/ PMW_SEED_BASE(默认 42)
+set -u
+
+REPO="${PMW_REPO:?PMW_REPO required}"
+DIR="${PMW_DIR:?PMW_DIR required}"
+COMMIT="${PMW_COMMIT:?PMW_COMMIT required}"
+WORLDS="${PMW_WORLDS:-10}"
+DAYS="${PMW_DAYS:-20}"
+NPCS="${PMW_NPCS:-30}"
+SAMPLE_EVERY="${PMW_SAMPLE_EVERY:-2}"
+SEED_BASE="${PMW_SEED_BASE:-42}"
+LOG="${PMW_LOG:-$REPO/artifacts/perf-multiworld/latest/acceptance.log}"
+UNIT="living-village-multiworld.service"
+DLL="$REPO/src/LivingVillage.Headless/bin/Release/net8.0/LivingVillage.Headless.dll"
+
+mkdir -p "$DIR"
+if [ ! -f "$DLL" ]; then
+ echo "[pmw] FATAL missing build: $DLL" >&2
+ exit 90
+fi
+
+STARTED="$(date -u +%Y-%m-%dT%H:%M:%SZ)"
+echo "$$" > "$DIR/pid"
+echo "[pmw] start unit=$UNIT pid=$$ commit=$COMMIT worlds=$WORLDS days=$DAYS npcs=$NPCS sample_every=$SAMPLE_EVERY seed_base=$SEED_BASE started_at=$STARTED"
+
+python3 - "$DIR/state.json" "$UNIT" "$COMMIT" "$WORLDS" "$DAYS" "$NPCS" "$SAMPLE_EVERY" "$SEED_BASE" "$LOG" "$STARTED" "$$" <<'PY'
+import json, sys
+out, unit, commit, worlds, days, npcs, sample, seed, log, started, pid = sys.argv[1:12]
+state = {
+ "pid": int(pid),
+ "unit": unit,
+ "log": log,
+ "commit": commit,
+ "params": {
+ "worlds": int(worlds),
+ "days": int(days),
+ "npcs": int(npcs),
+ "sample_every_days": int(sample),
+ "seed_base": int(seed),
+ },
+ "started_at": started,
+ "ended_at": None,
+ "exit": None,
+}
+with open(out, "w", encoding="utf-8") as fh:
+ json.dump(state, fh, ensure_ascii=False, indent=2, sort_keys=True)
+ fh.write("\n")
+PY
+
+( exec dotnet "$DLL" --profile-multiworld "$WORLDS" "$DAYS" "$NPCS" "$SAMPLE_EVERY" "$SEED_BASE" 2>&1 )
+CODE=$?
+
+ENDED="$(date -u +%Y-%m-%dT%H:%M:%SZ)"
+echo "[pmw] end pid=$$ exit=$CODE ended_at=$ENDED"
+
+python3 - "$DIR/state.json" "$CODE" "$ENDED" <<'PY'
+import json, sys
+path, code, ended = sys.argv[1:4]
+with open(path, encoding="utf-8") as fh:
+ state = json.load(fh)
+state["ended_at"] = ended
+state["exit"] = int(code)
+with open(path, "w", encoding="utf-8") as fh:
+ json.dump(state, fh, ensure_ascii=False, indent=2, sort_keys=True)
+ fh.write("\n")
+PY
+
+exit "$CODE"