我的机器出现了一些奇怪的问题:
随着时间的推移,性能不断下降。
我正在使用 TensorFlow 训练使用 GPU 的神经网络。我的数据是 xz 压缩的 float32 数组,它们驻留在一台机器的旋转磁盘驱动器上,以及另一台机器的 SSD 上。大约有 400,000 个数据文件。数据文件在后台线程中连续读取并放入队列中,该队列最多可以包含 1000 个项目。
在训练线程中,项目从队列前面弹出并以 200 个为一批传递给训练。
重启后,性能开始大约4每批只需几秒。经过几个小时的训练后,性能下降到16每批秒数。
我对训练的时间进行了详细的安排,一开始是这样的:
- 等待读取训练数据需 0.05 秒
- GPU 上处理一批数据需要 3.8 秒
- 写入摘要数据需要0.3秒。
训练后,时间变化很大:
- 读取数据需要 0.5 秒和 4 秒
- 处理一批需要 9 到 20 秒
- 写入摘要数据需 0.3 秒
值得注意的是,在批处理过程中,我以相当高的间隔监控了 nvidia-smi 的输出,并且似乎 GPU 利用率最多持续 1 秒。
这种糟糕的性能在多次调用训练过程以及注销和登录后仍然存在。重新启动机器会使时间恢复到原来水平。
自从这个问题出现后,我又买了一个 GPU(GTX 1080),并设置了一个几乎相同的系统。新机器也出现了速度变慢的情况。
我尝试过的事情
我检查了 CPU 使用率,最多使用 1 个 CPU,并且它的利用率始终保持在 100%,大多数时候是内核线程利用率。
我检查了内存使用情况,内存使用量为 10GB(总共 11GB)。这有点紧张,但系统没有启动交换(交换保持在 30MB)。
我检查了磁盘使用情况,除了我的代码执行数据读取之外,似乎没有发生任何奇怪的事情。
我已经使用 nvidia-smi 检查了 GPU 温度,它始终保持在 60°C 以下。
我检查了 CPU 和主板的温度,它们始终保持在 65°C 以下。
我不知道问题可能出在哪里。有什么想法吗?
眼镜
系统 1:
- Intel(R) Core(TM) i7 930 @ 2.80GHz,4 核,带超线程
- 11 GB 内存
- NVIDIA GeForce GTX 960,配备 4 GB VRAM
- Ubuntu 16.04.1 LTS 服务器,amd64 架构
- 专有 NVIDIA 驱动程序,版本 361.42
- 内核版本 4.4.0-31-generic
- Python 3.5.2
- TensorFlow 0.9.0
系统 2:
- Intel(R) Core(TM) i7 930 @ 2.80GHz,4 核,带超线程
- 11 GB 内存
- NVIDIA GeForce GTX 1080,配备 8 GB VRAM
- Ubuntu 16.04.1 LTS 服务器,amd64 架构
- 专有 NVIDIA 驱动程序,版本 367.35
- 内核版本 4.4.0-31-generic
- Python 3.5.2
- TensorFlow 0.9.0
更新
经过更多测试后,似乎速度缓慢的情况并不稳定。有时,批处理速度比最佳速度慢 10 倍,但随后又恢复正常。
I performed an strace on the process. The summary is this:
strace: Process 7351 attached
strace: Process 7351 detached
% time seconds usecs/call calls errors syscall
------ ----------- ----------- --------- --------- ----------------
95.40 0.674470 437 1545 126 futex
4.37 0.030860 2572 12 munmap
0.23 0.001627 814 2 madvise
0.00 0.000000 0 13 write
0.00 0.000000 0 10 mmap
0.00 0.000000 0 1 access
------ ----------- ----------- --------- --------- ----------------
100.00 0.706957 1583 126 total
然而,当一切似乎都正常工作时,这看起来非常相似。详细地说,我在这里上传了一个 strace 文件:
https://drive.google.com/open?id=0B8TdHRNT7E-0X3F4eF9xWlRsb2s
据我所知,几乎所有这些系统调用都是 futex 调用。我不太确定从中可以学到什么。
答案1
目前,我的问题似乎已经得到缓解。
libgoogle-perftools-dev
我通过安装软件包并在每次运行时启动以下命令完成了此操作:
LD_PRELOAD="/usr/lib/libmalloc.so"
这保证了更加稳定的性能,从那以后我再也没有遇到过任何明显的速度减慢的情况。
因此显然,GLIBC 分配器在长时间内收集垃圾时会遇到困难。
至于为什么我的问题似乎在调用过程中持续存在:我不知道。有可能是我误解了我的结果,并且各个进程彼此独立地变慢了。
无论如何,使用新的分配器运行我的代码超过一周并且没有出现任何速度减慢的情况,我可以说这个问题已经解决了。