feature: optimize the case where we are connected but not actively used#65
Conversation
fa8f6b1 to
e9ca3d0
Compare
fa37c61 to
e7ab762
Compare
| return tmp; | ||
| } | ||
|
|
||
| static void add_stack_frame_recursively(zend_execute_data *execute_data) |
There was a problem hiding this comment.
In a couple of cases (when stopping on xdebug_break or when responding to a xdebug_notify call) we may need to rebuild the stack, because we would not have been keeping it updated because we disabled the debugger as it was not being actively used. This function is used to rebuild the stack from the current execute data recursively
| } | ||
|
|
||
| XG_BASE(statement_handler_enabled) = XG_DBG(remote_connection_enabled); | ||
| if (XINI_DBG(on_demand_debugging_enabled)) { |
There was a problem hiding this comment.
This only needs to be done for the on_demand mode
| RETURN_FALSE; | ||
| } | ||
|
|
||
| if (!XG_BASE(observer_active)) { |
There was a problem hiding this comment.
In xdebug_break we rebuild the stack but we pop the last entry which would correspond to the xdebug_break call and which we don't want to be present
| XG_DBG(context).do_break = 1; | ||
| XG_DBG(context).pending_breakpoint = NULL; | ||
|
|
||
| XG_BASE(statement_handler_enabled) = true; |
There was a problem hiding this comment.
And we need to enable the statement handler in case it was disabled before this function was called
| free(option); | ||
| } while (0 == ret); | ||
|
|
||
| if (!XG_DBG(context).do_connect_to_client && |
There was a problem hiding this comment.
If none of these conditions is true it means that the debugger will not stop at any point (except maybe xdebug_break calls) so we can disable most of the debugger functionality
e7ab762 to
2636a26
Compare
|
@pronskiy I managed to fix eval handling so all tests are passing with this new optimization 🎉 |
| return false; | ||
| } | ||
|
|
||
| if (execute_data->func->type == ZEND_EVAL_CODE) |
There was a problem hiding this comment.
When we are within eval code, we let it be handled by the xdebug_execute_ex function as the normal call using the observers may have been disabled. This allows the debugger to register all eval'd functions, report on them and allow setting breakpoints on them
|
@claude review |
|
Claude finished @pronskiy's task in 10m 3s —— View job ReviewBig +1 on the overall direction — the optimization for "connected but idle" is a real-world common case and 80% improvement is meaningful. The mechanism (cmdloop detects no debug intent, disables 🔴 Bug: pause-while-connected can be silently dropped after the optimization fires []
} else {
action = xdebug_xml_node_init("action");
xdebug_xml_add_text(action, xdstrdup("Breakpoint Signalled"));
XG_DBG(context).do_break = 1;
}
This is a regression vs. the previous behavior, where The fix mirrors what XG_DBG(context).do_break = 1;
XG_BASE(statement_handler_enabled) = true;🟡 Concern: stack drifts after
|
|
@claude PR updated with your suggestions, do a new review |
|
Claude finished @carlos-granados's task in 5m 25s —— View job Re-review after updatesThanks for the iteration — both critical issues from the previous round are addressed cleanly. The pause-while-connected fix in One concern remaining though: there's a subtle asymmetry between 🟡
|
|
@claude updated, review again |
|
Claude finished @carlos-granados's task in 1m 10s —— View job Re-review after
|
bac24fe to
3bd0c5a
Compare
In this PR we optimise the case where the debugger connected to a debugging client but the debugging client did not actually provide any real interaction with the code: no breakpoints, no stepping into code, no start upon errors or exceptions, just connect and run the code. This is a usual situation when you have been debugging some code and you finish your debugging session but forget to stop listening on the IDE. Before this change, the debugger would be fully activated and your code would run slowly.
The way this works is that if we detect that after the initial connection no actual debugging actions have been set up, we can disable most of the debugger functionality as in the case when the debugger never connected. The code will not be as performant as in this second case because there are some things like the compiler flag to execute the statement handler which cannot be disabled at this stage.
Nevertheless, the performance of the code for this case is much better than before, it represents an improvement of close to 80% over the previous code, see the results of the performance run: https://github.com/php-debugger/php-debugger/actions/runs/25061631425
In most cases we end up with an overhead of 30%-50%, perhaps slightly noticeable but way better than what we had before.