Skip to content

Commit a3abbbd

Browse files
committed
expose an eager macro that skips the branch. make the lazy macro branch cold
1 parent 0093188 commit a3abbbd

File tree

7 files changed

+130
-36
lines changed

7 files changed

+130
-36
lines changed

probe-test-attr/src/main.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,7 @@ fn main() {
9696
let buffer = [2; 4];
9797
loop {
9898
test::start_work!(|| arg.x);
99+
test::start_work_eager!(|| arg.x);
99100
std::thread::sleep(std::time::Duration::from_secs(1));
100101
arg.x = arg.x.wrapping_add(1);
101102
test::stop_work!(|| { (format!("the probe has fired {}", arg.x), &arg) });

usdt-impl/src/common.rs

Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -205,30 +205,47 @@ pub(crate) fn build_probe_macro(
205205
config: &crate::CompileProvidersConfig,
206206
probe_name: &str,
207207
types: &[DataType],
208-
impl_block: TokenStream,
208+
eager: TokenStream,
209+
lazy: TokenStream,
209210
) -> TokenStream {
210211
let module = config.module_ident();
211-
let macro_name = config.probe_ident(probe_name);
212+
let lazy_macro_name = config.probe_ident(probe_name);
213+
let eager_macro_name = config.probe_ident_eager(probe_name);
214+
212215
let no_args_match = if types.is_empty() {
213-
quote! { () => { crate::#module::#macro_name!(|| ()) }; }
216+
quote! { () => { crate::#module::#eager_macro_name!(|| ()) }; }
214217
} else {
215218
quote! {}
216219
};
217220
quote! {
218221
#[allow(unused_macros)]
219-
macro_rules! #macro_name {
222+
macro_rules! #lazy_macro_name {
223+
#no_args_match
224+
($tree:tt) => {
225+
compile_error!("USDT probe macros should be invoked with a closure returning the arguments");
226+
};
227+
($args_lambda:expr) => {
228+
{
229+
#lazy
230+
}
231+
};
232+
}
233+
#[allow(unused_imports)]
234+
pub(crate) use #lazy_macro_name;
235+
#[allow(unused_macros)]
236+
macro_rules! #eager_macro_name {
220237
#no_args_match
221238
($tree:tt) => {
222239
compile_error!("USDT probe macros should be invoked with a closure returning the arguments");
223240
};
224241
($args_lambda:expr) => {
225242
{
226-
#impl_block
243+
#eager
227244
}
228245
};
229246
}
230247
#[allow(unused_imports)]
231-
pub(crate) use #macro_name;
248+
pub(crate) use #eager_macro_name;
232249
}
233250
}
234251

usdt-impl/src/lib.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,11 @@ impl CompileProvidersConfig {
100100
quote::format_ident!("{}", self.format_probe(probe_name))
101101
}
102102

103+
/// Return the formatted name of the probe as an identifier.
104+
pub fn probe_ident_eager(&self, probe_name: &str) -> proc_macro2::Ident {
105+
quote::format_ident!("{}_eager", self.format_probe(probe_name))
106+
}
107+
103108
/// Return the formatted module name as an identifier.
104109
pub fn module_ident(&self) -> proc_macro2::Ident {
105110
let name = self.module.as_ref().unwrap_or_else(|| {

usdt-impl/src/linker.rs

Lines changed: 34 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -180,7 +180,7 @@ fn compile_probe(
180180
#[cfg(not(any(target_arch = "x86_64", target_arch = "aarch64")))]
181181
compile_error!("USDT only supports x86_64 and AArch64 architectures");
182182

183-
let impl_block = quote! {
183+
let extern_block = quote! {
184184
unsafe extern "C" {
185185
#[allow(unused)]
186186
#[link_name = #stability]
@@ -198,26 +198,43 @@ fn compile_probe(
198198
#[link_name = #probe]
199199
fn #extern_probe_fn(#(#ffi_param_list,)*);
200200
}
201+
};
202+
203+
let call = quote! {
201204
unsafe {
202-
if #is_enabled_fn() != 0 {
203-
#arg_lambda
204-
#type_check_fn
205-
#unpacked_args
206-
::std::arch::asm!(
207-
".reference {typedefs}",
208-
#call_instruction,
209-
".reference {stability}",
210-
typedefs = sym #typedef_fn,
211-
extern_probe_fn = sym #extern_probe_fn,
212-
stability = sym #stability_fn,
213-
#in_regs
214-
options(nomem, nostack, preserves_flags)
215-
);
216-
}
205+
::std::arch::asm!(
206+
".reference {typedefs}",
207+
#call_instruction,
208+
".reference {stability}",
209+
typedefs = sym #typedef_fn,
210+
extern_probe_fn = sym #extern_probe_fn,
211+
stability = sym #stability_fn,
212+
#in_regs
213+
options(nomem, nostack, preserves_flags)
214+
);
215+
}
216+
};
217+
218+
let eager = quote! {
219+
#extern_block
220+
#arg_lambda
221+
#type_check_fn
222+
#unpacked_args
223+
#call
224+
};
225+
226+
let lazy = quote! {
227+
#extern_block
228+
if unsafe { #is_enabled_fn() } != 0 {
229+
::usdt::cold();
230+
#arg_lambda
231+
#type_check_fn
232+
#unpacked_args
233+
#call
217234
}
218235
};
219236

220-
common::build_probe_macro(config, probe_name, types, impl_block)
237+
common::build_probe_macro(config, probe_name, types, eager, lazy)
221238
}
222239

223240
#[derive(Debug, Default, Clone)]

usdt-impl/src/no-linker.rs

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,8 @@ fn compile_probe(
8989
&probe.types,
9090
);
9191

92-
let impl_block = quote! {
92+
// I don't know whether it's safe to remove the is_enabled check here.
93+
let eager = quote! {
9394
{
9495
let mut is_enabled: u64;
9596
unsafe {
@@ -116,7 +117,37 @@ fn compile_probe(
116117
}
117118
}
118119
};
119-
common::build_probe_macro(config, &probe.name, &probe.types, impl_block)
120+
121+
let lazy = quote! {
122+
{
123+
let mut is_enabled: u64;
124+
unsafe {
125+
::std::arch::asm!(
126+
"990: clr rax",
127+
#is_enabled_rec,
128+
out("rax") is_enabled,
129+
options(nomem, nostack)
130+
);
131+
}
132+
133+
if is_enabled != 0 {
134+
::usdt::cold();
135+
#arg_lambda
136+
#type_check_fn
137+
#unpacked_args
138+
unsafe {
139+
::std::arch::asm!(
140+
"990: nop",
141+
#probe_rec,
142+
#in_regs
143+
options(nomem, nostack, preserves_flags)
144+
);
145+
}
146+
}
147+
}
148+
};
149+
150+
common::build_probe_macro(config, &probe.name, &probe.types, eager, lazy)
120151
}
121152

122153
fn extract_probe_records_from_section() -> Result<Section, crate::Error> {

usdt-impl/src/stapsdt.rs

Lines changed: 30 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -202,7 +202,8 @@ fn compile_probe(
202202
);
203203

204204
let sema_name = format_ident!("__usdt_sema_{}_{}", provider.name, probe.name);
205-
let impl_block = quote! {
205+
206+
let extern_block = quote! {
206207
unsafe extern "C" {
207208
// Note: C libraries use a struct containing an unsigned short
208209
// for the semaphore counter. Using just a u16 here directly
@@ -211,28 +212,46 @@ fn compile_probe(
211212
// knowledge.
212213
static #sema_name: u16;
213214
}
215+
};
216+
217+
let call = quote! {
218+
#[allow(named_asm_labels)]
219+
unsafe {
220+
::std::arch::asm!(
221+
"990: nop",
222+
#probe_rec,
223+
#in_regs
224+
options(nomem, nostack, preserves_flags)
225+
);
226+
}
227+
};
228+
229+
let eager = quote! {
230+
#extern_block
231+
#arg_lambda
232+
#type_check_fn
233+
#unpacked_args
234+
#call
235+
};
236+
237+
let lazy =quote! {
238+
#extern_block
214239

215240
let is_enabled: u16;
216241
unsafe {
217242
is_enabled = (&raw const #sema_name).read_volatile();
218243
}
219244

220245
if is_enabled != 0 {
246+
::usdt::cold();
221247
#arg_lambda
222248
#type_check_fn
223249
#unpacked_args
224-
#[allow(named_asm_labels)]
225-
unsafe {
226-
::std::arch::asm!(
227-
"990: nop",
228-
#probe_rec,
229-
#in_regs
230-
options(nomem, nostack, preserves_flags)
231-
);
232-
}
250+
#call
233251
}
234252
};
235-
common::build_probe_macro(config, &probe.name, &probe.types, impl_block)
253+
254+
common::build_probe_macro(config, &probe.name, &probe.types, eager, lazy)
236255
}
237256

238257
pub fn register_probes() -> Result<(), crate::Error> {

usdt/src/lib.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -299,6 +299,10 @@ pub use usdt_impl::{to_json, SerializeString};
299299
pub use usdt_impl::{Error, UniqueId};
300300
pub use usdt_macro::dtrace_provider;
301301

302+
#[doc(hidden)]
303+
#[cold]
304+
pub fn cold() {}
305+
302306
/// A simple struct used to build DTrace probes into Rust code in a build.rs script.
303307
#[derive(Debug)]
304308
pub struct Builder {

0 commit comments

Comments
 (0)