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.
This commit is contained in:
Michel de Graaf
2026-09-07 16:17:42 +02:00
parent 63c2cf07f4
commit d0550b8461
+9 -6
View File
@@ -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<RwLock<ClientContext>>,
download: Option<Download>,
) -> 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