![]() 作者|王益、严浩翻译|程浩源、董文文 1GDB Python3PyTorch官方发布了如何使用GDB对Python触发的C++代码进行调试的指南,详情参考: https://github.com/pytorch/pytorch/blob/master/CONTRIBUTING.md#gdb-integration 其核心思路是运行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在调试模式下编译OneFlowLinux系统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:///' Conda或Docker环境OneFlow官方文档建议使用Conda或Docker镜像: https://github.com/Oneflow-Inc/oneflow#option-1-build-with-conda-recommended。本次运行使用Anaconda。使用Conda或Docker是为了修复C++编译器和其他构建工具链的版本。使用新版本的g++需要对源代码进行更新,如 https://github.com/Oneflow-Inc/oneflow/issues/8397。 编译调试版本这里要注意,必须先编译OneFlow的调试版本,因为GDB需要调试符号才能使 bt 和 l 的输出有意义。
我安装的是CPU版本的OneFlow,创建了cpu.cmake文件。因为我的 AWS 主机不在中国,所以是在international目录下创建文件。 报错在安装报错时,我在GitHub上提交了相关issue (https://github.com/Oneflow-Inc/oneflow/issues?q=is%3Aissue+author%3Awangkuiyi),OneFlow的研发人员快速给出了回应,向他们致敬! 编译步骤本小节将展示编译OneFlow的具体步骤: 1. 下载安装Anaconda。默认安装路径是 ~/anaconda3。安装时将环境变量添加到~/.bashrc。然后,获取环境变量或重新连接主机使更改生效。 2. 创建并激活Conda环境,具体步骤参考: https://github.com/Oneflow-Inc/conda-env 3. Git clone源码 mkdir ~/w cd ~/w git clone https://github.com/Oneflow-Inc/oneflow 4. 编译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 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。
导入的时间会比平时更长。如果显示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::one::CopyBetweenMirroredTensorAndNumpy。 要显示更多内容,可以输入l。在第 98 行,调用了tensor->is_eager()。
你可能会好奇,为什么在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的调用 ![]()
![]() 2.https://of-worldwide./JuQ0AuodVJn4/Use-GDB-to-Walkthrough-OneFlow-Source-Code (本文经授权后编译发布) |
|