Skip to content

Let an embedder observe guest execution and GX timing - #22

Open
dougchansan wants to merge 1 commit into
ExpansionPak:moderngekko-vendorfrom
dougchansan:feat/staticrecomp-observers
Open

Let an embedder observe guest execution and GX timing#22
dougchansan wants to merge 1 commit into
ExpansionPak:moderngekko-vendorfrom
dougchansan:feat/staticrecomp-observers

Conversation

@dougchansan

@dougchansan dougchansan commented Sep 6, 2026

Copy link
Copy Markdown

Groundwork for ExpansionPak/ModernGekko#37, where every diagnostics zone reads 0.00 ms because nothing below the diagnostics library can report into it.

Retargeted from main to moderngekko-vendor. main does not configure for a ModernGekko consumer — it fails at Externals/tinygltf with No SOURCES given to target, with or without these changes (verified against plain main at 78bdce82). moderngekko-vendor is also the branch upstream ModernGekko pins.

Change

Three headers of optional pointers an embedder installs, null unless installed:

StaticRecompObserver.h — guest PC, guest execution time, and the core's existing dispatch/fallback/exception tallies.
VideoZoneObserver.h — FIFO, vertex, texture and shader time, plus draw/vertex/texture/EFB/shader tallies.
MmioObserver.h — MMIO read and write tallies, its own header so Core/HW gains no dependency on the others.

Probes at the points that already funnel: the dispatch loop, RunFifo, RunVertices, TexDecoder_Decode, the four ShaderCache::Compile*Shader methods, CopyRenderTargetToTexture, and MMIO Read/Write. 210 insertions, 1 deletion.

Cost

Granularity is the design. The guest PC is published on a 4096-dispatch cadence, guest time is measured once per timing slice, and the FIFO scope wraps a batch rather than each opcode. Cumulative counters are republished per slice rather than incremented per event. Measured rates that justify this: dispatches ~2.5M/s, MMIO ~26.6k/s, draw calls ~13.1k/s.

guest_cpu_ns is cumulative because the core has no notion of a frame; the consumer differences it.

Verification

Clean clone of ModernGekko's diagnostics branch with vendor/dolphin on this branch, x86_64 Linux, gcc 13.3.0, RelWithDebInfo:

CFG=0  BUILD=0  CTEST=0
100% tests passed, 0 tests failed out of 46

Mario Kart Double Dash GM4E01, windowed Vulkan, trace level:

GuestCpu                  13.861 ms      static_recomp_dispatches   52349514
ShaderGeneration           0.791 ms      mmio_reads/writes    313671 / 221773
GxCommandProcessor         0.356 ms      draw_calls                   280654
VertexLoader               0.024 ms      vertices_loaded             1752014
TextureDecoder             0.016 ms      efb_copies                     1028

LIKELY BOTTLENECK: CPU / guest execution bound
  Guest execution consumed 55.7% of frame time

Previously the zone table read (no zone timings recorded), every counter was 0, and the verdict was Insufficient evidence at 0.0% instrumented. hotspots.csv went from header-only to 512 rows, topped by 0x800EB638, which matches the core's own top dispatch site. Report contents remain free of usernames, paths and addresses.

Overhead across basic/detailed/trace is indistinguishable; repeated runs land within run-to-run host variance.

Not covered

Pipelines: CreatePipeline has 30 call sites and 8 backend implementations, so counting it needs the virtual wrapped in AbstractGfx — including D3D11/D3D12, which cannot be compiled or verified here. A documented zero beats an unverifiable cross-backend rename.

TextureDecodeBytes needs a per-format bits-per-pixel lookup rather than a tally, and GuestInstructions would need new counting on the 2.5M/s dispatch path. Both left out rather than approximated.

Note

The six VideoCommon and MMIO files are byte-identical between this branch and the revision ModernGekko pins, so they carry over as tested. StaticRecompCore_Run.cpp differs and was re-expressed against this branch's loop — that version is what the verification above was built from.

@dougchansan dougchansan changed the title Let an embedder observe guest PC and guest execution time Let an embedder observe guest execution and GX timing Sep 6, 2026
The core and the GX paths already know where time goes; none of it was
reachable from outside. Three headers of optional pointers an embedder
installs, and probes at the points that already funnel.

Granularity is the design: the guest PC is published on a 4096-dispatch
cadence, guest time is measured once per timing slice, and the FIFO scope
wraps a batch rather than each opcode. All pointers are null unless
installed, so an unobserved build pays one predictable branch.

Rebased from main onto moderngekko-vendor: main currently fails to configure
for a ModernGekko consumer at Externals/tinygltf, with or without these
changes.
@dougchansan
dougchansan changed the base branch from main to moderngekko-vendor September 7, 2026 04:57
@dougchansan
dougchansan force-pushed the feat/staticrecomp-observers branch from e5086e0 to 842d6fa Compare September 7, 2026 04:57
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant