-
Notifications
You must be signed in to change notification settings - Fork 219
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
Unnecessary -var-create
and -var-delete
commands during a stack trace can cause noticeable pause each time the debuggee stops
#1349
Comments
…ues. This reduces the number of round-trips to the debugger, because when values are requested, the `-stack-list-arguments` command also returns the type of each argument immediately, avoiding the need for subsequent `-var-create` and `-var-delete` commands to get these types.
It feels like the best solution here is to have a launch.json knob to control the default stack trace format (and ideally context menu controls in the call stack window to change it during a debug session). |
Maybe—but first I think it is worth trying to see if GDB can be fixed. The underlying problem is that the GDB/MI command I think this is a bug, or at least an important oversight, in GDB, so I have filed bug 29554 together with a patch to GDB that updates (It might be that the GDB maintainers won't agree that this is a bug, but if so I can try again, this time leaving |
Even with that, I think we would still need a knob to turn off values for folks using older versions of GDB (unless we want to do version sniffing and turn it off by default). |
GDB/MI has built-in feature-detection via the |
Sounds reasonable. BTW: Due to GDB's licensing, I am not allowed to look at GDB source code. |
Newer versions of GDB support the `--scalar-values` option (with value 3) to the `-stack-list-arguments`, `-stack-list-locals` and `-stack-list-variables` commands. This option fetches names, types, and values for scalar types, or names and types only for non-scalar types. Use this in `DebuggedProcess.GetParameterInfoOnly()` if it is available, as this gets all the required information without the potential performance penalty of the `--simple-values` option which potentially fetches large values for references to arrays, structures, and unions. New method `MICommandFactory.SupportsScalarValues()` determines if `--scalar-values` is supported, using the `-list-features` command and checking for the presence of the `"scalar-values"` feature. We cache the result on the `DebuggedProcess` object, as the set of supported features does not change during the lifetime of the debug session.
Newer versions of GDB support the `--scalar-values` option (with value 3) to the `-stack-list-arguments`, `-stack-list-locals` and `-stack-list-variables` commands. This option fetches names, types, and values for scalar types, or names and types only for non-scalar types. Use this in `DebuggedProcess.GetParameterInfoOnly()` if it is available, as this gets all the required information without the potential performance penalty of the `--simple-values` option which potentially fetches large values for references to arrays, structures, and unions. New method `MICommandFactory.SupportsScalarValues()` determines if `--scalar-values` is supported, using the `-list-features` command and checking for the presence of the `"scalar-values"` feature. We cache the result on the `DebuggedProcess` object, as the set of supported features does not change during the lifetime of the debug session.
Newer versions of GDB support the `--scalar-values` option (with value 3) to the `-stack-list-arguments`, `-stack-list-locals` and `-stack-list-variables` commands. This option fetches names, types, and values for scalar types, or names and types only for non-scalar types. Use this in `DebuggedProcess.GetParameterInfoOnly()` if it is available, as this gets all the required information without the potential performance penalty of the `--simple-values` option which potentially fetches large values for references to arrays, structures, and unions. New method `MICommandFactory.SupportsScalarValues()` determines if `--scalar-values` is supported, using the `-list-features` command and checking for the presence of the `"scalar-values"` feature. We cache the result on the `DebuggedProcess` object, as the set of supported features does not change during the lifetime of the debug session.
In newer versions of GDB, the `--simple-values` option to the `-stack-list-arguments`, `-stack-list-locals` and `-stack-list-variables` commands no longer prints the value for references to compound types. This improves the performance of these commands when the stack has references to large data structures. When these versions of GDB are available, take advantage by using `--simple-values` in `DebuggedProcess.GetParameterInfoOnly` to fetch names and types in a single `-stack-list-arguments` command. This is faster than the old approach of using `--no-values` followed with `-var-create` and `-var-delete` for each parameter to get the type. The new method `MICommandFactory.SupportsSimpleValuesExcludesRefTypes` determines if the debugger supports the improved behaviour of the `--simple-values` option, by executing the `-list-features` command and checking for the `"simple-values-ref-types"` feature in the output. We cache the result on the `DebuggedProcess` object as the set of supported features does not change during the lifetime of the debug session.
In newer versions of GDB, the `--simple-values` option to the `-stack-list-arguments`, `-stack-list-locals` and `-stack-list-variables` commands no longer prints the value for references to compound types. This improves the performance of these commands when the stack has references to large data structures. When these versions of GDB are available, take advantage by using `--simple-values` in `DebuggedProcess.GetParameterInfoOnly` to fetch names and types in a single `-stack-list-arguments` command. This is faster than the old approach of using `--no-values` followed with `-var-create` and `-var-delete` for each parameter to get the type. The new method `MICommandFactory.SupportsSimpleValuesExcludesRefTypes` determines if the debugger supports the improved behaviour of the `--simple-values` option, by executing the `-list-features` command and checking for the `"simple-values-ref-types"` feature in the output. We cache the result on the `DebuggedProcess` object as the set of supported features does not change during the lifetime of the debug session.
* [#1349] Always use `--simple-values` in newer versions of GDB. In newer versions of GDB, the `--simple-values` option to the `-stack-list-arguments`, `-stack-list-locals` and `-stack-list-variables` commands no longer prints the value for references to compound types. This improves the performance of these commands when the stack has references to large data structures. When these versions of GDB are available, take advantage by using `--simple-values` in `DebuggedProcess.GetParameterInfoOnly` to fetch names and types in a single `-stack-list-arguments` command. This is faster than the old approach of using `--no-values` followed with `-var-create` and `-var-delete` for each parameter to get the type. The new method `MICommandFactory.SupportsSimpleValuesExcludesRefTypes` determines if the debugger supports the improved behaviour of the `--simple-values` option, by executing the `-list-features` command and checking for the `"simple-values-ref-types"` feature in the output. We cache the result on the `DebuggedProcess` object as the set of supported features does not change during the lifetime of the debug session. * fixup! [#1349] Always use `--simple-values` in newer versions of GDB.
Summary
Each time the debuggee stops, Visual Studio Code requests a stack trace of the threads that are expanded in the CALL STACK window. Turning on
engineLogging
shows that MIEngine implements a stack trace for a thread by issuing a-stack-list-arguments
for the thread, and then issuing a-var-create
and-var-delete
command for every argument in every frame in the stack.When there are many stack frames with many arguments, or if the debugger is behind a sluggish network connection, or if the user installs a hook that runs on every GDB prompt, the time taken to execute these commands can amount to a significant delay.
These
-var-create
and-var-delete
commands ought to be unnecessary as explained below.Reproduction
Put this program in a suitable file, say recurse.c:
Compile it with debugging information, for example
gcc -g -o recurse recurse.c
.Open Visual Studio Code and create a new launch configuration using the "(gdb) launch" template, supplying
recurse
as the value for the"program"
key, and turning on engineLogging:Select View ⟶ Run to switch to the run panel, select the new launch configuration in the RUN AND DEBUG dropdown, and press F5 to start debugging.
Click "Step Into" a few times until there are multiple frames on the stack.
Look at the DEBUG CONSOLE to see the GDB/MI commands sent by MIEngine. I took a copy of the commands issued by a single Step Over operation with ten frames on the stack and attached them here: stack-list-arguments.gz. Here's a summary of the commands issued by MIEngine to GDB:
-stack-list-arguments
-stack-list-frames
-stack-list-variables
-stack-select-frame
-var-create
-var-delete
If each of the
-var-create
and-var-delete
commands takes only a millisecond due to network lag or a GDB before-prompt hook, then there's a 0.4-second pause each time the debuggee stops.Analysis
You can see from the log output that each
-var-create
is followed immediately by a-var-delete
. This means that MIEngine is only issuing these commands to collect information about the variables (not to get a variable reference that it can later use). Why is this? The culprit isDebuggedProcess.GetParameterInfoOnly()
which has a comment explaining what's happening:MIEngine/src/MIDebugEngine/Engine.Impl/DebuggedProcess.cs
Lines 1975 to 1976 in c594534
The problem is that
GetParameterInfoOnly()
was called withvalues = false
and so it passedPrintValue.NoValues
to the-stack-list-arguments
call and then followed up with-var-create
and-var-delete
commands to get the types of the arguments.The reason why
values = false
here is thatAD7DebugSession.HandleStackTraceRequestAsync()
did not set theFIF_FUNCNAME_ARGS_VALUES
flag when callingAD7Thread.EnumFrameInfo()
. And the reason why this flag is unset is that VSCode did not pass aformat
argument to theStackTrace
request, and so we are in the "default format" case:MIEngine/src/OpenDebugAD7/AD7DebugSession.cs
Lines 1706 to 1710 in c594534
Solution ideas
The default format could include
FIF_FUNCNAME_ARGS_VALUES
: thenGetParameterInfoOnly()
would passPrintValue.SimpleValues
to the the-stack-list-arguments
call, which would return the types immediately and there would be no need for the subsequent-var-create
and-var-delete
calls.GetParameterInfoOnly()
could passPrintValue.SimpleValues
to the the-stack-list-arguments
call if either types or values were required, discarding the values information if it is not needed.Software versions
Cpptools extension: 1.12.4
VSCode: 1.71.0
Commit: 784b0177c56c607789f9638da7b6bf3230d47a8c
Date: 2022-09-01T07:25:10.472Z
Electron: 19.0.12
Chromium: 102.0.5005.167
Node.js: 16.14.2
V8: 10.2.154.15-electron.0
OS: Linux x64 5.4.0-124-generic
Sandboxed: No
The text was updated successfully, but these errors were encountered: