内存对象OpenCL的基地址

时间:2013-01-15 02:35:36

标签: pointers opencl base memory-address

我想用 OpenCL 在GPU上遍历一棵树,所以我在主机的一个连续块中组装树,然后我改变所有指针的地址,以便在设备上保持一致,如下所示:

TreeAddressDevice =(size_t)BaseAddressDevice +((size_t)TreeAddressHost - (size_t)BaseAddressHost);

我想要内存缓冲区的基地址: 在主机i为缓冲区分配内存,如下所示:         cl_mem tree_d = clCreateBuffer(...);

问题是cl_mems是跟踪数据内部表示的对象。从技术上讲,它们是指向对象的指针,但它们不是指向数据的指针。从内核中访问cl_mem的唯一方法是通过setKernelArgs将其作为参数传递。

这里http://www.proxya.net/browse.php?u=%3A%2F%2Fwww.khronos.org%2Fmessage_boards%2Fviewtopic.php%3Ff%3D37%26amp%3Bt%3D2900&b=28我找到了以下解决方案,但它不起作用:

__kernel void getPtr( __global void *ptr, __global void *out )

    {
    *out = ptr;
    }

可以按如下方式调用

代码:

...

    cl_mem auxBuf = clCreateBuffer( context, CL_MEM_READ_WRITE, sizeof(void*), NULL, NULL );
    void *gpuPtr;

    clSetKernelArg( getterKernel, 0, sizeof(cl_mem), &myBuf );
    clSetKernelArg( getterKernel, 1, sizeof(cl_mem), &auxBuf );
    clEnqueueTask( commandQueue, getterKernel, 0, NULL, NULL );
    clEnqueueReadBuffer( commandQueue, auxBuf, CL_TRUE, 0, sizeof(void*), &gpuPtr, 0, NULL, NULL );

    clReleaseMemObject(auxBuf);

...

现在" gpuPtr"应包含" myBuf"开头的地址在GPU内存空间。

解决方案很明显,我无法找到它?如何在创建缓冲区时返回指向设备内存的指针?

2 个答案:

答案 0 :(得分:1)

这是因为在OpenCL模型中,主机内存和设备内存是不相交的。设备内存中的指针在主机上没有任何意义。

您可以使用clEnqueueMapBuffer将设备缓冲区映射到主机内存。映射将使设备与主机同步,取消映射将使主机与设备同步。

<强>更新即可。正如您在评论中解释的那样,您希望将树结构发送到GPU。一种解决方案是将所有树节点存储在数组中,将指针替换为数组中具有索引的节点。

答案 1 :(得分:0)

正如Eric指出的那样,需要考虑两组内存:主机内存和设备内存。基本上,OpenCL尝试通过引入缓冲区对象来隐藏此交互的粗略细节,以便我们在主机端的程序中进行交互。现在,正如您所指出的,这种方法的问题在于,当我们想要做一些比OpenCL开发人员想要或允许在其范围内更棘手的东西时,它隐藏了我们设备的细节。这里的解决方案是记住OpenCL内核使用C99,并且该语言允许我们访问指针而没有任何问题。考虑到这一点,我们可以要求将指针存储在无符号整数变量中,以便稍后引用。

您的实现是在正确的轨道上,但它需要更多的C语法来完成传输。

OpenCL内核:

// Kernel used to obtain pointer from target buffer
__kernel void mem_ptr(__global char * buffer, __global ulong * ptr)
{
    ptr[0] = &buffer[0];
}

// Kernel to demonstrate how to use that pointer again after we extract it.
__kernel void use_ptr(__global ulong * ptr)
{
    char * print_me = (char *)ptr[0];
    /* Code that uses all of our hard work */
    /* ... */
}

主持人计划:

// Create the buffer that we want the device pointer from (target_buffer) 
//  and a place to store it (ptr_buffer).
cl_mem target_buffer = clCreateBuffer(context, CL_MEM_READ_WRITE, 
                                      MEM_SIZE * sizeof(char), NULL, &ret);
cl_mem ptr_buffer    = clCreateBuffer(context, CL_MEM_READ_WRITE,
                                      1 * sizeof(cl_ulong), NULL, &ret);

/* Setup the rest of our OpenCL program */    
/* .... */

// Setup our kernel arguments from the host...
ret = clSetKernelArg(kernel_mem_ptr, 0, sizeof(cl_mem), (void *)&target_buffer);
ret = clSetKernelArg(kernel_mem_ptr, 1, sizeof(cl_mem), (void *)&ptr_buffer);
ret = clEnqueueTask(command_queue, kernel_mem_ptr, 0, NULL, NULL);

// Now it's just a matter of storing the pointer where we want to use it for later.
ret = clEnqueueCopyBuffer(command_queue, ptr_buffer, dst_buffer, 0, 1 * sizeof(cl_ulong),
                          sizeof(cl_ulong), 0, NULL, NULL);
ret = clEnqueueReadBuffer(command_queue, ptr_buffer, CL_TRUE, 0,
                          1 * sizeof(cl_ulong), buffer_ptrs, 0, NULL, NULL);  

你有它。现在,请记住,您不必使用我使用的char变量;它适用于任何类型。但是,我建议使用cl_ulong来存储指针。对于可访问内存小于4GB的设备而言,这不重要。但对于具有较大地址空间的设备,您必须使用cl_ulong。如果您绝对需要在设备上节省空间,但设备的内存大于&gt; 4GB,那么您可以创建一个结构,可以将地址的低32位LSB存储为uint类型,MSB存储在一个小类型中。