jklincn


VSCode 配置 PyTorch C++ 源码开发环境(编译与调试)


版本信息

  • OS:Ubuntu 22.04.5 LTS (通过 SSH 远程连接)
  • GCC:11.4.0
  • VSCode 版本:1.95.0

环境准备

创建目录,下载源代码

mkdir pytorch_dev
cd pytorch_dev
git clone --recursive https://github.com/pytorch/pytorch

创建虚拟环境

conda create -y -n pytorch_dev python==3.12
conda activate pytorch_dev

安装编译依赖,包括一些编译加速工具(ccache)

pip install mkl-static mkl-include
pip install -r pytorch/requirements.txt

conda install -y cmake ninja
conda install -y ccache -c conda-forge

# 配置 ccache 存储上限
ccache -M 25Gi
ccache -F 0

源码编译

MAX_JOBS 的大小请自行调整(建议按照 CPU 内存比 1:4 来调,避免 OOM,比如 16 核 32 GB 的机器可以设置成 8。作者的机器是 128 核 128GB 内存,因此设置为 32)

export CMAKE_PREFIX_PATH="${CONDA_PREFIX:-'$(dirname $(which conda))/../'}:${CMAKE_PREFIX_PATH}"
cd pytorch
DEBUG=1 MAX_JOBS=32 python setup.py install

其他编译选项可以参考 pytorch/CONTRIBUTING.md at main · pytorch/pytorch

在 pytorch_dev 下创建测试文件 test.py

1
2
3
4
5
6
import torch

M = torch.rand(100, 100)
R = M.mm(M)
print(R)
print(torch.cuda.is_available())

运行

python test.py

如果没有问题,则会输出以下内容(cuda 是否可用取决于具体情况,本文不介绍如何安装 cuda)

tensor([[25.3774, 25.7640, 27.0730,  ..., 25.3814, 22.5268, 26.2766],
        [25.5186, 24.3556, 25.2432,  ..., 25.7233, 22.3721, 25.9354],
        [23.4678, 22.8769, 24.5955,  ..., 22.7279, 20.1115, 23.8574],
        ...,
        [28.4061, 27.1574, 28.1965,  ..., 26.7858, 23.3654, 27.7717],
        [21.5448, 22.8987, 23.0728,  ..., 20.8371, 19.4624, 23.0139],
        [22.8249, 22.4210, 24.9273,  ..., 23.4396, 21.3405, 25.5342]])
True

此时目录结构为

~/pytorch_dev$ ls
pytorch test.py

把 pytorch 源码放在子目录,让测试代码和它同级的目的是可以在 VSCode 中正确地跳转,否则 VSCode 调试过程中无法进入到 pytorch 的 python 源码中。这和 python setup.py 是使用 install 还是 develop 有关,本文统一使用 install 。(欢迎勘误)

C++ 源码跳转

由于早期 C/C++ 插件存在内存泄漏问题,因此个人现在偏向于使用 clangd,这会与 C/C++ 插件冲突。如果读者已使用 C/C++ 插件,那么以下内容可能不适合你。并且在 C++ 源码调试时,需要修改成 cppdbg,具体请自行搜索。如果有更好用的 C++ 插件,也可以在评论区指出或者联系我。

PyTorch 编译后之后,在 build 文件夹中会生成 compile_commands.json 文件,我们可以使用它来进行函数定义的跳转。

在系统上安装 clangd

sudo apt install clangd

安装 VSCode 扩展 clangd(llvm-vs-code-extensions.vscode-clangd)

打开 clangd 扩展设置,在远程选项卡中找到 Clangd: Path,其默认值为 clangd,我们修改为 /usr/bin/clangd 来解决 VSCode 提示找不到 clangd 的问题。(虽然我不知道为什么会这样,但这个问题在我这里经常发生,这是一个有效的解决方法)

然后重新加载窗口,可以使用 Ctrl+Shift+P 打开命令面板,输入 reload window 来选择。

重新加载窗口后可以看到界面左下角 clangd 会开始索引,等待完成后就可以进行跳转。

调试

使用 VSCode 打开 pytorch_dev 目录

code pytorch_dev

python 代码调试

前提:安装 Python 扩展(ms-python.python)

创建配置文件

mkdir -p .vscode
touch .vscode/launch.json

保存以下内容

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
{
  "version": "0.2.0",
  "configurations": [
    {
      "name": "Python Debugger: launch",
      "type": "debugpy",
      "request": "launch",
      "program": "${file}",
      "console": "integratedTerminal",
      "justMyCode": false
    }
  ]
}

在 VSCode 界面,代码行数左边进行设置断点,如下图设置了两处断点

image-1

使用 F5 启动调试,可以看到程序在第三行暂停

image-2

可以使用中间上方悬浮的工具条进行控制,也可以使用快捷键:继续(F5)、逐过程(F10)、单步调试(F11)、单步跳出(Shift+F11)、重启(Ctrl+Shift+F5)、停止(Shift+F5)

先按一次 F11,发现 torch.rand 函数无法进入,直接跳到了 R = M.mm(M)

image-3

再按一次 F11,发现 M.mm(M) 也无法进入,直接跳到了 print(R),同时左侧变量一栏显示了当前的 M 和 R 的值

image-4

继续按一次 F11,发现可以跳转到 Tensor 对象的 __repr__ 方法,这是被 print 函数间接调用的。

使用 Shift+F11 单步跳出,回到 test.py 中,再使用 F5 继续运行,可以看到终端正常输出了 R 的值,并且程序暂停在第六行代码。

image-5

再使用 F11 单步调试,发现可以正常进入到 is_available 函数的内部实现

image-6

这里是想说明单步调试进入内部实现存在限制:必须是我们可以直接跳转过去的函数,而不能有多个定义。比如我们日常想查看 torch.rand 函数时,VSCode 会弹出小框表示存在多个定义。所以在调试时,torch.rand 就无法正确跳转进入。(个人理解,如果有解决办法欢迎联系)

image-7

C++ 代码调试

前提:安装 CodeLLDB 扩展(vadimcn.vscode-lldb)

先在终端设置 ptrace,允许任意进程调试其他进程

sudo sysctl -w kernel.yama.ptrace_scope=0

修改 .vscode/launch.json 文件,加入 LLDB 调试

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
{
  "version": "0.2.0",
  "configurations": [
    {
      "type": "lldb",
      "request": "attach",
      "name": "LLDB: Attach",
      "pid": "${command:pickMyProcess}"
    },
    {
      "name": "Python Debugger: launch",
      "type": "debugpy",
      "request": "launch",
      "program": "${file}",
      "console": "integratedTerminal",
      "justMyCode": false
    }
  ]
}

设置断点,这次要在我们的 python 文件和想要查看的 C++ 文件中同时设置。

例如,python 中断点

image-8

C++ 中断点

image-9

设置好断点后,先在运行和调试中启动 python 调试器

image-10

可以看到和之前一样,程序正确地在第四行暂停了

image-11

接着切换到 LLDB 调试器,点击启动

image-12

这时会有一个弹窗来选择进程,我们输入运行的文件名(test.py)进行搜索,然后选择第二个

image-13

可以看到在左下界面中,调用堆栈中多了一个 LLDB: Attach,并且状态是正在运行

image-14

此时我们切换回 Python 调试器,选择继续

image-15

此时可以观察到调用堆栈中 LLDB: Attach 的状态变为:因 BREAKPOINT 已暂停。

我们切换到 C++ 文件中查看,可以看到断点处有黄色阴影。(至于为什么左边那个点还是红色的,我觉得可能是 bug,不影响调试)

image-16

将调试器切换回 LLDB,即可正常地在 C++ 中调试。

下图是逐过程一步之后的结果,左下角调用堆栈中可以正常显示函数的调用情况

image-17


本站不记录浏览量,但如果您觉得本内容有帮助,请点个小红心,让我知道您的喜欢。