15 个版本

0.2.12 2022 年 12 月 17 日
0.2.11 2022 年 12 月 17 日
0.1.2 2022 年 12 月 13 日

#142 in 性能分析

40 次每月下载

MIT 许可证

11KB
141

一套用于功能分析的宏

包含一些方便的宏来分析函数执行,如 count 来了解函数被调用的次数,trace 来记录函数的进入/退出及其参数,以及用于纯函数缓存的 cache

特性

特性 描述 其他依赖
count 提供 count! 宏,以获取函数被调用的次数
trace 在标记函数的进入/退出时打印并显示其参数
cache 为标记函数实现记忆化 once_cellhashbrown
time 在函数内打印经过的时间
depth 根据“函数深度”添加缩进格式化
visible 改变缓存存储和计数器的可见性

可以在属性声明中禁止、强制或设置每个特性的默认值(默认值是通过特性设置的)。例如

// `cache` and `visible` will not be implemented
// `count` will obligatory be implemented
// `time`/`depth` will be implemented if the feature `time`/`depth` is enable
#[moneta_fn::moneta(cache = "forbid", visible = "forbid", count = "force", time = "default")]
fn foo(a: u8) -> u8 {
    unimplemented!()
}

类型依赖

在函数中启用时,cache 需要所有参数实现 Debug 特性和返回类型的 Clone

等等... 为什么参数需要 Debug,而不是 Clone 呢?

考虑以下场景

#[moneta_fn::moneta]
fn foo<'a, T>(lhs: &'a T, rhs: &'a T) -> T {
    unimplemented!()
}

很难创建具有泛型键和生命周期的缓存存储,一旦它不能被解析为全局 RwLock 的等效格式。

此外,它还允许对关联类型进行一些优化

#[moneta_fn::moneta]
fn foo<T: AsRef<str> + Debug>(lhs: T, rhs: T) -> T {
    unimplemented!()
}

我不想在发布构建中使用 trace/count/cache。我该如何禁用它?

目前还没有一种很好的方法来在不同的配置文件中启用/禁用特定特性。您需要将 default-features 设置为 false 并定义您想要的特性。例如

[dependencies]
moneta_fn = { version = "*", default-features = false, features = ["cache", "count", "time"] }

另一种方法是设置默认特性。

[dependencies]
moneta_fn = { version = "*", default-features = false, features = ["cache", "count", "time"] }

[features]
default = ["debug_mode"]
debug_mode = ["moneta_fn/trace"]

当使用配置文件发布编译时,使用 --no-default-features

cargo build --release --no-default-features

我该如何只为一个函数启用/禁用 trace/count/cache

trace/count/cache 设置为 force/forbid

#[moneta_fn::moneta(cache = "forbid")] // Will not update cache storage
fn foo(a: u8) -> u8 {
    unimplemented!()
}

宏定义

存在宏来管理实现变量

宏定义 外部特性 描述
count count 返回一个包含函数被调用次数的 usize
get_counter count 返回对应函数的 std::sync::AtomicUsize 计数器
reset_count count 将函数计数设置为 0
get_cache cache 返回包含函数返回类型的 once_cell::Lazy<std::sync::RwLock<hashbrown::HashMap<String, T>>> 缓存存储,其中 T 是函数的返回类型

所有这些宏都需要一个包含函数全局路径的参数。例如

#[moneta_fn::moneta]
fn foo() {
    unimplemented!()
}

pub mod bar {
    #[moneta_fn:moneta]
    pub fn baz() {
        unimplemented!()
    }
}

assert!(get_cache(foo).read().unwrap().is_empty())
assert_eq!(count!(bar::baz), 0)

当外部特性被禁用时,宏调用会中断吗?

不会。计数或缓存将不会更新。

依赖项

~3.5MB
~64K SLoC