From 05fb2709a575aad2b412145f76f521dd9d5658ee Mon Sep 17 00:00:00 2001 From: Matthew Jackson Date: Sun, 17 May 2026 08:09:57 -0700 Subject: [PATCH] iter6: revert depth bump + WRITEBACK_CHUNK_BYTES 32->8 MiB MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit iter5 (256-frame channel) regressed -1.8 MB/s vs iter4. Reverting to 32 frames. iter4 sample pattern shows clear ~30 s oscillation (peak 45 MB/s → dip 3 MB/s → recovery). Matches Linux vm.dirty_expire_centisecs default (30 s). 32 MiB chunks at 25 MB/s issue WAIT_AFTER every ~1.3 s, which can't outrun the kernel's own page-age limit, so pages buildup then flush in bursts. Smaller 8 MiB chunks (WAIT_AFTER every ~0.33 s) should keep the dirty-page set young and eliminate the periodic flush-burst dip. --- .claude/worktrees/agent-a1cbe2cec72727536 | 1 + .claude/worktrees/agent-a82b8fb113069acd9 | 1 + .claude/worktrees/agent-ae58900dbeb230583 | 1 + .claude/worktrees/agent-aee3289bc097d110f | 1 + src/io/pipeline.rs | 11 +---------- src/io/writeback_file/mod.rs | 8 +++++++- 6 files changed, 12 insertions(+), 11 deletions(-) create mode 160000 .claude/worktrees/agent-a1cbe2cec72727536 create mode 160000 .claude/worktrees/agent-a82b8fb113069acd9 create mode 160000 .claude/worktrees/agent-ae58900dbeb230583 create mode 160000 .claude/worktrees/agent-aee3289bc097d110f diff --git a/.claude/worktrees/agent-a1cbe2cec72727536 b/.claude/worktrees/agent-a1cbe2cec72727536 new file mode 160000 index 0000000..f952bcf --- /dev/null +++ b/.claude/worktrees/agent-a1cbe2cec72727536 @@ -0,0 +1 @@ +Subproject commit f952bcfce99a1e45d365576c2b65a9555aa40951 diff --git a/.claude/worktrees/agent-a82b8fb113069acd9 b/.claude/worktrees/agent-a82b8fb113069acd9 new file mode 160000 index 0000000..dcde016 --- /dev/null +++ b/.claude/worktrees/agent-a82b8fb113069acd9 @@ -0,0 +1 @@ +Subproject commit dcde016bd39ef2fcf4560b1a09e015c0ce96c73c diff --git a/.claude/worktrees/agent-ae58900dbeb230583 b/.claude/worktrees/agent-ae58900dbeb230583 new file mode 160000 index 0000000..ccf7d97 --- /dev/null +++ b/.claude/worktrees/agent-ae58900dbeb230583 @@ -0,0 +1 @@ +Subproject commit ccf7d976406e062b1290b8afe2268313a97d90e7 diff --git a/.claude/worktrees/agent-aee3289bc097d110f b/.claude/worktrees/agent-aee3289bc097d110f new file mode 160000 index 0000000..0d48799 --- /dev/null +++ b/.claude/worktrees/agent-aee3289bc097d110f @@ -0,0 +1 @@ +Subproject commit 0d4879948b6fdb063ce4a92ece4aefb5c48ffa0f diff --git a/src/io/pipeline.rs b/src/io/pipeline.rs index 7e60c4c..91bb1db 100644 --- a/src/io/pipeline.rs +++ b/src/io/pipeline.rs @@ -90,16 +90,7 @@ pub const DEFAULT_PIPELINE_DEPTH: usize = 4; /// Read pipeline depth. Larger buffer compensates for drive variability /// and NFS sync_file_range stalls; keeps ISO reader thread fed even when /// consumer blocks on write. -/// -/// iter5 (2026-05-17): bumped 32 → 256 frames. autorip iter4 measured -/// dips to 2.8 MB/s with the previous 32-frame channel (~1.6 MiB at -/// ~50 KB/frame avg). When the producer thread hits any micro-stall -/// (UDF metadata cache miss, NFS RTT, decrypt key lookup), a 1.6 MiB -/// buffer drains in <100 ms and the consumer sits idle. 256 frames is -/// ~12 MiB — ~3-4 seconds of consumer drain at 4 MB/s worst-case -/// sustained output rate, enough to coast through any single-event -/// producer pause without starving the consumer. -pub const READ_PIPELINE_DEPTH: usize = 256; +pub const READ_PIPELINE_DEPTH: usize = 32; /// Write pipeline depth. Smaller buffer reduces backpressure risk when /// sync_file_range blocks; prevents producer from accumulating too much diff --git a/src/io/writeback_file/mod.rs b/src/io/writeback_file/mod.rs index 9f63a44..0408ed9 100644 --- a/src/io/writeback_file/mod.rs +++ b/src/io/writeback_file/mod.rs @@ -124,7 +124,13 @@ use super::writeback::WritebackPipeline; /// Granularity at which the Linux writeback pipeline issues /// `sync_file_range` / `posix_fadvise(DONTNEED)` pairs. 32 MiB is the /// historical default — bounded-cache pressure stays at ~2 × this size. -const WRITEBACK_CHUNK_BYTES: u64 = 32 * 1024 * 1024; +/// +/// iter6 (2026-05-17): 32 → 8 MiB. iter4 data showed ~30 s +/// oscillation (peak 45 → dip 3 MB/s with ~30 s period) matching +/// Linux's `vm.dirty_expire_centisecs` (30 s default). Smaller chunks +/// keep dirty pages younger so the kernel flusher daemon's bursts are +/// shorter. +const WRITEBACK_CHUNK_BYTES: u64 = 8 * 1024 * 1024; /// Maximum bytes outstanding in the muxer → writer-thread ring. Sized /// to cover ~4 s of muxer output at a 32 MB/s peak — enough to absorb a