#analysis #allocation #counter

no-std alloc_counter

Count allocations, reallocations, deallocations. Allow, deny, or forbid allocations on an expression or function basis.

5 releases

0.0.4 Nov 29, 2019
0.0.3 Nov 3, 2019
0.0.2 Feb 6, 2019
0.0.1 Feb 6, 2019
0.0.0 Feb 6, 2019

#145 in Debugging

Download history 1128/week @ 2023-06-11 1061/week @ 2023-06-18 703/week @ 2023-06-25 304/week @ 2023-07-02 218/week @ 2023-07-09 255/week @ 2023-07-16 217/week @ 2023-07-23 227/week @ 2023-07-30 361/week @ 2023-08-06 345/week @ 2023-08-13 377/week @ 2023-08-20 234/week @ 2023-08-27 304/week @ 2023-09-03 323/week @ 2023-09-10 346/week @ 2023-09-17 237/week @ 2023-09-24

1,223 downloads per month
Used in 16 crates (15 directly)

MIT/Apache

16KB
170 lines

alloc_counter

Alloc counters

A redesign of the Quick and Dirty Allocation Profiling Tool.

Features

  • Although #[no_std] is intended, it isn't currently supported due to the lack of portable thread_local implementation. This may be "fixed" with a feature flag to use a global atomic under the contract that the program is single threaded.

  • Count allocations, reallocations and deallocations individually with count_alloc.

  • Allow, deny, and forbid use of the global allocator with allow_alloc, deny_alloc and forbid_alloc.

  • #[no_alloc] function attribute to deny and #[no_alloc(forbid)] to forbid use of the global allocator.

  • #[count_alloc] function attribute to print the counts to stderr. Alternatively use #[count_alloc(func = "my_function")] where my_function accepts a triple of usizes and returns () to redirect the output.

Limitations and known issues

  • Methods must either take a reference to self or Self must be a Copy type.

  • Ordinary and async functions must be treated differently. Use count_alloc for functions and count_alloc_future for futures.

Usage

An AllocCounter<A> wraps an allocator A to individually count the number of calls to alloc, realloc, and dealloc.

use alloc_counter::AllocCounter;

type MyAllocator = std::alloc::System;
const MyAllocator: MyAllocator = std::alloc::System;

#[global_allocator]
static A: AllocCounter<MyAllocator> = AllocCounter(MyAllocator);

Std-users may prefer to inherit their system's allocator.

use alloc_counter::AllocCounterSystem;

#[global_allocator]
static A: AllocCounterSystem = AllocCounterSystem;

To count the allocations of an expression, use count_alloc.

let (counts, v) = count_alloc(|| {
    // no alloc
    let mut v = Vec::new();
    // alloc
    v.push(0);
    // realloc
    v.push(1);
    // return the vector without deallocating
    v
});
assert_eq!(counts, (1, 1, 0));

To deny allocations for an expression use deny_alloc.

fn foo(b: Box<i32>) {
    // dropping causes a panic
    deny_alloc(|| drop(b))
}
foo(Box::new(0));

Similar to Rust's lints, you can still allow allocation inside a deny block.

fn foo(b: Box<i32>) {
    deny_alloc(|| allow_alloc(|| drop(b)))
}
foo(Box::new(0));

Forbidding allocations forces a panic even when allow_alloc is used.

fn foo(b: Box<i32>) {
    // panics because of outer `forbid`, even though drop happens in an allow block
    forbid_alloc(|| allow_alloc(|| drop(b)))
}
foo(Box::new(0));

For added sugar you may use the #[no_alloc] attribute on functions, including methods with self-binds. #[no_alloc] expands to calling deny_alloc and forcefully moves the parameters into the checked block. #[no_alloc(forbid)] calls forbid_alloc.

#[no_alloc(forbid)]
fn foo(b: Box<i32>) {
    allow_alloc(|| drop(b))
}
foo(Box::new(0));

License: MIT OR Apache-2.0

Dependencies

~190KB