performance - OpenCL clCreateContextFromType 函数导致内存泄漏
问题描述
我跑到valgrind
我的一个开源 OpenCL 代码 ( https://github.com/fangq/mmc ),它在OpenCL 主机代码中检测到大量内存泄漏。大多数人都指向我使用创建上下文对象的那一行clCreateContextFromType
。
我仔细检查了我所有的 OpenCL 变量、命令队列、内核和程序,并确保它们都已正确释放,但是,在对示例程序进行测试时,对mmc_run_cl()
函数的每次调用都会增加 300MB-400MB 的内存并且不会返回时释放。
您可以通过在终端中运行以下命令来重现 valgrind 报告:
git clone https://github.com/fangq/mmc.git
cd mmc/src
make clean
make all
cd ../examples/validation
valgrind --show-leak-kinds=all --leak-check=full ../../src/bin/mmc -f cube2.inp -G 1 -s cube2 -n 1e4 -b 0 -D TP -M G -F bin
假设您的系统安装了 gcc/git/libOpenCL 和 valgrind。-G 1
如果您想在其他 OpenCL 设备上运行它,请将输入更改为不同的数字(添加-L
到列表)。
在下表中,我列出了使用最新驱动程序+cuda 9 在 Linux 机器(Ubuntu 16.04)上的 NVIDIA GPU(TitanV)上检测到的每个 valgrind 泄漏的重复计数。
同样,大多数泄漏都与该clCreateContextFromType
行相关,我假设一些 GPU 内存没有释放,但我确实在主机代码的末尾释放了所有 GPU 资源。
您是否注意到我在主机代码中遗漏的任何内容?非常感谢您的意见
counts | error message
------------------------------------------------------------------------------------
380 ==27828== by 0x402C77: main (mmc.c:67)
Code: entry point to the below errors
64 ==27828== by 0x41CF02: mcx_list_gpu (mmc_cl_utils.c:135)
Code: OCL_ASSERT((clGetPlatformIDs(0, NULL, &numPlatforms)));
4 ==27828== by 0x41D032: mcx_list_gpu (mmc_cl_utils.c:154)
Code: context=clCreateContextFromType(cps,devtype[j],NULL,NULL,&status);
58 ==27828== by 0x41DF8A: mmc_run_cl (mmc_cl_host.c:111)
Code: entry point to the below errors
438 ==27828== by 0x41E006: mmc_run_cl (mmc_cl_host.c:124)
Code: OCL_ASSERT(((mcxcontext=clCreateContextFromType(cprops,CL_DEVICE_TYPE_ALL,...));
13 ==27828== by 0x41E238: mmc_run_cl (mmc_cl_host.c:144)
Code: OCL_ASSERT(((mcxqueue[i]=clCreateCommandQueue(mcxcontext,devices[i],prop,&status),status)));
1 ==27828== by 0x41E7A6: mmc_run_cl (mmc_cl_host.c:224)
Code: OCL_ASSERT(((gprogress[0]=clCreateBufferNV(mcxcontext,CL_MEM_READ_WRITE, NV_PIN, ...);
1 ==27828== by 0x41E7F9: mmc_run_cl (mmc_cl_host.c:225)
Code: progress = (cl_uint *)clEnqueueMapBuffer(mcxqueue[0], gprogress[0], CL_TRUE, ...);
10 ==27828== by 0x41EDFA: mmc_run_cl (mmc_cl_host.c:290)
Code: status=clBuildProgram(mcxprogram, 0, NULL, opt, NULL, NULL);
7 ==27828== by 0x41F95C: mmc_run_cl (mmc_cl_host.c:417)
Code: OCL_ASSERT((clEnqueueReadBuffer(mcxqueue[devid],greporter[devid],CL_TRUE,0,...));
更新 [2020 年 4 月 11 日]:
阅读@doqtor 的评论,我在 5 个不同的设备、2 个 NVIDIA GPU、2 个 AMD GPU 和 1 个 Intel CPU 上进行了以下测试。他说的是正确的——英特尔 OpenCL 库不会发生内存泄漏,我还发现 AMD OpenCL 驱动程序也很好。唯一的问题是 NVIDIA OpenCL 库似乎在我测试的两个 GPU(Titan V 和 RTX2080)上都有泄漏。
我的测试结果如下。使用本文介绍的psrecord 进行内存/CPU 分析。
我将提出一个关于如何使用 NVIDIA OpenCL 减少这种内存泄漏的新问题和赏金。如果你有这方面的经验,请分享。将在下面发布链接。谢谢
解决方案
我仔细检查了我所有的 OpenCL 变量、命令队列、内核和程序,并确保它们都已正确发布...
好吧,我仍然在 mmc 代码中发现了一个(微小的)内存泄漏:
==15320== 8 bytes in 1 blocks are definitely lost in loss record 14 of 1,905
==15320== at 0x4C2FB0F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==15320== by 0x128D48: mmc_run_cl (mmc_cl_host.c:137)
==15320== by 0x11E71E: main (mmc.c:67)
分配的内存greporter
不会被释放。所以这要由你来解决。
其余的是 OpenCL 库中的潜在内存泄漏。它们可能是也可能不是内存泄漏,例如库可能使用valgrind
无法识别或执行其他一些技巧的自定义内存分配器。有很多关于此的主题:
- clGetPlatformIDs 内存泄漏
- https://software.intel.com/en-us/forums/opencl/topic/753786
- https://github.com/KhronosGroup/OpenCL-ICD-Loader/issues/13
- OpenCL clGetPlatformIDs 给出了大约 230 个 valgrind memcheck 错误
一般来说,除非您想深入研究库代码并对此做点什么,否则您对此无能为力。我建议仔细压制那些来自图书馆的报道。可以按照 valgrind 手册中的说明生成抑制文件:https ://valgrind.org/docs/manual/manual-core.html#manual-core.suppress
...但是,在对示例程序进行测试时,对 mmc_run_cl() 函数的每次调用都会将内存增加 300MB-400MB,并且不会在返回时释放
你是怎么检查的?我还没有看到内存可疑地增长。我设置-n 1000e4
并让它运行了大约 2 分钟,其中分配的内存一直保持在我 RAM 大小的 ~0.6% 处。请注意,我没有在英特尔 GPU 和 CPU 上使用nvidia CUDA
,而是在 Ubuntu 18.04 上从包中安装。因此,您可以尝试尝试一下并检查是否有任何改变。POCL
libOpenCL
ocl-icd-libopencl1:amd64
========更新=================================
我已经按照您在评论中的描述重新运行它,第一次迭代后内存使用率为 0.6%,然后在第二次迭代后增加到 0.9%,之后下一次迭代没有增加内存使用率。除了我之前观察到的之外,Valgrind 也没有报告任何更新的内容。所以我建议链接到不同于 nvidia-cuda libOpenCL 并重新测试。
推荐阅读
- apache-kafka - Kafka中的retention.bytes是否限制每个副本的分区大小或分区的所有副本组合的大小?
- android - 空对象引用上的 onSaveInstanceState
- ios - React Native 在哪里可以找到 APPID
- arrays - 如何从 Typescript 中的数组中获取不同的值
- assembly - RISC-V 指令将脏缓存行写入下一级缓存
- vlc - 使用 VLC 到 RTSP 流屏幕捕获转码为 MJPEG
- postgresql - 如何防止使用 postgresql 自动转换时区?
- javascript - 使用 [key, object] 值迭代映射
- reactjs - 无法从反应 pod 向服务 pod 发出请求
- azure - Azure ARM 模板:使用变量设置参数值