Struct divan::AllocProfiler

source ·
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:

  1. Load the thread-local slot for allocation information.

    On macOS, this is via the gs/tpidrro_el0 registers for pthread_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.

  2. 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 AllocProfiler

source

pub const fn system() -> Self

Profiles the System allocator.

source§

impl<A> AllocProfiler<A>

source

pub const fn new(alloc: A) -> Self

Profiles a GlobalAlloc.

Trait Implementations§

source§

impl<Alloc: Debug> Debug for AllocProfiler<Alloc>

source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
source§

impl<Alloc: Default> Default for AllocProfiler<Alloc>

source§

fn default() -> AllocProfiler<Alloc>

Returns the “default value” for a type. Read more
source§

impl<A: GlobalAlloc> GlobalAlloc for AllocProfiler<A>

source§

unsafe fn alloc(&self, layout: Layout) -> *mut u8

Allocate memory as described by the given layout. Read more
source§

unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8

Behaves like alloc, but also ensures that the contents are set to zero before being returned. Read more
source§

unsafe fn realloc( &self, ptr: *mut u8, layout: Layout, new_size: usize ) -> *mut u8

Shrink or grow a block of memory to the given new_size in bytes. The block is described by the given ptr pointer and layout. Read more
source§

unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout)

Deallocate the block of memory at the given ptr pointer with the given layout. Read more

Auto Trait Implementations§

§

impl<Alloc> RefUnwindSafe for AllocProfiler<Alloc>
where Alloc: RefUnwindSafe,

§

impl<Alloc> Send for AllocProfiler<Alloc>
where Alloc: Send,

§

impl<Alloc> Sync for AllocProfiler<Alloc>
where Alloc: Sync,

§

impl<Alloc> Unpin for AllocProfiler<Alloc>
where Alloc: Unpin,

§

impl<Alloc> UnwindSafe for AllocProfiler<Alloc>
where Alloc: UnwindSafe,

Blanket Implementations§

source§

impl<T> Any for T
where T: 'static + ?Sized,

source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
source§

impl<T> Borrow<T> for T
where T: ?Sized,

source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
source§

impl<T> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

source§

impl<T, U> Into<U> for T
where U: From<T>,

source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

§

type Error = Infallible

The type returned in the event of a conversion error.
source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.