Debugger status and future plans?

This is not a problem. Julia is conducive to using TDD and small functions. It is possible to avoid using the debugger. Using the REPL w/o a debugger indicates an advantage of Julia, not a disadvantage.

Edit: Disambiguated.

1 Like

The Julia debugger works pretty well in terms of correctness and features but it is indeed slow. It is likely a different approach than the current is needed to get significant speedups. I don’t know of anyone working on that, at the moment.

As a note, Julia is actually pretty hard to interpret quickly. Julia code gets written with the assumption that abstractions will optimize away, which isn’t the case in the interpreter. Stepping through a simple indexing into an array is pretty illuminating, showing how much stuff the Interpreter executed vs what in compiled mode turns into a few assembly instructions.

12 Likes

I use the debugger on VSC all the time and level of satisfaction is moderate. IMO, debugging in Julia is so fundamental needed as in C or Matlab (my experience). It’s very nice to say that small functions and unit test find bugs easily. But what about FIXING them?

One thing I find annoying is to to step into a function. Often I need to step in and out lots of other functions that are implicit in the function arguments. Another thing is that it not-so-rarely does not stop at the breakpoints.

In summary, things have improved a LOT (really thankful for that) but when I compare it with the Matlab/VS experience … it’s still not there.

5 Likes

I don’t see the connection between using the REPL and not using a debugger.

Also, debuggers can be used for exploring codebases. It’s extremely useful, and I don’t frankly understand how it’s possible to understand code without stepping through it.

Fortunately, Julia has both.

1 Like

I am referring to a mode of using Julia, not to a limitation on the availability of a debugger.
If someone has a use for a debugger, great. So, I meant REPL as opposed to “I have to start an IDE and step through the thing line-by-line in order to get anywhere”.

And I mean to say that I don’t see how a REPL decreases the need for a debugger. I’m always used to using them in tandem.

7 Likes

I came from MATLAB and the debugging there is really fast. What is principle difference between interpreters of MATLAB/PYTHON and Julia?

I’m not very familiar with the inner workings of Julia compared to other languages. Are there any languages similar to Julia that have managed to get a debugger working flawlessly?

Secondly, I realize how my post might come across as being very negative of the current debugger, and I just want to thank you, and acknowledge the amazing work you guys put into the debugger.

Also, debuggers can be used for exploring codebases. It’s extremely useful, and I don’t frankly understand how it’s possible to understand code without stepping through it.

I just want to vouch for this as well, especially in machine learning where everyone basically clones each others code and work from there.
As a specific example I was testing out CycleGAN last year, because we wanted to do something similar with a reversible hyperbolic network. Within 20 minutes I had run their code and stepped all the way through it and had a basic understanding of how it worked, and 1 hour later I had merged our network into their code and were transforming horses to zebras with our network.
I dread to think how that would have gone without a debugger, and I don’t see REPL being much help in a situation like that.

1 Like

Running Julia in the debugger is about the same speed as running Matlab or Python is all the time — ie 10-100x slower than Julia normally is. They’re implemented in the same way, using an interpreter. So if you’re happy with the speed of Matlab/Python then you should be fine with Julia’s debugger.

5 Likes

Well, I tried debugger in Atom and VS Code and both are very slow. MATLAB debugging is simply much faster.

Not sure, where is a bottleneck?

There can be a much bigger overhead for code that’s sensitive to certain compiler optimizations:

julia> x = rand(100);

julia> f(x) = sum(x)
f (generic function with 1 method)

julia> @btime f(x)
  28.302 ns (1 allocation: 16 bytes)
50.057362567545745

julia> @btime @interpret f(x)
  4.612 ms (30859 allocations: 1.15 MiB)
50.05736256754573

Running in “compiled mode” recovers a lot of that performance, but also disables breakpoints in functions further down the callstack:

julia> function interpret_compiled(f, args...; kwargs...)
         frame = JuliaInterpreter.enter_call(f, args...; kwargs...)
         return JuliaInterpreter.finish_and_return!(JuliaInterpreter.Compiled(), frame)
       end
interpret_compiled (generic function with 1 method)

julia> @btime interpret_compiled(f, x)
  7.373 μs (86 allocations: 5.56 KiB)
50.057362567545745

The probably best short-term solution is a mixed-mode debugger that combines Infiltrator and JuliaInterpreter; the long term solution would be reviving Gallium.jl.

6 Likes

Sorry if this has been covered already, but debugger in REPL is quite nice. I can find exactly where something is happening by file and line. The only exception to this is when I occasionally get deep into some code that can only show me the compiled code (which is typically still pretty manageable).

As for performance, I ditched Atom before I even knew about Julia because everything slowed it down. VSCode is less sensitive to that but you can still end up adding so many extensions that you slow it down if you’re not careful. I find the first time running @enter on something has a bit of a wait but besides that I’ve got nothing to complain about.

I’ve never cared for big fancy debuggers GUI debuggers though so if that’s what you’re after I can’t help you.

What I was trying to explain is that your Matlab code is always as slow as Julia code in the debugger. Matlab only has one speed—slow. Slow normally, slow in the debugger. But the debugger is just as fast as the normal speed, so win? Julia, on the other hand, normally runs at hyperspeed, but can’t in the debugger. So it “feels” too slow when you debug it, but that’s just because it’s much faster normally. So if you wrote the same code in Matlab and Julia and it was fast enough in Matlab, then it would also be fast enough in Julia’s debugger. If you have code that’s too slow in Julia’s debugger then it would also be too slow in Matlab no matter how you run it, debugger or not.

6 Likes

I think it would be fair to say that Matlab is between 1-100x slower than Julia (very approximately) depending on many things.

Matlab’s debugger is probably comparable to a ‘mixed mode’ debugger in Julia. The interpreted code is slow like ordinary Matlab code (except the chunks that are jit’ed), but Matlab also calls out to Fortran/C a lot, its so-called ‘built-in’ functions, and that code is not slow. Also, you cannot step into those functions.

5 Likes

Btw, that approach is also somewhat feasible with the current JuliaInterpreter – you can e.g. exclude Base from being interpreted:

julia> push!(JuliaInterpreter.compiled_modules, Base);

julia> @btime @interpret f(x)
  12.201 μs (98 allocations: 6.03 KiB)
49.62499829212982
9 Likes

That’s fair. And Julia calls to C or Fortran libraries are also fast but there are a lot fewer of them in Julia since most functionality is pure Julia. Automatically switching to compiled mode for built-in functions would be a good direction for someone to explore.

2 Likes

I can not agree. Usually, I rewrite MATLAB code to Julia and still the debugging the MATLAB code is much faster.

I believe that excluding Base and other “external” packages from being interpreted and leaving only my own functions will be the best way.

1 Like

That looks like a very nice solution! Worth a mention in the docs. Does that give up control flow completely? Eg will sum(f, x) break on a breakpoint in f?

Yeah, that’s the big problem:

julia> g(x) = 2x
g (generic function with 1 method)

julia> @breakpoint g(2)
g(x) in Main at REPL[42]:1

julia> @interpret sum(g, x)
(Frame for sum(f, a::AbstractArray; dims) in Base at reducedim.jl:653
  1 653  1 ─      nothing
  2 653  │   %2 = (Base.#sum#584)(Colon(), #self#, f, a)
  3 653  └──      return %2
f = g
a = [0.929103, 0.117293, 0.193176, 0.706207, 0.198638, 0.88355, 0.454533, 0.714572, 0.775677, 0.230185  …  0.456054, 0.114394, 0.496087, 0.295862, 0.215286, 0.269377, 0.684313, 0.903918, 0.0682543, 0.798796]
callee: #sum#584(dims, ::typeof(sum), f, a::AbstractArray) in Base at reducedim.jl:653, breakpoint(g(x) in Main at REPL[42]:1, line 1))

julia> push!(JuliaInterpreter.compiled_modules, Base);

julia> @interpret sum(g, x)
99.24999658425963