Skip to main content

ModAlloc

Struct ModAlloc 

Source
pub struct ModAlloc { /* private fields */ }
Expand description

Global allocator wrapper that tracks allocations.

Install as #[global_allocator] to enable tracking. The wrapper forwards every allocation, deallocation, reallocation, and zero-initialised allocation to std::alloc::System and records the event in four lock-free AtomicU64 counters.

§Example

use mod_alloc::ModAlloc;

#[global_allocator]
static GLOBAL: ModAlloc = ModAlloc::new();

fn main() {
    let v: Vec<u8> = vec![0; 1024];
    let stats = GLOBAL.snapshot();
    assert!(stats.alloc_count >= 1);
    drop(v);
}

Implementations§

Source§

impl ModAlloc

Source

pub const fn new() -> Self

Construct a new ModAlloc allocator wrapper.

All counters start at zero. This function is const, which allows construction in a static for use as #[global_allocator].

§Example
use mod_alloc::ModAlloc;

static GLOBAL: ModAlloc = ModAlloc::new();
let stats = GLOBAL.snapshot();
assert_eq!(stats.alloc_count, 0);
Examples found in repository?
examples/basic.rs (line 8)
8static GLOBAL: ModAlloc = ModAlloc::new();
More examples
Hide additional examples
examples/bench_overhead.rs (line 20)
20static GLOBAL: ModAlloc = ModAlloc::new();
Source

pub fn snapshot(&self) -> AllocStats

Snapshot the current counter values.

Each counter is read independently with Relaxed ordering; the resulting AllocStats is a coherent best-effort view but does not represent a single atomic moment in time. For scoped measurement, prefer Profiler.

§Example
use mod_alloc::ModAlloc;

let alloc = ModAlloc::new();
let stats = alloc.snapshot();
assert_eq!(stats.alloc_count, 0);
Examples found in repository?
examples/bench_overhead.rs (line 40)
26fn main() {
27    for _ in 0..WARMUP {
28        let v: Vec<u8> = Vec::with_capacity(SIZE);
29        std::hint::black_box(&v);
30    }
31
32    GLOBAL.reset();
33    let start = Instant::now();
34    for _ in 0..N {
35        let v: Vec<u8> = Vec::with_capacity(SIZE);
36        std::hint::black_box(&v);
37    }
38    let elapsed = start.elapsed();
39
40    let snap = GLOBAL.snapshot();
41    let per_cycle_ns = elapsed.as_nanos() as f64 / N as f64;
42
43    println!("bench_overhead:");
44    println!("  iterations:           {N}");
45    println!("  allocation size:      {SIZE} bytes");
46    println!("  elapsed:              {elapsed:?}");
47    println!("  per alloc+dealloc:    {per_cycle_ns:.1} ns");
48    println!();
49    println!("counter snapshot after run:");
50    println!("  alloc_count:   {}", snap.alloc_count);
51    println!("  total_bytes:   {}", snap.total_bytes);
52    println!("  current_bytes: {}", snap.current_bytes);
53    println!("  peak_bytes:    {}", snap.peak_bytes);
54}
More examples
Hide additional examples
examples/basic.rs (line 30)
10fn main() {
11    let p = Profiler::start();
12
13    let v: Vec<u64> = (0..1_000).collect();
14    let sum: u64 = v.iter().sum();
15    drop(v);
16
17    let mut owned: Vec<String> = Vec::with_capacity(100);
18    for i in 0..100 {
19        owned.push(format!("item-{i}"));
20    }
21    drop(owned);
22
23    let delta = p.stop();
24    println!("Profiler delta (alloc/total/current = delta; peak = absolute):");
25    println!("  alloc_count:   {}", delta.alloc_count);
26    println!("  total_bytes:   {}", delta.total_bytes);
27    println!("  current_bytes: {}", delta.current_bytes);
28    println!("  peak_bytes:    {}", delta.peak_bytes);
29
30    let snap = GLOBAL.snapshot();
31    println!();
32    println!("Process-wide snapshot:");
33    println!("  alloc_count:   {}", snap.alloc_count);
34    println!("  total_bytes:   {}", snap.total_bytes);
35    println!("  current_bytes: {}", snap.current_bytes);
36    println!("  peak_bytes:    {}", snap.peak_bytes);
37
38    println!();
39    println!("(workload checksum: {sum})");
40}
Source

pub fn reset(&self)

Reset all counters to zero.

Intended for use at the start of a profile run, before any outstanding allocations exist. Calling reset while allocations are live can cause current_bytes to wrap on subsequent deallocations; the other counters are unaffected.

§Example
use mod_alloc::ModAlloc;

let alloc = ModAlloc::new();
alloc.reset();
let stats = alloc.snapshot();
assert_eq!(stats.alloc_count, 0);
Examples found in repository?
examples/bench_overhead.rs (line 32)
26fn main() {
27    for _ in 0..WARMUP {
28        let v: Vec<u8> = Vec::with_capacity(SIZE);
29        std::hint::black_box(&v);
30    }
31
32    GLOBAL.reset();
33    let start = Instant::now();
34    for _ in 0..N {
35        let v: Vec<u8> = Vec::with_capacity(SIZE);
36        std::hint::black_box(&v);
37    }
38    let elapsed = start.elapsed();
39
40    let snap = GLOBAL.snapshot();
41    let per_cycle_ns = elapsed.as_nanos() as f64 / N as f64;
42
43    println!("bench_overhead:");
44    println!("  iterations:           {N}");
45    println!("  allocation size:      {SIZE} bytes");
46    println!("  elapsed:              {elapsed:?}");
47    println!("  per alloc+dealloc:    {per_cycle_ns:.1} ns");
48    println!();
49    println!("counter snapshot after run:");
50    println!("  alloc_count:   {}", snap.alloc_count);
51    println!("  total_bytes:   {}", snap.total_bytes);
52    println!("  current_bytes: {}", snap.current_bytes);
53    println!("  peak_bytes:    {}", snap.peak_bytes);
54}

Trait Implementations§

Source§

impl Default for ModAlloc

Source§

fn default() -> Self

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

impl GlobalAlloc for ModAlloc

Source§

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

Allocates 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 dealloc(&self, ptr: *mut u8, layout: Layout)

Deallocates the block of memory at the given ptr pointer with the given layout. Read more
Source§

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

Shrinks or grows a block of memory to the given new_size in bytes. The block is described by the given ptr pointer and layout. Read more

Auto Trait Implementations§

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>,

Source§

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>,

Source§

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.