From f06755045c523418a6a06e9292e9c2ac41342dd1 Mon Sep 17 00:00:00 2001 From: BD103 <59022059+BD103@users.noreply.github.com> Date: Fri, 5 Jan 2024 12:59:01 -0500 Subject: [PATCH 1/2] feat: use atomic instead of mutex in du function --- crates/cargo-util/src/du.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/crates/cargo-util/src/du.rs b/crates/cargo-util/src/du.rs index 14634c47bc1..97fe8bfc602 100644 --- a/crates/cargo-util/src/du.rs +++ b/crates/cargo-util/src/du.rs @@ -4,6 +4,7 @@ use anyhow::{Context, Result}; use ignore::overrides::OverrideBuilder; use ignore::{WalkBuilder, WalkState}; use std::path::Path; +use std::sync::atomic::{AtomicU64, Ordering}; use std::sync::{Arc, Mutex}; /// Determines the disk usage of all files in the given directory. @@ -39,7 +40,7 @@ fn du_inner(path: &Path, patterns: &[&str]) -> Result { .git_ignore(false) .git_exclude(false); let walker = builder.build_parallel(); - let total = Arc::new(Mutex::new(0u64)); + let total = AtomicU64::new(0); // A slot used to indicate there was an error while walking. // // It is possible that more than one error happens (such as in different @@ -51,8 +52,8 @@ fn du_inner(path: &Path, patterns: &[&str]) -> Result { Ok(entry) => match entry.metadata() { Ok(meta) => { if meta.is_file() { - let mut lock = total.lock().unwrap(); - *lock += meta.len(); + // Note that fetch_add may wrap the u64. + total.fetch_add(meta.len(), Ordering::Relaxed); } } Err(e) => { @@ -73,6 +74,5 @@ fn du_inner(path: &Path, patterns: &[&str]) -> Result { return Err(e); } - let total = *total.lock().unwrap(); - Ok(total) + Ok(total.load(Ordering::Relaxed)) } From cf76fa65d218e6dd3bd38c4b7b6c6fc5e57b2374 Mon Sep 17 00:00:00 2001 From: BD103 <59022059+BD103@users.noreply.github.com> Date: Mon, 8 Jan 2024 10:10:45 -0500 Subject: [PATCH 2/2] feat: cfg-gate atomic in du function --- crates/cargo-util/src/du.rs | 32 ++++++++++++++++++++++++++++---- 1 file changed, 28 insertions(+), 4 deletions(-) diff --git a/crates/cargo-util/src/du.rs b/crates/cargo-util/src/du.rs index 97fe8bfc602..eaa2edeab1a 100644 --- a/crates/cargo-util/src/du.rs +++ b/crates/cargo-util/src/du.rs @@ -4,9 +4,11 @@ use anyhow::{Context, Result}; use ignore::overrides::OverrideBuilder; use ignore::{WalkBuilder, WalkState}; use std::path::Path; -use std::sync::atomic::{AtomicU64, Ordering}; use std::sync::{Arc, Mutex}; +#[cfg(target_has_atomic = "64")] +use std::sync::atomic::{AtomicU64, Ordering}; + /// Determines the disk usage of all files in the given directory. /// /// The given patterns are gitignore style patterns relative to the given @@ -40,7 +42,16 @@ fn du_inner(path: &Path, patterns: &[&str]) -> Result { .git_ignore(false) .git_exclude(false); let walker = builder.build_parallel(); + + // Not all targets support atomics, so a mutex is used as a fallback + // https://github.com/rust-lang/cargo/pull/12981 + // https://doc.rust-lang.org/std/sync/atomic/index.html#portability + #[cfg(target_has_atomic = "64")] let total = AtomicU64::new(0); + + #[cfg(not(target_has_atomic = "64"))] + let total = Arc::new(Mutex::new(0_u64)); + // A slot used to indicate there was an error while walking. // // It is possible that more than one error happens (such as in different @@ -52,8 +63,17 @@ fn du_inner(path: &Path, patterns: &[&str]) -> Result { Ok(entry) => match entry.metadata() { Ok(meta) => { if meta.is_file() { - // Note that fetch_add may wrap the u64. - total.fetch_add(meta.len(), Ordering::Relaxed); + #[cfg(target_has_atomic = "64")] + { + // Note that fetch_add may wrap the u64. + total.fetch_add(meta.len(), Ordering::Relaxed); + } + + #[cfg(not(target_has_atomic = "64"))] + { + let mut lock = total.lock().unwrap(); + *lock += meta.len(); + } } } Err(e) => { @@ -74,5 +94,9 @@ fn du_inner(path: &Path, patterns: &[&str]) -> Result { return Err(e); } - Ok(total.load(Ordering::Relaxed)) + #[cfg(target_has_atomic = "64")] + return Ok(total.load(Ordering::Relaxed)); + + #[cfg(not(target_has_atomic = "64"))] + Ok(*total.lock().unwrap()) }