light_profiler_macro/
lib.rs1use proc_macro::TokenStream;
2
3#[proc_macro_attribute]
4pub fn profile(_attr: TokenStream, item: TokenStream) -> TokenStream {
5 #[cfg(not(feature = "profile-program"))]
7 {
8 return item;
9 }
10
11 #[cfg(feature = "profile-program")]
12 {
13 use quote::quote;
14 use syn::{parse_macro_input, ItemFn, ReturnType};
15 let mut f = parse_macro_input!(item as ItemFn);
16 let original_body = f.block.clone();
17 let sig = f.sig.clone();
18 let ident = sig.ident.clone();
19 let fn_name_str = ident.to_string();
20 let returns_value = !matches!(sig.output, ReturnType::Default);
21
22 let program_id_width = 43;
25 let fn_name_len = fn_name_str.len();
26 let front_padding = " ".repeat(8); let back_padding = if fn_name_len < program_id_width {
28 " ".repeat(program_id_width - fn_name_len) } else {
30 " ".to_string() };
32
33 let profile_start = quote! {
35 #[cfg(all(target_os = "solana", feature = "profile-program"))]
36 {
37 extern "C" {
38 #[inline(always)]
39 fn sol_log_compute_units_start(id_addr: u64, id_len: u64, heap_value: u64, with_heap: u64, _arg5: u64);
40 }
41 const PROFILE_ID: &str = concat!(#fn_name_str, "\n", #front_padding, file!(), ":", line!(), #back_padding);
43
44 #[cfg(feature = "profile-heap")]
45 unsafe {
46 sol_log_compute_units_start(
47 PROFILE_ID.as_ptr() as u64,
48 PROFILE_ID.len() as u64,
49 ::light_heap::GLOBAL_ALLOCATOR.get_used_heap(),
50 1u64,
51 0
52 );
53 }
54
55 #[cfg(not(feature = "profile-heap"))]
56 unsafe {
57 sol_log_compute_units_start(
58 PROFILE_ID.as_ptr() as u64,
59 PROFILE_ID.len() as u64,
60 0u64,
61 0u64,
62 0
63 );
64 }
65 }
66 };
67
68 let profile_end = quote! {
69 #[cfg(all(target_os = "solana", feature = "profile-program"))]
70 {
71 extern "C" {
72 #[inline(always)]
73 fn sol_log_compute_units_end(id_addr: u64, id_len: u64, heap_value: u64, with_heap: u64, _arg5: u64);
74 }
75 const PROFILE_ID: &str = concat!(#fn_name_str, "\n", #front_padding, file!(), ":", line!(), #back_padding);
77 #[cfg(feature = "profile-heap")]
78 unsafe {
79 sol_log_compute_units_end(
80 PROFILE_ID.as_ptr() as u64,
81 PROFILE_ID.len() as u64,
82 ::light_heap::GLOBAL_ALLOCATOR.get_used_heap(),
83 1u64,
84 0
85 );
86 }
87
88 #[cfg(target_os = "solana")]
89 #[cfg(not(feature = "profile-heap"))]
90 unsafe {
91 sol_log_compute_units_end(
92 PROFILE_ID.as_ptr() as u64,
93 PROFILE_ID.len() as u64,
94 0u64,
95 0u64,
96 0
97 );
98 }
99 }
100 };
101
102 let original_stmts = &original_body.stmts;
104 let new_body = if returns_value {
105 quote! {
106 {
107 #profile_start
108 let __result = {
109 #(#original_stmts)*
110 };
111 #profile_end
112 __result
113 }
114 }
115 } else {
116 quote! {
117 {
118 #profile_start
119 #(#original_stmts)*
120 #profile_end
121 }
122 }
123 };
124
125 f.attrs.retain(|a| !a.path().is_ident("profile"));
127 #[cfg(feature = "inline")]
128 {
129 f.attrs.push(syn::parse_quote!(#[inline(always)]));
130 }
131 f.block = syn::parse2(new_body).unwrap();
132
133 TokenStream::from(quote! {
134 #f
135 })
136 }
137}