From d0550b8461117808a89c3547a28f0f9479f042af Mon Sep 17 00:00:00 2001 From: Michel de Graaf Date: Mon, 7 Sep 2026 15:53:05 +0200 Subject: [PATCH] perf(lib): read downloads in 64 KiB slices Downloads read the peer socket 8 KiB at a time, eight syscalls where one now does; the reference clients read 50 to 256 KiB. Progress was reported every fifteen reads, a cadence that stops meaning anything once a read can be anywhere from a few bytes to 64 KiB, so a report now lands every 128 KiB received instead: the same volume as before for a fast peer, and a window wide enough for a slow peer's rate to mean something. --- soulseek-rs-lib/src/peer/download_peer.rs | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/soulseek-rs-lib/src/peer/download_peer.rs b/soulseek-rs-lib/src/peer/download_peer.rs index 786baa0..b941d32 100644 --- a/soulseek-rs-lib/src/peer/download_peer.rs +++ b/soulseek-rs-lib/src/peer/download_peer.rs @@ -13,10 +13,15 @@ use crate::trace; use crate::types::{Download, DownloadStatus}; use crate::utils::path::{PART_SUFFIX, expand_tilde}; -const READ_BUFFER_SIZE: usize = 8192; +/// Read in 64 KiB slices: an eighth of the syscalls of the 8 KiB reads before, +/// and what a fast peer fills per read. slskd reads 256 KiB, Nicotine+ ~50 KiB. +const READ_BUFFER_SIZE: usize = 64 * 1024; const CANCEL_POLL: Duration = Duration::from_secs(1); const STALL_DEADLINE: Duration = Duration::from_secs(30); -const PROGRESS_UPDATE_CHUNKS: usize = 15; +/// Bytes between progress reports. Counting bytes rather than reads keeps +/// the report volume flat however big a read is, and gives a slow peer's +/// rate a window wide enough to mean something. +const PROGRESS_INTERVAL_BYTES: usize = 128 * 1024; #[derive(Debug)] pub enum DownloadError { @@ -351,8 +356,7 @@ impl DownloadPeer { client_context: &Arc>, download: Option, ) -> Result<(Download, String), DownloadError> { - let mut read_buffer = [0u8; READ_BUFFER_SIZE]; - let mut chunk_counter = 0usize; + let mut read_buffer = vec![0u8; READ_BUFFER_SIZE]; let mut bytes_since_last_update = 0usize; let mut last_update_time = Instant::now(); let mut last_data = Instant::now(); @@ -414,10 +418,9 @@ impl DownloadPeer { }; part.write(data)?; - chunk_counter += 1; bytes_since_last_update += bytes_read; - if chunk_counter.is_multiple_of(PROGRESS_UPDATE_CHUNKS) { + if bytes_since_last_update >= PROGRESS_INTERVAL_BYTES { let elapsed = last_update_time.elapsed().as_secs_f64(); let speed = if elapsed > 0.0 { bytes_since_last_update as f64 / elapsed