diff --git a/library/Cargo.lock b/library/Cargo.lock index 73a517fb449f9..efb6b83a093ec 100644 --- a/library/Cargo.lock +++ b/library/Cargo.lock @@ -28,7 +28,6 @@ dependencies = [ name = "alloc" version = "0.0.0" dependencies = [ - "bdwgc", "compiler_builtins", "core", "rand", @@ -41,16 +40,6 @@ version = "0.2.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" -[[package]] -name = "bdwgc" -version = "0.1.0" -dependencies = [ - "cmake", - "compiler_builtins", - "libc", - "rustc-std-workspace-core", -] - [[package]] name = "cc" version = "1.2.0" @@ -70,15 +59,6 @@ dependencies = [ "rustc-std-workspace-core", ] -[[package]] -name = "cmake" -version = "0.1.54" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7caa3f9de89ddbe2c607f4101924c5abec803763ae9534e4f4d7d8f84aa81f0" -dependencies = [ - "cc", -] - [[package]] name = "compiler_builtins" version = "0.1.150" diff --git a/library/alloc/Cargo.toml b/library/alloc/Cargo.toml index 524de49bf1df4..4ff837bd56aec 100644 --- a/library/alloc/Cargo.toml +++ b/library/alloc/Cargo.toml @@ -11,7 +11,6 @@ autobenches = false edition = "2021" [dependencies] -bdwgc = { path = "../bdwgc" } core = { path = "../core", public = true } compiler_builtins = { version = "=0.1.150", features = ['rustc-dep-of-std'] } @@ -43,11 +42,11 @@ compiler-builtins-c = ["compiler_builtins/c"] compiler-builtins-no-asm = ["compiler_builtins/no-asm"] compiler-builtins-no-f16-f128 = ["compiler_builtins/no-f16-f128"] compiler-builtins-mangled-names = ["compiler_builtins/mangled-names"] -log-stats = [] # Make panics and failed asserts immediately abort without formatting any message panic_immediate_abort = ["core/panic_immediate_abort"] # Choose algorithms that are optimized for binary size instead of runtime performance optimize_for_size = ["core/optimize_for_size"] +gc-metrics = [] [lints.rust.unexpected_cfgs] level = "warn" diff --git a/library/bdwgc/build.rs b/library/alloc/build.rs similarity index 97% rename from library/bdwgc/build.rs rename to library/alloc/build.rs index e95ecaa187490..e73ce49360416 100644 --- a/library/bdwgc/build.rs +++ b/library/alloc/build.rs @@ -21,7 +21,7 @@ fn main() { let status = Command::new(bindgen) .args(&[ "--ctypes-prefix", - "libc", + "core::ffi", "--use-core", "-o", out.to_str().unwrap(), diff --git a/library/alloc/src/alloc.rs b/library/alloc/src/alloc.rs index 9367ccb724c50..57ae656b79a63 100644 --- a/library/alloc/src/alloc.rs +++ b/library/alloc/src/alloc.rs @@ -9,37 +9,6 @@ pub use core::alloc::*; use core::hint; #[cfg(not(test))] use core::ptr::{self, NonNull}; -#[cfg(feature = "log-stats")] -use core::sync::atomic::AtomicU64; - -#[cfg(feature = "log-stats")] -#[unstable(feature = "gc", issue = "none")] -/// Global counters for various GC stats. -pub static GC_COUNTERS: GcCounters = GcCounters { - finalizers_registered: AtomicU64::new(0), - finalizers_elidable: AtomicU64::new(0), - finalizers_completed: AtomicU64::new(0), - barriers_visited: AtomicU64::new(0), - allocated_gc: AtomicU64::new(0), - allocated_boxed: AtomicU64::new(0), - allocated_rc: AtomicU64::new(0), - allocated_arc: AtomicU64::new(0), -}; - -#[cfg(feature = "log-stats")] -#[unstable(feature = "gc", issue = "none")] -#[allow(missing_docs)] -#[derive(Debug, Default)] -pub struct GcCounters { - pub finalizers_registered: AtomicU64, - pub finalizers_elidable: AtomicU64, - pub finalizers_completed: AtomicU64, - pub barriers_visited: AtomicU64, - pub allocated_gc: AtomicU64, - pub allocated_boxed: AtomicU64, - pub allocated_rc: AtomicU64, - pub allocated_arc: AtomicU64, -} unsafe extern "Rust" { // These are the magic symbols to call the global allocator. rustc generates diff --git a/library/alloc/src/bdwgc.rs b/library/alloc/src/bdwgc.rs new file mode 100644 index 0000000000000..2186d2b06dac6 --- /dev/null +++ b/library/alloc/src/bdwgc.rs @@ -0,0 +1,157 @@ +#![allow(missing_docs)] + +#[cfg(not(no_gc))] +#[allow(nonstandard_style)] +#[allow(missing_debug_implementations)] +pub mod api { + include!(concat!(env!("OUT_DIR"), "/bindings.rs")); +} + +#[cfg(not(no_gc))] +pub use api::*; + +pub mod metrics { + #[derive(Copy, Clone, Debug)] + pub enum Metric { + AllocationsArc, + AllocationsGc, + AllocationsRc, + AllocationsBox, + FinalizersRun, + FinalizersElided, + FinalizersRegistered, + } + + trait MetricsImpl { + fn init(&self) {} + fn increment(&self, _amount: u64, _metric: Metric) {} + fn capture(&self, _is_last: bool) {} + } + + #[cfg(feature = "gc-metrics")] + mod active { + use core::sync::atomic::{AtomicU64, Ordering}; + + use super::{Metric, MetricsImpl}; + + pub(super) struct Metrics { + finalizers_registered: AtomicU64, + finalizers_elidable: AtomicU64, + finalizers_completed: AtomicU64, + barriers_visited: AtomicU64, + allocated_gc: AtomicU64, + allocated_arc: AtomicU64, + allocated_rc: AtomicU64, + allocated_boxed: AtomicU64, + } + + impl Metrics { + pub const fn new() -> Self { + Self { + finalizers_registered: AtomicU64::new(0), + finalizers_elidable: AtomicU64::new(0), + finalizers_completed: AtomicU64::new(0), + barriers_visited: AtomicU64::new(0), + allocated_gc: AtomicU64::new(0), + allocated_arc: AtomicU64::new(0), + allocated_rc: AtomicU64::new(0), + allocated_boxed: AtomicU64::new(0), + } + } + } + + pub extern "C" fn record_post_collection(event: crate::GC_EventType) { + if event == crate::GC_EventType_GC_EVENT_END { + super::METRICS.capture(false); + } + } + + impl MetricsImpl for Metrics { + fn init(&self) { + unsafe { + crate::GC_enable_benchmark_stats(); + crate::GC_set_on_collection_event(Some(record_post_collection)); + } + } + + fn increment(&self, amount: u64, metric: Metric) { + match metric { + Metric::AllocationsArc => { + self.allocated_boxed.fetch_sub(amount, Ordering::Relaxed); + self.allocated_arc.fetch_add(amount, Ordering::Relaxed); + } + Metric::AllocationsRc => { + self.allocated_boxed.fetch_sub(amount, Ordering::Relaxed); + self.allocated_rc.fetch_add(amount, Ordering::Relaxed); + } + Metric::AllocationsBox => { + self.allocated_boxed.fetch_add(amount, Ordering::Relaxed); + } + Metric::AllocationsGc => { + self.allocated_gc.fetch_add(amount, Ordering::Relaxed); + } + Metric::FinalizersRun => { + self.finalizers_completed.fetch_add(amount, Ordering::Relaxed); + } + Metric::FinalizersElided => { + self.finalizers_completed.fetch_add(amount, Ordering::Relaxed); + } + Metric::FinalizersRegistered => { + self.finalizers_registered.fetch_add(amount, Ordering::Relaxed); + } + } + } + + fn capture(&self, is_last: bool) { + // Must preserve this ordering as it's hardcoded inside BDWGC. + // See src/bdwgc/misc.c:2812 + unsafe { + crate::GC_log_metrics( + self.finalizers_completed.load(Ordering::Relaxed), + self.finalizers_registered.load(Ordering::Relaxed), + self.allocated_gc.load(Ordering::Relaxed), + self.allocated_arc.load(Ordering::Relaxed), + self.allocated_rc.load(Ordering::Relaxed), + self.allocated_boxed.load(Ordering::Relaxed), + is_last as i32, + ); + } + } + } + } + + #[cfg(not(feature = "gc-metrics"))] + pub mod noop { + use super::MetricsImpl; + + #[derive(Debug, Default)] + pub struct Metrics; + + impl Metrics { + pub const fn new() -> Self { + Self + } + } + + impl MetricsImpl for Metrics {} + } + + #[cfg(feature = "gc-metrics")] + use active::Metrics; + #[cfg(not(feature = "gc-metrics"))] + use noop::Metrics; + + static METRICS: Metrics = Metrics::new(); + + pub fn init() { + METRICS.init(); + } + + pub fn record_final() { + METRICS.capture(true); + } + + pub fn increment(amount: u64, metric: Metric) { + METRICS.increment(amount, metric); + } +} diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs index 631bf2208b631..949d44eeced76 100644 --- a/library/alloc/src/lib.rs +++ b/library/alloc/src/lib.rs @@ -254,9 +254,8 @@ pub mod __export { pub use core::hint::must_use; } -#[cfg(not(no_gc))] #[unstable(feature = "gc", issue = "none")] -pub use bdwgc; +pub mod bdwgc; #[cfg(test)] #[allow(dead_code)] // Not used in all configurations diff --git a/library/alloc/src/rc.rs b/library/alloc/src/rc.rs index fb5f2f0f15bd5..d619c8d36b718 100644 --- a/library/alloc/src/rc.rs +++ b/library/alloc/src/rc.rs @@ -261,17 +261,14 @@ use core::pin::PinCoerceUnsized; use core::ptr::{self, NonNull, drop_in_place}; #[cfg(not(no_global_oom_handling))] use core::slice::from_raw_parts_mut; -#[cfg(feature = "log-stats")] -use core::sync::atomic; use core::{borrow, fmt, hint}; #[cfg(test)] use std::boxed::Box; -#[cfg(feature = "log-stats")] -use crate::alloc::GC_COUNTERS; #[cfg(not(no_global_oom_handling))] use crate::alloc::handle_alloc_error; use crate::alloc::{AllocError, Allocator, Global, Layout}; +use crate::bdwgc::metrics::{self, Metric}; use crate::borrow::{Cow, ToOwned}; #[cfg(not(test))] use crate::boxed::Box; @@ -412,11 +409,7 @@ impl Rc { #[cfg(not(no_global_oom_handling))] #[stable(feature = "rust1", since = "1.0.0")] pub fn new(value: T) -> Rc { - #[cfg(feature = "log-stats")] - { - GC_COUNTERS.allocated_rc.fetch_add(1, atomic::Ordering::Relaxed); - GC_COUNTERS.allocated_boxed.fetch_sub(1, atomic::Ordering::Relaxed); - } + metrics::increment(1, Metric::AllocationsRc); // There is an implicit weak pointer owned by all the strong // pointers, which ensures that the weak destructor never frees // the allocation while the strong destructor is running, even @@ -511,12 +504,7 @@ impl Rc { #[stable(feature = "new_uninit", since = "1.82.0")] #[must_use] pub fn new_uninit() -> Rc> { - #[cfg(feature = "log-stats")] - { - GC_COUNTERS.allocated_rc.fetch_add(1, atomic::Ordering::Relaxed); - // Decrement because `Rc` uses the global allocator. - GC_COUNTERS.allocated_boxed.fetch_sub(1, atomic::Ordering::Relaxed); - } + metrics::increment(1, Metric::AllocationsRc); unsafe { Rc::from_ptr(Rc::allocate_for_layout( Layout::new::(), @@ -576,12 +564,7 @@ impl Rc { // pointers, which ensures that the weak destructor never frees // the allocation while the strong destructor is running, even // if the weak pointer is stored inside the strong one. - #[cfg(feature = "log-stats")] - { - GC_COUNTERS.allocated_rc.fetch_add(1, atomic::Ordering::Relaxed); - // Decrement because `Rc` uses the global allocator. - GC_COUNTERS.allocated_boxed.fetch_sub(1, atomic::Ordering::Relaxed); - } + metrics::increment(1, Metric::AllocationsRc); unsafe { Ok(Self::from_inner( Box::leak(Box::try_new(RcInner { @@ -804,12 +787,7 @@ impl Rc { where F: FnOnce(&Weak) -> T, { - #[cfg(feature = "log-stats")] - { - GC_COUNTERS.allocated_rc.fetch_add(1, atomic::Ordering::Relaxed); - // Decrement because `Rc` uses the global allocator. - GC_COUNTERS.allocated_boxed.fetch_sub(1, atomic::Ordering::Relaxed); - } + metrics::increment(1, Metric::AllocationsRc); // Construct the inner in the "uninitialized" state with a single // weak reference. let (uninit_raw_ptr, alloc) = Box::into_raw_with_allocator(Box::new_in( @@ -877,12 +855,7 @@ impl Rc { RcInner { strong: Cell::new(1), weak: Cell::new(1), value }, alloc, )?); - #[cfg(feature = "log-stats")] - { - GC_COUNTERS.allocated_rc.fetch_add(1, atomic::Ordering::Relaxed); - // Decrement because `Rc` uses the global allocator. - GC_COUNTERS.allocated_boxed.fetch_sub(1, atomic::Ordering::Relaxed); - } + metrics::increment(1, Metric::AllocationsRc); Ok(unsafe { Self::from_inner_in(ptr.into(), alloc) }) } @@ -1107,12 +1080,7 @@ impl Rc<[T]> { #[unstable(feature = "new_zeroed_alloc", issue = "129396")] #[must_use] pub fn new_zeroed_slice(len: usize) -> Rc<[mem::MaybeUninit]> { - #[cfg(feature = "log-stats")] - { - GC_COUNTERS.allocated_rc.fetch_add(1, atomic::Ordering::Relaxed); - // Decrement because `Rc` uses the global allocator. - GC_COUNTERS.allocated_boxed.fetch_sub(1, atomic::Ordering::Relaxed); - } + metrics::increment(1, Metric::AllocationsRc); unsafe { Rc::from_ptr(Rc::allocate_for_layout( Layout::array::(len).unwrap(), @@ -2093,12 +2061,7 @@ impl Rc { allocate: impl FnOnce(Layout) -> Result, AllocError>, mem_to_rc_inner: impl FnOnce(*mut u8) -> *mut RcInner, ) -> *mut RcInner { - #[cfg(feature = "log-stats")] - { - GC_COUNTERS.allocated_rc.fetch_add(1, atomic::Ordering::Relaxed); - // Decrement because `Rc` uses the global allocator. - GC_COUNTERS.allocated_boxed.fetch_sub(1, atomic::Ordering::Relaxed); - } + metrics::increment(1, Metric::AllocationsRc); let layout = rc_inner_layout_for_value_layout(value_layout); unsafe { Rc::try_allocate_for_layout(value_layout, allocate, mem_to_rc_inner) @@ -2393,12 +2356,7 @@ impl Default for Rc { /// ``` #[inline] fn default() -> Rc { - #[cfg(feature = "log-stats")] - { - GC_COUNTERS.allocated_rc.fetch_add(1, atomic::Ordering::Relaxed); - // Decrement because `Rc` uses the global allocator. - GC_COUNTERS.allocated_boxed.fetch_sub(1, atomic::Ordering::Relaxed); - } + metrics::increment(1, Metric::AllocationsRc); unsafe { Self::from_inner( Box::leak(Box::write( @@ -4040,12 +3998,7 @@ impl UniqueRc { #[cfg(not(no_global_oom_handling))] #[unstable(feature = "unique_rc_arc", issue = "112566")] pub fn new_in(value: T, alloc: A) -> Self { - #[cfg(feature = "log-stats")] - { - GC_COUNTERS.allocated_rc.fetch_add(1, atomic::Ordering::Relaxed); - // Decrement because `Rc` uses the global allocator. - GC_COUNTERS.allocated_boxed.fetch_sub(1, atomic::Ordering::Relaxed); - } + metrics::increment(1, Metric::AllocationsRc); let (ptr, alloc) = Box::into_unique(Box::new_in( RcInner { strong: Cell::new(0), diff --git a/library/alloc/src/sync.rs b/library/alloc/src/sync.rs index c6709283b891d..62cd88b505e64 100644 --- a/library/alloc/src/sync.rs +++ b/library/alloc/src/sync.rs @@ -29,11 +29,10 @@ use core::sync::atomic; use core::sync::atomic::Ordering::{Acquire, Relaxed, Release}; use core::{borrow, fmt, hint}; -#[cfg(feature = "log-stats")] -use crate::alloc::GC_COUNTERS; #[cfg(not(no_global_oom_handling))] use crate::alloc::handle_alloc_error; use crate::alloc::{AllocError, Allocator, Global, Layout}; +use crate::bdwgc::metrics::{self, Metric}; use crate::borrow::{Cow, ToOwned}; use crate::boxed::Box; use crate::rc::is_dangling; @@ -388,11 +387,7 @@ impl Arc { pub fn new(data: T) -> Arc { // Start the weak pointer count as 1 which is the weak pointer that's // held by all the strong pointers (kinda), see std/rc.rs for more info - #[cfg(feature = "log-stats")] - { - GC_COUNTERS.allocated_arc.fetch_add(1, atomic::Ordering::Relaxed); - GC_COUNTERS.allocated_boxed.fetch_sub(1, atomic::Ordering::Relaxed); - } + metrics::increment(1, Metric::AllocationsArc); let x: Box<_> = Box::new(ArcInner { strong: atomic::AtomicUsize::new(1), weak: atomic::AtomicUsize::new(1), @@ -560,11 +555,7 @@ impl Arc { pub fn try_new(data: T) -> Result, AllocError> { // Start the weak pointer count as 1 which is the weak pointer that's // held by all the strong pointers (kinda), see std/rc.rs for more info - #[cfg(feature = "log-stats")] - { - GC_COUNTERS.allocated_arc.fetch_add(1, atomic::Ordering::Relaxed); - GC_COUNTERS.allocated_boxed.fetch_sub(1, atomic::Ordering::Relaxed); - } + metrics::increment(1, Metric::AllocationsArc); let x: Box<_> = Box::try_new(ArcInner { strong: atomic::AtomicUsize::new(1), weak: atomic::AtomicUsize::new(1), @@ -659,12 +650,7 @@ impl Arc { pub fn new_in(data: T, alloc: A) -> Arc { // Start the weak pointer count as 1 which is the weak pointer that's // held by all the strong pointers (kinda), see std/rc.rs for more info - #[cfg(feature = "log-stats")] - { - GC_COUNTERS.allocated_arc.fetch_add(1, Relaxed); - // Decrement because `Arc` uses the global allocator. - GC_COUNTERS.allocated_boxed.fetch_sub(1, Relaxed); - } + metrics::increment(1, Metric::AllocationsArc); let x = Box::new_in( ArcInner { strong: atomic::AtomicUsize::new(1), @@ -704,11 +690,7 @@ impl Arc { // #[unstable(feature = "new_uninit", issue = "63291")] #[inline] pub fn new_uninit_in(alloc: A) -> Arc, A> { - #[cfg(feature = "log-stats")] - { - GC_COUNTERS.allocated_arc.fetch_add(1, atomic::Ordering::Relaxed); - GC_COUNTERS.allocated_boxed.fetch_sub(1, atomic::Ordering::Relaxed); - } + metrics::increment(1, Metric::AllocationsArc); unsafe { Arc::from_ptr_in( Arc::allocate_for_layout( @@ -795,11 +777,7 @@ impl Arc { where F: FnOnce(&Weak) -> T, { - #[cfg(feature = "log-stats")] - { - GC_COUNTERS.allocated_arc.fetch_add(1, atomic::Ordering::Relaxed); - GC_COUNTERS.allocated_boxed.fetch_sub(1, atomic::Ordering::Relaxed); - } + metrics::increment(1, Metric::AllocationsArc); // Construct the inner in the "uninitialized" state with a single // weak reference. let (uninit_raw_ptr, alloc) = Box::into_raw_with_allocator(Box::new_in( @@ -1975,11 +1953,7 @@ impl Arc { allocate: impl FnOnce(Layout) -> Result, AllocError>, mem_to_arcinner: impl FnOnce(*mut u8) -> *mut ArcInner, ) -> *mut ArcInner { - #[cfg(feature = "log-stats")] - { - GC_COUNTERS.allocated_arc.fetch_add(1, atomic::Ordering::Relaxed); - GC_COUNTERS.allocated_boxed.fetch_sub(1, atomic::Ordering::Relaxed); - } + metrics::increment(1, Metric::AllocationsArc); let layout = arcinner_layout_for_value_layout(value_layout); let ptr = allocate(layout).unwrap_or_else(|_| handle_alloc_error(layout)); diff --git a/library/bdwgc/Cargo.toml b/library/bdwgc/Cargo.toml deleted file mode 100644 index ac1d1e5c3076a..0000000000000 --- a/library/bdwgc/Cargo.toml +++ /dev/null @@ -1,16 +0,0 @@ -cargo-features = ["public-dependency"] - -[package] -name = "bdwgc" -version = "0.1.0" -authors = ["Jake Hughes "] -edition = "2021" -license = "Apache-2.0 OR MIT" - -[dependencies] -core = { version = "1.0.0", package = 'rustc-std-workspace-core' } -compiler_builtins = { version = "0.1.10", features = ['rustc-dep-of-std'] } -libc = { version = "0.2.148", default-features = false, features = ['rustc-dep-of-std'], public = true } - -[build-dependencies] -cmake = "0.1" diff --git a/library/bdwgc/src/lib.rs b/library/bdwgc/src/lib.rs deleted file mode 100644 index 91730f4d40e9b..0000000000000 --- a/library/bdwgc/src/lib.rs +++ /dev/null @@ -1,35 +0,0 @@ -#![no_std] -#![allow(non_camel_case_types)] -#![allow(non_upper_case_globals)] - -include!(concat!(env!("OUT_DIR"), "/bindings.rs")); - -#[repr(C)] -#[derive(Default)] -pub struct ProfileStats { - /// Heap size in bytes (including area unmapped to OS). - pub heapsize_full: usize, - /// Total bytes contained in free and unmapped blocks. - pub free_bytes_full: usize, - /// Amount of memory unmapped to OS. - pub unmapped_bytes: usize, - /// Number of bytes allocated since the recent collection. - pub bytes_allocd_since_gc: usize, - /// Number of bytes allocated before the recent collection. - /// The value may wrap. - pub allocd_bytes_before_gc: usize, - /// Number of bytes not considered candidates for garbage collection. - pub non_gc_bytes: usize, - /// Garbage collection cycle number. - /// The value may wrap. - pub gc_no: usize, - /// Number of marker threads (excluding the initiating one). - pub markers_m1: usize, - /// Approximate number of reclaimed bytes after recent collection. - pub bytes_reclaimed_since_gc: usize, - /// Approximate number of bytes reclaimed before the recent collection. - /// The value may wrap. - pub reclaimed_bytes_before_gc: usize, - /// Number of bytes freed explicitly since the recent GC. - pub expl_freed_bytes_since_gc: usize, -} diff --git a/library/std/Cargo.toml b/library/std/Cargo.toml index 666205f253763..414113ce157ab 100644 --- a/library/std/Cargo.toml +++ b/library/std/Cargo.toml @@ -103,7 +103,7 @@ llvm-libunwind = ["unwind/llvm-libunwind"] system-llvm-libunwind = ["unwind/system-llvm-libunwind"] # Alloy debug flags -log-stats = ["alloc/log-stats"] +gc-metrics = ["alloc/gc-metrics"] premature-finalizer-prevention = [] premature-finalizer-prevention-optimize = [] finalizer-elision = [] diff --git a/library/std/src/gc.rs b/library/std/src/gc.rs index b2a39d2b85d79..e7d43fac5a246 100644 --- a/library/std/src/gc.rs +++ b/library/std/src/gc.rs @@ -48,34 +48,14 @@ use core::ops::{CoerceUnsized, Deref, DispatchFromDyn, LegacyReceiver}; use core::ptr::{self, NonNull, drop_in_place}; #[cfg(not(no_global_oom_handling))] use core::slice::from_raw_parts_mut; -#[cfg(feature = "log-stats")] -use core::sync::atomic; use core::{fmt, iter}; -#[cfg(feature = "log-stats")] -use crate::alloc::GC_COUNTERS; #[cfg(not(no_global_oom_handling))] use crate::alloc::{Global, handle_alloc_error}; use crate::bdwgc; +use crate::bdwgc::metrics::Metric; use crate::sync::{Condvar, Mutex}; -#[cfg(feature = "log-stats")] -#[derive(Debug, Copy, Clone)] -pub struct GcStats { - pub elision_enabled: bool, - pub prem_enabled: bool, - pub premopt_enabled: bool, - pub finalizers_registered: u64, - pub finalizers_completed: u64, - pub finalizers_elidable: u64, - pub barriers_visited: u64, - pub allocated_gc: u64, - pub allocated_boxed: u64, - pub allocated_rc: u64, - pub allocated_arc: u64, - pub num_gcs: u64, -} - static FINALIZER_THREAD_EXISTS: Mutex = Mutex::new(false); //////////////////////////////////////////////////////////////////////////////// @@ -91,8 +71,7 @@ pub struct GcAllocator; unsafe impl GlobalAlloc for GcAllocator { #[inline] unsafe fn alloc(&self, layout: Layout) -> *mut u8 { - #[cfg(feature = "log-stats")] - GC_COUNTERS.allocated_boxed.fetch_add(1, atomic::Ordering::Relaxed); + bdwgc::metrics::increment(1, Metric::AllocationsBox); unsafe { gc_malloc(layout) } } @@ -152,8 +131,7 @@ unsafe fn gc_free(ptr: *mut u8, _: Layout) { unsafe impl Allocator for GcAllocator { #[inline] fn allocate(&self, layout: Layout) -> Result, AllocError> { - #[cfg(feature = "log-stats")] - GC_COUNTERS.allocated_gc.fetch_add(1, atomic::Ordering::Relaxed); + bdwgc::metrics::increment(1, Metric::AllocationsGc); match layout.size() { 0 => Ok(NonNull::slice_from_raw_parts(layout.dangling(), 0)), size => unsafe { @@ -176,45 +154,16 @@ impl GcAllocator { //////////////////////////////////////////////////////////////////////////////// // Free functions //////////////////////////////////////////////////////////////////////////////// -#[cfg(feature = "log-stats")] -pub fn stats() -> GcStats { - #[cfg(feature = "finalizer-elision")] - let elision_enabled = true; - #[cfg(not(feature = "finalizer-elision"))] - let elision_enabled = false; - #[cfg(feature = "premature-finalizer-prevention")] - let prem_enabled = true; - #[cfg(not(feature = "premature-finalizer-prevention"))] - let prem_enabled = false; - #[cfg(feature = "premature-finalizer-prevention-optimize")] - let premopt_enabled = true; - #[cfg(not(feature = "premature-finalizer-prevention-optimize"))] - let premopt_enabled = false; - GcStats { - elision_enabled, - prem_enabled, - premopt_enabled, - finalizers_registered: GC_COUNTERS.finalizers_registered.load(atomic::Ordering::Relaxed), - finalizers_completed: GC_COUNTERS.finalizers_completed.load(atomic::Ordering::Relaxed), - finalizers_elidable: GC_COUNTERS.finalizers_elidable.load(atomic::Ordering::Relaxed), - allocated_gc: GC_COUNTERS.allocated_gc.load(atomic::Ordering::Relaxed), - allocated_boxed: GC_COUNTERS.allocated_boxed.load(atomic::Ordering::Relaxed), - allocated_rc: GC_COUNTERS.allocated_rc.load(atomic::Ordering::Relaxed), - allocated_arc: GC_COUNTERS.allocated_arc.load(atomic::Ordering::Relaxed), - barriers_visited: GC_COUNTERS.barriers_visited.load(atomic::Ordering::Relaxed), - num_gcs: unsafe { bdwgc::GC_get_gc_no() }, - } -} pub fn init() { unsafe { - bdwgc::GC_init(); bdwgc::GC_set_finalize_on_demand(1); bdwgc::GC_set_finalizer_notifier(Some(notify_finalizer_thread)); #[cfg(feature = "bdwgc-disable")] bdwgc::GC_disable(); - #[cfg(feature = "log-stats")] - bdwgc::GC_enable_benchmark_stats(); + bdwgc::metrics::init(); + // The final initialization must come last. + bdwgc::GC_init(); } } @@ -269,15 +218,8 @@ fn run_finalizers() { if unsafe { bdwgc::GC_should_invoke_finalizers() } == 0 { guard = cvar.wait(guard).unwrap(); } else { - #[cfg(feature = "log-stats")] - { - let finalized = unsafe { bdwgc::GC_invoke_finalizers() }; - GC_COUNTERS.finalizers_completed.fetch_add(finalized, atomic::Ordering::Relaxed); - } - #[cfg(not(feature = "log-stats"))] - unsafe { - bdwgc::GC_invoke_finalizers(); - } + let finalized = unsafe { bdwgc::GC_invoke_finalizers() }; + crate::bdwgc::metrics::increment(finalized.try_into().unwrap(), Metric::FinalizersRun); } drop(guard) } @@ -360,8 +302,6 @@ impl, U: ?Sized> DispatchFromDyn> for Gc {} #[cfg(all(not(bootstrap), not(test)))] impl Drop for Gc { fn drop(&mut self) { - #[cfg(feature = "log-stats")] - GC_COUNTERS.barriers_visited.fetch_add(1, atomic::Ordering::Relaxed); unsafe { // asm macros clobber by default, so this is enough to introduce a // barrier. @@ -595,14 +535,7 @@ impl Gc { let needs_finalizer = crate::mem::needs_drop::(); if !needs_finalizer { - #[cfg(feature = "log-stats")] - { - GC_COUNTERS.finalizers_elidable.fetch_add( - crate::mem::needs_finalizer::() as u64, - atomic::Ordering::Relaxed, - ); - GC_COUNTERS.finalizers_registered.fetch_add(1, atomic::Ordering::Relaxed); - } + crate::bdwgc::metrics::increment(1, Metric::FinalizersElided); return unsafe { Self::from_inner(Box::leak(Box::new_in(GcBox { value }, GcAllocator)).into()) }; @@ -635,8 +568,7 @@ impl Gc { ptr::null_mut(), ); } - #[cfg(feature = "log-stats")] - GC_COUNTERS.finalizers_registered.fetch_add(1, atomic::Ordering::Relaxed); + crate::bdwgc::metrics::increment(1, Metric::FinalizersRegistered); unsafe { Self::from_inner(ptr.into()) } } } diff --git a/library/std/src/process.rs b/library/std/src/process.rs index 3d1d4e73fbeff..e623bd099ffe8 100644 --- a/library/std/src/process.rs +++ b/library/std/src/process.rs @@ -2039,8 +2039,7 @@ impl ExitCode { /// ``` #[unstable(feature = "exitcode_exit_method", issue = "97100")] pub fn exit_process(self) -> ! { - #[cfg(feature = "log-stats")] - crate::rt::log_stats(); + crate::bdwgc::metrics::record_final(); exit(self.to_i32()) } } @@ -2317,8 +2316,7 @@ impl Child { #[cfg_attr(not(test), rustc_diagnostic_item = "process_exit")] pub fn exit(code: i32) -> ! { crate::rt::cleanup(); - #[cfg(feature = "log-stats")] - crate::rt::log_stats(); + crate::bdwgc::metrics::record_final(); crate::sys::os::exit(code) } diff --git a/library/std/src/rt.rs b/library/std/src/rt.rs index 48d4ebcbe7ff0..5b683618b6267 100644 --- a/library/std/src/rt.rs +++ b/library/std/src/rt.rs @@ -135,51 +135,6 @@ pub(crate) fn thread_cleanup() { .unwrap_or_else(handle_rt_panic); } -#[cfg(feature = "log-stats")] -pub(crate) fn log_stats() { - if crate::env::var("ALLOY_LOG").is_err() { - return; - } - - use crate::io::Write; - let mut filename = crate::fs::OpenOptions::new() - .write(true) - .create(true) - .append(true) - .open(crate::env::var("ALLOY_LOG").unwrap()) - .unwrap(); - - let headers = "elision enabled,\ - pfp enabled,\ - premopt enabled,\ - finalizers registered,\ - finalizers completed,\ - finalizers elidable,\ - barriers visited,\ - Gc allocated,\ - Box allocated,\ - Rc allocated,\ - Arc allocated,\ - num GCs"; - let stats = crate::gc::stats(); - let stats = format!( - "{},{},{},{},{},{},{},{},{},{},{},{}\n", - stats.elision_enabled, - stats.prem_enabled, - stats.premopt_enabled, - stats.finalizers_registered, - stats.finalizers_completed, - stats.finalizers_elidable, - stats.barriers_visited, - stats.allocated_gc, - stats.allocated_boxed, - stats.allocated_rc, - stats.allocated_arc, - stats.num_gcs - ); - write!(filename, "{}", format!("{headers}\n{stats}")).unwrap(); -} - // One-time runtime cleanup. // Runs after `main` or at program exit. // NOTE: this is not guaranteed to run, for example when the program aborts. @@ -255,7 +210,6 @@ fn lang_start( argv, sigpipe, ); - #[cfg(feature = "log-stats")] - crate::rt::log_stats(); + crate::bdwgc::metrics::record_final(); status } diff --git a/library/sysroot/Cargo.toml b/library/sysroot/Cargo.toml index 10da3c36ca530..5002932293281 100644 --- a/library/sysroot/Cargo.toml +++ b/library/sysroot/Cargo.toml @@ -34,8 +34,8 @@ std_detect_dlsym_getauxval = ["std/std_detect_dlsym_getauxval"] std_detect_env_override = ["std/std_detect_env_override"] windows_raw_dylib = ["std/windows_raw_dylib"] # Alloy debug flags -log-stats = ["std/log-stats"] finalizer-elision = ["std/finalizer-elision"] premature-finalizer-prevention = ["std/premature-finalizer-prevention"] premature-finalizer-prevention-optimize = ["std/premature-finalizer-prevention-optimize"] bdwgc-disable = ["std/bdwgc-disable"] +gc-metrics = ["std/gc-metrics"] diff --git a/src/bdwgc b/src/bdwgc index 95bee9a212cfc..b82674100bb89 160000 --- a/src/bdwgc +++ b/src/bdwgc @@ -1 +1 @@ -Subproject commit 95bee9a212cfc155fd0a2ae6a93575d0dfa6236d +Subproject commit b82674100bb89011d36b4fd3997d14505ae55b7c diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs index aec0c758c63d8..4acb60a7ff1a0 100644 --- a/src/bootstrap/src/core/config/config.rs +++ b/src/bootstrap/src/core/config/config.rs @@ -346,7 +346,7 @@ pub struct Config { pub backtrace: bool, // support for RUST_BACKTRACE // alloy debug features - pub log_stats: bool, // support for LOG_ALLOY_STATS + pub gc_metrics: bool, pub finalizer_elision: bool, pub finalizer_safety_analysis: bool, pub premature_finalizer_prevention: bool, @@ -1232,7 +1232,7 @@ define_config! { define_config! { /// TOML representation of Alloy build configurations. struct Alloy { - log_stats: Option = "log-stats", + gc_metrics: Option = "gc-metrics", finalizer_elision: Option = "finalizer-elision", finalizer_safety_analysis: Option = "finalizer-safety-analysis", premature_finalizer_prevention: Option = "premature-finalizer-prevention", @@ -1323,7 +1323,7 @@ impl Config { // `rust-objcopy` to workaround bad `strip`s on macOS. llvm_tools_enabled: true, // alloy opts - log_stats: false, + gc_metrics: false, finalizer_elision: true, finalizer_safety_analysis: true, premature_finalizer_prevention: true, @@ -2059,7 +2059,7 @@ impl Config { if let Some(alloy) = toml.alloy { let Alloy { - log_stats, + gc_metrics, finalizer_elision, finalizer_safety_analysis, premature_finalizer_prevention, @@ -2069,7 +2069,7 @@ impl Config { bdwgc_disable, } = alloy; - set(&mut config.log_stats, log_stats); + set(&mut config.gc_metrics, gc_metrics); set(&mut config.finalizer_elision, finalizer_elision); set(&mut config.finalizer_safety_analysis, finalizer_safety_analysis); set(&mut config.premature_finalizer_prevention, premature_finalizer_prevention); diff --git a/src/bootstrap/src/lib.rs b/src/bootstrap/src/lib.rs index 0ff54dbfd2adb..9cae8f303fc21 100644 --- a/src/bootstrap/src/lib.rs +++ b/src/bootstrap/src/lib.rs @@ -680,8 +680,8 @@ impl Build { features.insert("compiler-builtins-mem"); } // Alloy features - if self.config.log_stats { - features.insert("log-stats"); + if self.config.gc_metrics { + features.insert("gc-metrics"); } if self.config.finalizer_elision { features.insert("finalizer-elision"); @@ -729,7 +729,7 @@ impl Build { if !self.config.finalizer_elision { features.push("rustc_no_elision"); } - if self.config.log_stats { + if self.config.gc_metrics { features.push("rustc_log_gc_stats"); } diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs index 641f3c3ca9a90..51e58b4e4fcfd 100644 --- a/src/tools/tidy/src/deps.rs +++ b/src/tools/tidy/src/deps.rs @@ -465,7 +465,6 @@ const PERMITTED_STDLIB_DEPENDENCIES: &[&str] = &[ "allocator-api2", "cc", "cfg-if", - "cmake", "compiler_builtins", "dlmalloc", "fortanix-sgx-abi", diff --git a/tests/run-make/linker-warning/short-error.txt b/tests/run-make/linker-warning/short-error.txt index c3cfb5c85b23a..ccbabd81037df 100644 --- a/tests/run-make/linker-warning/short-error.txt +++ b/tests/run-make/linker-warning/short-error.txt @@ -1,6 +1,6 @@ error: linking with `./fake-linker` failed: exit status: 1 | - = note: "./fake-linker" "-m64" "/symbols.o" "-Wl,-rpath,/lib" "-Wl,-Bdynamic" "-Wl,--no-as-needed" "-lgc" "-Wl,--as-needed" "<2 object files omitted>" "-Wl,--as-needed" "-Wl,-Bstatic" "/lib/rustlib/x86_64-unknown-linux-gnu/lib/{libstd-*,libpanic_unwind-*,libobject-*,libmemchr-*,libaddr2line-*,libgimli-*,librustc_demangle-*,libstd_detect-*,libhashbrown-*,librustc_std_workspace_alloc-*,libminiz_oxide-*,libadler2-*,libunwind-*,libcfg_if-*,liballoc-*,libbdwgc-*,liblibc-*,librustc_std_workspace_core-*,libcore-*,libcompiler_builtins-*}.rlib" "-Wl,-Bdynamic" "-lgcc_s" "-lgc" "-lutil" "-lrt" "-lpthread" "-lm" "-ldl" "-lc" "-L" "/raw-dylibs" "-Wl,--eh-frame-hdr" "-Wl,-z,noexecstack" "-L" "/build-root/test/run-make/linker-warning/rmake_out" "-L" "/build-root/bdwgc/lib" "-L" "/lib/rustlib/x86_64-unknown-linux-gnu/lib" "-o" "main" "-Wl,--gc-sections" "-pie" "-Wl,-z,relro,-z,now" "-nodefaultlibs" "run_make_error" + = note: "./fake-linker" "-m64" "/symbols.o" "-Wl,-rpath,/lib" "-Wl,-Bdynamic" "-Wl,--no-as-needed" "-lgc" "-Wl,--as-needed" "<2 object files omitted>" "-Wl,--as-needed" "-Wl,-Bstatic" "/lib/rustlib/x86_64-unknown-linux-gnu/lib/{libstd-*,libpanic_unwind-*,libobject-*,libmemchr-*,libaddr2line-*,libgimli-*,librustc_demangle-*,libstd_detect-*,libhashbrown-*,librustc_std_workspace_alloc-*,libminiz_oxide-*,libadler2-*,libunwind-*,libcfg_if-*,liblibc-*,liballoc-*,librustc_std_workspace_core-*,libcore-*,libcompiler_builtins-*}.rlib" "-Wl,-Bdynamic" "-lgcc_s" "-lutil" "-lrt" "-lpthread" "-lm" "-ldl" "-lc" "-lgc" "-L" "/raw-dylibs" "-Wl,--eh-frame-hdr" "-Wl,-z,noexecstack" "-L" "/build-root/test/run-make/linker-warning/rmake_out" "-L" "/build-root/bdwgc/lib" "-L" "/lib/rustlib/x86_64-unknown-linux-gnu/lib" "-o" "main" "-Wl,--gc-sections" "-pie" "-Wl,-z,relro,-z,now" "-nodefaultlibs" "run_make_error" = note: some arguments are omitted. use `--verbose` to show all linker arguments = note: error: baz