# Debugger discussion
:::info
Context: During JuliaCon 2022, David Anthoff and Valentin Churavy had a disucssion
over what is needed for a better Debugger experience.
**Personae dramatis**:
- David Anthoff (@davidanthoff)
- Valentin Churavy (@vchuravy)
- Keno Fischer (@keno)
- Sebastian Pfitzner (@pfitzseb)
- Stefan Karpinski (@StefanKarpinski)
:::
## JuliaCon 2022 discussion as recalled by VC
- Debugger.jl/JuliaInterpreter.jl rather slow
- (Someone guessed a 50x performance improvement needed)
- GDB is not that helpful since we don't emit debug information about variables
- Example: Rust has a debug mode that emits much more information, but also turns of optimizations
- GDB is probably not the tool Julia users want to use as the primary debugger
- Challenge is how to mainatain information while still optimizing
- Reverse mapping from user code to running code is always hard, variables, is hard
- Idea: Patch-points for function
- What about inlined functions
- Breakpoints wouldn't be reliable
- de-optimization support (annoying for the optimizer to deal with)
- David then outlined an idea from Keno (roughly JuliaCon 2019?)
- Use overlay method tables to replace the function that has a breakpoint in it with a variant that enters the debugger
VC roughed out a prototype https://github.com/vchuravy/FancyDebugger.jl/commit/9e5dbc96fbc66d515c61759a450493c468f09530 that used some code VC and Shuhei Kadowaki (@aviatesk) had prototyped two days prior https://gist.github.com/aviatesk/9b247e5e64f78454a70c3ec94c1ab2ad to try to answer the question how to execute code generated by an AbstractInterpreter without using a custom ORC JIT, raising https://github.com/JuliaLang/julia/issues/46220
## Follow-up Slack conversation
> [name=David Anthoff][time=July 30, 2022]
>
> @vchuravy put together https://github.com/vchuravy/FancyDebugger.jl today. My understanding is that this is essentially the kind of design that
> @keno has had in mind for the debugger, i.e. a way to run compiled code while still supporting breakpoints.
> I am off on a vacation and won't be at the Hackathon tomorrow, but I would just love to see an effort to adopt that kind of technique in JuliaInterperter.jl. I'm just going to ping everyone I know who might be able to help with this effort, please feel entirely free to just ignore this ping. This is just me trying to rally some troops :wink: CC
> Some random comments:
> - I think ideally this would all live in JuliaInterpreter.jl, right?
> - For those that are not so familiar with the VS Code/Debugger.jl split, essentially both VS Code and Debugger.jl are front-end/UIs for the actual debug engine in JuliaInterpreter.jl. So ideally something like this would live in JuliaInterpreter.jl, so that the extension and Debugger.jl could benefit from this.
> Just FYI, the code that integrates JuliaInterpreter.jl into VS Code is https://github.com/julia-vscode/DebugAdapter.jl. @pfitzseb probably knows it better at this point than me :wink:
> - One (maybe major?) complication is that we from the VS Code extension try to keep dependencies as low as possible. At the moment FancyDebugger.jl has a dependency on GPUCompiler.jl, and that seems to pull in a bunch of other things. That would probably be too much for us... But I took a very quick look at what FancyDebugger.jl is using, and it seems only a small fraction? I.e. GPUCompiler.CodeCache and some related methods? Maybe one could either vendor those parts into JuliaInterpreter.jl so that there is no additional dependency at all, or put just that stuff into a new package CodeCaches.jl, so that we only have to add one additional dependency?
> - We also in general have tried to support old Julia versions, but obviously this would presumably only be Julia 1.9 and newer. I think the benefits of that would be so great that we would most definitely be OK with that, but we would then need to think hard about some strategy to keep shipping today's debugger for older Julia versions. I just want to bring it up, we can probably ignore for now and then
> @pfitzseb
> and I will have to figure that one out.
> - Just as a general comment: the most useful breakpoints for us are ones that are specified as filename/line, not the function breakpoints.
> In any case, folks probably already have plans for the Hackathon tomorrow, but maybe we could also try to rekindle an effort to make progress on this outside of Juliacon? Much of this stuff is too low level for me and I probably won't be able to help a ton, but I am on sabbatical the entire next year and could easily help with any and all integration issues for the VS Code extension.
> [name=David Anthoff][time=July 30, 2022]
>
> @vchuravy
> ok, I stared at your code and I think I kind of understand it. One question: would this kind of idea support "step out" functionality? Say we have this code:
> ```julia
> function f()
> x = 5
> y = g(x)
> println(y)
> end
>
> function g(a)
> b = 2*a
> return a*2
> end
> ```
>
> and we set a breakpoint on the and we set a breakpoint on the b = ... line in g. So if I understand FancyDebugger, we would essentially "replace" g with a version that just jumps into the interpreter for running g. But what if the user at the end of g selects the command "step out", i.e. at that point they would expect that the debugger now pauses somewhere after the call to g in the function f , with access to local vars x and y in f etc. My understanding from the design is that f is essentially completely unmodified from a normal non-debug run.
> Essentially what we need is the ability to run f compiled, break in g and then continue to run f after the breakpoint has been hit in a child in interpreter mode... That seems tricky?
> [name=Sebastian Pfitzner][time=July 30, 2022]
>
> IIUC, no, it won't let you step out of the overlaid method.
> [name=David Anthoff][time=July 30, 2022]
>
> Hm, yeah, that is how it looked to me as well :disappointed: I think step out is a really crucial feature, so if this design would not be able to accommodate that, then I think we probably need to look for some other approach in general? Or do @vchuravy or @keno have an idea how that might be accomplished with overlay methods?
>[name=Valentin Churavy][time=Aug 1, 2022]
>
> No I don't see a way of doing that with method overlays.
> You also can't add breakpoint once you already started debugging (at least not reliably...)
> Part of the issue here is that it's really hard to define a optimized code -> debuggable frame transform. We might have optimized away at any of the stages the variable you want to inspect
> So JuliaInterpreter.jl is a constructive debugger, it keeps around as much information as possible to enable effective debugging.
> GDB is an observational debugger, it let's you observe the code as it is executed
> Now some languages have de-optimization points and we could think about that as well, but that's hard to do without losing performance
>[name=Stefan Karpinski][time=Aug 3, 2022]
>
> What about this kind of transformation of the example:
> ```julia
> function f'()
> x = 5
> g'(x, f_tail)
> function f_tail(y)
> println(y)
> end
> end
>
> function g'(a, f_tail)
> b = 2*a
> return f_tail(a*2)
> end
> ```
>
> It’s essentially a continuation-passing transform: you replace f with a version that calls a modified g as a return call with an extra continuation argument, i.e. a closure implementing the rest of f which takes the result of g as its argument and computes the rest of f. Then when interpreting g you have two choices upon returning: you can call g' with a compiled f_tail which will run at full speed (modulo closure issues, but that’s still faster than interpreting) or you can call it with a stub that interprets f_tail and lets you keep debugging.
>
> You’d need to transform the entire call stack down to the breakpointed g call, but that could be doable
>