15 releases

0.2.12 Dec 17, 2022
0.2.11 Dec 17, 2022
0.1.2 Dec 13, 2022

#206 in Profiling

40 downloads per month

MIT license

11KB
141 lines

A set of macros to function profiling

Contains some convenient macros to analyze function execution, like count to know how many times a function was called, trace to log when entering/exiting from a function and what are its arguments, and cache for pure functions cache.

Features

Feature Description Additional dependencies
count Makes available a macro count! to get how many times a function was called None
trace Prints when entering/exiting in a tagged function and its arguments None
cache Implements memoization for a tagged function once_cell and hashbrown
time Prints the elapsed time inside a function None
depth Add tabulation formatting according to the "function depth" None
visible Changes the cache storage and counter visibility None

Each feature can be forbided, forced or setted to default (which is setted using features) in the attribute declaration. E.g:

// `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!()
}

Type dependencies

When enabled in a function, cache requires that all parameters implement the Debug trait and Clone for the return type.

Wait... Why Debug for parameters and not Clone?

Consider these scenarios:

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

It's hard to create cache storage with generic keys and lifetimes, once it can't be parsed in an equivalent format for a global RwLock.

Furthermore, it allows some optimizations for liked types:

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

I don't want trace/count/cache in my release builds. How do I disable it?

There isn't yet a good way to enable/disable specific features in different profiles. You'll need to set default-features to false and define which features you want. E.g:

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

Another way to do it, is using a setting a default feature.

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

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

And when compiling with a profile relase, use --no-default-features

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

How do I enable/disable trace/count/cache for just one function?

Set trace/count/cache as force/forbid

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

Macros

There are macros to manage implementation variables:

Macro Outter feature Description
count count Return an usize containing how many times an function was called
get_counter count Return the std::sync::AtomicUsize counter for the respective function
reset_count count Set the function counting to 0
get_cache cache Return the once_cell::Lazy<std::sync::RwLock<hashbrown::HashMap<String, T>>> cache storage, where T is the function's return type

All of these macros requires an argument containing the function's global path. E.g:

#[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)

Will macro calls break when the outter feature be disabled?

No. The counting or cache will just not be updated.

Dependencies

~3.5MB
~65K SLoC