2014-10-09 68 views
0

我对使用OpenCL映射缓冲区的代码是否正确有点困惑。OpenCL缓冲区分配和映射的最佳实践

我有两个例子,一个使用CL_MEM_USE_HOST_PTR,一个使用CL_MEM_ALLOC_HOST_PTR。两者都在我的本地机器和OpenCL设备上运行并运行,但我对这是否是正确的映射方式感兴趣,以及它是否适用于所有OpenCL设备。我特别不确定USE_HOST_PTR的例子。

我只对缓冲区/地图的具体操作感兴趣。我知道我应该做错误检查等等。

CL_MEM_ALLOC_HOST_PTR:

// pointer to hold the result 
int * host_ptr = malloc(size * sizeof(int)); 

d_mem = clCreateBuffer(context,CL_MEM_READ_WRITE|CL_MEM_ALLOC_HOST_PTR, 
         size*sizeof(cl_int), NULL, &ret); 

int * map_ptr = clEnqueueMapBuffer(command_queue,d_mem,CL_TRUE,CL_MAP_WRITE, 
            0,size*sizeof(int),0,NULL,NULL,&ret); 
// initialize data 
for (i=0; i<size;i++) { 
    map_ptr[i] = i; 
} 

ret = clEnqueueUnmapMemObject(command_queue,d_mem,map_ptr,0,NULL,NULL); 

//Set OpenCL Kernel Parameters 
ret = clSetKernelArg(kernel, 0, sizeof(cl_mem), (void *)&d_mem); 

size_t global_work[1] = { size }; 
//Execute OpenCL Kernel 
ret = clEnqueueNDRangeKernel(command_queue, kernel, 1, NULL, 
          global_work, NULL, 0, 0, NULL); 

map_ptr = clEnqueueMapBuffer(command_queue,d_mem,CL_TRUE,CL_MAP_READ, 
          0,size*sizeof(int),0,NULL,NULL,&ret); 
// copy the data to result array 
for (i=0; i<size;i++){ 
    host_ptr[i] = map_ptr[i]; 
} 

ret = clEnqueueUnmapMemObject(command_queue,d_mem,map_ptr,0,NULL,NULL);   

// cl finish etc  

CL_MEM_USE_HOST_PTR:

// pointer to hold the result 
int * host_ptr = malloc(size * sizeof(int)); 
int i; 
for(i=0; i<size;i++) { 
    host_ptr[i] = i; 
} 

d_mem = clCreateBuffer(context,CL_MEM_READ_WRITE|CL_MEM_USE_HOST_PTR, 
         size*sizeof(cl_int), host_ptr, &ret); 

// No need to map or unmap here, as we use the HOST_PTR the original data 
// is already initialized into the buffer? 

//Set OpenCL Kernel Parameters 
ret = clSetKernelArg(kernel, 0, sizeof(cl_mem), (void *)&d_mem); 

size_t global_work[1] = { size }; 
//Execute OpenCL Kernel 
ret = clEnqueueNDRangeKernel(command_queue, kernel, 1, NULL, 
          global_work, NULL, 0, 0, NULL); 

// this returns the host_ptr so need need to save it (I assume it always will?) 
// although we do need to call the map function 
// to ensure the data is copied back. 
// There's no need to manually copy it back into host_ptr 
// as it uses this by default 
clEnqueueMapBuffer(command_queue,d_mem,CL_TRUE,CL_MAP_READ, 
        0,size*sizeof(int),0,NULL,NULL,&ret); 

ret = clEnqueueUnmapMemObject(command_queue,d_mem,map_ptr,0,NULL,NULL);   

// cl finish, cleanup etc 
+0

是的,看来你的理解是正确的。 – 2014-10-09 11:39:26

回答

0

如果使用CL_MEM_ALLOC_HOST_PTR 你有机会是OpenCL的底层实现可能使用页面锁定内存

这意味着该页面不能换出到磁盘上,并且主机和设备内存之间的传输将完成DMA风格而不会浪费CPU周期。因此,在这种情况下,CL_MEM_ALLOC_HOST_PTR将是最佳解决方案。

nVidia具有页面锁定(固定)内存功能,他们也应该在其OpenCL实现中使用它。对于AMD来说,如果他们也这样做,并不确定。查询here了解更多详情。

使用CL_MEM_USE_HOST_PTR只会让程序员的生活更容易,所以在不太可能的情况下当硬件不能使用页面锁定内存时,您可以使用此选项。

+0

嗨,谢谢你的回答。你能否包含一个更好的方法来实现不会引起性能问题的第一个例子?我不太确定我明白为什么我不确定使用设备内存中的缓存副本。 – AzaraT 2014-10-09 11:47:07

+0

嗯,这很有趣。我认为nVidia建议按照http://www.nvidia.com/content/cudazone/cudabrowser/downloads/papers/nvidia_opencl_bestpracticesguide.pdf进行映射,分配,写入,内核执行,并且他们还建议使用ALLOC_HOST_PTR来代替USE_HOST_PTR。我认为英特尔还建议使用ALLOC_HOST_PTR,否则您需要确保正确的页面边界。 https://software.intel.com/sites/landingpage/opencl/optimization-guide/index.htm。 ARM也是如此:http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0538e/BABJHCCH.html – AzaraT 2014-10-09 12:53:06

+1

ALLOC_HOST_PTR可能优于USE_HOST_PTR,因为运行时尽力获得最快的内存(例如固定页面)。 – 2014-10-09 13:02:48