#counter #allocation #analysis

no-std alloc_counter

统计分配、重新分配和释放。基于表达式或函数允许、拒绝或禁止分配。

5个版本

0.0.4 2019年11月29日
0.0.3 2019年11月3日
0.0.2 2019年2月6日
0.0.1 2019年2月6日
0.0.0 2019年2月6日

#146调试

Download history 260/week @ 2024-03-11 308/week @ 2024-03-18 201/week @ 2024-03-25 313/week @ 2024-04-01 176/week @ 2024-04-08 296/week @ 2024-04-15 192/week @ 2024-04-22 279/week @ 2024-04-29 224/week @ 2024-05-06 255/week @ 2024-05-13 302/week @ 2024-05-20 265/week @ 2024-05-27 199/week @ 2024-06-03 285/week @ 2024-06-10 155/week @ 2024-06-17 231/week @ 2024-06-24

877 每月下载量
用于 17 个crate(16个直接使用)

MIT/Apache

16KB
170

alloc_counter

分配计数器

快速且简单的分配分析工具的重设计。

特性

  • 尽管预期使用#[no_std],但由于缺少可移植的thread_local实现,目前不支持。这可以通过使用全局原子的功能标志“修复”,前提是程序是单线程的。

  • 使用count_alloc分别统计分配、重新分配和释放。

  • 使用allow_allocdeny_allocforbid_alloc允许、拒绝和禁止使用全局分配器。

  • 使用函数属性#[no_alloc]拒绝和#[no_alloc(forbid)]禁止使用全局分配器。

  • #[count_alloc] 函数属性用于将计数打印到 stderr。或者使用 #[count_alloc(func = "my_function")],其中 my_function 接受三个 usize 的三元组并返回 () 来重定向输出。

限制和已知问题

  • 方法必须要么接受 self 的引用,要么 Self 必须是一个 Copy 类型。

  • 普通和异步函数必须分别处理。使用 count_alloc 对函数进行计数,使用 count_alloc_future 对未来进行计数。

用法

AllocCounter<A> 包装分配器 A 以单独计算对 allocreallocdealloc 的调用次数。

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 可能更喜欢继承其系统的分配器。

use alloc_counter::AllocCounterSystem;

#[global_allocator]
static A: AllocCounterSystem = AllocCounterSystem;

要计算表达式的分配,请使用 count_alloc

# use alloc_counter::{count_alloc, AllocCounterSystem};
# #[global_allocator]
# static A: AllocCounterSystem = AllocCounterSystem;
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));

要拒绝表达式的分配,请使用 deny_alloc

# use alloc_counter::{deny_alloc, AllocCounterSystem};
# #[global_allocator]
# static A: AllocCounterSystem = AllocCounterSystem;
fn foo(b: Box<i32>) {
    // dropping causes a panic
    deny_alloc(|| drop(b))
}
foo(Box::new(0));

类似于 Rust 的 lint,你仍然可以在 deny 块内允许分配。

# use alloc_counter::{allow_alloc, deny_alloc, AllocCounterSystem};
# #[global_allocator]
# static A: AllocCounterSystem = AllocCounterSystem;
fn foo(b: Box<i32>) {
    deny_alloc(|| allow_alloc(|| drop(b)))
}
foo(Box::new(0));

禁止分配强制引发 panic,即使使用了 allow_alloc

# use alloc_counter::{allow_alloc, forbid_alloc, AllocCounterSystem};
# #[global_allocator]
# static A: AllocCounterSystem = AllocCounterSystem;
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));

为了增加便利,你可以在函数上使用 #[no_alloc] 属性,包括具有 self 绑定的方法。 #[no_alloc] 展开为调用 deny_alloc 并强制将参数移动到检查块中。 #[no_alloc(forbid)] 调用 forbid_alloc

# #[cfg(not(feature = "macros"))]
# panic!("macros feature disabled");
# #[cfg(feature = "macros")] {
# use alloc_counter::{allow_alloc, no_alloc, AllocCounterSystem};
# #[global_allocator]
# static A: AllocCounterSystem = AllocCounterSystem;
#[no_alloc(forbid)]
fn foo(b: Box<i32>) {
    allow_alloc(|| drop(b))
}
foo(Box::new(0));
# }

许可证:MIT OR Apache-2.0

依赖项

~220KB