NVidia-Docker2 性能优化
前面介绍了NVidia-docker的运行原理,那么接下来就是我们要考虑的重点了——启动性能。
在我的测试环境中,对比了使用nvidia-runtime启动容器与使用runc启动容器的启动延时:
使用runc启动一个nginx容器,耗时在400~600ms不等
使用nvidia-runtime启动一个nginx容器,耗时在1.3~1.5s不等
对比发现,差距还是很明显的,好奇问题发生在哪里?下面我们就来一探究竟。
打开日志
为了能够更好的查看各个组件的时间消耗,我们需要将日志级别调高以便能够清楚各个组件的时间消耗。
Docker daemon, 修改配置文件/etc/docker/daemon.json
中的,设置"debug": true, "log-level": "debug",
Containerd, 修改配置文件 /etc/containerd/config.toml
,设置[debug] address = "/run/containerd/debug.sock" # uid = 0 # gid = 0 level = "trace" [plugins] [plugins.linux] shim_debug = true
NVidia container runtime, 修改配置文件 /etc/nvidia-container-runtime/config.toml
,设置
[nvidia-container-cli] debug = "/var/log/nvidia-container-runtime-hook.log" [nvidia-container-runtime] debug = "/var/log/nvidia-container-runtime.log"
分析问题
通过nvidia-docker创建并运行一个GPU容器
分别查看各个组件的日志
通过docker+runc创建并运行一个普通容器
分别查看各个组件的日志
对比两个容器的创建和运行过程,发现nvidia-container-cli
耗时相对是最长的。而这个组件也是只有GPU容器才会运行的,由文档中所介绍所述,该组件主要是为了我们所创建的普通容器增加额外的NVidia驱动、软件库以及相应的命令。
查看该组件的日志:
研究上面的日志,可以发现有几点时间消耗比较长:
starting driver service
这个步骤消耗时间比较长,与下一个阶段花费了大概550ms结尾部分
terminating driver service
这个步骤,大概花费了220ms
发现耗时比较长的地方,那么就需要研究代码了
starting driver service
这个部分代码在这里,具体的调用过程,简单如下:
基于这个流程,我们不难发现日志中间花费了比较长的时间,主要就是设置了一个RPC-server,用来跟cuda以及nvml相关的驱动交互获取信息。
terminating driver service
这个部分代码在这里
优化
目前我们确认了耗时时间比较长的原因,那么我们如何优化呢?
一般特定场景都是有比较多的优化空间的,而我们这样的场景就是一个典型的特定场景
所有机器都存在于IDC机房
硬件偶尔可能会出错
驱动定期会升级
软件库版本会定期升级
也就是说上面分析的nvidia-container-cli 所查询的内容会变化,但是不是一直在变化的,因此基于这个出发点,我们可以制定优化策略:
将NVidia GPU卡的型号、驱动软件以及库版本、地址等信息固化到一个配置文件中,nvidia-container-cli去文件中查询
定期更新该信息文件
通过这种方式,预期可以节省500~800ms的查询时间。
解决
编译环境
最终会制作出RPM软件包,存在于dist目录中。
验证想法
为了能够快速验证想法,我将一台测试机器的硬件信息以及软件库版本信息硬编码到代码中,完成了一个初始版本,并在测试环境中验证。
结论
经过验证发现,启动一个GPU的容器,速度由原来的1.3~1.5s压缩到800ms左右,性能提升了40%多。
具体可以看下图,启动一个8卡的GPU容器时间(其中图中 Created
是容器创建时间,StartedAt
是容器启动时间,通过这两个时间的差,可以看出启动速度):
修改之前
修改之后
展望
在分析过程中只是分析了主要的流程,很多其他微小的间隔,没有深入分析,但是还是有很大潜力的,后面会继续深入挖掘。
版权声明: 本文为 InfoQ 作者【薛磊】的原创文章。
原文链接:【http://xie.infoq.cn/article/7dc9080bd107d7a47bec2acc3】。文章转载请联系作者。
评论