Visual Studio Dynamic Debugging (original) (raw)
The MSVC team is experimenting with new /dynamicdeopt
builds, which are regular optimized builds that also bundle an unoptimized version of the code for each function. With a bit of debugger trickery, this lets Visual Studio switch to the unoptimized version of the function when hitting a breakpoint, allowing you to inspect variables which would otherwise have been optimized away, without compromising performance during the rest of the execution.
I haven’t looked too closely yet but most of the magic seems to be in Visual Studio itself, so I’m wondering if we could make it work with clang builds if we produced compatible binaries and debug info.
It could also be worth it to implement something like this in lldb.
I am also interested in this. Most of the magic should happen in the debugger on Visual Studio side. It seems like it writes a second obj file for each TU that’s unoptimized, at least that what I could glean from a quick check. But if someone have done a more in-depth analysis that would be helpful.
I also wonder if something like this could be of interest to lldb as well?
pogo59 June 10, 2025, 5:21pm 3
Traditionally, one wants to perturb the process being debugged as little as possible–ideally not at all–in order to avoid “heisenbugs” where the act of debugging causes the bug to vanish. My personal experience is that heisenbugs fall into two broad categories: cases where the compiler has optimized the function in a valid way that the programmer did not anticipate, and cases of compiler bugs. Both categories relate to compiler behavior, not program behavior, which is why compiler people might be sensitive to them. Absent mysterious compiler behavior, though, swapping in an unoptimized version of the function is likely to be helpful.
I see that the blog post is about game development, where building the whole app unoptimized is often not going to work (high-end games being constrained by both hard and soft real-time requirements). Having deoptimized functions immediately available (i.e., not having to iterate on selectively building certain functions without optimization) would be a huge productivity win. The other obvious approach would be to imitate JIT behavior, doing recompilation on demand.
The AOT (ahead-of-time) approach would have a big space+time cost in the build cycle, but makes the debugger’s life easier. The JIT approach would avoid the build-time cost, in favor of adding complexity in the debugger to rebuild the necessary bits on demand. I expect different studios will have different ideas about which they would prefer. The more complicated the build, the more likely AOT will be the way to go.
I can see it being a win for some game studios, and games are a big piece of the Clang user space.
I wonder how this would integrate with reverse debuggers such as rr
Might be useful to record a bug in the optimized build, and then “restart” the current stack frame unoptimized, so I can more easily see why things went wrong