1. 环境准备
- docker镜像:
registry.baidubce.com/paddlepaddle/paddle:latest-dev-cuda11.4.1-cudnn8-gcc82
- 容器创建命令:
1
nvidia-docker run --ulimit core=-1 --cap-add SYS_ADMIN --security-opt seccomp=unconfined --name tf-wz --shm-size="8g" --net=host -d -v $PWD/.ccache:/root/.ccache -v $PWD/.cache:/root/.cache -v $PWD/.tmp:/tmp -v $PWD:/work -v /ssd3/datasets:/work/datasets -it registry.baidubce.com/paddlepaddle/paddle:latest-dev-cuda11.4.1-cudnn8-gcc82 /bin/bash
不使用
nvidia-docker
命令创建容器的方法(此文不使用,仅记录):1 2 3 4 5
export CUDA_SO="$(\ls /usr/lib64/libcuda* | xargs -I{} echo '-v {}:{}') $(\ls /usr/lib64/libnvidia* | xargs -I{} echo '-v {}:{}')" export DEVICES=$(\ls /dev/nvidia* | xargs -I{} echo '--device {}:{}') sudo /usr/bin/docker run ${CUDA_SO} ${DEVICES} --ulimit core=-1 --cap-add SYS_ADMIN --security-opt seccomp=unconfined --name tf-wz --shm-size="8g" --net=host -d -v /usr/bin/nvidia-smi:/usr/bin/nvidia-smi -v $PWD/.ccache:/root/.ccache -v $PWD/.cache:/root/.cache -v $PWD/.tmp:/tmp -v $PWD:/work -it registry.baidubce.com/paddlepaddle/paddle:latest-dev-cuda11.4.1-cudnn8-gcc82 /bin/bash # 进入容器再设置一下环境变量:export LD_LIBRARY_PATH=/usr/lib64:/usr/local/lib:$LD_LIBRARY_PATH
- 进入docker命令:
nvidia-docker exec -it tf-wz /bin/bash
注意以下操作均在容器内完成。
2. 获取TensorFlow源码
1
2
3
4
5
git clone https://github.com/tensorflow/tensorflow.git
# 切换到r1.14分支
git fetch origin r1.14:study_r1.14
git checkout study_r1.14
3. 安装bazel-0.24.1(对应于tf r1.14)
1
2
3
4
# https://github.com/bazelbuild/bazel/releases
wget https://github.com/bazelbuild/bazel/releases/download/0.24.1/bazel-0.24.1-installer-linux-x86_64.sh
chmod +x bazel-0.24.1-installer-linux-x86_64.sh
./bazel-0.24.1-installer-linux-x86_64.sh --user
4. 编译TensorFlow
-
创建虚环境
1 2
mkvirtualenv --python=python3.7 tf-study # workon tf-study
virtualenv的安装及使用方法参考此处。
-
安装TensorFlow编译依赖包(python包)
1 2 3 4
pip install numpy==1.18.5 pip install -U pip six wheel setuptools mock 'future>=0.17.1' pip install -U keras_applications --no-deps pip install -U keras_preprocessing --no-deps
-
进行编译选项配置
1 2 3
export PATH=/root/bin:$PATH ./configure # 根据提示进行配置,主要是遇到“是否编译cuda时”选择“y”,其他默认选择即可。
-
执行编译
参考此文,为了编译带调试信息的TensorFlow,需要执行如下编译命令:
1 2
bazel build -c opt --config=cuda --copt="-g" --cxxopt="-g" //tensorflow/tools/pip_package:build_pip_package # tf 2.x: bazel build -c opt --config=cuda --copt="-g" --cxxopt="-g" --cxxopt="-D_GLIBCXX_USE_CXX11_ABI=0" //tensorflow/tools/pip_package:build_pip_package
注意: 编译遇到
C++ compilation of rule '//tensorflow/python:bfloat16_lib' failed
错误,需要将numpy版本降到1.18.5
版本(<1.19.0
),然后使用bazel clean
命令清空之前的编译结果,最后再重新编译。
5. 构建whl
软件包
1
./bazel-bin/tensorflow/tools/pip_package/build_pip_package /tmp/tensorflow_pkg
6. 安装whl
软件包
1
pip install -U /tmp/tensorflow_pkg/tensorflow-*.whl
7. gdb调试python代码方法
7.1 安装python-debuginfo包
1
2
# apt install python3-dbg
apt install -y python3.7-dbg
安装完成后,/usr/share/gdb/auto-load/usr/bin/python3.7m-gdb.py
即为后续调试python脚本所需的libpython.py
。
7.2 设置python脚本启动断点
在要调的 python 代码前面加上如下一段代码,用于获取待调试的python脚本进程号并暂停脚本运行,点击查看示例。
1
2
3
4
5
import os
PID = os.getpid()
print('Program pid:', PID)
print('Pause here to enter DBG')
os.system("read _")
使用python -m pdb test_debug.py
命令执行python脚本,接着执行gdb -p PID
即可进行调试。
使用pdd可对python脚本进行调试,使用gdb可对c++库文件进行调试。
os.system("read _")
相当于人为地打了一处断点,设置完python调试命令后,在gdb模式中输入c
指令(可在输入c
指令前设置一些C/C++文件中的断点,如break TF_NewBuffer
),然后再在python脚本运行窗口中按Enter键即可让python程序继续运行。
7.3 加载python调试指令
- 方法一:
为了可以使用py-list
之类的python调试指令,进入gdb模式后,需要执行如下代码:
1
2
3
4
5
6
7
(gdb) python
>import sys
# "/Python-3.7.0/Tools/gdb/libpython.py"
>sys.path.append('/Python-3.7.0/Tools/gdb')
>import libpython
>end
(gdb) ...
- 方法二:
为了方便起见,可以选择将libpython.py文件拷贝到gdb命令执行时所在的目录下,然后执行如下命令完成python调试指令的加载:
1
2
3
4
5
6
(gdb) python
>import sys
>sys.path.append('.')
>import libpython
>end
(gdb) ...
- 方法三:
为了省略每次运行gdb后都需要进行python调试指令的加载,可以在HOME目录下添加.gdbinit
配置文件,内容如下所示:
1
2
3
4
5
6
7
8
9
# 加载python调试指令
python
import sys
sys.path.append('/Python-3.7.0/Tools/gdb')
import libpython
end
# 保存历史命令
set history filename ~/.gdb_history
set history save on
这样每次运行gdb时,即可自动加载python调试指令。
- 方法四(推荐):
为了最大化减少gdb启动后运行的设置命令数,可以在gdb命令执行时所处目录(一般为用户工程项目路径)下新建.gdbinit
配置文件,并将libpython.py放置在同一目录下,最后设置.gdbinit
文件为如下内容:
1
2
3
4
5
6
7
8
9
# 加载python调试指令
python
import sys
sys.path.insert(0, ".")
import libpython
end
# 设置tensorflow源码目录,以便查找代码
set directories /work/study/tf-learn/tensorflow/
设置上述gdb初始化配置文件后运行gdb命令时会出现如下类似警告(此时亦可发现当前目录下的.gdbinit
文件配置命令并没有执行):
1
2
3
4
5
6
7
warning: File "/work/study/tf-learn/tf-test/.gdbinit" auto-loading has been declined by your `auto-load safe-path' set to "$debugdir:$datadir/auto-load".
To enable execution of this file add
add-auto-load-safe-path /work/study/tf-learn/tf-test/.gdbinit
line to your configuration file "/root/.gdbinit".
To completely disable this security protection add
set auto-load safe-path /
line to your configuration file "/root/.gdbinit".
根据警告提示,需要在HOME目录下也新建一个.gdbinit
配置文件,其内容如下所示:
1
2
3
4
5
# 保存历史命令
set history filename ~/.gdb_history
set history save on
# 自动加载任意目录下的.gdbinit文件配置内容
set auto-load safe-path /
7.4 gdb调试时注意事项:
- 运行python脚本不能在tensorflow源码根目录下,否则会出错。但是需要在tensorflow源码根目录下存放一个对应的软连接文件(
ln -s python脚本文件 tensorflow/python脚本文件
),以便使用py-list
时可以查看脚本源码内容。 - 执行
gdb -p PID
命令最佳方案:在tensorflow源码根目录下运行gdb。否则,需要在gdb模式下使用set directories /work/study/tf-learn/tensorflow/
指令设置tensorflow源码根目录路径。 - TensorFlow的gdb调试方法详见此文档1。
- 给类成员函数设置断点的方法:
- 需要加上命名空间,写法如
b tensorflow::DirectSession::Run
; - 对于带有匿名命名空间的断点设置写法示例:
b tensorflow::(anonymous namespace)::ExecutorState::ScheduleReady
,其第二个命名空间为namespace {}
。
- 需要加上命名空间,写法如
7.5 使用GDB dashboard
7.5.1 设置GDB dashboard
执行如下命令,在home目录下设置dashboard配置文件(下载.gdbinit
文件到home目录):
1
2
rm -f ~/.gdbinit
wget -P ~ https://git.io/.gdbinit
为了可以加载任意目录下的.gdbinit
文件,需要在~/.gdbinit
文件中新增如下内容:
1
set auto-load safe-path /
点击此处下载修改后的主目录.gdbinit
文件。
7.5.2 打印stl容器的内容
从https://sourceware.org/gdb/wiki/STLSupport网站下载stl-views-1.0.3.gdb文件并将其放到所在工作目录下。然后,修改所在工作目录下的.gdbinit
内容如下(即增加source stl-views-1.0.3.gdb
语句):
1
2
3
4
5
6
7
8
9
10
11
12
# 加载python调试指令
python
import sys
sys.path.insert(0, ".")
import libpython
end
# 设置tensorflow源码目录,以便查找代码
set directories /work/study/tf-learn/tensorflow/
# 设置后可查看stl容器内容
source stl-views-1.0.3.gdb
点击此处下载修改后的工作目录.gdbinit
文件。
8. 安装GDB 8.3并高亮显示源码
推荐使用附录中的命令行方式安装
gdb-10
,其自带源码高亮功能。
8.1 安装支持source-highlight的GDB
- 源码编译并安装source-highlight
1
2
3
4
5
6
7
8
9
10
11
12
13
14
apt install libboost-dev libboost-regex-dev
# ln -s /usr/lib/x86_64-linux-gnu/libboost_regex.so.1.58.0 /usr/lib/x86_64-linux-gnu/libboost_regex.so
wget http://ftp.gnu.org/gnu/src-highlite/source-highlight-3.1.8.tar.gz
tar zxvf source-highlight-3.1.8.tar.gz
cd source-highlight-3.1.8
autoreconf -i
mkdir build
cd build
../configure
make -j
make install
# export LD_LIBRARY_PATH=/usr/local/lib:$LD_LIBRARY_PATH
- 源码编译并安装GDB 8.32
1
2
3
4
5
6
7
8
9
10
11
12
13
14
apt install texinfo wget ncurses-dev
wget http://ftp.gnu.org/gnu/gdb/gdb-8.3.tar.gz
tar zxvf gdb-8.3.tar.gz
cd gdb-8.3
mkdir build && cd build/
../configure --prefix=/usr/local/gdb83 --enable-source-highlight=yes --enable-tui=yes --enable-gold=yes --enable-ld=yes --enable-libada --enable-libssp --enable-lto --enable-vtable-verify --enable-werror
make -j
make install
update-alternatives --install /usr/bin/gdb gdb /usr/local/gdb83/bin/gdb 83 --slave /usr/bin/gdbserver gdbserver /usr/local/gdb83/bin/gdbserver --slave /usr/bin/gdb-add-index gdb-add-index /usr/local/gdb83/bin/gdb-add-index
# ln -s /usr/local/gdb83/bin/gdb /usr/bin/gdb
# ln -s /usr/local/gdb83/bin/gdbserver /usr/bin/gdbserver
8.2 使用gdb的tui模式
直接使用gdb -p PID
调试代码,在需要的时候使用切换键ctrl+x a
调出gdbtui,再次使用ctrl+x a
则退出gdbtui模式3。示例图如下所示:
9. Q&A
-
Q: 运行
build_pip_package
命令时出现OverflowError: Size does not fit in an unsigned int
错误。 A: 需要使用python3.7+进行打包。操作命令如下:1 2 3
which python3.7 # /usr/local/bin/python3.7 # 编辑tools/python_bin_path.sh,将其内容修改为: # export PYTHON_BIN_PATH="/usr/local/bin/python3.7"
然后再执行打包命令:
1 2
./bazel-bin/tensorflow/tools/pip_package/build_pip_package /tmp/tensorflow_pkg # 这样得到的结果为:tensorflow-1.14.1-cp37-cp37m-linux_x86_64.whl
然而这样打包得到的
whl
包只能在python3.7环境中进行安装,所以编译时使用python3.7是最好的选择。
附录
下面对本文所使用的docker容器中的一些配置文件进行记录。
apt软件包中国源
修改/etc/apt/sources.list
文件,修改后内容如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
deb-src http://archive.ubuntu.com/ubuntu xenial main restricted #Added by software-properties
deb http://mirrors.aliyun.com/ubuntu/ xenial main restricted
deb-src http://mirrors.aliyun.com/ubuntu/ xenial main restricted multiverse universe #Added by software-properties
deb http://mirrors.aliyun.com/ubuntu/ xenial-updates main restricted
deb-src http://mirrors.aliyun.com/ubuntu/ xenial-updates main restricted multiverse universe #Added by software-properties
deb http://mirrors.aliyun.com/ubuntu/ xenial universe
deb http://mirrors.aliyun.com/ubuntu/ xenial-updates universe
deb http://mirrors.aliyun.com/ubuntu/ xenial multiverse
deb http://mirrors.aliyun.com/ubuntu/ xenial-updates multiverse
deb http://mirrors.aliyun.com/ubuntu/ xenial-backports main restricted universe multiverse
deb-src http://mirrors.aliyun.com/ubuntu/ xenial-backports main restricted universe multiverse #Added by software-properties
deb http://archive.canonical.com/ubuntu xenial partner
deb-src http://archive.canonical.com/ubuntu xenial partner
deb http://mirrors.aliyun.com/ubuntu/ xenial-security main restricted
deb-src http://mirrors.aliyun.com/ubuntu/ xenial-security main restricted multiverse universe #Added by software-properties
deb http://mirrors.aliyun.com/ubuntu/ xenial-security universe
deb http://mirrors.aliyun.com/ubuntu/ xenial-security multiverse
pip中国源
修改~/.pip/pip.conf
文件,修改后内容如下:
1
2
3
[global]
trusted-host = mirrors.aliyun.com
index-url = https://mirrors.aliyun.com/pypi/simple
参考资料
- Python开发必备神器之一:virtualenv
- TensorFlow 拆包(一):Session.Run
- 从源代码构建TensorFlow
- Bazel安装方法
- gdb调试python进程(包括core dump调试)
- gdb调试命令总结
- gdb在类成员函数上设置断点
- 100个gdb小技巧
- 10分钟教程掌握Python调试器pdb
-
文档来源于TensorFlow代码阅读指南。 ↩
-
此处参考编译并安装GDB 8.3。 ↩
-
此处参考在gdb中显示源码(gdbtui使用方法)。 ↩