Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Provide a pause token argument for the debug_command function #381

Open
davidanthoff opened this issue Feb 24, 2020 · 9 comments
Open

Provide a pause token argument for the debug_command function #381

davidanthoff opened this issue Feb 24, 2020 · 9 comments

Comments

@davidanthoff
Copy link
Contributor

davidanthoff commented Feb 24, 2020

EDIT: See at the end of the thread, I would actually prefer a different design now than described up here.

In the VS Code extension, we have a situation that the UI can send a PAUSE request while the debugger is currently running code. It can also set a request to add another breakpoint while code is running in the interpreter.

I've looked through the upcoming Jupyter debug support, and we have the same situation there, i.e. we should ideally support a scenario where we can handle a few key requests while the debugger is actually running user code.

Maybe one way to handle that is provide the ability to provide a callback function to the debugger that will be run after every statement that the interpreter is running. And maybe we could say there are two things that can happen in such a callback function: it can change the breakpoints that are set, and if it returns some particular value, the debugger will pause debugging at whatever statement it is right now.

Obviously such a callback function would have to be super fast, because it would be called a lot.

The way I would implement it in the VS Code debugging code would probably something like this:

  • First, check whether at least 0.5 seconds have elapsed since the last time it did any processing. If not, return immediately (so this would guarantee that it adds really minimal overhead in most cases).
  • Check whether a PAUSE or breakpoint request was received from the client, and then handle things accordingly.

I could imagine that I might move the message handling into a background thread eventually (once we have a notion of background threads that run with a certain priority and are not potentially flooded with the PARTR task scheduling logic), but even then I think this kind of cooperative callback option would be the way to go: in that case it might just check some channel for the existence of a new message that triggers a PAUSE or breakpoint.

I'm not super sure about this design, so would be quite interested to hear other ideas how we could solve this as well! But it would be good if we could add something like that in some way.

I imagine that this would be infinitely more difficult if some of the compile ideas via Cassette were implemented... Or maybe not? @oxinabox just pinging you here to make sure this is on your radar.

@timholy
Copy link
Member

timholy commented Feb 24, 2020

I'd want to make it less overhead than checking the clock and any pending requests. But just a counter, and doing a more thorough check every 10^4 operations, would likely have very little overhead.

@oxinabox
Copy link
Contributor

Can you clarify why this needs to be part of JuliaInterpretter at all?

Why not just another task running on a timer that disables / creates breakpoints ?

@KristofferC
Copy link
Member

Yeah, I think that should at least be tried first. Of course, you are not going to know exactly when the task gets scheduled but I don't think it will be a problem in practice.

@timholy
Copy link
Member

timholy commented Feb 24, 2020

Given our performance problems, though, a way for GUIs to be able to interrupt without having to know where to set a breakpoint seems like a good thing? Or is there a good way to do that too?

@KristofferC
Copy link
Member

KristofferC commented Feb 24, 2020

A "break now!" button seems reasonable. Could be added as a flag check to shouldbreak. The question is how you activate it. By a task that sets the flag, or a callback you pass in, in the beginning?

@pfitzseb
Copy link
Member

pfitzseb commented Feb 24, 2020

A callback that's called every once in a while (i.e. every x instructions) seems like a good solution, imho.

@davidanthoff
Copy link
Contributor Author

I'd want to make it less overhead than checking the clock and any pending requests. But just a counter, and doing a more thorough check every 10^4 operations, would likely have very little overhead.

I could have that check in the callback, right? So say while we still don't have background threading in Julia, I could have a check in the callback that just counts up to 10^4 operations, and then checks for something more meaningful (like new messages or something like that). Once we have support for background threading, the callback could just check for some atomic flag. It seems generally more flexible if that check happens outside of JuliaInterpreter.

Why not just another task running on a timer that disables / creates breakpoints ?

What if I'm debugging some code that never yields? Then this other task will never run, but I'd still like to be able to add bps or pause such code. Of course JuliaInterpreter could periodically yield, but that seems higher overhead to me than calling a very small callback function.

@davidanthoff
Copy link
Contributor Author

From the VS Code extension point of view, a design that would work really well would be this: debug_command accepts another argument, namely a callback function. The callback function would accept no argument. If it returned true, JuliaInterpreter would pause execution, if it returned false it would just continue.

@davidanthoff
Copy link
Contributor Author

I would now actually prefer a different design than a callback :) I adjusted the title of the issue accordingly.

From the VS Code extensions point of view, ideally we could pass something akin to a "pause"-token to debug_command, where the token is either an Atomic{Bool} or an Event (the latter doesn't work on Julia 1.0, so that would be a problem).

JuliaInterpreter.jl would then just periodically somewhere in its loop check whether that pause token is true (or in signaled state in the case of Event), and if it is, pause execution and return as if there had been a breakpoint. It would be extra nice if the return value of debug_command allowed us to distinguish whether the interpreter paused because of this pause signal, or because it hit a "real" breakpoint.

@davidanthoff davidanthoff changed the title Provide a callback option that can pause and set bps Provide a pause token argument for the debug_command function Jun 24, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants