Memory management 如何在OpenCL中使用程序(全局)范围内的数组

Memory management 如何在OpenCL中使用程序(全局)范围内的数组,memory-management,global-variables,constants,opencl,Memory Management,Global Variables,Constants,Opencl,AMD OpenCL编程指南,第6.3节恒定内存优化: 全局作用域常量数组。这些数组已初始化, 全局作用域,并在常量地址空间中(如中所指定 OpenCL规范第6.5.3节)。如果数组的大小为 在64KB以下,它被放置在硬件常量缓冲区中;否则, 使用全局内存。这方面的一个例子是数学查找表 功能 我想使用这个“全局作用域常量数组”。我用纯C语言编写了这样的代码 #define SIZE 101 int *reciprocal_table; int reciprocal(int number){

AMD OpenCL编程指南,第6.3节恒定内存优化:

全局作用域常量数组。这些数组已初始化, 全局作用域,并在常量地址空间中(如中所指定 OpenCL规范第6.5.3节)。如果数组的大小为 在64KB以下,它被放置在硬件常量缓冲区中;否则, 使用全局内存。这方面的一个例子是数学查找表 功能

我想使用这个“全局作用域常量数组”。我用纯C语言编写了这样的代码

#define SIZE 101
int *reciprocal_table;

int reciprocal(int number){
  return reciprocal_table[number];
}

void kernel(int *output)
{
  for(int i=0; i < SIZE; i+)
    output[i] = reciprocal(i);
}
我应该如何处理全局变量
倒数_表
?如果我尝试向其添加
\uuu全局
\uu常量
,我会得到一个错误:

global variable must be declared in addrSpace constant
我不想将
常量int*倒数表
内核
传递到
倒数
。是否可以以某种方式初始化全局变量?我知道我可以把它写进代码中,但还有其他的方法吗

另外,我正在使用AMD OpenCL

UPD以上代码只是一个示例。我有很多函数的复杂代码。所以我想在程序范围内创建数组,以便在所有函数中使用它

UPD2更改了示例代码并添加了《编程指南》中的引文

#define SIZE 2
int constant array[SIZE] = {0, 1};

kernel void
foo (global int* input,
     global int* output)
{
    const uint id = get_global_id (0);
    output[id] = input[id] + array[id];
}
我可以得到上述编译与英特尔以及AMD。它也可以在不初始化数组的情况下工作,但是您将不知道数组中有什么,并且由于它位于常量地址空间中,因此无法分配任何值

如本标准第6.5.3节所述,程序全局变量必须位于_常量地址空间中

更新现在,我完全理解了这个问题:

对我来说,一件有效的事情是在常量空间中定义数组,然后通过传递一个内核参数
constant int*array
覆盖数组来覆盖它。 仅在GPU设备上产生正确的结果。AMD CPU设备和Intel CPU设备没有覆盖阵列地址。它也可能不符合标准

下面是它的外观:

#define SIZE 2
int constant foo[SIZE] = {100, 100};

int
baz (int i)
{
  return foo[i];
}

kernel void
bar (global int* input,
     global int* output,
     constant int* foo)
{
    const uint id = get_global_id (0);
    output[id] = input[id] + baz (id);
}
对于input={2,3}和foo={0,1},这将在我的hd7850设备(Ubuntu 12.10,Catalyst 9.0.2)上生成{2,4}但是在CPU上,我得到了{102103}的OCL实现(AMD,Intel)。所以我不能强调,我个人有多大程度上不会这样做,因为这只是时间问题,在这一切结束之前

实现这一点的另一种方法是在运行时使用主机根据数组的定义(或预定义它们)计算.h文件,并在编译时通过编译器选项将它们传递给内核。当然,这需要为每个不同的LUT重新编译clProgram/clKernel

我可以得到上述编译与英特尔以及AMD。它也可以在不初始化数组的情况下工作,但是您将不知道数组中有什么,并且由于它位于常量地址空间中,因此无法分配任何值

如本标准第6.5.3节所述,程序全局变量必须位于_常量地址空间中

更新现在,我完全理解了这个问题:

对我来说,一件有效的事情是在常量空间中定义数组,然后通过传递一个内核参数
constant int*array
覆盖数组来覆盖它。 仅在GPU设备上产生正确的结果。AMD CPU设备和Intel CPU设备没有覆盖阵列地址。它也可能不符合标准

下面是它的外观:

#define SIZE 2
int constant foo[SIZE] = {100, 100};

int
baz (int i)
{
  return foo[i];
}

kernel void
bar (global int* input,
     global int* output,
     constant int* foo)
{
    const uint id = get_global_id (0);
    output[id] = input[id] + baz (id);
}
对于input={2,3}和foo={0,1},这将在我的hd7850设备(Ubuntu 12.10,Catalyst 9.0.2)上生成{2,4}但是在CPU上,我得到了{102103}的OCL实现(AMD,Intel)。所以我不能强调,我个人有多大程度上不会这样做,因为这只是时间问题,在这一切结束之前


实现这一点的另一种方法是在运行时使用主机根据数组的定义(或预定义它们)计算.h文件,并在编译时通过编译器选项将它们传递给内核。当然,这需要为每个不同的LUT重新编译clProgram/clKernel。

看起来“array”是一个查找表。您需要使用clCreateBuffer和clEnqueueWriteBuffer,这样GPU就可以使用它的一个副本。

它看起来像是一个查找表。您需要clCreateBuffer和clEnqueueWriteBuffer,这样GPU就可以使用它的副本了。

不久前,我在自己的程序中很难找到这项工作。 我没有找到任何方法通过一些clEnqueueWriteBuffer等从主机初始化常量或全局作用域数组。唯一的方法是在.cl源文件中明确地编写它

所以在这里,我从主机初始化它的技巧是使用您实际上是从主机编译源代码的事实,这也意味着您可以在编译之前更改src.cl文件

首先,我的src.cl文件读取:

__constant double lookup[SIZE] = { LOOKUP };    // precomputed table (in constant memory).

double func(int idx) {
  return(lookup[idx])
}

__kernel void ker1(__global double *in, __global double *out)
{
   ... do something ...
   double t = func(i)
   ...
}
请注意,查找表是用lookup初始化的

然后,在宿主程序中,在编译OpenCL代码之前:

  • 计算主机_值[]中我的查找表的值
  • 在主机上,运行以下操作:

    char *buf = (char*) malloc( 10000 );
    int count = sprintf(buf, "#define LOOKUP ");    // actual source generation !
    for (int i=0;i<SIZE;i++) count += sprintf(buf+count, "%g, ",host_values[i]);
    count += sprintf(buf+count,"\n");
    
    char*buf=(char*)malloc(10000);
    int count=sprintf(buf,#定义查找”);//实际源代码生成!
    
    对于(inti=0;i,不久前我努力在自己的程序中获得这项工作。 我没有找到任何方法通过clEnqueueWriteBuffer等从主机初始化常量或全局作用域数组。唯一的方法是在.cl源文件中明确地写入它

    所以在这里,我从主机初始化它的技巧是使用您实际上是从主机编译源代码的事实,这也意味着您可以在编译之前更改src.cl文件

    首先是我的src.cl文件r