svaarala / duktape

Duktape - embeddable Javascript engine with a focus on portability and compact footprint
MIT License
5.93k stars 514 forks source link

Separate concept of debugger connected vs. debugger attached #768

Open svaarala opened 8 years ago

svaarala commented 8 years ago

At the moment a debug connection is attached via duk_debugger_attach() and that automatically pauses execution moving Duktape into "debug mode". Even when execution is then resumed, Duktape remains in "debug mode" e.g. checking active breakpoints when entering a new function. Being in "debug mode" slows down execution a bit so it's not necessarily acceptable unless an active debug session is going on. (The slowdown is not drastic because if there are no active breakpoints in a function, there's virtually no performance difference; but breakpoint checks will be performed at function entry.)

It would be possible to separate the state handling so that it would be possible to have a debugger connection but for the debugger state to be "detached". An application could still send AppNotify notifications (for example, to forward console output) and respond to AppRequest commands if the execution loop retained the occasional debug message peek without actually performing breakpoint checks.

Technically speaking the debug connection would then be more of a "maintenance connection" with the ability to do debugging but perhaps also non-debugger-related things, such as memory state inspection or target specific commands, at a later time.

Not sure if this is ultimately worth the changes, but this crossed my mind again when moving print/alert stuff into extras. Related requests have been about the initial execution state when a debugger is attached: it's not always preferable for the target to pause so maybe some more control would be nice.

fatcerberus commented 8 years ago

I'm a little confused... I think the idea is for the connected debug client to "step back", relinquishing control to Duktape but still receiving notifications from the target? If so I'm not sure that's worth the trouble either.

You still lose performance when debugging support is compiled in anyway because the debugger could be attached at any time, so some optimizations just can't be done. And it's been my experience that, when resuming execution but leaving the debugger connected, I still want to hit breakpoints and pause-on-error. If I didn't, I wouldn't have connected to the target in the first place. :)

svaarala commented 8 years ago

Right, the minimum amount of overhead is to, occasionally, peek into the debug transport to check for incoming commands like "attach now".

But that doesn't mean the breakpoint checks etc need to be done. These two are now always tied state-wise.

svaarala commented 8 years ago

Re: resuming and hitting breakpoints etc - that's what you want to do when you're actively debugging.

What I'm talking about is, for example, using the debug connection (being a misnomer here as I pointed out above) to, for example, deliver memory statistics as the target executes without actually doing any debugging.

The difference is not that big but some other language environments separate these two concerns (a connection to the target existing and dispatching commands vs. the target being in active debug mode).

fatcerberus commented 8 years ago

You also have the overhead of losing some optimizations even when not attached/connected. I think right now the extent of it is that Duktape needs to always create _Varmap and arguments objects, but there might be more I don't know about.

svaarala commented 8 years ago

Maybe to underline the performance difference between just peeking for commands vs. debug mode:

svaarala commented 8 years ago

Right, this change would also mean that is should be possible to enable the "maintenance connection" support without actually enabling debugger support. The connection could then, for example, dispatch application specific commands etc.

This can of course be independently by the application: but it's rather weird that you can't e.g. get a memory state dump or upload a new script (via AppRequest command) unless you've also enabled full debug mode support.

fatcerberus commented 8 years ago

That makes sense. Something to think about as 2.x development proceeds, at least.

svaarala commented 8 years ago

So I guess one use case I'd like to solve is a release build having the ability to do at least application specific commands driven by a very lightweight periodic peek integrated into the executor interrupt. This would then allow e.g. script updates to be pushed even in a release build if that makes sense for the target, without having to develop a separate protocol for that.

fatcerberus commented 8 years ago

I guess one case where this could be useful is profiling - to get a clearer picture of the performance characteristics while still being able to peek into the execution state.