1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
use proc_macro::TokenStream;
#[proc_macro_attribute]
pub fn profile(_attr: TokenStream, item: TokenStream) -> TokenStream {
// If profile-program feature is not enabled, return the original function completely unchanged
#[cfg(not(feature = "profile-program"))]
{
return item;
}
#[cfg(feature = "profile-program")]
{
use quote::quote;
use syn::{parse_macro_input, ItemFn, ReturnType};
let mut f = parse_macro_input!(item as ItemFn);
let original_body = f.block.clone();
let sig = f.sig.clone();
let ident = sig.ident.clone();
let fn_name_str = ident.to_string();
let returns_value = !matches!(sig.output, ReturnType::Default);
// Add padding before function name to align with program ID position
// and padding after to align "consumed" with program's "consumed"
let program_id_width = 43;
let fn_name_len = fn_name_str.len();
let front_padding = " ".repeat(8); // Same as "Program " length to align start position
let back_padding = if fn_name_len < program_id_width {
" ".repeat(program_id_width - fn_name_len) // Add 1 extra space to fix alignment
} else {
" ".to_string() // minimum one space
};
// Create profiling start and end calls with feature flag and compile-time caller info
let profile_start = quote! {
#[cfg(all(target_os = "solana", feature = "profile-program"))]
{
extern "C" {
#[inline(always)]
fn sol_log_compute_units_start(id_addr: u64, id_len: u64, heap_value: u64, with_heap: u64, _arg5: u64);
}
// Dynamic padding calculated at compile time
const PROFILE_ID: &str = concat!(#fn_name_str, "\n", #front_padding, file!(), ":", line!(), #back_padding);
#[cfg(feature = "profile-heap")]
unsafe {
sol_log_compute_units_start(
PROFILE_ID.as_ptr() as u64,
PROFILE_ID.len() as u64,
::light_heap::GLOBAL_ALLOCATOR.get_used_heap(),
1u64,
0
);
}
#[cfg(not(feature = "profile-heap"))]
unsafe {
sol_log_compute_units_start(
PROFILE_ID.as_ptr() as u64,
PROFILE_ID.len() as u64,
0u64,
0u64,
0
);
}
}
};
let profile_end = quote! {
#[cfg(all(target_os = "solana", feature = "profile-program"))]
{
extern "C" {
#[inline(always)]
fn sol_log_compute_units_end(id_addr: u64, id_len: u64, heap_value: u64, with_heap: u64, _arg5: u64);
}
// Dynamic padding calculated at compile time
const PROFILE_ID: &str = concat!(#fn_name_str, "\n", #front_padding, file!(), ":", line!(), #back_padding);
#[cfg(feature = "profile-heap")]
unsafe {
sol_log_compute_units_end(
PROFILE_ID.as_ptr() as u64,
PROFILE_ID.len() as u64,
::light_heap::GLOBAL_ALLOCATOR.get_used_heap(),
1u64,
0
);
}
#[cfg(target_os = "solana")]
#[cfg(not(feature = "profile-heap"))]
unsafe {
sol_log_compute_units_end(
PROFILE_ID.as_ptr() as u64,
PROFILE_ID.len() as u64,
0u64,
0u64,
0
);
}
}
};
// Build the new function body by wrapping the original body with profiling calls
let original_stmts = &original_body.stmts;
let new_body = if returns_value {
quote! {
{
#profile_start
let __result = {
#(#original_stmts)*
};
#profile_end
__result
}
}
} else {
quote! {
{
#profile_start
#(#original_stmts)*
#profile_end
}
}
};
// Filter out the profile attribute, add inline(always), and replace the function body
f.attrs.retain(|a| !a.path().is_ident("profile"));
#[cfg(feature = "inline")]
{
f.attrs.push(syn::parse_quote!(#[inline(always)]));
}
f.block = syn::parse2(new_body).unwrap();
TokenStream::from(quote! {
#f
})
}
}