metrics

package
v0.0.21 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 21, 2026 License: MIT Imports: 8 Imported by: 0

Documentation

Overview

Package metrics tracks per-frame timing budgets for imzero2 — Go render, Rust interpret, and vsync slack. Exposes a metrics.Current singleton that the metrics-overlay widget reads each frame.

Index

Constants

View Source
const SlowFrameThresholdNs int64 = 25_000_000

SlowFrameThresholdNs is the real-work budget at or above which FrameMetrics.RecordBytes emits a structured warning. "Real work" is the Go-side widget build (render) plus the Rust-side interpret — the two slots the app can actually regress, and disjoint ones (the Rust side nets out the time it spent waiting on Go's stream, so this is not render counted twice). Sync wait is deliberately excluded; see [shouldWarnSlowFrame] for why. Set to 1.5 × the 60 Hz frame budget so jitter that stays inside vsync slack stays quiet, but a frame whose work missed its deadline surfaces with its breakdown (render_us / sync_us / interpret_us / written_b / read_b / frame).

The log line is intentionally emitted from RecordBytes — last call in the frame lifecycle — so the timings (set by EndFrame just before) and the wire byte counters (set inside RecordBytes itself) line up against the same frame. Use case is stutter triage: a run of log lines whose render_us or interpret_us is elevated names the slot — Go-render or Rust-interpret — that overran. Zero disables.

Variables

View Source
var Current = NewFrameMetrics()

Current is the singleton consumed by the overlay widget and written to from the frame loop. Zero-value usable via NewFrameMetrics.

View Source
var PackageProps = packageprops.Props{
	WASMWASI:         packageprops.WASMCompiles,
	WASMJS:           packageprops.WASMCompiles,
	WASMFreestanding: packageprops.WASMCompiles,
}

PackageProps records this package's curated properties (ADR-0080). Seeded by `boxer code analysis golang wasmsurvey props generate`; curate by hand. The same group's `props verify` reconciles it.

Functions

This section is empty.

Types

type FrameMetrics

type FrameMetrics struct {
	LastRenderNs    int64
	LastSyncNs      int64
	LastTotalNs     int64
	LastWritten     int64
	LastRead        int64
	LastInterpretNs int64
	LastPassNr      uint64

	EmaRenderNs    float64
	EmaSyncNs      float64
	EmaTotalNs     float64
	EmaWritten     float64
	EmaRead        float64
	EmaInterpretNs float64
	// contains filtered or unexported fields
}

FrameMetrics holds per-frame counters captured on the Go side. The struct is single-threaded by construction: the imzero2 frame loop runs in one goroutine, so no synchronisation is required.

The lifecycle of a single frame is:

BeginFrame()   — at StartServersideFrame, stamps tStart
BeforeSync()   — after user widget code, before End/Reset/Sync
EndFrame()     — after Sync returns, commits render/sync deltas
RecordBytes()  — from the application loop, after RenderLoopHandler
                  returned, captures wire bytes for the just-finished frame

All "Last*" fields hold the most recently committed frame; the overlay renders these at the *next* frame's MenuBar (one-frame display lag, invisible at 60 Hz).

func NewFrameMetrics

func NewFrameMetrics() *FrameMetrics

func (*FrameMetrics) BeforeSync

func (inst *FrameMetrics) BeforeSync()

func (*FrameMetrics) BeginFrame

func (inst *FrameMetrics) BeginFrame()

func (*FrameMetrics) EndFrame

func (inst *FrameMetrics) EndFrame()

EndFrame commits the timing deltas measured between BeginFrame, BeforeSync, and now. Tolerant of a missing BeforeSync stamp: if BeforeSync was never called for this frame (e.g. an early-return path in the renderer) render time is reported as the full frame and sync time as zero, rather than spuriously spiking the display.

func (*FrameMetrics) FpsDigest

func (inst *FrameMetrics) FpsDigest() *tdigest.TDigest

FpsDigest returns the windowed frame-rate distribution for the overlay to hand to a distsummary widget. The pointer is stable across frames; the digest is rebuilt in place by rebuildFpsDigest. Single-threaded with the frame loop (same goroutine), so no synchronisation is required.

func (*FrameMetrics) RecordBytes

func (inst *FrameMetrics) RecordBytes(written int, read int)

RecordBytes is called from the outer frame loop once the just-finished frame's wire counters can be sampled (after RenderLoopHandler returned and Sync drained the inbound register fetches).

When the frame's real work (render + interpret) crosses SlowFrameThresholdNs — see [shouldWarnSlowFrame] — a structured warning is emitted with the full per-frame breakdown, total_us included so the excluded sync wait stays visible during triage.

func (*FrameMetrics) RecordRust

func (inst *FrameMetrics) RecordRust(interpretUs uint64, passNr uint64)

RecordRust commits the Rust-side per-frame metrics drained from the fetchFrameMetrics fetcher in StateManager.Sync. Reports the previous completed Rust frame's interpret_commands_outer elapsed (one-frame display lag, invisible at 60 Hz). interpretUs is microseconds; 0 means the first frame has not yet completed Rust-side.

func (*FrameMetrics) Snapshot

func (inst *FrameMetrics) Snapshot() (s Snapshot)

type Snapshot

type Snapshot struct {
	FrameCounter uint64
	RenderNs     int64
	SyncNs       int64
	TotalNs      int64
	RawTotalNs   int64
	InterpretNs  int64
	SlackNs      int64
	WrittenBytes int64
	ReadBytes    int64
	RustPassNr   uint64
}

Snapshot is an immutable view of the last completed frame, suitable for rendering. All ns values are smoothed via EMA; LastTotalNs is also included raw for callers that want the unsmoothed value. SlackNs is the vsync residual: TotalNs (Go-side wall clock = render + sync) minus InterpretNs (Rust compute). It captures how much of the 16.6 ms budget is spent waiting on the next vsync rather than on either side's work.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL