OpenCL clBuildProgram 缓存源代码,如果#include 的源代码发生变化则不会重新编译

OpenCL clBuildProgram caches source, and does not recompile if #include'd source changes

我用opencl实现了一个项目。我有一个包含内核函数的文件,内核使用的函数包含在一个单独的头文件中,但是当我更改包含的文件时,有时应用更改,有时不应用更改,这让我感到困惑应用程序是否有错误。

我检查了 Whosebug 中的其他帖子,发现 nvidia 在传递 -I{include directory} 方面存在严重问题,所以我更改了它并明确给出了头文件地址,但 opencl 编译器仍然无法找到错误在包含在内核文件名中的头文件中。

此外,我使用的是 nvidia gtx 980,我的电脑上安装了 CUDA 7.0。

有人有同样的经历吗?我该如何解决?

所以,假设我有这样一个内核:

#include "../../src/cl/test_kernel_include.cl"

void __kernel test_kernel(
  __global int* result,
  int n
  )
{
  int thread_idx = get_global_id(0);
  result[thread_idx] = test_func();
}

其中test_kernel_include.cl如下:

int test_func()
{
  return 1;
}

然后我 运行 代码,我得到一个数组,如我们所料,所有成员都等于 1。现在,我将 test_kernel_include.cl 更改为:

int test_func()
{
  return 2;
}

但结果仍然是一个数组,所有成员都等于 1,应该更改为 2,但事实并非如此。

为了缩短内核编译时间,NVIDIA 实施了一种缓存方案,将编译后的内核二进制文件存储到磁盘,并在下次编译同一内核时加载。一些散列是在内核源代码上计算出来的,然后用作编译内核缓存的索引。

不幸的是,这些散列不包含任何主要内核源代码包含的头文件。这意味着当您更改包含的头文件中的某些内容时,驱动程序将基本上忽略更改并从磁盘重新加载以前的内核二进制文件(除非主内核源代码中也发生了更改)。

在 Linux 系统上,内核缓存可以在 ~/.nv/ComputeCache 中找到。如果您在更改其中一个包含文件后删除此目录,那么它应该会强制驱动程序实际重新编译 OpenCL 内核。

在平台初始化之前执行此操作:

setenv("CUDA_CACHE_DISABLE", "1", 1);

它将禁用构建的缓存机制。 它也适用于 OpenCL 平台,即使它说的是 CUDA。