Debugging extremely slow

Or is the second line not needed given that the third line will be executed?

Correct

How does this compare with clicking on the + sign in the Run and Debug area of VSCode and adding MyPackage?

I think that they are identical (meaning that VS Code executes that push! command internally). One of the VS Code devs might be able to comment on what happens if it does have internal modules (I don’t know what happens in that case).

I tried a variety of strategies to make debugged code run faster. The bottom line is that adding my own packages to the list of compiled packages in VSCode works quite well, but the code you suggested does not seem to work in my system. Here is what I did:

  1. Commented or uncommented all commands referring to Revise.jl.

  2. Always imported MyPackage1, MyPackage2, MyPackage3, and MyPackage4. These are packages I created.

  3. Further down in the code I always imported these two packages:
    using MethodAnalysis
    import JuliaInterpreter

  4. Further down I inserted these lines in my code and in some cases commented them out:

union!(JuliaInterpreter.compiled_modules, child_modules(Base))
push!(JuliaInterpreter.compiled_modules, MyPackage1)
push!(JuliaInterpreter.compiled_modules, MyPackage2)
push!(JuliaInterpreter.compiled_modules, MyPackage3)
push!(JuliaInterpreter.compiled_modules, MyPackage4)
  1. Copied the last section of my code, called Backtest, and pasted it at the end of the code so that that section would run twice. This was to evaluate the effect of compilation on execution speed. So I have Backtest1 and Backtest2, which runs faster.

  2. Ran the program under several combinations of:
    a) Pressing F5 (debugging) or Ctrl+F5 (not debugging).
    b) Using Revise.jl or not (see 1) above)
    c) Three alternatives:
    i) Using the + sign in the Run and Debug section on the right-hand pane of VSCode to add my packages to the list of compiled packages, and commenting out the code in 4) above (Compiled forced by VSCode),
    ii) using the code in 4) above and removing my packages from list of compiled packages in the Run and Debug section (Compiled forced by code),
    iii) commenting out the code in 4) above and removing my packages from the list of compiled packages on the Run and Debug section (Not compiled),
    ii) using the code in 4) above and adding my packages to the list of compiled packages in the Run and Debug section (Compiled forced by code),

The following table contains the results.

From the last two lines one can see that the code in 4) above did not have any effect. What did I do wrong?

If you’re using VS Code rather than the command-line Debugger.jl, it’s possible that VS Code is using an internal vendored copy of JuliaInterpreter and so the manual commands I described won’t work. (In essence there may be two JuliaInterpreters and my commands add the packages to the wrong one.) Adding packages via VS Code’s GUI must be doing exactly the same thing internally so I don’t think you have to worry that you’re missing out on something.

1 Like

Thanks so much for your continued help here Tim. I am using VSCode so it is difficult to explicitly run things in the same REPL as the debugger. As a result I’m having a hard time figuring out how to add Base to the compiled modules in my situation. (Where would I run the push! code you sent?) Additionally, I want to basically always use the debugger in this Matlab-like way so am looking for a way to turn on this behavior by default. Any tips?

Although I just saw your last message in this thread. So I guess it is a losing battle. But would be great to figure out if there was a way to use the VSCode debugger in the Matlab-like way. I think it would really enhance the user experience for a lot of people.

@pfitzseb @davidanthoff any tips?

Take a look at the Julia: Compiled Code section in the VS Code debugger pane:
image

It allows you to set modules or functions as compiled/interpreted, which has the exact same effect as the function calls Tim outlined above.

7 Likes

Amazing, thank you so much!!

@Soldalma, @fmvin, @gmantegna
I have created a documentation on how to speed-up the debugger in vscode.

settings-to-speed-up-the-debugger

It’s a combination of:

See the documented example-for-faster-debugging

While I show how to set packages/modules as compiled in settings.json, you can also add individual functions there, e.g. Main.SomeModule.somefun.

4 Likes

@tim.holy How can we push! all modules and submodules except Main, with this approach? Usually we only debug Main.
Why is this needed? We use additional packages beside Base, let’s say GLMakie for plotting. And GLMakie installs a plethora of other packages as dependencies, and we obviously don’t want to push! them manually into the interpreter.

How can we push! all modules and submodules except Main, with this approach? Usually we only debug Main.

union!(JuliaInterpreter.compiled_modules, setdiff(Base.loaded_modules_array(), Main))

Why is this needed?

What do you do if you want to step into a function defined in another package? Once you get into compiled mode, stepping in and breakpoints are no longer supported.

1 Like

Usually I don’t. If someone wants to do debug SomePackage for whatever reason, he simply has to

using SomePackage
union!(JuliaInterpreter.compiled_modules, setdiff(Base.loaded_modules_array(), [Main, SomePackage]))

Note your code has to be adjusted a bit: union!(JuliaInterpreter.compiled_modules, setdiff(Base.loaded_modules_array(), [Main]))

Question:
Beside Base.loaded_modules_array(), do we also need to step in each loaded module with child_modules(...)?

Usually I don’t.

Fair enough. But usually I do. I’m not sure what the default should be, but for a user who hasn’t read the documentation carefully and got bit one way or another, one has to choose between the lesser of two evils:

  • “Julia’s debugger can’t step into any function not defined in Main!”
  • “Julia’s debugger is slow!”

To me the second is not nearly as bad as the first. And if someday we improve the performance of the debugger, we might regret it if we had gone with the first.

Question:mBeside Base.loaded_modules_array(), do we also need to step in each loaded module with child_modules(...)?

Yes, if you want to be completely comprehensive. I’d be comfortable with merging a pull request to JuliaInterpreter that makes all this easier.

2 Likes

Debugging in Julia is just decent for the code I have tested. The problem is rather we don’t document all the features we provide, and some of them are essential. This must be improved, because we end-up spending more time guiding users in forums than creating a complete documentation.

Imagine a new user who wants to debug. He starts here: Debugging · Julia in VS Code (julia-vscode.org). They need to imediatelly know all available configs for debbuging and all external tools like Debugger.jl and Infiltrator.jl.
Here is a modest PR in this regard: Minimally document externall debugging tools by MariusDrulea · Pull Request #77 · julia-vscode/docs (github.com).

Improving the docs menu will help as well: Include headings level 3 in the menu, on click · Issue #75 · julia-vscode/docs (github.com)

There shall be 2 PR. One in JuliaInterpreter and another one to show the users how to use this feature Debugging.

Don’t worry, we want to debug other modules than Main, like calling map(my_fun, some_array). For now, at least most of Main shall be easily debug-able.

I’m not sure that is so. Debugger.jl is simply an alternative to the VS Code debugging UI. If one is using the VS Code UI, I don’t really think one needs to know about or use Debugger.jl at all (and vice versa). Infiltrator.jl strikes me as useful, but also a bit more advanced.

1 Like

To be honest, I am not entirely satisfied with the current UI debugging option, see my experience here Documentation for fast debugging by MariusDrulea · Pull Request #74 · julia-vscode/docs (github.com). I do prefer to use the settings.json to set up the compiled/interpreted modules, just like in the PR. Equivalently, other users might prefer to set-up the compiled modules in the code, by pushing them to JuliaInterpreter list of compiled modules. And I might also go this route in the future.