diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/LivingVillage.Desktop.Tests/M3BatchOutputTests.fs | 5 | ||||
| -rw-r--r-- | src/LivingVillage.Headless/BatchOutput.fs | 4 | ||||
| -rw-r--r-- | src/LivingVillage.Headless/Program.fs | 19 |
3 files changed, 24 insertions, 4 deletions
diff --git a/src/LivingVillage.Desktop.Tests/M3BatchOutputTests.fs b/src/LivingVillage.Desktop.Tests/M3BatchOutputTests.fs index e962e57..b1822c7 100644 --- a/src/LivingVillage.Desktop.Tests/M3BatchOutputTests.fs +++ b/src/LivingVillage.Desktop.Tests/M3BatchOutputTests.fs @@ -27,6 +27,11 @@ type M3BatchOutputTests () = Assert.AreEqual<string>("[done 4/4] elapsed=600.0s world=3", BatchOutput.doneLine 4 4 600.0 3) [<TestMethod>] + member _.ProgressLineReportsSteppedDayWithinWorld () = + Assert.AreEqual<string>("[world 7] progress day=5/15 elapsed=61.2s", BatchOutput.progressLine 7 5L 15L 61.2) + Assert.AreEqual<string>("[world 0] progress day=15/15 elapsed=260.0s", BatchOutput.progressLine 0 15L 15L 260.0) + + [<TestMethod>] member _.SummaryLineKeepsOldFieldsAndAppendsWallClock () = let line = BatchOutput.summaryLine 4 3 1 4 1.100 9.900 0.010 0.400 4 610.5 // 监督器正则只读前三个字段,前缀必须逐字保持。 diff --git a/src/LivingVillage.Headless/BatchOutput.fs b/src/LivingVillage.Headless/BatchOutput.fs index aeaef52..971da97 100644 --- a/src/LivingVillage.Headless/BatchOutput.fs +++ b/src/LivingVillage.Headless/BatchOutput.fs @@ -22,6 +22,10 @@ module BatchOutput = let doneLine (completed: int) (total: int) (elapsedSeconds: float) (world: int) : string = sprintf "[done %d/%d] elapsed=%.1fs world=%d" completed total elapsedSeconds world + /// 单世界内部步进进度行:每推进 stepEvery 个模拟日打印一次,长世界不再零进度。 + let progressLine (world: int) (day: int64) (totalDays: int64) (elapsedSeconds: float) : string = + sprintf "[world %d] progress day=%d/%d elapsed=%.1fs" world day totalDays elapsedSeconds + /// batch_summary:旧字段原样保留,追加 workers 与 wall_s(总墙钟,append 不删旧字段)。 let summaryLine (worlds: int) diff --git a/src/LivingVillage.Headless/Program.fs b/src/LivingVillage.Headless/Program.fs index 23434d0..4bd6424 100644 --- a/src/LivingVillage.Headless/Program.fs +++ b/src/LivingVillage.Headless/Program.fs @@ -71,7 +71,7 @@ type RunStats = OutOfBounds: int64 World: World } -let runSimulation (verbose: bool) (days: int64) (seed: uint64) (npcCount: int) : RunStats = +let runSimulationCore (verbose: bool) (days: int64) (seed: uint64) (npcCount: int) (onSimDay: int64 -> unit) : RunStats = let totalTicks = days * ticksPerDay if verbose then printfn "living-village headless days=%d seed=%d npcs=%d ticks=%d tickrate=%d" days seed npcCount totalTicks ticksPerSecond @@ -102,6 +102,7 @@ let runSimulation (verbose: bool) (days: int64) (seed: uint64) (npcCount: int) : driver <- d world <- Sim.step { Input = input } world t <- t + 1L + if t % ticksPerDay = 0L then onSimDay (t / ticksPerDay) let nightNow = Sim.isNightTick t if nightNow then nightTicks <- nightTicks + 1L else dayTicks <- dayTicks + 1L for npc in world.Npcs do @@ -152,6 +153,9 @@ let runSimulation (verbose: bool) (days: int64) (seed: uint64) (npcCount: int) : OutOfBounds = outOfBounds World = world } +let runSimulation (verbose: bool) (days: int64) (seed: uint64) (npcCount: int) : RunStats = + runSimulationCore verbose days seed npcCount ignore + let dumpRelations (world: World) : unit = let m = Sim.relationMatrix world let n = Array2D.length1 m @@ -405,9 +409,9 @@ type WorldVerdict = Ratio: float Gini: float } -let evalWorld (days: int64) (k: int) : WorldVerdict = +let evalWorld (days: int64) (k: int) (onSimDay: int64 -> unit) : WorldVerdict = let seed = 42UL + uint64 k - let stats = runSimulation false days seed Sim.npcCount + let stats = runSimulationCore false days seed Sim.npcCount onSimDay let m = Sim.relationMatrix stats.World let n = Array2D.length1 m let mutable hasNonFinite = stats.NonFinite > 0L @@ -461,11 +465,18 @@ let runBatch (worlds: int) (days: int64) : int = let wall = System.Diagnostics.Stopwatch.StartNew() // 逐世界流式:每个世界一完成立刻打印该行(行尾追加 elapsed_s),再打印一行 // [done k/N] 进度,并 flush,使长批次不再整轮零进度。结果仍按 world 序号落数组。 + let progressGate = obj () + let progressEvery = if days <= 5L then 1L else (days + 4L) / 5L let results = LivingVillage.Headless.BatchOutput.runStreaming worlds workers (fun k -> let sw = System.Diagnostics.Stopwatch.StartNew() - let verdict = evalWorld days k + let verdict = + evalWorld days k (fun day -> + if day % progressEvery = 0L then + lock progressGate (fun () -> + printfn "%s" (LivingVillage.Headless.BatchOutput.progressLine k day days sw.Elapsed.TotalSeconds) + Console.Out.Flush())) sw.Stop() (verdict, sw.Elapsed.TotalSeconds)) (fun k (verdict, seconds) doneCount -> |
