Skip to content

RustyNES v2.9.1 — "Hone" (what the optimisation bars measure, and what clears them)

Choose a tag to compare

@github-actions github-actions released this 27 Sep 19:24
47f848c

RustyNES v2.9.1 — "Hone"

The second release of the v2.9.x line that ADR 0041 put before the SuperStation One core (v3.0.0). It is the optimisation release, and it opens with the tool that judges optimisations: scripts/perf/ab_check.sh had been timing the old code on both sides of every code comparison. That is fixed and proven, and every earlier rejection that could be rebuilt was measured again. Emulation output does not change.

No hardware has run any bitstream; that is v2.9.2's subject.

The A/B tool compared the old code with itself

ab_check.sh built the reference (a worktree of the base commit) and the candidate (the working tree) into one cargo target directory. Cargo names a workspace member's build by its path relative to the workspace root, so the two trees shared artifact names, and cargo decides freshness by file time. The candidate step therefore ran the reference's binary. The proof: given a candidate that deliberately did its work twice, the old script reported "no change" (46.0 µs on both sides); the fixed one reports +146%. Each side now builds into a fresh directory of its own on every run.

A comparison of old code with itself can only ever say "no change", so the verdicts at risk were the rejections. Twelve were rebuilt and measured again, two runs each on a quiet host:

  • Three were wrong. Dropping the per-dot call to the dead NMI edge detector is 4.1% to 4.7% faster on palette-heavy frames. It is removed at v3.0.0 together with the detector and its save-state fields (ADR 0042, maintainer decision), because removing it now would change a deprecated method and two save-state fields in a minor release. Two "the ceiling is zero" results were not zero either, so correct candidates were built under both: a per-mapper capability that lets the bus skip the unmapped-read check for program reads (with a test over every board), and two branch-free palette mirrors. All three are rejected. Each gains at most about 1% on the palette-heavy workload and makes the default path slower in both runs, and a result that helps one workload while hurting another is a rejection, not an average.
  • The rest stay rejected, now on evidence, several of them measurably slower.

The full table, and the seven older rejections that survive only as prose and so stay unverified, are in docs/performance.md.

A two-screen Vs. cabinet saves about 9x faster

RetroArch saves the whole machine every frame for rewind and run-ahead. For the four two-screen Vs. System cabinets that meant two full console snapshots with thumbnails, into fresh buffers. VsDualSystem::snapshot_into writes both into a buffer RetroArch's call reuses: −88.9% and −88.5% on two runs. A pooled buffer for the matching restore measured no change and was not kept.

The MiSTer core

  • The off-die build keeps CHR and PRG in different SDRAM banks. A program read used to close the row a pattern fetch had open. Over a rendering workload the memory's row closes fell from 132,235 to 24,880, and the worst pattern fetch from 20 to 18 cycles of its 22. The worst program read stayed at 22 of 24: a refresh closes every bank, so the access after one misses wherever the data lives. A scheduled arbiter that also places refresh waits until after v3.0.0, since nothing before then adds memory traffic.
  • The co-simulation ladder runs every gate in one pass, the 16-ROM instruction battery included; v2.9.0 ran that battery by hand.
  • The timing check reads the SDRAM clock from the constraints and checks that the console clock is exactly four SDRAM clocks.
  • Fitter seed 2, from eight seeds per build, all sixteen closing timing. It has the most on-die margin on both measures. Two clean compiles of each build are byte-identical.

Verification

Check Result
cargo test --workspace --features test-roms 2,812 passed, 0 failed, 20 ignored
AccuracyCoin / nestest 144/144 / 0-diff
fmt, clippy (every feature set, wasm), rustdoc, no_std build clean
Co-simulation, on-die 171 passed, 0 failed, 1 expected failure (one clean-checkout run)
Co-simulation, off-die (USE_SDRAM=1) 172 passed, 0 failed, 1 expected failure (one clean-checkout run)
Quartus 17.0.2, seed 2, on-die setup +0.542 ns, hold +0.115 ns; 22,585 ALMs, 468 RAM blocks, 33 DSP; two clean compiles byte-identical
Quartus 17.0.2, seed 2, off-die setup +0.193 ns, hold +0.080 ns (SDRAM read +0.447 / +1.184 ns); 22,569 ALMs, 84 RAM blocks, 33 DSP; two clean compiles byte-identical

Next: v2.9.2, the release-candidate bitstream pair and the board session on the SuperStation One.

Install

  • Download the pre-built binaries for Linux, macOS, and Windows below.
  • The MiSTer core bitstreams are attached below: RustyNES_MiSTer-v2.9.1.rbf (on-die) and RustyNES_MiSTer-v2.9.1-offdie.rbf (cartridge in SDRAM; its name is provisional until v3.0.0). Neither has run on hardware.
  • The WebAssembly build is live at doublegate.github.io/RustyNES.
  • The RetroArch core is in RetroArch's Online Updater on the platforms the libretro buildbot publishes to.
  • Licensed under GPL-3.0-or-later.