diff --git a/benches/fetch_sweep.sh b/benches/fetch_sweep.sh index 7ce0ebd..75ec106 100755 --- a/benches/fetch_sweep.sh +++ b/benches/fetch_sweep.sh @@ -40,7 +40,7 @@ export XDG_STATE_HOME="$WORK/state" emit() { # label -> reads $WORK/t.txt awk -v l="$1" '/^real/{r=$2}/^user/{u=$2}/^sys/{s=$2} - END{c=u+s; printf "%-18s real=%7.2fs cpu=%6.2fs io_wait=%7.2fs (%2.0f%% wait)\n", l, r, c, r-c, r>0?100*(r-c)/r:0}' "$WORK/t.txt" + END{c=u+s; w=0; if(r>0) w=100*(r-c)/r; printf "%-18s real=%7.2fs cpu=%6.2fs io_wait=%7.2fs (%2.0f%% wait)\n", l, r, c, r-c, w}' "$WORK/t.txt" } sync_timed() { # jobs cold|warm -> exit nonzero on phora failure local jobs="$1" mode="$2" diff --git a/src/sync/resolve.rs b/src/sync/resolve.rs index 30025b2..a763e63 100644 --- a/src/sync/resolve.rs +++ b/src/sync/resolve.rs @@ -225,11 +225,12 @@ fn resolve_unit( })) } -/// Default rayon pool size when `--jobs` is unset: one thread per unit, capped at -/// twice the core count so network-bound fetch overlaps I/O waits without unbounded -/// oversubscription of the CPU resolve/digest phase. +/// Default rayon pool size when `--jobs` is unset. The cap's floor of 50 is +/// measured, not derived from cores: fetch is network-wait-bound and parked +/// threads cost memory, not CPU, so many small fetches stall on the pool +/// ceiling long before the box is busy (`benches/fetch_sweep.sh`). fn default_thread_count(units: usize, cores: usize) -> usize { - units.min(2 * cores) + units.min((2 * cores).max(50)) } #[expect( @@ -346,8 +347,18 @@ mod tests { } #[test] - fn default_thread_count_caps_at_twice_cores() { - assert_eq!(default_thread_count(20, 8), 16); + fn default_thread_count_uses_one_thread_per_unit_up_to_floor() { + assert_eq!(default_thread_count(50, 8), 50); + } + + #[test] + fn default_thread_count_caps_at_floor_when_twice_cores_is_below_it() { + assert_eq!(default_thread_count(60, 8), 50); + } + + #[test] + fn default_thread_count_caps_at_twice_cores_when_above_floor() { + assert_eq!(default_thread_count(200, 32), 64); } #[test] @@ -356,8 +367,8 @@ mod tests { } #[test] - fn default_thread_count_single_core_caps_at_two() { - assert_eq!(default_thread_count(5, 1), 2); + fn default_thread_count_single_core_uses_floor_not_cores() { + assert_eq!(default_thread_count(60, 1), 50); } #[test]