Breaking Into the Source With a Debugger
This page explains how to debug the native source code of the PJRT plugin.
Prerequisites
- Clone and build the TT-XLA project.
- The build has to be of the
Debugtype, e.g.-DCMAKE_BUILD_TYPE=Debug. - This is needed for native binaries to have debug symbols.
- The build has to be of the
- Verify
gdbis installed by runninggdb --version.- Needed for debugging of native code.
- This guide is scoped to Visual Studio Code only.
- Install "C/C++" (by Microsoft) and "Python" (by Microsoft) VS Code extensions.
- "Python" will auto-install the "Python Debugger" extension as well.
- "Python Debugger" extension enables
debugpydebugging.
- Create an empty
launch.jsonfile.- In the repository root, create a
.vscode/directory (note that this directory is ignored bygit). - Create a new file
.vscode/launch.jsonwith the following JSON content:
This file is used for configuring multiple debugging profiles.{ "version": "0.2.0", "configurations": [] }
- In the repository root, create a
Debugging Python Integration Tests
How to run a Python script or test in debugpy
Create a new debugging profile called Python: Current File in launch.json:
{
"version": "0.2.0",
"configurations": [
{ // Python: Current File
"name": "Python: Current File",
"type": "debugpy",
"request": "launch",
"program": "${file}",
"console": "integratedTerminal",
"justMyCode": false
}
]
}
Verify that the profile works:
- Create a new Python script and set a breakpoint in VS Code.
- Run a VS Code command
Debug: Select and Start Debuggingand select thePython: Current Fileprofile while the Python script tab is open. - Validate that the breakpoint will be hit.
Now, replace the Python: Current File with a new profile for running tests,
PyTest: Current File:
{
"version": "0.2.0",
"configurations": [
{ // PyTest: Current File
"name": "PyTest: Current File",
"type": "debugpy",
"request": "launch",
"module": "pytest",
"args": [
"-s",
"${file}"
],
"console": "integratedTerminal",
"justMyCode": false
}
]
}
Verify that this profile works:
- Make sure
venvis activated andgitsubmodules are initialized. - Open a Python test from the
tests/directory and set a breakpoint. - Run the new
PyTest: Current Fileprofile and validate that the breakpoint will be hit.
How to attach gdb to a running PJRT client
Since running Python tests is the most common way to also test the PJRT plugin, and because it is common to debug Python and native code side-by-side, this section will focus on that scenario. However, this step can be applied to any running process, assuming you have the time to attach the debugger to the process before it exits.
First, create a new debugging profile Native: Attach to PJRT Client
in launch.json:
{
"version": "0.2.0",
"configurations": [
{ // PyTest: Current File (from previous section)
},
{ // Native: Attach to PJRT Client
"name": "Native: Attach to PJRT Client",
"type": "cppdbg",
"request": "attach",
"program": "${workspaceFolder}/venv/bin/python",
"processId": "${command:pickProcess}",
"MIMode": "gdb",
// pjrt_plugin_tt.so is in this location
"additionalSOLibSearchPath": "${workspaceFolder}/build/pjrt_implementation/src"
},
]
}
Verify that this profile works:
- Make sure
venvis activated andgitsubmodules are initialized. - Select a Python test to run from the
tests/directory and set a breakpoint at the beginning of the test. - Run the
PyTest: Current Filedebugging profile and wait fordebugpyto break into the Python code.- At this point, the process running the test is stalled, and you have time
to attach
gdbto the process.
- At this point, the process running the test is stalled, and you have time
to attach
- Open a C++ file that you wish to debug, and put a breakpoint where you
wish to break. For exercise, almost all tests should pass through
ClientInstance::initialize. - Run the
Native: Attach to PJRT Clientdebugging profile without stopping the existingPyTest: Current Fileprofile (that would kill the test driver process), which will prompt you to select which process you want to attach to. Select thepytestprocess that is running your test. Note that when you are in a remote SSH workspace session you will see multiple options, and you need to pick the remote one (the server). - Resume execution of the
PyTest: Current Fileprofile to unblock the Python interpreter, and wait for the breakpoint in C++ code to be hit in theNative: Attach to PJRT Clientdebugger session. - Once the breakpoint is hit, you can debug the native PJRT code.
Debugging PJRT Unit Tests
Create a new debugging profile called GTest: Filter and Run Tests in
launch.json:
{
"version": "0.2.0",
"configurations": [
{ // GTest: Filter and Run Tests
"name": "GTest: Filter and Run Tests",
"type": "cppdbg",
"request": "launch",
"program": "${workspaceFolder}/build/tests/pjrt/TTPJRTTests",
"args": [
"--gtest_filter=${input:gtestFilter}"
],
"stopAtEntry": false,
"cwd": "${workspaceFolder}",
"environment": [],
"externalConsole": false,
"MIMode": "gdb",
}
],
"inputs": [
{
"id": "gtestFilter",
"type": "promptString",
"description": "Enter gtest filter (e.g., TestSuite.TestName or TestSuite.* for all tests in a suite)",
"default": "*"
}
]
}
Verify that this profile works:
- Set a breakpoint in one of the PJRT unit tests.
- Run the
GTest: Filter and Run Testsdebugging profile and enter a filter that matches the test (e.g.*TestName*). - Once the breakpoint is hit, you can start debugging the test. Note that you can debug multiple tests within the same session, as long as they match the given filter.