Skip to content

Hot Path PFIFO Constant Status Read

github-actions[bot] edited this page Sep 14, 2026 · 4 revisions

PFIFO Constant Status Read

Lifecycle: Performance - Unproven · Type: Assumption lock bypass
State: Source-backed; runtime value is not established.

Status: Source-backed low-priority MMIO experiment; not implemented as a lock-free path and not benchmarked.

Reviewed source: 322986f4c5502b3fa887a9605ac8cd88e9b2c579

Scope: Exact reads of NV_PFIFO_RUNOUT_STATUS in pfifo_read().

This is the literal “xemu already knows the response” candidate from the additional audit. The current handler acquires the PFIFO mutex and enters the general register switch, but the NV_PFIFO_RUNOUT_STATUS branch returns a fixed xemu value without consulting mutable PFIFO state.

It is a candidate for one narrow early-read path—not a proposal to make status registers generally constant or to bypass MMIO semantics.

Why this is applicable

Current flow is effectively:

MMIO read
    -> acquire pfifo.lock
    -> switch address
    -> RUNOUT_STATUS returns LOW_MARK
    -> release lock
    -> register logging

The returned value is currently:

NV_PFIFO_RUNOUT_STATUS_LOW_MARK /* low mark empty */

The lock protects other PFIFO registers and state, but this branch does not read that state.

This is not already covered by Fast Fence Polling. The fence path serves an asynchronously changing PGRAPH register with ordered atomic publication. This candidate serves a constant value in xemu's current model and has a different proof obligation.

Why it may help

Potentially avoided work is limited to:

  • PFIFO mutex acquisition/release;
  • contention with the PFIFO pusher/puller thread;
  • general switch execution after an exact-address check.

However, MMIO dispatch, TCG exit/dispatch and register logging may dominate. This candidate matters only if guest software reads the status frequently and lock wait or lock traffic is measurable.

Current flow

flowchart TD
    A[Guest MMIO read] --> B[QEMU MemoryRegion dispatch]
    B --> C[pfifo_read]
    C --> D[Acquire pfifo.lock]
    D --> E[Switch register address]
    E -->|RUNOUT_STATUS| F[Return LOW_MARK constant]
    F --> G[Release pfifo.lock]
    G --> H[Log register read]
    H --> I[Return to guest]
Loading

Candidate flow

flowchart TD
    A[Guest MMIO read] --> B[QEMU MemoryRegion dispatch]
    B --> C[pfifo_read]
    C --> D{Exact RUNOUT_STATUS access accepted?}
    D -->|Yes| E[Use current modeled LOW_MARK value]
    E --> F[Preserve register logging]
    F --> G[Return to guest without pfifo.lock]
    D -->|No| H[Acquire pfifo.lock]
    H --> I[Use existing general register path]
    I --> J[Release lock and log]
Loading

Required access contract

Before bypassing the lock, verify the same conditions as the current MMIO registration/handler contract:

  • exact register address;
  • accepted access width and alignment;
  • endianness and masking behavior;
  • register logging/tracing;
  • no required side effect on read;
  • reset/snapshot behavior of the modeled value;
  • error behavior for unsupported access sizes.

Do not copy the PGRAPH fence path mechanically. A memory barrier pair is meaningful for a changing published fence value; it is unnecessary decoration for a true constant and could hide that the model itself should be improved instead.

Emulation boundary

The fixed response is an xemu implementation choice, not proof that physical NV2A hardware returns the value unconditionally under every FIFO condition.

The shortcut preserves current xemu behavior. If future hardware research implements dynamic runout state, this early path must be removed or changed to read the authoritative state.

Therefore the page and code should label the route as:

constant in the current model

not:

hardware constant

Seen in the wild

Internal xemu precedent: narrowly specialized MMIO paths already exist where a register has a proven cheaper access contract, including the PGRAPH fence fast path and direct fixed responses in other NV2A blocks.

General emulator precedent: device models often use direct handlers for side-effect-free constant or capability registers. The optimization is only useful when the register is hot; correctness comes from matching the device model's access contract, not from the constant itself.

Code and ownership map

Area Role
hw/xbox/nv2a/pfifo.c::pfifo_read() Current locked read and constant branch
PFIFO mutex Protects mutable PFIFO state used by other registers
MMIO registration/MemoryRegionOps Defines valid sizes/alignment/endianness
NV2A register logger Must remain observable when enabled
vCPU thread Executes the guest MMIO read
PFIFO worker Potential lock-contention peer

Evidence and counters

Before code changes, measure:

pfifo_mmio_reads
pfifo_runout_status_reads
pfifo_read_lock_acquisitions
pfifo_read_lock_wait_ns
pfifo_runout_status_read_cpu_ns
TCG/MMIO dispatch samples around the read

After a candidate:

runout_fast_reads
runout_reference_reads
unsupported_width_fallbacks
value/oracle mismatches

A high register-read count with negligible lock wait may still yield no useful improvement because the MMIO/TCG boundary remains.

Risks

  • Optimizing a cold register and adding permanent complexity for no gain.
  • Bypassing access-width or logging behavior.
  • Treating a current stub value as hardware truth.
  • Leaving the fast path after a future dynamic runout implementation.
  • Moving the bottleneck to MMIO/TCG dispatch with no guest-progress improvement.
  • Broadening the idea into unsafe lock-free reads of mutable PFIFO registers.

Qualification

  1. Count the register in representative titles before implementing.
  2. Confirm accepted access sizes and logging with focused MMIO tests.
  3. Add same-binary reference/fast route counters.
  4. Stress simultaneous guest reads and PFIFO worker activity.
  5. Compare exact returned values and traces.
  6. Profile vCPU/MMIO/lock cost in optimized Release builds with matching DWARF.
  7. Measure fixed guest progress and tails, not only helper nanoseconds.
  8. Add a source comment that invalidates the shortcut if runout status becomes dynamic.
  9. Remove the candidate if the route is cold or the improvement is below maintenance value.

Disposition

Applicable as a tiny measurement-driven experiment, not a priority feature. Add counters first. A permanent Advanced control is unlikely to be justified if the modeled response remains exact and exhaustive tests pass.

Related pages

Full technical reference

Primary reference: This subject page is the design and research reference for PFIFO Constant Status Read. Pull requests are implementation/test history only.
Lifecycle: Performance - Unproven · Mechanism: Current-model constant-response lock bypass
Reviewed source: 322986f4c5502b3fa887a9605ac8cd88e9b2c579 · Acceptance class: intended exact or behavior-preserving for its admitted scope

1. Scope

Return the value already modeled as constant for NV_PFIFO_RUNOUT_STATUS without taking the general PFIFO mutex, if access semantics and instrumentation remain intact.

This entry remains Unproven: the source path and opportunity are concrete, but no accepted xemu runtime result has established that the candidate improves representative workloads. The page defines what must be bypassed, what remains mandatory, and how the hypothesis can be rejected.

2. Source seams

File / function Role
hw/xbox/nv2a/pfifo.c pfifo_read() and NV_PFIFO_RUNOUT_STATUS handling

3. Current execution path

flowchart TD
    N0["Guest MMIO read"]
    N1["Enter generic PFIFO read route"]
    N0 --> N1
    N2["Acquire PFIFO mutex"]
    N1 --> N2
    N3["Switch on register"]
    N2 --> N3
    N4["Return LOW_MARK constant"]
    N3 --> N4
    N5["Release mutex"]
    N4 --> N5
Loading

4. Candidate execution path

flowchart TD
    N0["Guest MMIO read"]
    N1["Recognize exact address/width"]
    N0 --> N1
    N2["Return current-model constant atomically"]
    N1 --> N2
    N3["Use generic route for every other case"]
    N2 --> N3
Loading

5. Why it may help

The register branch returns a fixed value without consulting mutable PFIFO state. If the guest polls it frequently and lock acquisition contributes material cost, a narrow early return can preserve current emulator behavior while avoiding contention. This does not prove the physical hardware register is constant.

6. Work removed

  • PFIFO mutex acquisition/release
  • Generic register switch dispatch for this exact read

7. Work that remains mandatory

  • MMIO decode
  • Access-size/alignment checks
  • Tracing and counters
  • Every other register
  • Future model changes that make status dynamic

8. Implementation sketch

if (addr == NV_PFIFO_RUNOUT_STATUS && size == 4 &&
    current_model_runout_is_constant) {
    stats.runout_fast_reads++;
    return NV_PFIFO_RUNOUT_STATUS_LOW_MARK;
}
return pfifo_read_reference(d, addr, size);

The sketch defines the intended boundary; it is not a complete patch and does not replace source review, ownership design, or focused tests.

9. Correctness contract

  • The fast value must equal the reference path for the same access.
  • Access width, alignment, endianness, tracing, and fault behavior must remain identical.
  • The shortcut must be removed or disabled if the model gains mutable runout state.

10. State, ownership, invalidation, and fallback

No cached mutable object is required. The safety contract is tied to the current register model and should be encoded with a focused helper/assertion rather than a broad 'constant MMIO' framework.

The maintained reference path remains the fallback whenever admission, capability, lifetime, or validation is uncertain. A fast result with an unproven dependency is not acceptable as an exact optimization.

11. Advantages

  • Very small change
  • Exact maintained fallback
  • Can reduce lock contention in a true poll loop
  • Easy same-binary A/B and differential testing

12. Costs and failure modes

  • Likely negligible if MMIO/TCG dispatch dominates
  • Can fossilize an incomplete hardware model
  • Broadening to other registers would be dangerous
  • Added branch may cost more when the register is rare

13. Evidence counters

Counters must be cheap, subsystem-owned, and snapshotted outside the hot loop. Record at least:

  • runout_status_reads
  • runout_fast_reads
  • generic_pfifo_reads
  • pfifo_lock_wait_us
  • vCPU samples in MMIO dispatch
  • guest progress

A local reduction is not enough. Evidence must connect route reachability and removed work to fixed guest progress, CPU/GPU time where applicable, and p95/p99 behavior.

14. Qualification matrix

  • Compare fast/reference return and side effects
  • All access widths/alignment cases
  • Concurrent PFIFO activity
  • Trace/counter parity
  • A title or synthetic loop that reads the register heavily
  • Release A/B with route counters disabled for acceptance

Correctness runs may use validation layers, detailed comparisons, and fault injection. Performance acceptance must use optimized Release builds with matching symbols and minimal instrumentation.

15. Acceptance rule

Promote only if the register is read frequently enough and lock/dispatch measurements show repeatable benefit while preserving the current model exactly.

16. Rejection rule

Reject if route frequency is low, the lock is uncontended, MMIO dispatch dominates, or the register should become stateful for fidelity.

17. Related architecture and history

Platform-and-I-O · Performance-Unproven · Hot-Path-PGRAPH-Fast-Fence-Polling · Hot-Path-vCPU-Recognized-Poll-Loop-Wait

PR pages may be linked as supporting evidence, but they are not substitutes for this reference.

Clone this wiki locally