summaryrefslogtreecommitdiff
path: root/src/LivingVillage.Kernel.Tests
diff options
context:
space:
mode:
authorSomhairle H. Marisol <[email protected]>2026-09-22 10:46:16 +0800
committerSomhairle H. Marisol <[email protected]>2026-09-22 10:46:16 +0800
commita0597455629618a282b582d13c23bfeab786e7d2 (patch)
tree5809eb48e9fcd7cba6823ba0b6c8ae5ae8a28ce2 /src/LivingVillage.Kernel.Tests
parent164f4749460a304c1aaad4900ef3facc29859eb0 (diff)
downloadliving-village-a0597455629618a282b582d13c23bfeab786e7d2.tar.gz
perf(kernel): P27 第二步 — Rumor 扫描去装箱 + 裁剪判定 O(1)
两条互相独立、均不改变保留集合与查询结果的优化: 1) 扫描去装箱:latestRumorFor / rumorIsDuplicate 用 `=` 比较 [<Struct>] 的 NpcId/RumorId(含 RumorId option)会走泛型结构相等并逐条装箱(实测 ~24 B/条, Sim.chat 单独测得 N=16000 时 393,736 B/次、随 N 线性)。改为先解构底层 int/int64 再比较;Parent 用 int64 option 比较替代 RumorId option 结构相等。 语义完全等价,扫描不再逐条分配。 2) 裁剪判定 O(1):World 新增派生镜像 RumorCount/RumorOldestDay(不参与存档, 读档由列表经 rumorWorkingSetStats 重建)。appendRumor 用「count+1>capacity 或 min(oldest,day)<cutoff」O(1) 判定,仅真需裁剪时才走 trimRumors;旧 consRumor 每次追加都 rumorsNeedTrim 全表扫一遍。条件与 needTrim 逐字等价,保留集合相同。 等价性验证:5 天 2000 聊天/天跑两遍 WorldSave.save 逐字节相同, RumorCount/RumorOldestDay 与对列表重算一致(count=8000、oldest_day=1)。 Kernel 长跑基准 30 NPC × 2000 聊天/天(--rumor-bench D 30 2000): days 修复前 alloc / ms 修复后 alloc / ms 3 930,716,456 / 1626.7 482,716,192 / 1511.3 30 13,419,045,864 / 12182.5 4,884,067,640 / 8879.6 60 27,297,668,608 / 23769.7 9,774,660,360 / 17078.2 60 天分配 -64%、耗时 -28%,retained_id_checksum=927964000 前后一致。 门槛:final_digest=953775FAEB2F... 三次一致、performance_determinism=PASS; Kernel 92 / Desktop 143 全绿;--cost-probe 1/5 天 18.7s/18.8GB、90.4s/94.6GB (全模拟分配由逐 tick NPC 快照主导,谣言子系统占比很小,故全模拟基本持平)。
Diffstat (limited to 'src/LivingVillage.Kernel.Tests')
-rw-r--r--src/LivingVillage.Kernel.Tests/RelationTests.fs4
-rw-r--r--src/LivingVillage.Kernel.Tests/RumorTests.fs2
-rw-r--r--src/LivingVillage.Kernel.Tests/TradeTests.fs2
3 files changed, 8 insertions, 0 deletions
diff --git a/src/LivingVillage.Kernel.Tests/RelationTests.fs b/src/LivingVillage.Kernel.Tests/RelationTests.fs
index b98252d..1a6d178 100644
--- a/src/LivingVillage.Kernel.Tests/RelationTests.fs
+++ b/src/LivingVillage.Kernel.Tests/RelationTests.fs
@@ -47,6 +47,8 @@ module RelationHarness =
Npcs = [| mkNpc 0 mem0; mkNpc 1 mem1 |]
Events = []
Rumors = []
+ RumorCount = 0
+ RumorOldestDay = System.Int64.MaxValue
Annals = [] }
let chatted (tick: int64) (partner: int) : MemoryEvent =
@@ -208,6 +210,8 @@ type RelationTests () =
Npcs = [| self; nearest; alternate |]
Events = []
Rumors = []
+ RumorCount = 0
+ RumorOldestDay = System.Int64.MaxValue
Annals = [] }
let next = Sim.step RelationHarness.zeroInput world
match List.tryHead next.Npcs.[0].Mind.Memory with
diff --git a/src/LivingVillage.Kernel.Tests/RumorTests.fs b/src/LivingVillage.Kernel.Tests/RumorTests.fs
index 2cbb189..e8cf07a 100644
--- a/src/LivingVillage.Kernel.Tests/RumorTests.fs
+++ b/src/LivingVillage.Kernel.Tests/RumorTests.fs
@@ -52,6 +52,8 @@ module private RumorHarness =
Npcs = Array.init count npc
Events = []
Rumors = []
+ RumorCount = 0
+ RumorOldestDay = System.Int64.MaxValue
Annals = [] }
let readyForChat (world: World) : World =
diff --git a/src/LivingVillage.Kernel.Tests/TradeTests.fs b/src/LivingVillage.Kernel.Tests/TradeTests.fs
index 77e5658..fa40ac3 100644
--- a/src/LivingVillage.Kernel.Tests/TradeTests.fs
+++ b/src/LivingVillage.Kernel.Tests/TradeTests.fs
@@ -56,6 +56,8 @@ module private TradeHarness =
npc 1 sellerMoney sellerHunger sellerFood sellerMemory None |]
Events = []
Rumors = []
+ RumorCount = 0
+ RumorOldestDay = System.Int64.MaxValue
Annals = [] }
let request quantity =