Skip to content

Commit 42951d1

Browse files
Lazily evaluate debug info (#4269)
Internally, Kani uses the `call_with_panic_debug_info()` function to call closures with a string that explains what they're trying to do, allowing better error messages if they internally panics. However, this function is currently called for every harness we codegen and has to pretty format the harness' function instance--something that calls into rustc internals and takes a non-negligible amount of time. We should instead accept a closure that can generate debug info, but only when (and if) it's needed. ### Results Based on initial flamegraphing, the formatting passed to `call_with_panic_debug_info()` went from taking 2.3% of codegen on `s2n-codec` to not being called a single time (since there are no compiler errors in a typical execution). This change made a solid **4.6% reduction in the end to end compile time of the standard library** (at std commit [177d0fd](model-checking/verify-rust-std@177d0fd); assuming #4257, #4259 & #4268 are already merged into Kani). By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 and MIT licenses.
1 parent 5998658 commit 42951d1

File tree

2 files changed

+25
-15
lines changed

2 files changed

+25
-15
lines changed

kani-compiler/src/codegen_cprover_gotoc/compiler_interface.rs

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -151,14 +151,14 @@ impl GotocCodegenBackend {
151151
MonoItem::Fn(instance) => {
152152
gcx.call_with_panic_debug_info(
153153
|ctx| ctx.declare_function(instance),
154-
format!("declare_function: {}", instance.name()),
154+
move || format!("declare_function: {}", instance.name()),
155155
instance.def,
156156
);
157157
}
158158
MonoItem::Static(def) => {
159159
gcx.call_with_panic_debug_info(
160160
|ctx| ctx.declare_static(def),
161-
format!("declare_static: {}", def.name()),
161+
move || format!("declare_static: {}", def.name()),
162162
def,
163163
);
164164
}
@@ -172,18 +172,20 @@ impl GotocCodegenBackend {
172172
MonoItem::Fn(instance) => {
173173
gcx.call_with_panic_debug_info(
174174
|ctx| ctx.codegen_function(instance),
175-
format!(
176-
"codegen_function: {}\n{}",
177-
instance.name(),
178-
instance.mangled_name()
179-
),
175+
move || {
176+
format!(
177+
"codegen_function: {}\n{}",
178+
instance.name(),
179+
instance.mangled_name()
180+
)
181+
},
180182
instance.def,
181183
);
182184
}
183185
MonoItem::Static(def) => {
184186
gcx.call_with_panic_debug_info(
185187
|ctx| ctx.codegen_static(def),
186-
format!("codegen_static: {}", def.name()),
188+
move || format!("codegen_static: {}", def.name()),
187189
def,
188190
);
189191
}

kani-compiler/src/codegen_cprover_gotoc/utils/debug.rs

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,8 @@ use tracing::debug;
1616
// Use a thread-local global variable to track the current codegen item for debugging.
1717
// If Kani panics during codegen, we can grab this item to include the problematic
1818
// codegen item in the panic trace.
19-
thread_local!(static CURRENT_CODEGEN_ITEM: RefCell<(Option<String>, Option<Location>)> = const { RefCell::new((None, None)) });
19+
type FindCurrentItemFn = Box<dyn Fn() -> String>;
20+
thread_local!(static CURRENT_CODEGEN_ITEM: RefCell<(Option<FindCurrentItemFn>, Option<Location>)> = const { RefCell::new((None, None)) });
2021

2122
pub fn init() {
2223
// Install panic hook
@@ -36,9 +37,9 @@ static DEFAULT_HOOK: LazyLock<Box<dyn Fn(&panic::PanicHookInfo<'_>) + Sync + Sen
3637

3738
// Print the current function if available
3839
CURRENT_CODEGEN_ITEM.with(|cell| {
39-
let t = cell.borrow().clone();
40-
if let Some(current_item) = t.0 {
41-
eprintln!("[Kani] current codegen item: {current_item}");
40+
let t = cell.borrow();
41+
if let Some(get_current_item) = &t.0 {
42+
eprintln!("[Kani] current codegen item: {}", get_current_item());
4243
} else {
4344
eprintln!("[Kani] no current codegen item.");
4445
}
@@ -55,14 +56,21 @@ static DEFAULT_HOOK: LazyLock<Box<dyn Fn(&panic::PanicHookInfo<'_>) + Sync + Sen
5556
impl<'tcx> GotocCtx<'tcx> {
5657
// Calls the closure while updating the tracked global variable marking the
5758
// codegen item for panic debugging.
58-
pub fn call_with_panic_debug_info<D: CrateDef, F: FnOnce(&mut GotocCtx<'tcx>)>(
59+
pub fn call_with_panic_debug_info<
60+
D: CrateDef,
61+
F: FnOnce(&mut GotocCtx<'tcx>),
62+
S: Fn() -> String + 'static,
63+
>(
5964
&mut self,
6065
call: F,
61-
panic_debug: String,
66+
debug_str_generator: S,
6267
def: D,
6368
) {
6469
CURRENT_CODEGEN_ITEM.with(|odb_cell| {
65-
odb_cell.replace((Some(panic_debug), Some(self.codegen_span_stable(def.span()))));
70+
odb_cell.replace((
71+
Some(Box::new(debug_str_generator)),
72+
Some(self.codegen_span_stable(def.span())),
73+
));
6674
call(self);
6775
odb_cell.replace((None, None));
6876
});

0 commit comments

Comments
 (0)