Skip to content

Performance Research A08 Voice Sample Spans

github-actions[bot] edited this page Sep 15, 2026 · 1 revision

Span-based voice fetch

A08 — Implementation and validation notes

Field Value
Evidence state Source-confirmed repeated translation; span observation semantics pending
Inspected source 322986f4c5502b3fa887a9605ac8cd88e9b2c579
First experiment One boundary-limited ordinary-RAM span
Scope Addendum dated September 15, 2026; not a current-main benchmark or implementation status

Unproven performance research · Performance research — common test protocol · Performance research — reproducible checks

Evidence and implementation reasoning

Confirmed route. voice_get_samples() walks PCM samples through physical-memory helpers. Non-streaming PCM translates an SGE-backed address per sample, and non-streaming ADPCM fetches block words through repeated SGE translation and physical reads. The source explicitly raises cross-page handling as an issue. Fetch implementation.

Implementation. Build a span limited by the earliest of the mapped RAM boundary, SGE/page boundary, SSL segment end, loop/end cursor, ADPCM block, or required notification/state transition. Decode a span while retaining the same state/cursor updates. Ordinary RAM can take the fast path; MMIO or ambiguous mappings retain the helper route.

Correctness boundary. Reading a span early changes when guest memory is observed. Establish the ownership/synchronization interval; a successful map does not make the underlying contents immutable. Avoid assuming physical contiguity from virtual/SGE contiguity, or trusting a sample's first byte to prove the remaining bytes are mapped identically. QEMU's memory API distinguishes direct RAM access, region lifetime, and dirty/invalidation obligations. Memory API.

Expected gain. Fewer helper calls and repeated address translations; more benefit for many active voices, small PCM samples, or fragmented non-streaming paths than for already contiguous streaming ADPCM. Measure translations and bytes per span.

Acceptance. Include page-crossing stereo samples, loops, SSL transitions, pause, end-of-stream notifications, partial reads, resampler callback repetition, and guest updates at span boundaries.

First patch boundary

Keep scalar/MMIO fallbacks. A mapped pointer does not freeze guest data; define when the batch observes writes before increasing span size.

sample cursor -> earliest mapping/SGE/SSL/loop/block boundary -> decode eligible span -> same cursor/notify updates

Locate the inspected seam before editing; names or ownership may have changed since the pinned review:

git grep -n -E 'voice_get_samples|get_data_ptr|adpcm' -- hw/xbox/mcpx/apu/vp

Proposed focused tests

These are implementation gates to add or exercise, not claims that production tests already exist or passed. Retained standalone checks are on the checks page.

Test ID Setup / deliberate control Required oracle
A08.01 A stereo sample crosses a page/SGE boundary into a noncontiguous physical mapping. Every byte comes from its correct mapping; the span splits before an invalid assumption.
A08.02 PCM and ADPCM around loop end, SSL segment transition, end-of-stream and repeated resampler callbacks. Decoded samples, cursor state and notification order match scalar behavior.
A08.03 Change guest sample memory at a declared span boundary; use MMIO/ambiguous mapping as a fallback control. The observation contract and fallback route are respected.

Counters and rejection criteria

Collect: sample_bytes, span_count, span_length_histogram, sge_translations, physical_reads, fallback_reasons, fetch_cpu_ns. Keep exact counts separate from sampled durations; use an uninstrumented build for performance qualification.

Reject or hold: Reject an output/cursor/notification difference or a change to guest-memory visibility. More bytes per span is not useful if it creates read-ahead work or stalls.

Follow the common protocol for source identities, previous-main/fixed-baseline controls, raw results, confidence and retail/XISO qualification. No gain becomes proven from a model, cache hit, local operation count, or shifted wait label alone.

Clone this wiki locally