1use log::Record;
2use std::{
3 fmt::Display,
4 sync::atomic::{AtomicUsize, Ordering},
5};
6
7use crate::constants;
8
9static ID: AtomicUsize = AtomicUsize::new(0);
10
11pub fn profile_core<L, F, T>(label: L, location: &'static str, func: F, quiet: bool) -> T
12where
13 L: Display,
14 F: FnOnce() -> T,
15{
16 let id = ID.fetch_add(1, Ordering::SeqCst); log::logger().log(
18 &Record::builder()
19 .key_values(&[(constants::INCREMENT, ())])
20 .build(),
21 );
22 log::logger().log(
23 &Record::builder()
24 .level(log::Level::Info)
25 .key_values(&[
26 (constants::ID, id),
27 (constants::QUIET, if quiet { 1 } else { 0 }),
28 ])
29 .target(location)
30 .args(format_args!("{label}"))
31 .build(),
32 );
33
34 let now = std::time::Instant::now();
35
36 log::logger().log(
37 &Record::builder()
38 .key_values(&[(constants::INCREMENT, ())])
39 .build(),
40 );
41 let rv = func();
42 log::logger().log(
43 &Record::builder()
44 .key_values(&[(constants::DECREMENT, ())])
45 .build(),
46 );
47
48 let elapsed = now.elapsed().as_millis();
49 log::logger().log(
50 &Record::builder()
51 .key_values(&[
52 (constants::SET_TIME, ""),
53 (constants::TIME, &elapsed.to_string()),
54 (constants::ID, &id.to_string()),
55 ])
56 .build(),
57 );
58 log::logger().log(
59 &Record::builder()
60 .key_values(&[(constants::DECREMENT, ())])
61 .build(),
62 );
63 rv
64}
65
66#[macro_export]
75macro_rules! profile {
76 ($label:expr, $func:expr) => {
77 tree_logger::profile::profile_core($label, file!(), $func, false)
78 };
79}
80
81#[macro_export]
82macro_rules! profile_quiet {
83 ($label:literal, $func:expr) => {
84 tree_logger::profile::profile_core($label, file!(), $func, true)
85 };
86}