pub struct AllocProfiler<Alloc = System> { /* private fields */ }
Expand description
Measures GlobalAlloc
memory usage.
§Examples
The default usage is to create a
#[global_allocator]
that wraps the System
allocator with AllocProfiler::system()
:
use std::collections::*;
use divan::AllocProfiler;
#[global_allocator]
static ALLOC: AllocProfiler = AllocProfiler::system();
fn main() {
divan::main();
}
#[divan::bench(types = [
Vec<i32>,
LinkedList<i32>,
HashSet<i32>,
])]
fn from_iter<T>() -> T
where
T: FromIterator<i32>,
{
(0..100).collect()
}
#[divan::bench(types = [
Vec<i32>,
LinkedList<i32>,
HashSet<i32>,
])]
fn drop<T>(bencher: divan::Bencher)
where
T: FromIterator<i32>,
{
bencher
.with_inputs(|| (0..100).collect::<T>())
.bench_values(std::mem::drop);
}
Wrap other GlobalAlloc
implementations like
mimalloc
with AllocProfiler::new()
:
use divan::AllocProfiler;
use mimalloc::MiMalloc;
#[global_allocator]
static ALLOC: AllocProfiler<MiMalloc> = AllocProfiler::new(MiMalloc);
See string
and collections
benchmarks for more examples.
§Implementation
Collecting allocation information happens at any point during which Divan is also measuring the time. As a result, counting allocations affects timing.
To reduce Divan’s footprint during benchmarking:
- Allocation information is recorded in thread-local storage to prevent
contention when benchmarks involve multiple threads, either through
options like
threads
or internally spawning their own threads. - It does not check for overflow and assumes it will not happen. This is subject to change in the future.
- Fast thread-local storage access is assembly-optimized on macOS.
Allocation information is the only data Divan records outside of timing, and thus it also has the only code that affects timing. Steps for recording alloc info:
-
Load the thread-local slot for allocation information.
On macOS, this is via the
gs
/tpidrro_el0
registers forpthread_getspecific
. Although this is not guaranteed as stable ABI, in practice many programs assume these registers store thread-local data.thread_local!
is used on all other platforms. -
Increment allocation operation invocation count and bytes count (a.k.a. size).
Allocation information is recorded in thread-local storage to prevent
slowdowns from synchronized sharing when using multiple threads, through
options like threads
.
Note that allocations in threads not controlled by Divan are not currently counted.
Implementations§
Source§impl<A> AllocProfiler<A>
impl<A> AllocProfiler<A>
Sourcepub const fn new(alloc: A) -> Self
pub const fn new(alloc: A) -> Self
Profiles a GlobalAlloc
.
Trait Implementations§
Source§impl<Alloc: Debug> Debug for AllocProfiler<Alloc>
impl<Alloc: Debug> Debug for AllocProfiler<Alloc>
Source§impl<Alloc: Default> Default for AllocProfiler<Alloc>
impl<Alloc: Default> Default for AllocProfiler<Alloc>
Source§fn default() -> AllocProfiler<Alloc>
fn default() -> AllocProfiler<Alloc>
Source§impl<A: GlobalAlloc> GlobalAlloc for AllocProfiler<A>
impl<A: GlobalAlloc> GlobalAlloc for AllocProfiler<A>
Source§unsafe fn alloc(&self, layout: Layout) -> *mut u8
unsafe fn alloc(&self, layout: Layout) -> *mut u8
layout
. Read moreSource§unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8
unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8
alloc
, but also ensures that the contents
are set to zero before being returned. Read more