From 6de869cc88a5774383c70bd0412ac83e6329a28e Mon Sep 17 00:00:00 2001 From: Matthew Mckee Date: Thu, 11 Dec 2025 17:11:01 +0000 Subject: [PATCH] Speed up cache size command (#17015) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Summary `uv cache size` can be quite slow. Here i use https://github.com/sharkdp/diskus to walk the cache directory with in multiple threads. Add cli option to set the number of threads and default to ` std::thread::available_parallelism()` or 1. ## Test Plan Added cli statement with info log test. I believe this is a fair test, where i set cache dir to a large directory. ```bash matthew@matthew-main ~/develop/personal/uv [14:17:50] [±cache-size-speed-up ✓▴] > $ uv cache size --preview-features cache-size -H --cache-dir ~/develop/ [±cache-size-speed-up ✓▴] 75.7GiB matthew@matthew-main ~/develop/personal/uv [14:18:24] > $ hyperfine 'uv cache size --preview-features cache-size -H --cache-dir ~/develop/' 'target/debug/uv cache size --preview-features cache-size -H --cache-dir ~/develop/' [±cache-size-speed-up ✓▴] Benchmark 1: uv cache size --preview-features cache-size -H --cache-dir ~/develop/ Time (mean ± σ): 1.059 s ± 0.014 s [User: 0.171 s, System: 0.884 s] Range (min … max): 1.048 s … 1.097 s 10 runs Benchmark 2: target/debug/uv cache size --preview-features cache-size -H --cache-dir ~/develop/ Time (mean ± σ): 413.8 ms ± 17.1 ms [User: 5789.2 ms, System: 1682.0 ms] Range (min … max): 386.3 ms … 441.6 ms 10 runs Summary target/debug/uv cache size --preview-features cache-size -H --cache-dir ~/develop/ ran 2.56 ± 0.11 times faster than uv cache size --preview-features cache-size -H --cache-dir ~/develop/ ``` --- Cargo.lock | 28 ++++++++++++++++++++++++---- Cargo.toml | 1 + crates/uv/Cargo.toml | 1 + crates/uv/src/commands/cache_size.rs | 14 ++++---------- 4 files changed, 30 insertions(+), 14 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 5dab67119..42a4fa3c2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1038,6 +1038,15 @@ dependencies = [ "itertools 0.10.5", ] +[[package]] +name = "crossbeam-channel" +version = "0.5.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82b8f8f868b36967f9606790d1903570de9ceaf870a7bf9fbbd3016d636a2cb2" +dependencies = [ + "crossbeam-utils", +] + [[package]] name = "crossbeam-deque" version = "0.8.6" @@ -1255,6 +1264,16 @@ dependencies = [ "windows-sys 0.61.0", ] +[[package]] +name = "diskus" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec07379c016f78e7ddcd953663b9ed17928ff384928d34d824ed7e463bd3d908" +dependencies = [ + "crossbeam-channel", + "rayon", +] + [[package]] name = "dispatch2" version = "0.3.0" @@ -3443,9 +3462,9 @@ dependencies = [ [[package]] name = "rayon" -version = "1.10.0" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa" +checksum = "368f01d005bf8fd9b1206fb6fa653e6c4a81ceb1466406b81792d87c5677a58f" dependencies = [ "either", "rayon-core", @@ -3453,9 +3472,9 @@ dependencies = [ [[package]] name = "rayon-core" -version = "1.12.1" +version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2" +checksum = "22e18b0f0062d30d4230b2e85ff77fdfe4326feb054b9783a3460d8435c8ab91" dependencies = [ "crossbeam-deque", "crossbeam-utils", @@ -5402,6 +5421,7 @@ dependencies = [ "clap", "console 0.16.1", "ctrlc", + "diskus", "dotenvy", "dunce", "embed-manifest", diff --git a/Cargo.toml b/Cargo.toml index b6a8912f4..f812b996f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -103,6 +103,7 @@ ctrlc = { version = "3.4.5" } cyclonedx-bom = { version = "0.8.0" } dashmap = { version = "6.1.0" } data-encoding = { version = "2.6.0" } +diskus = { version = "0.9.0", default-features = false } dotenvy = { version = "0.15.7" } dunce = { version = "1.0.5" } either = { version = "1.13.0" } diff --git a/crates/uv/Cargo.toml b/crates/uv/Cargo.toml index e3de5b629..97c0a5476 100644 --- a/crates/uv/Cargo.toml +++ b/crates/uv/Cargo.toml @@ -75,6 +75,7 @@ base64 = { workspace = true } clap = { workspace = true, features = ["derive", "string", "wrap_help"] } console = { workspace = true } ctrlc = { workspace = true } +diskus = { workspace = true } dotenvy = { workspace = true } dunce = { workspace = true } flate2 = { workspace = true, default-features = false } diff --git a/crates/uv/src/commands/cache_size.rs b/crates/uv/src/commands/cache_size.rs index dfeecfc9c..46ef3216d 100644 --- a/crates/uv/src/commands/cache_size.rs +++ b/crates/uv/src/commands/cache_size.rs @@ -1,6 +1,7 @@ use std::fmt::Write; use anyhow::Result; +use diskus::DiskUsage; use crate::commands::{ExitStatus, human_readable_bytes}; use crate::printer::Printer; @@ -31,16 +32,9 @@ pub(crate) fn cache_size( return Ok(ExitStatus::Success); } - // Walk the entire cache root - let total_bytes: u64 = walkdir::WalkDir::new(cache.root()) - .follow_links(false) - .into_iter() - .filter_map(Result::ok) - .filter_map(|entry| match entry.metadata() { - Ok(metadata) if metadata.is_file() => Some(metadata.len()), - _ => None, - }) - .sum(); + let disk_usage = DiskUsage::new(vec![cache.root().to_path_buf()]); + + let total_bytes = disk_usage.count_ignoring_errors(); if human_readable { let (bytes, unit) = human_readable_bytes(total_bytes);