Skip to content

Commit

Permalink
attributes: skip async spans if level disabled (#1607)
Browse files Browse the repository at this point in the history
## Motivation

In #1600, the `instrument` code generation was changed to avoid ever
constructing a `Span` struct if the level is explicitly disabled.
However, for `async` functions, `#[instrument]` will currently still
create the span, but simply skips constructing an `Instrument` future if
the level is disabled.

## Solution

This branch changes the `#[instrument]` code generation for async blocks
to totally skip constructing the span if the level is disabled. I also
simplfied the code generation a bit by combining the shared code between
the `err` and non-`err` cases, reducing code duplication a bit.

Signed-off-by: Eliza Weisman <[email protected]>
  • Loading branch information
hawkw committed Oct 1, 2021
1 parent ca3a51c commit c9db496
Showing 1 changed file with 47 additions and 61 deletions.
108 changes: 47 additions & 61 deletions tracing-attributes/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -711,12 +711,9 @@ fn gen_block(
// enter the span and then perform the rest of the body.
// If `err` is in args, instrument any resulting `Err`s.
if async_context {
if err {
let mk_fut = if err {
quote_spanned!(block.span()=>
let __tracing_attr_span = #span;
// See comment on the default case at the end of this function
// for why we do this a bit roundabout.
let fut = async move {
async move {
match async move { #block }.await {
#[allow(clippy::unit_arg)]
Ok(x) => Ok(x),
Expand All @@ -725,46 +722,52 @@ fn gen_block(
Err(e)
}
}
};
if tracing::level_enabled!(#level) {
tracing::Instrument::instrument(
fut,
__tracing_attr_span
)
.await
} else {
fut.await
}
)
} else {
quote_spanned!(block.span()=>
let __tracing_attr_span = #span;
// See comment on the default case at the end of this function
// for why we do this a bit roundabout.
let fut = async move { #block };
if tracing::level_enabled!(#level) {
tracing::Instrument::instrument(
fut,
__tracing_attr_span
)
.await
} else {
fut.await
}
async move { #block }
)
}
} else if err {
quote_spanned!(block.span()=>
// See comment on the default case at the end of this function
// for why we do this a bit roundabout.
let __tracing_attr_span;
let __tracing_attr_guard;
};

return quote_spanned!(block.span()=>
if tracing::level_enabled!(#level) {
__tracing_attr_span = #span;
__tracing_attr_guard = __tracing_attr_span.enter();
let __tracing_attr_span = #span;
tracing::Instrument::instrument(
#mk_fut,
__tracing_attr_span
)
.await
} else {
#mk_fut.await
}
// pacify clippy::suspicious_else_formatting
let _ = ();
);
}

let span = quote_spanned!(block.span()=>
// These variables are left uninitialized and initialized only
// if the tracing level is statically enabled at this point.
// While the tracing level is also checked at span creation
// time, that will still create a dummy span, and a dummy guard
// and drop the dummy guard later. By lazily initializing these
// variables, Rust will generate a drop flag for them and thus
// only drop the guard if it was created. This creates code that
// is very straightforward for LLVM to optimize out if the tracing
// level is statically disabled, while not causing any performance
// regression in case the level is enabled.
let __tracing_attr_span;
let __tracing_attr_guard;
if tracing::level_enabled!(#level) {
__tracing_attr_span = #span;
__tracing_attr_guard = __tracing_attr_span.enter();
}
// pacify clippy::suspicious_else_formatting
let _ = ();
);

if err {
return quote_spanned!(block.span()=>
#span
#[allow(clippy::redundant_closure_call)]
match (move || #block)() {
#[allow(clippy::unit_arg)]
Expand All @@ -774,30 +777,13 @@ fn gen_block(
Err(e)
}
}
)
} else {
quote_spanned!(block.span()=>
// These variables are left uninitialized and initialized only
// if the tracing level is statically enabled at this point.
// While the tracing level is also checked at span creation
// time, that will still create a dummy span, and a dummy guard
// and drop the dummy guard later. By lazily initializing these
// variables, Rust will generate a drop flag for them and thus
// only drop the guard if it was created. This creates code that
// is very straightforward for LLVM to optimize out if the tracing
// level is statically disabled, while not causing any performance
// regression in case the level is enabled.
let __tracing_attr_span;
let __tracing_attr_guard;
if tracing::level_enabled!(#level) {
__tracing_attr_span = #span;
__tracing_attr_guard = __tracing_attr_span.enter();
}
// pacify clippy::suspicious_else_formatting
let _ = ();
#block
)
);
}

quote_spanned!(block.span()=>
#span
#block
)
}

#[derive(Default, Debug)]
Expand Down

0 comments on commit c9db496

Please sign in to comment.