aboutsummaryrefslogtreecommitdiff
path: root/lib/std/debug.zig
diff options
context:
space:
mode:
authormlugg <mlugg@mlugg.co.uk>2025-09-26 10:52:09 +0100
committermlugg <mlugg@mlugg.co.uk>2025-09-30 13:44:56 +0100
commit156cd8f678ebdcccc48382d093a3ef7e45c85a45 (patch)
treeca3f4c37bda9cf1d039ac25ba37b2c45ab5a345f /lib/std/debug.zig
parent3f84b6c80ed3306f040dd98b8ccba561a052167a (diff)
downloadzig-156cd8f678ebdcccc48382d093a3ef7e45c85a45.tar.gz
zig-156cd8f678ebdcccc48382d093a3ef7e45c85a45.zip
std.debug: significantly speed up capturing stack traces
By my estimation, these changes speed up DWARF unwinding when using the self-hosted x86_64 backend by around 7x. There are two very significant enhancements: we no longer iterate frames which don't fit in the stack trace buffer, and we cache register rules (in a fixed buffer) to avoid re-parsing and evaluating CFI instructions in most cases. Alongside this are a bunch of smaller enhancements, such as pre-caching the result of evaluating the CIE's initial instructions, avoiding re-parsing of CIEs, and big simplifications to the `Dwarf.Unwind.VirtualMachine` logic.
Diffstat (limited to 'lib/std/debug.zig')
-rw-r--r--lib/std/debug.zig15
1 files changed, 9 insertions, 6 deletions
diff --git a/lib/std/debug.zig b/lib/std/debug.zig
index 4dc178b02d..abd3e8102f 100644
--- a/lib/std/debug.zig
+++ b/lib/std/debug.zig
@@ -572,9 +572,12 @@ pub fn captureCurrentStackTrace(options: StackUnwindOptions, addr_buf: []usize)
defer it.deinit();
if (!it.stratOk(options.allow_unsafe_unwind)) return empty_trace;
var total_frames: usize = 0;
- var frame_idx: usize = 0;
+ var index: usize = 0;
var wait_for = options.first_address;
- while (true) switch (it.next()) {
+ // Ideally, we would iterate the whole stack so that the `index` in the returned trace was
+ // indicative of how many frames were skipped. However, this has a significant runtime cost
+ // in some cases, so at least for now, we don't do that.
+ while (index < addr_buf.len) switch (it.next()) {
.switch_to_fp => if (!it.stratOk(options.allow_unsafe_unwind)) break,
.end => break,
.frame => |ret_addr| {
@@ -588,13 +591,13 @@ pub fn captureCurrentStackTrace(options: StackUnwindOptions, addr_buf: []usize)
if (ret_addr != target) continue;
wait_for = null;
}
- if (frame_idx < addr_buf.len) addr_buf[frame_idx] = ret_addr;
- frame_idx += 1;
+ addr_buf[index] = ret_addr;
+ index += 1;
},
};
return .{
- .index = frame_idx,
- .instruction_addresses = addr_buf[0..@min(frame_idx, addr_buf.len)],
+ .index = index,
+ .instruction_addresses = addr_buf[0..index],
};
}
/// Write the current stack trace to `writer`, annotated with source locations.