A developer tool for in-game CPU profiling of BepInEx mods. Shows per-mod and per-method CPU load, spike alerts, A/B snapshots comparison and report export. Not intended for regular gameplay.
All notable changes to this project are documented here.
Format follows Keep a Changelog.
[1.1.1] — 2026-02-22
Added
nothing (welcome message)
[1.1.0] — 2026-02-22
Added
Method-level drill-down — click any mod row in the table to expand and see the top-10 heaviest methods inside it with individual AvgMs and Calls/s values.
Worst Frame line — orange line on the CPU graph showing a rolling per-frame maximum with slow decay. Helps spot intermittent lag spikes that averages would hide.
Event Markers — press MARK EVENT button to stamp a visible green vertical marker on the graph at the exact moment of interest (entering a dungeon, opening inventory, starting a fight, etc.).
Alerts tab — automatic spike detection. Any mod exceeding 16.6 ms in a single frame is recorded with timestamp and peak value. Stores up to 100 events, clearable on demand.
A/B Snapshot Compare tab — save two profiling snapshots and see a colour-coded delta table: red = regression, green = improvement.
Export to file — EXPORT button writes a full human-readable .txt report (per-mod stats, method details, alert log) to BepInEx/profiler_reports/.
Search & filter — live text filter on the mod table + toggle to hide mods below 0.1 ms noise threshold.
Resume Monitoring — after stopping, re-enable data collection without re-scanning all mods. Previously applied hooks remain active.
Stop Monitoring button — scan/monitor button is now a toggle: green SCAN MODS → red STOP MONITORING and back. State is always visible.
Fixed
Namespace mismatch (ProfilerValheim.Zeta vs ValheimModProfiler) that prevented the project from compiling.
missing using ValheimModProfiler.Instrumentation in IngameProfiler — ProfilerBootstrapper was not resolving, causing the scan button to flicker back to green in ~0.1 s.
_isRecording and _stack were not [ThreadStatic] — could corrupt self-time calculation under multi-threaded BepInEx hooks.
Silent catch {} blocks replaced with Logger.LogWarning(...) throughout ProfilerRecorder and ProfilerBootstrapper.
DrawLine / graph rendering called outside EventType.Repaint — caused Unity IMGUI warnings and visual artifacts. All graph drawing is now guarded.
GUI.contentColor leak — impact colour was not always reset after coloured rows, causing subsequent rows to inherit the wrong tint.
AvgMs in DrawLine used Atan instead of Atan2 — incorrect angle for nearly-vertical graph segments.
Dead file Class1.cs with mismatched namespace removed from project.
Changed
Snapshot accumulator now publishes a clonedTotalHistory and per-mod history arrays — UI can no longer read a buffer while EndFrame is writing into it.
CachedCallsString now shows N/s (calls per second) instead of a raw accumulation counter.
GlobalHistory now also maintained as WorstFrameHistory with slow decay for the worst-frame overlay.
[1.0.0] — 2026-02-22
Added
Initial release.
In-game profiler overlay (toggle with F8).
Per-mod CPU load: AvgMs, Impact %, Calls/s.
Rolling 300-frame CPU graph with per-mod colour lines and interactive tooltip.
SCAN MODS button — applies Harmony hooks to Update / FixedUpdate / LateUpdate of all installed BepInEx plugins at runtime.
Self-time measurement via call-stack tracking — child method time is subtracted from the parent, so each mod's cost is shown without double-counting.
Thread-safe sample collection via ConcurrentDictionary + Interlocked.