乐趣区

关于源码:OneFlow源码一览GDB编译调试

作者|王益、严浩
翻译|程浩源、董文文

1

GDB Python3

PyTorch 官网公布了如何应用 GDB 对 Python 触发的 C ++ 代码进行调试的指南,详情参考:
https://github.com/pytorch/py…

其外围思路是运行gdb python3。在 GDB 会话中,能够为给定的 C ++ 函数名设置断点,如at::Tensor::neg。GDB 以后无奈找到这个函数,prompt 中会提醒是否在共享库加载时将断点挂起,答复 yes。而后输出run,GDB 会启动 Python 解释器。Python 解释器会提醒输出 Python 源码。输出import torch,而后回车。

当 Python 解释器执行 import 语句时,会加载相干的共享库。GDB 会监督加载并设置断点。执行 Python 源码,触发断点,而后关上 GDB prompt 进行 C ++ 调试,例如应用 bt 查看回溯,应用 l 显示 Python 调用的 C ++ 代码。

2

在调试模式下编译 OneFlow

Linux 零碎

OneFlow 反对 Linux,暂不反对 macOS 和 Windows。本文次要介绍在 AWS GPU 主机上运行 Amazon Linux 2(相似于 CentOS)。

(base) [wkyi ~]$ cat /etc/os-release
NAME="Amazon Linux"
VERSION="2"
ID="amzn"
ID_LIKE="centos rhel fedora"
VERSION_ID="2"
PRETTY_NAME="Amazon Linux 2"
ANSI_COLOR="0;33"
CPE_NAME="cpe:2.3:o:amazon:amazon_linux:2"
HOME_URL="https://amazonlinux.com/"

Conda 或 Docker 环境

OneFlow 官网文档倡议应用 Conda 或 Docker 镜像:
https://github.com/Oneflow-In…。本次运行应用 Anaconda。应用 Conda 或 Docker 是为了修复 C ++ 编译器和其余构建工具链的版本。应用新版本的 g ++ 须要对源代码进行更新,如
https://github.com/Oneflow-In…

编译调试版本

这里要留神,必须先编译 OneFlow 的调试版本,因为 GDB 须要调试符号能力使 btl 的输入有意义。

cd ~/w/oneflow/build
CMAKE_BUILD_TYPE=Debug cmake .. -C ../cmake/caches/international/cpu.cmake

我装置的是 CPU 版本的 OneFlow,创立了 cpu.cmake 文件。因为我的 AWS 主机不在中国,所以是在 international 目录下创立文件。

报错

在装置报错时,我在 GitHub 上提交了相干 issue
https://github.com/Oneflow-In…),OneFlow 的研发人员疾速给出了回应,向他们致敬!

编译步骤

本大节将展现编译 OneFlow 的具体步骤:

  1. 下载安装 Anaconda。默认装置门路是 ~/anaconda3。装置时将环境变量增加到~/.bashrc。而后,获取环境变量或从新连贯主机使更改失效。
  2. 创立并激活 Conda 环境,具体步骤参考:
    https://github.com/Oneflow-In…
  3. Git clone 源码

mkdir ~/w cd ~/w git clone https://github.com/Oneflow-In…

  1. 编译 OneFlow

cd oneflow mkdir build cd build `
CMAKE_BUILD_TYPE=Debug cmake .. -C ../cmake/caches/international/cpu.cmake
make -k -j $(nproc)`

运行和调试

装置好后,在 ~/w/oneflow/build 目录中会呈现 source.sh 文件,这个文件设置了 PYTHONPATH 环境。运行下列命令使设置失效。

source source.sh

而后,用 GDB 运行 Python 编辑器。

gdb python3

在 GDB prompt 中,我在
oneflow::one::Tensor::is_eager 设置了一个断点,在共享库加载时会将断点挂起。

(gdb) b oneflow::one::Tensor::is_eager
Function "oneflow::one::Tensor::is_eager" not defined.
Make breakpoint pending on future shared library load? (y or [n]) y
Breakpoint 1 (oneflow::one::Tensor::is_eager) pending.

再而后,输出 run 运行 Python 编辑器。在 Python prompt 中,输出oneflow

(gdb) run
Starting program: /home/wkyi/anaconda3/envs/oneflow-dev-gcc7-v2/bin/python3
Missing separate debuginfos, use: debuginfo-install glibc-2.26-58.amzn2.x86_64
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib64/libthread_db.so.1".
Python 3.7.10 (default, Feb 26 2021, 18:47:35)
[GCC 7.3.0] :: Anaconda, Inc. on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import oneflow

导入的工夫会比平时更长。如果显示ImportError,要查看是否运行了source source.sh

接下来就能够来创立 tensor 了。

a = oneflow.tensor(1)

Thread 1 "python3" hit Breakpoint 1, oneflow::one::CopyBetweenMirroredTensorAndNumpy<long> (t=..., array=array@entry=0x7fffe5905150, Copy=<optimized out>,
    Copy@entry=0x7fffefc977e0 <oneflow::BlobNumpyCopyUtil<long>::From(unsigned long, oneflow::NumPyArrayPtr const&)>, modifier=...,
    block_host_until_done=block_host_until_done@entry=false) at /home/wkyi/w/oneflow/oneflow/api/python/utils/tensor_utils.h:98
98      CHECK_OR_RETURN(tensor->is_eager()) << "eager tensors supported only.";

输出回车,此行代码执行会触发断点。

上述信息表明在源文件的第 98 行有一个名为 tensor->is_eager() 的函数 oneflow::CopyBetweenMirroredTensorAndNumpy

要显示更多内容,能够输出 l。在第 98 行,调用了tensor->is_eager()

(gdb) l
93    inline Maybe<void> CopyBetweenMirroredTensorAndNumpy(
94        const std::shared_ptr<Tensor>& t, PyObject* array,
95        Maybe<void> (*Copy)(uint64_t, const NumPyArrayPtr&), const std::string& modifier,
96        bool block_host_until_done) {97      auto tensor = JUST(t->AsMirroredTensor());
98      CHECK_OR_RETURN(tensor->is_eager()) << "eager tensors supported only.";
99
100      if (block_host_until_done) {101        NumPyArrayPtr array_ptr(array);
102        const auto& Callback = [array_ptr, Copy](uint64_t ofblob_ptr) {

你可能会好奇,为什么在 Python 中创立 tensor 会触发对 Tensor::is_eager 的调用?能够输出 bt 来显示更多信息。

(gdb) bt
#0  oneflow::one::CopyBetweenMirroredTensorAndNumpy<long> (t=..., array=array@entry=0x7fffe5905150, Copy=<optimized out>,
    Copy@entry=0x7fffefc977e0 <oneflow::BlobNumpyCopyUtil<long>::From(unsigned long, oneflow::NumPyArrayPtr const&)>, modifier=...,
    block_host_until_done=block_host_until_done@entry=false) at /home/wkyi/w/oneflow/oneflow/api/python/utils/tensor_utils.h:98
#1  0x00007fffefd5aa5c in oneflow::one::CopyMirroredTensorFromUntypedArray<long> (array=0x7fffe5905150, tensor=...)
    at /home/wkyi/w/oneflow/oneflow/api/python/utils/tensor_utils.cpp:61

#13 0x00007fffefbe433f in oneflow::one::functional::tensor (self=<optimized out>, args=<optimized out>, kwargs=<optimized out>)
    at /home/wkyi/w/oneflow/build/oneflow/api/python/functional/tensor_api.yaml.pybind.cpp:96
#14 0x00005555556b98b4 in _PyMethodDef_RawFastCallKeywords () at /tmp/build/80754af9/python_1614362349910/work/Objects/call.c:693
#15 0x00005555556b99d1 in _PyCFunction_FastCallKeywords (func=0x7ffdc75675a0, args=<optimized out>, nargs=<optimized out>, kwnames=<optimized out>)
    at /tmp/build/80754af9/python_1614362349910/work/Objects/call.c:732

#29 0x000055555578c22c in _Py_UnixMain () at /tmp/build/80754af9/python_1614362349910/work/Modules/main.c:3495
#30 0x00007ffff783113a in __libc_start_main () from /lib64/libc.so.6
#31 0x0000555555730e90 in _start () at ../sysdeps/x86_64/elf/start.S:103

调用堆栈的底部是 _stack,它是 Python 编辑器的入口点。从下面的代码中能够看到 Python 和 OneFlow 共享库之间的调用边界——Python 中的_PyMethodDef_RawFastCallKeywords 函数调用了 OneFlow 的 C ++ 函数 oneflow::one::functional::tensor,进而触发了对oneflow::one::Tensor::is_eager 的调用

上述内容展现了如何应用 GDB 对 C ++ 编写的 Python 库进行调试。以下将更进一步,展现如何在 VSCode 中调用 GDB,以便更轻松地定位代码。

要想在 Python C++ 库中应用 GDB,须要进行如下操作:

  1. 构建 C ++ 库的调试版本
  2. 用 GDB 启动 Python 解释器
  3. 在 C ++ 函数中设置断点,例如 b
    oneflow::one::functional::tensor
  4. 在 Python REPL 中运行代码,触发断点,而后 GDB 会在断点处暂停

依照以下办法改良 VSCode 用户界面

  1. 装置 Microsoft 的“C/C++”扩大,该扩大反对 GDB 调试器
  2. 增加新的调试启动配置
  1. 增加下列配置
{
   "version": "0.2.0",
   "configurations": [
       {
          "type": "cppdbg",
          "request": "launch",
          "name": "GDB",
          "program": "/home/charlieyan/anaconda3/envs/oneflow-dev-gcc7-v2/bin/python"cwd":".","environment": [
              {
                  "name": "PYTHONPATH",
                  "value": "/home/charlieyan/proj/oneflow/python"
              }
          ]
       }
   ]   
}
  1. 而后就能够启动调试器“GDB”并设置断点。当调试器在断点处暂停时,VSCode 也会跳转到源代码行,侧边栏中的变量会与调用栈一起显示。要想更好地了解代码,也能够单步执行各个函数。

参考起源:

1.https://code.visualstudio.com…

2.https://of-worldwide.quip.com…

本文经受权后编译公布

欢送下载体验 OneFlow v0.7.0 最新版本:
https://github.com/Oneflow-In…

退出移动版