Skip to content

soundserver takes rubato without its FFT resampler: rustfft and five more crates leave the lockfile, the resampling code unchanged - #811

Open
Japabu wants to merge 1 commit into
mainfrom
wt/toyos-rubato-r0
Open

Japabu wants to merge 1 commit into
mainfrom
wt/toyos-rubato-r0

Conversation

@Japabu

@Japabu Japabu commented Oct 9, 2026 •

Copy link
Copy Markdown
Collaborator

soundserver depends on rubato with default-features = false. soundserver builds only SincFixedOut. rubato's one default feature, fft_resampler, compiles only synchro.rs (FftFixedIn/FftFixedInOut/FftFixedOut) and swaps the FftNum bound on Sample from realfft's trait to a local trait with the same bounds (rubato-0.16.2/src/lib.rs:44,58, src/sample.rs:3-15). Turning it off removes six crates from Cargo.lock: rustfft, realfft, num-complex, strength_reduce, transpose and primal-check. Together they hold 66,876 lines of .rs in the registry sources (find <crate> -name '*.rs' | xargs cat | wc -l; rustfft alone has 59,502). rubato, num-integer and num-traits stay.

This is stage R0 of the audio resampler work. It changes nothing in soundserver's source.

The audio path is unchanged; the binary is not byte-identical

The evidence is in the PR comment "Evidence: the resampling path is unchanged". In short:

  • Host differential. Over a fixed input, rubato 0.16.2 with and without fft_resampler produces bit-identical output and the same input_frames_next/used/produced sequence. The test uses soundserver's exact parameters at 19 rate pairs. Both runs exit 0, both outputs hash to sha256 e0073d81…, and cmp returns 0. Negative control: changing f_cutoff by 1e-7 changes the output (cmp returns 1).
  • Shipped x86_64 soundserver. The binary changes: 916584 → 914032 bytes. After normalizing names and addresses, every function in both binaries has identical instructions, and the resampler path (rubato, toyos_mixer, soundserver::client) is identical. The constants that path loads are the same bytes. What went away is two allocator helpers rustfft had instantiated (RawVec::grow_one, finish_grow). Their instructions match the copies the binary keeps, and identical code folding now merges them.

Gates

Gate Head Exit Log
cargo run -- --build-only (base d6298c83e) base 0 build-before.log
cargo run -- --build-only 1c87ae677 0 build-after.log
cargo run -- --ci host 1c87ae677 0 (Host: 78 step(s), all green) ci-host.log
cargo test (whole guest suite) 1c87ae677 0 (41 passed, 41 total; uptime load 48.71 68.28 79.47 at start, 60.38 67.77 77.45 at end). An earlier run hit a full host disk (ENOSPC) and is void. guest.log
cargo test --test toyos-build -- --metal --metal-readback <dir> boot:testcases 1c87ae677 2: staged, machine not touched. testcases/image.img sha256 22682b7a…, testcases-watchdog/image.img 3440a70a… metal-stage.log
T14 boot:testcases, run by the orchestrator (both images' hashes checked, --fat32-check 0) 1c87ae677 judge 0: [metal] 249 passed, 0 failed, 2 boot(s), with hda_tone, hda_client_stall, shipped_client_departures, audio_idle_suspend green

Diff

Cargo.lock: −59 lines (six [[package]] entries, plus num-complex and realfft from rubato's dependencies). userland/soundserver/Cargo.toml: one line changed.

What I am unsure of

  • The object-code comparison covers x86_64 only. What proves AArch64 is the source argument: with fft_resampler off, the Sample bound is a local trait with the same bounds as rustfft's FftNum, no items and a blanket impl, so no item SincFixedOut<f32> calls changes. The host differential (rubato's NEON path on aarch64-apple-darwin) is a witness to that, not the proof.

🤖 Generated with Claude Code

https://claude.ai/code/session_017cSFvbD35xJ2kGANVdm23C

soundserver builds only `SincFixedOut`, which never reaches rubato's
`fft_resampler` feature: that default feature compiles `synchro.rs`
(`FftFixedIn`/`FftFixedInOut`/`FftFixedOut`) and swaps the `FftNum` bound
on `Sample` from realfft's to a local trait of the same bounds. Turning the
default off removes rustfft, realfft, num-complex, strength_reduce,
transpose and primal-check from the lockfile and the image's build.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017cSFvbD35xJ2kGANVdm23C
@Japabu

Japabu commented Oct 9, 2026

Copy link
Copy Markdown
Collaborator Author

Evidence: the resampling path is unchanged

Head 1c87ae677, base d6298c83e.

1. Host differential: rubato 0.16.2 with and without fft_resampler, soundserver's configuration

Two scratch crates outside the tree, identical but for the dependency line (rubato = "=0.16.2" vs rubato = { version = "=0.16.2", default-features = false }), built cargo build --release --offline, both share main.rs below. It runs SincFixedOut<f32> with client.rs's parameters (sinc_len 128, f_cutoff 0.95, Cubic, oversampling 128, BlackmanHarris2, max ratio 2.0, 128-frame chunks, 2 channels) over every pair {8000, 11025, 16000, 22050, 32000, 44100, 48000, 88200, 96000, 192000} → {44100, 48000}, 400 chunks each through the input_frames_next pull pattern, printing need/used/produced per call and every output sample's f32 bits (21600 lines). Host aarch64-apple-darwin, so rubato takes its NEON path.

fft   build EXIT=0  run EXIT=0  sha256 e0073d819cd52e3d851f45e594176a61c5df24a6d59d79f6d21501771a667299
nofft build EXIT=0  run EXIT=0  sha256 e0073d819cd52e3d851f45e594176a61c5df24a6d59d79f6d21501771a667299
cmp out-fft.txt out-nofft.txt -> CMP=0

Negative control — the oracle sees a one-ulp-scale change: this patch, applied to a third copy (no default features), turns it red:

15c15
<                 f_cutoff: 0.95,
---
>                 f_cutoff: 0.9500001,
mut build EXIT=0  run EXIT=0  sha256 32f17c02ed15f9421c512e3f56ec18e6b833d9ff82686706d859ea54fce55ca9
cmp out-nofft.txt out-mut.txt -> CMP=1
main.rs (the instrument)
//! Runs soundserver's resampler configuration (userland/soundserver/src/client.rs)
//! over a fixed input at each rate pair and writes every output sample's bits to stdout.
use rubato::{Resampler, SincFixedOut, SincInterpolationParameters, SincInterpolationType, WindowFunction};
use std::io::Write;

fn main() {
    let mut out = std::io::stdout().lock();
    let ins = [8000u32, 11025, 16000, 22050, 32000, 44100, 48000, 88200, 96000, 192000];
    for &dev in &[44100u32, 48000] {
        for &inr in &ins {
            if inr == dev { continue; }
            let channels = 2usize;
            let params = SincInterpolationParameters {
                sinc_len: 128,
                f_cutoff: 0.95,
                interpolation: SincInterpolationType::Cubic,
                oversampling_factor: 128,
                window: WindowFunction::BlackmanHarris2,
            };
            let mut r = SincFixedOut::<f32>::new(dev as f64 / inr as f64, 2.0, params, 128, channels).unwrap();
            let mut outbuf = r.output_buffer_allocate(true);
            // Deterministic input: two tones plus an LCG noise floor, per channel.
            let mut seed: u32 = 0x1234_5678 ^ inr;
            let mut t: u64 = 0;
            for _period in 0..400 {
                let need = r.input_frames_next();
                let mut inp = vec![Vec::with_capacity(need); channels];
                for _ in 0..need {
                    let x = t as f64 / inr as f64;
                    for (c, ch) in inp.iter_mut().enumerate() {
                        seed = seed.wrapping_mul(1664525).wrapping_add(1013904223);
                        let noise = (seed >> 8) as f32 / (1u32 << 24) as f32 - 0.5;
                        let f1 = 440.0 * (c + 1) as f64;
                        let f2 = 0.45 * inr as f64;
                        let v = 0.5 * (2.0 * std::f64::consts::PI * f1 * x).sin()
                            + 0.3 * (2.0 * std::f64::consts::PI * f2 * x).sin();
                        ch.push(v as f32 + 0.01 * noise);
                    }
                    t += 1;
                }
                write!(out, "{inr}->{dev} need={need} ").unwrap();
                let (used, produced) = r.process_into_buffer(&inp, &mut outbuf, None).unwrap();
                write!(out, "used={used} produced={produced}\n").unwrap();
                for ch in &outbuf {
                    for s in &ch[..produced] {
                        write!(out, "{:08x}", s.to_bits()).unwrap();
                    }
                    writeln!(out).unwrap();
                }
            }
        }
    }
}

2. The shipped x86_64 soundserver: object code compared

cargo run -- --build-only at the base and at the head (both EXIT=0), target/x86_64-unknown-toyos/toyos/soundserver kept from each:

before 916584 bytes sha256 90e95bd1523053db9940b179845aae4bea080db3a71c543e90f62001ac1b96e1
after  914032 bytes sha256 d21cf516ee2cc7592d007f027f9c69e4993e1d4b7f293d2f9323cfe399a1d7d0

The binary changes (2552 bytes smaller). Disassembled with llvm-objdump -d --no-show-raw-insn --no-leading-addr (rustup llvm-tools), normalized for crate disambiguators (Cs…_), .llvm.N suffixes, absolute addresses and anon.<hash>.N comment labels, split per function and compared as a multiset:

  • 1210 functions before, 1208 after. Every function present in both is instruction-identical except for the call label of one ICF-folded helper (below) and the sign of 13 rip-relative lea displacements in 7 non-resampler functions (main, three Snapshot::put, two Refusal Displays, Virtio::poll_events), which is layout.
  • Gone: RawVec<u64>::grow_one and RawVecInner::finish_grow instantiated in rustfft, and the soundserver's RawVec<u32>::grow_one, all instruction-identical to the one RawVec<u64>::grow_one (now soundserver's) and finish_grow the after binary keeps; callers that called them now call that one. That and the matching .rodata/.eh_frame entries are the 2552 bytes (.text 454503 → 453959, .rodata 65760 → 65072).
  • All 52 rubato symbols are present in both with identical sizes (llvm-nm -S).
  • The resampler path — every function whose name contains rubato, toyos_mixer or soundserver::client (104 records) — is identical after normalization: cmp → 0.
  • Every value that path loads from the read-only segment (105 loads; width from the dword/qword/xmmword operand) is the same bytes in both binaries: cmp → 0. Its other 311 rip-relative references are leas (addresses), and 24 are loads from the RELRO/data segments (pointers to std statics), not compared by value.

3. cargo tree -p soundserver -e normal

Before:

soundserver v0.0.0 (<worktree>/userland/soundserver)
├── rubato v0.16.2
│   ├── num-complex v0.4.6
│   │   └── num-traits v0.2.19
│   ├── num-integer v0.1.46
│   │   └── num-traits v0.2.19
│   ├── num-traits v0.2.19
│   └── realfft v3.5.0
│       └── rustfft v6.4.1
│           ├── num-complex v0.4.6 (*)
│           ├── num-integer v0.1.46 (*)
│           ├── num-traits v0.2.19
│           ├── primal-check v0.3.4
│           │   └── num-integer v0.1.46 (*)
│           ├── strength_reduce v0.2.4
│           └── transpose v0.2.3
│               ├── num-integer v0.1.46 (*)
│               └── strength_reduce v0.2.4
├── toyos v0.18.0 (<worktree>/toyos)
│   └── toyos-abi v0.16.0 (<worktree>/toyos-abi)
├── toyos-abi v0.16.0 (<worktree>/toyos-abi)
├── toyos-hda v0.1.0 (<worktree>/toyos-hda)
├── toyos-inspect v0.1.0 (<worktree>/toyos-inspect)
│   └── toyos-abi v0.16.0 (<worktree>/toyos-abi)
└── toyos-mixer v0.1.0 (<worktree>/userland/soundserver/mixer)

After:

soundserver v0.0.0 (<worktree>/userland/soundserver)
├── rubato v0.16.2
│   ├── num-integer v0.1.46
│   │   └── num-traits v0.2.19
│   └── num-traits v0.2.19
├── toyos v0.18.0 (<worktree>/toyos)
│   └── toyos-abi v0.16.0 (<worktree>/toyos-abi)
├── toyos-abi v0.16.0 (<worktree>/toyos-abi)
├── toyos-hda v0.1.0 (<worktree>/toyos-hda)
├── toyos-inspect v0.1.0 (<worktree>/toyos-inspect)
│   └── toyos-abi v0.16.0 (<worktree>/toyos-abi)
└── toyos-mixer v0.1.0 (<worktree>/userland/soundserver/mixer)

@Japabu

Japabu commented Oct 9, 2026

Copy link
Copy Markdown
Collaborator Author

Gate logs (excerpts, head 1c87ae677)

cargo run -- --ci host — last lines of the 9728-line log:

16:42:11 [ci] nothing left in $TMPDIR or /tmp: every test took its scratch with it
16:42:11 [ci] Host: 78 step(s), all green
EXIT=0

cargo run -- --build-only at base and at head — last lines:

16:01:42 Build finished.
Boot image: <worktree>/target/bootable.img
EXIT=0
16:02:31 Build finished.
Boot image: <worktree>/target/bootable.img
EXIT=0

cargo test — it did not run: the volume was full. The first failures and the exit:

error: could not compile `kernel` (bin "kernel")

Caused by:
  failed to create file `<worktree>/target/aarch64-unknown-none-softfloat/toyos/.fingerprint/kernel-369992b221d3b60a/output-bin-kernel`

Caused by:
  failed to parse process output: `rustc --crate-name kernel --edition=2021 kernel/src/main.rs --error-format=json --json=diagnostic-rendered-ansi,artifacts,future-incompat --crate-type bin --emit=dep-info,link -C opt-level=2 -C embed-bitcode=no -C debuginfo=2 -C debug-assertions=on --check-cfg 'cfg(docsrs,test)' --check-cfg 'cfg(feature, values("boot-actuators", "commit-ignores-notify", "counting-allocator", "debug-wait", "device-irq-lossy", "df-witness", "df-witness-mutate", "doorbell-kick-relaxed", "dump-report-relaxed", "entry-df-unclean", "gate-fence-off", "heap-band-nohead", "heap-band-notail", "heap-lockspin", "heap-sweep", "heap-tripwire", "lock-acquire-off", "log-commit-release-off", "loom", "mask-windows", "mutate-claim-teardown-always-wins", "mutate-first-out-tears-down", "mutate-join-collects-in-a-teardown", "mutate-kill-waits-for-its-victims", "mutate-landed-child-retires-nothing", "mutate-last-out-leaves-before-its-teardown", "mutate-place-skips-the-insert-recheck", "mutate-publish-before-the-children", "mutate-refused-spawn-keeps-the-count", "mutate-spawn-skips-the-insert-recheck", "mutate-spawner-handle-after-the-landing", "mutate-spawner-handle-before-the-childs-own", "mutate-walk-in-one-hold", "notify-flag-load-only", "owed-fence-off", "pass-spin", "placement-ignores-staleness", "poll-fire-load-store", "post-is-an-answer", "protocol-port", "push-fence-relaxed", "reap-raise-relaxed", "roster-commit-relaxed", "sched-check", "sched-tripwire", "seqlock-writer-fence-off", "serial-try-lock-then-some", "shard-publish-relaxed", "shootdown-serve-relaxed", "shootdown-served-relaxed", "sleeplock-acquire-off", "smp-ready-split", "stack-witness", "switch-witness", "switch-witness-mutate-frame", "switch-witness-mutate-rsp", "test-actuators", "wake-fence-off"))' -C metadata=8d4fb38e6418b6f5 -C extra-filename=-369992b221d3b60a --out-dir <worktree>/target/aarch64-unknown-none-softfloat/toyos/deps --target aarch64-unknown-none-softfloat -C incremental=<worktree>/target/aarch64-unknown-none-softfloat/toyos/incremental -C strip=debuginfo -L dependency=<worktree>/target/aarch64-unknown-none-softfloat/toyos/deps -L dependency=<worktree>/target/toyos/deps --extern bcachefs=<worktree>/target/aarch64-unknown-none-softfloat/toyos/deps/libbcachefs-0b2a893fcc094fb2.rlib --extern dlmalloc=<worktree>/target/aarch64-unknown-none-softfloat/toyos/deps/libdlmalloc-456245eb2513b112.rlib --extern hashbrown=<worktree>/target/aarch64-unknown-none-softfloat/toyos/deps/libhashbrown-86ace452c15b30be.rlib --extern kernel=<worktree>/target/aarch64-unknown-none-softfloat/toyos/deps/libkernel-f50dfce09d85fc2e.rlib --extern toyos_abi=<worktree>/target/aarch64-unknown-none-softfloat/toyos/deps/libtoyos_abi-e03fd19c006f5083.rlib --extern toyos_acpi=<worktree>/target/aarch64-unknown-none-softfloat/toyos/deps/libtoyos_acpi-28a851871acfb5a6.rlib --extern toyos_blackbox=<worktree>/target/aarch64-unknown-none-softfloat/toyos/deps/libtoyos_blackbox-c3954691e94ae14a.rlib --extern toyos_blockhold=<worktree>/target/aarch64-unknown-none-softfloat/toyos/deps/libtoyos_blockhold-638f8f1a4e5c5c69.rlib --extern toyos_bootmap=<worktree>/target/aarch64-unknown-none-softfloat/toyos/deps/libtoyos_bootmap-7a93791d2e7a9ae2.rlib --extern toyos_cpuvuln=<worktree>/target/aarch64-unknown-none-softfloat/toyos/deps/libtoyos_cpuvuln-c798c335ad71c964.rlib --extern toyos_dma=<worktree>/target/aarch64-unknown-none-softfloat/toyos/deps/libtoyos_dma-f21e7207f146806e.rlib --extern toyos_elf=<worktree>/target/aarch64-unknown-none-softfloat/toyos/deps/libtoyos_elf-f3ce47725138a57c.rlib --extern toyos_fat32=<worktree>/target/aarch64-unknown-none-softfloat/toyos/deps/libtoyos_fat32-9f142cf5313666fa.rlib --extern toyos_gicv3=<worktree>/target/aarch64-unknown-none-softfloat/toyos/deps/libtoyos_gicv3-7a2c5d78e319a29e.rlib --extern toyos_gpt=<worktree>/target/aarch64-unknown-none-softfloat/toyos/deps/libtoyos_gpt-ce956f56a663c0f2.rlib --extern toyos_hda=<worktree>/target/aarch64-unknown-none-softfloat/toyos/deps/libtoyos_hda-2bc2ed7a43544ba4.rlib --extern toyos_pci=<worktree>/target/aarch64-unknown-none-softfloat/toyos/deps/libtoyos_pci-c0b86fa888825989.rlib --extern toyos_ps2=<worktree>/target/aarch64-unknown-none-softfloat/toyos/deps/libtoyos_ps2-86f41dafac01ad01.rlib --extern toyos_quiesce=<worktree>/target/aarch64-unknown-none-softfloat/toyos/deps/libtoyos_quiesce-d65fcfa4c652d122.rlib --extern toyos_random=<worktree>/target/aarch64-unknown-none-softfloat/toyos/deps/libtoyos_random-ad19720070e3cf9a.rlib --extern toyos_rootimage=<worktree>/target/aarch64-unknown-none-softfloat/toyos/deps/libtoyos_rootimage-131ffe88d29e454d.rlib --extern toyos_symbols=<worktree>/target/aarch64-unknown-none-softfloat/toyos/deps/libtoyos_symbols-4bd21125249c2faa.rlib --extern toyos_tco=<worktree>/target/aarch64-unknown-none-softfloat/toyos/deps/libtoyos_tco-c19256fd30f68d8e.rlib --extern toyos_tsc=<worktree>/target/aarch64-unknown-none-softfloat/toyos/deps/libtoyos_tsc-0086ca79b6628c5a.rlib --extern toyos_untrusted=<worktree>/target/aarch64-unknown-none-softfloat/toyos/deps/libtoyos_untrusted-8b0e90fa3bd488a4.rlib --extern toyos_userbound=<worktree>/target/aarch64-unknown-none-softfloat/toyos/deps/libtoyos_userbound-79cfbfebfeffa5bc.rlib --extern toyos_wallclock=<worktree>/target/aarch64-unknown-none-softfloat/toyos/deps/libtoyos_wallclock-69ee22fbf206febc.rlib --extern toyos_xhci=<worktree>/target/aarch64-unknown-none-softfloat/toyos/deps/libtoyos_xhci-f35b77011bd25629.rlib -Dwarnings -Cforce-frame-pointers=yes -Adead_code -Aunfulfilled_lint_expectations -Clink-arg=-pie -Clink-arg=-znotext` (exit status: 1)

thread '<unnamed>' (228077031) panicked at src/build.rs:400:9:
cargo build failed in <worktree>
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
16:47:24   FAIL  aarch64 kernel, loader, ROOT of tests/testcases, for virt_user_mode  (142s)
16:47:24 [build-lock] artifact staging acquired after 134.9s
16:47:24 FAIL virt_user_mode: cargo build failed in <worktree>
16:47:24   FAIL  virt_user_mode  (75ms)
16:47:24   RUN   virt_ring0_timer_in_syscall
error: failed to create file encoder: No space left on device (os error 28)

error: could not compile `memmap2` (lib) due to 1 previous error
error: couldn't create a temp dir: No space left on device (os error 28) at path "<worktree>/tests/toyos-rust-tests/target/aarch64-unknown-toyos/toyos/deps/rmetaok03Bp"

error: could not compile `toyos-font` (lib) due to 1 previous error
error: couldn't create a temp dir: No space left on device (os error 28) at path "<worktree>/tests/toyos-rust-tests/target/aarch64-unknown-toyos/toyos/deps/rmetaJZOM9f"
EXIT=1

df -h right after: 926Gi 900Gi 132Mi 100%.

@Japabu

Japabu commented Oct 9, 2026

Copy link
Copy Markdown
Collaborator Author

Guest suite, head 1c87ae677 (the run that replaces the ENOSPC one)

18:51  up 10 days,  6:35, 6 users, load averages: 48.71 68.28 79.47
<volume>   926Gi   858Gi    42Gi    96%     12M  443M    3%   /System/Volumes/Data
18:54  up 10 days,  6:38, 6 users, load averages: 60.38 67.77 77.45
16:52:33   PASS  nested_nmi_is_loud  (12s)
16:52:39   PASS  console_image_boots  (17s)
16:52:42   PASS  acpi_power_button  (20s)
16:52:43   PASS  machine_shutdown  (20s)
16:52:45   PASS  netstack_socket_churn  (20s)
16:52:45   PASS  acpi_lock_given_back_on_one_cpu  (19s)
16:52:45   PASS  machine_shutdown_short_stop  (20s)
16:52:46   PASS  acpi_supply_outlives_holder  (29s)
16:52:46   PASS  acpi_mediated_access  (28s)
16:52:46   PASS  screen_panic_muted  (8s)
16:52:46   PASS  bar_map_again  (18s)
16:52:48   PASS  libc_sockets  (27s)
16:52:55   PASS  screen_fatal_behind_a_painter  (13s)
16:52:58   PASS  screen_loader_clears  (13s)
16:53:01   PASS  screen_fatal_halt_composited  (14s)
16:53:04   PASS  virt_early_panic  (995ms)
16:53:05   PASS  virt_early_fault  (1s)
16:53:06   PASS  virt_el2_drop  (2s)
16:53:07   PASS  iommu_virtio_platform  (45s)
16:53:11   PASS  nvme_disk_keeps_log_and_home  (37s)
16:53:27   PASS  virt_user_mode  (3s)
16:53:32   PASS  virt_timer_floor  (3s)
16:53:45   PASS  virt_irq_storm  (16s)
16:53:45   PASS  virt_timer_preempts  (3s)
16:53:46   PASS  virt_ring0_timer_in_syscall  (34s)
16:53:47   PASS  virt_unmap_touch  (39s)
16:53:49   PASS  virt_first_entry  (51s)
16:53:49   PASS  virt_fp_isolation  (55s)
16:53:49   PASS  virt_debug_refused  (45s)
16:53:50   PASS  virt_readonly_copyout  (45s)
16:53:57   PASS  virt_no_seed_refused  (8s)
16:53:59   PASS  virt_jobs_at_el2  (10s)
16:53:59   PASS  virt_random_differs  (10s)
16:54:19   PASS  virt_reboot_refused_without_psci  (3s)
16:54:20   PASS  virt_reboot  (4s)
16:54:21   PASS  virt_smp  (40s)
16:54:21   PASS  virt_mask_windows  (44s)
16:54:22   PASS  virt_el1_smp  (15s)
16:54:22   PASS  virt_fatal_halts_the_others_first  (6s)
16:54:23   PASS  virt_failed_ap_leaves_no_hole  (21s)
16:54:27   PASS  virt_off_names_the_cpus_left_on  (10s)
16:54:27 test result: ok. 41 passed, 41 total (137.0s; workers: 653s building, 829s testing)
EXIT=0

Metal staging (--metal-readback, machine untouched), last lines:

16:57:09 [metal] staged 2 image(s); <metal-dir>/request.txt lists them. The machine was not touched, so this run establishes nothing about it.
error: test failed, to rerun pass `--test toyos-build`

Caused by:
  process didn't exit successfully: `<worktree>/target/debug/deps/toyos_build-497f416569e2c965 --metal --metal-readback <metal-dir>/ 'boot:testcases'` (exit status: 2)
EXIT=2

@Japabu

Japabu commented Oct 9, 2026

Copy link
Copy Markdown
Collaborator Author

Review of head 1c87ae677 against origin/main d6298c83e (merge base is the same commit).

Net lines (git diff --shortstat origin/main...1c87ae677): 2 files, +1 / −60. Production: one manifest line changed and 59 lockfile lines deleted. Tests: 0.

Is "the audio is unchanged" proven? Yes, for the resampler's output on both architectures.

  • Source. With fft_resampler off, rubato's compiled code changes in two ways only. mod synchro and its re-exports are gone, and nothing on soundserver's path uses them: num_integer is used only in synchro.rs. The FftNum bound on Sample becomes a local trait (rubato-0.16.2/src/sample.rs:6-15), which has the same bounds as rustfft-6.4.1/src/common.rs:5-7, has no items and has a blanket impl. So no item that SincFixedOut<f32> calls changes.
  • Language. Rust applies no fast-math and no FP contraction. That means a codegen change that is only layout or inlining cannot change an f32 result.
  • x86_64. Comparing the shipped binary's object code is the independent oracle, and it agrees. The resampler path and the 105 constants it loads are identical (cmp 0). The pipeline is shown to be sensitive: it found the folded helpers and the lea sign flips.
  • AArch64. What covers AArch64 is the source and language argument above. The host differential (aarch64-apple-darwin, NEON) is a second witness to the same fact, not the proof. It is enough without an aarch64 object comparison.

What the PR does not show is that the binary is unchanged. It is not, so the timing judges have to be read on the machine.

  • The layout moved: .rodata now sits after .gcc_except_table, every address shifted, and three allocator instances were folded into one.
  • The audio rows judge timing (underruns, deferred), and timing verdicts come only from metal.

BLOCKER

  • Evidence (PR body, Gates row --metal): the T14 reading is missing. The change ships a different soundserver binary to the hardware it drives, and the body records only --metal-readback staging (exit 2, "establishes nothing about it"). It closes when the PR body carries boot:testcases run on the T14 at 1c87ae677: the command, its exit code and its log. That reading must show all of the following.
    • It booted the staged image, sha256 22682b7a… (or a rebuild at this head whose hash the log names).
    • hda_tone: soundserver: hda path configured in is present and the null-sink line is absent. Summed underruns is 0 in the test_rs_audio_tone window.
    • hda_client_stall:
      • no repeated completion for free buffer;
      • soundserver: resumed after the first stream's end;
      • underruns > 0 and deferred = 0 across both streams.
    • shipped_client_departures: test_rs_null_sink_client_exits passed, and both departures are named.
    • audio_idle_suspend: no soundserver: resumed in its window.
    • Every other row in that boot is green, or is shown red on main's last reading of the same boot. A row that is red only here belongs to this change.
    • soundserver_log_stall (LOGSTALLCASE) is not required: its judge counts log lines rather than timing, and the object code says the logic is identical.

NOTE

  • PR body, "What I am unsure of": "AArch64 is covered by the host differential". The differential runs on macOS's std, not on the shipped aarch64-unknown-toyos binary. What proves AArch64 is the cfg argument above (identical-bounds blanket trait, no items), with the differential as a witness. This is prose in the record.

SEND BACK

@Japabu

Japabu commented Oct 9, 2026

Copy link
Copy Markdown
Collaborator Author

T14 at 1c87ae677, run by the orchestrator: boot:testcases, two boots, each image's sha256 checked against request.txt before its flash (testcases 22682b7a…2b2e0c97, the review's image; testcases-watchdog 3440a70a…00ab974e), each toyos-metal --fat32-check exit 0. Judge cargo test --test toyos-build -- --metal --metal-readback <dir> boot:testcases: EXIT=0, [metal] 249 passed, 0 failed, 2 boot(s), every row green including PASS hda_tone, PASS hda_client_stall, PASS shipped_client_departures, PASS audio_idle_suspend (their judges hold the review's conditions: the hda path, underruns, deferred, resume and departure lines).

@Japabu

Japabu commented Oct 9, 2026

Copy link
Copy Markdown
Collaborator Author

Round 2, head 1c87ae677 (the same head as round 1), against origin/main d6298c83e. Net lines: 2 files, +1 / −60, all production (the manifest and the lockfile); tests 0.

Round 1's BLOCKER

  • The T14 reading is missing. CLOSED. The orchestrator ran boot:testcases on the T14 at 1c87ae677 and posted the result in a comment on this pull request. Its run log is t14-rubato.log and the judge log is judge.log. I checked it against each condition I set in round 1:
    • The image is the staged one. t14-rubato-testcases.log:2 hashes the image to 22682b7a8a8b61f67c34b712a026132856f4ed8673fba7d04a8b53842b2e0c97, which matches request.txt, before the flash. testcases-watchdog boots 3440a70a…00ab974e, also as staged. Both boots have rc=0 and toyos-fat32-check passes on both.
    • hda_tone. kernel.log:339 has soundserver: hda path configured in 14 verbs, stream tag 1. The boot has no null-sink fallback line; the only "null sink" line is the message of the test named test_rs_null_sink_client_exits, at line 450. Both stat lines in the test_rs_audio_tone window (lines 399 and 401) read underruns=0.
    • hda_client_stall. The boot has no repeated completion. The first stream ends at line 410 and soundserver: suspended follows at line 411; the second stream opens and soundserver: resumed appears at line 414. Underruns are 104 + 26, which is more than 0. Both streams have deferred=0.
    • shipped_client_departures. test_rs_null_sink_client_exits exits 0 (line 452). Both departures are named: client 3 removed (closed) (line 435) and client 4 removed (closed) (line 446).
    • audio_idle_suspend. Its window (lines 387 to 393) has no soundserver: resumed, and the idle CPU delta is 0ns over ~1s.
    • Every other row. The judge exits 0 with [metal] 249 passed, 0 failed, 2 boot(s), so nothing is red here that needs comparing against main's last reading.

BLOCKER

None.

NOTE

  • Round 1's prose NOTE is still open. The PR body's "What I am unsure of" still says "AArch64 is covered by the host differential". What proves AArch64 is the cfg argument: the replacement trait has the same bounds, no items and a blanket impl. The differential only bears witness to it.
  • The PR body's metal Gates row is stale. It still records only the --metal-readback staging, exit 2. It should record the T14 boot:testcases reading at 1c87ae677: judge exit 0, 249 passed, 0 failed, 2 boots. The last bullet of "What I am unsure of" ("staged, not yet run") should go.

LAND

@Japabu
Japabu marked this pull request as ready for review October 9, 2026 17:35
@Japabu

Japabu commented Oct 9, 2026

Copy link
Copy Markdown
Collaborator Author

CI at 1c87ae677, read from each job's log: host 79 steps all green; toolchain restored (llvm a2cc063281d9f279, compiler 6c76c19e5ffcc869, freestanding 0f5a5faab7bbc78c, sysroot fcaf4949f5310fa6); guest suite 41/41 ok. Merges clean with main 198a9d38e. Queued.

@Japabu
Japabu added this pull request to the merge queue Oct 9, 2026
@github-merge-queue
github-merge-queue Bot removed this pull request from the merge queue due to failed status checks Oct 9, 2026
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