首页 > 解决方案 > 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 减少这种内存泄漏的新问题和赏金。如果你有这方面的经验,请分享。将在下面发布链接。谢谢

标签: performancedebuggingmemory-leaksopenclvalgrind

解决方案


我仔细检查了我所有的 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无法识别或执行其他一些技巧的自定义内存分配器。有很多关于此的主题:

一般来说,除非您想深入研究库代码并对此做点什么,否则您对此无能为力。我建议仔细压制那些来自图书馆的报道。可以按照 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 上从包中安装。因此,您可以尝试尝试一下并检查是否有任何改变。POCLlibOpenCLocl-icd-libopencl1:amd64

========更新=================================

我已经按照您在评论中的描述重新运行它,第一次迭代后内存使用率为 0.6%,然后在第二次迭代后增加到 0.9%,之后下一次迭代没有增加内存使用率。除了我之前观察到的之外,Valgrind 也没有报告任何更新的内容。所以我建议链接到不同于 nvidia-cuda libOpenCL 并重新测试。


推荐阅读