注:如下是在做深度学习框架开发时,用到的火焰图pprof和 CUDA Nsys 配置指南,可能对大家有一些帮助,就此分享。一些是基于飞桨的Docker镜像配置的。
# 1.构建镜像, 记得映射端口,可以多映射几个;记得挂载ssd目录,因为数据都在ssd盘上
nvidia-docker run -it --name=profile_dev --shm-size 128G --ulimit core=-1 --cap-add ALL -v $PWD:/workspace -v /ssd1:/ssd1 -v /ssd2:/ssd2 -v /ssd3:/ssd3 --net=host -p 9422:22 -p 9423:9423 -p 9424:9424 registry.baidubce.com/paddlepaddle/paddle:latest-dev-cuda11.2-cudnn8-gcc82 /bin/bash
# 2.更新设置,安装vim
apt update
apt install vim
# 3. 将代理保存到 ~/.my_profile
# 4.安装zsh 和 oh_my_zsh
apt install zsh
sh -c "$(curl -fsSL https://raw.github.com/ohmyzsh/ohmyzsh/master/tools/install.sh)"
# 5. 自动初始化个性化设置
vim ~/.zshrc
# 最后一行添加 source ~/.my_profile
# 6. 配置性能优化工具
apt install libgoogle-perftools-dev
# 7. 创建全局python3.7 沙盒
virtualenv env3.7 --python=python3.7
source env3.7/bin/activate
# 8. 配置pprof
rm -rf /usr/local/go
tar -xzf go1.16.4.linux-amd64.tar.gz -C /usr/local
export GOROOT=/usr/local/go
export PATH=/root/gopath/bin:$GOROOT/bin:$PATH
go version
go get github.com/google/pprof
NsightSystem 是一个集终端 CUDA Profile 日志生成和 前端可视化 timeline 分析的强大工具。安装 nsys 需要分别下载适合Unix 的 Installer 和 Mac/Windows 的可视化终端。
首先,在创建 docker 镜像时,需要加上 --privileged=true
,否则可能无权限读取Performance Counter。比如:
--privileged=true
了,只需要加 --cap-add ALL
即可然后,在 docker 容器中的命令行下,安装 nsys:
# step 1: 此处是旧的,推荐大家下载最新的按照包
bash NsightSystems-linux-public-2020.4.1.144-20fdc64.run
# step 2: 然后 Enter 键,并翻页到最后,键入 ACCEPT 接受协议
# step 3: 输入安装路径,或者回车使用默认路径,完成安装。
Enter install path: [ default is /opt/nvidia/nsight-systems/2020.4.1 ]:
...
========================================
To uninstall the Nsight Systems 2020.4.1, please delete "/opt/nvidia/nsight-systems/2020.4.1"
Installation Complete
# step 4: 将安装路径加入PATH
$ export PATH=/opt/nvidia/nsight-systems/2020.4.1/bin:$PATH
$ which nsys
/opt/nvidia/nsight-systems/2020.4.1/bin/nsys
注:桌面可视化的客户端安装非常简单,和安装其他软件无差别。
常用命令如下:
nsys profile -w true -t cuda,nvtx,osrt,cudnn,cublas -s cpu --cud -x true python abs.py
"""
–stats=true,表示在收集完信息后,会在终端输出本次profiling的统计概要。
-t cuda,用于指定待profiling的 API.可以设置为cublas, cuda, cudnn, nvtx, opengl, openacc, openmp, osrt, mpi, vulkan, none
"""
注:更多用法,可以参考:nsys文档。
命令执行完,会在当前路径下生成一个 *.qdrep
文件,将其拖入 NSight GUI 工具即可。
C++的性能分析工具非常多。常见的包括gprof
, valgrind
, google-perftools
。但是调试Python中使用的动态链接库与直接调试原始二进制相比增加了很多复杂度。幸而Python的一个第三方库yep
提供了方便的和google-perftools
交互的方法。于是这里使用yep
进行Python与C++混合代码的性能分析。
使用yep
前需要安装google-perftools
与yep
包。ubuntu下安装命令为:
apt update
apt install libgoogle-perftools-dev
pip install yep
因为C++与Python不同,编译时可能会去掉调试信息,运行时也可能因为多线程产生混乱不可读的性能分析结果。为了生成更可读的性能分析结果,可以采取下面几点措施:
-g
生成调试信息。使用cmake的话,可以将CMAKE_BUILD_TYPE指定为RelWithDebInfo
Debug
编译性能会和-O2
或者-O3
有非常大的差别。Debug
模式下的性能测试是没有意义的OMP_NUM_THREADS=1
这个环境变量关闭openmp优化在运行完性能分析后,会生成性能分析结果文件。我们可以使用pprof
来显示性能分析结果。注意,这里使用了用Go
语言重构后的pprof
,因为这个工具具有web服务界面,且展示效果更好。
首先,安装 GO 环境,以Linux为例:
# step 1: 下载较新的的 GO 安装文件
wget https://golang.org/dl/go1.16.4.linux-amd64.tar.gz
# step 2: 删除系统旧版的 go
rm -rf /usr/local/go
# step 3: 解压到 /usr/local 目录
tar -xzf go1.16.4.linux-amd64.tar.gz -C /usr/local
# step 4: 设置环境变量
export GOROOT=/usr/local/go
export PATH=/root/gopath/bin:$GOROOT/bin:$PATH
# step 5: 验证安装
go version
然后,安装 pprof 命令:
go get github.com/google/pprof
生成日志文件:
python -m yep -- model.py --device=GPU ....
可以启动一个服务,查看火焰图:
pprof -http=0.0.0.0:8878 `which python` ./main.py.prof
对于模型代码,需要在训练的 for
循环中,添加如下代码:
if iter == 100:
profiler.start_profiler("All", "OpDetail")
if iter == 110:
profiler.stop_profiler("total", "./profile")
return
其中
start_profiler
的 trace_option 建议设置为 “Default“ 或 “OpDetail“ ,取10次迭代数据。
执行完之后,会在终端输出日志汇总结果,同时也会生成一个文件。该文件的路径为./profile
执行如下命令,可以生成 timeline 文件,方便在 chrom 浏览器中查看:
python Paddle/tools/timeline.py --profile_path=./profile --timeline_path=timeline
在模型训练相关的 for 循环中,添加如下代码:
nvprof_start()
和core.nvprof_stop()
控制profile的开始和结束core.nvprof_nvtx_push()
和core.nvprof_nvtx_pop()
添加要统计的特定event。在event开始前push event 的名称,在event结束后,进行 pop。for iter_id, data in enumerate(train_loader):
if iter_id == 100:
core.nvprof_start()
core.nvprof_enable_record_event()
core.nvprof_nvtx_push(str(iter_id))
if iter_id == 110:
core.nvprof_nvtx_pop()
core.nvprof_stop()
if iter_id > 100 and iter_id < 110:
core.nvprof_nvtx_pop()
core.nvprof_nvtx_push(str(iter_id))
执行如下命令生成 timeline 文件(参考:Paddle 30567):
nsys profile -o my_report -w true -t cuda,nvtx,osrt,cudnn,cublas -s cpu --capture-range=cudaProfilerApi --stop-on-range-end=true --cudabacktrace=true -x true -o my_profile python train.py
在可视化客户端中加载此文件,效果如下:
Profile Report中可以重点关注OP的调用次数,CPU时间和GPU时间。
timeline展示了模型训练过程中各个事件在时间轴上情况,模型训练时每一个step经历的阶段都是具有规律的,比如下图中的动态图模型timeline大致具有以下阶段:
数据读取 →前向计算→反向计算→optimizer参数更新→ClearGradient
我们可以根据需要,通过nvprof_nvtx_push
为一个step的不同阶段打上标记。
模型分析时,我们要关注timeline的哪些信息呢?
图中蓝色的矩形块显示了CUDA Kernel的执行,下面是CPU执行,左侧展示出了Kernel的GPU时间占比,可以结合这3部分确定模型的性能瓶颈。
timeline的表现可能有以下4种:下图中上面一行表示CPU执行,下面一行表示GPU执行
模型中可能是多种问题的混合。
前面提到的Profile Report可以给我们相对宏观的统计信息,要定位具体的性能瓶颈,常常还需要结合timeline的表现。通常可以按照以下技巧:
num_workers>0
时,使用多进程方式异步加载数据。如果发现两个step间隔较大,可尝试调大这个参数。如何评估一个优化点的性能收益
当timeline上发现某个kernel耗时严重,如何确认它的配置是什么?
有一些OP占比高,就只能通过优化CUDA Kernel吗?
OP1 -> OP2 -> OP3 -> OP4 -> OP2 -> OP5OP1 -> cast_to_float32 -> OP2 -> cast_to_float16 -> OP3 -> OP4 -> cast_to_float32 -> OP2 -> cast_to_float16 -> OP5
nsys profile -w true -t cuda,nvtx,osrt,cudnn,cublas -s cpu --capture-range=cudaProfilerApi --**stop**-**on**-range-**end**=true --cudabacktrace=true -x true -o my_profile python main.py
随着硬件算力的发展,以及AI技术的日益增进,我们不仅可以借助深度学习框架来加速分子动力学模拟,以及降低分子模拟开发的门槛。还可以实现高通量模拟,使得用最小的开销并行的运行多个分子模拟成为可能。