c++ - CL_MEM_ALLOC_HOST_PTR 比 CL_MEM_USE_HOST_PTR 慢

标签 c++ memory opencl

所以我现在一直在研究 OpenCL 并测试主机和设备之间的内存传输速度。 我正在使用英特尔 OpenCL SDK 并在 Intel i5 Processor 上运行集成显卡。 然后我发现 clEnqueueMapBuffer 而不是 clEnqueueWriteBuffer 当像这样使用固定内存时,它的速度快了将近 10 倍:

int amt = 16*1024*1024;
...
k_a = clCreateBuffer(context,CL_MEM_READ_ONLY | CL_MEM_USE_HOST_PTR, sizeof(int)*amt, a, NULL);
k_b = clCreateBuffer(context,CL_MEM_READ_ONLY | CL_MEM_USE_HOST_PTR, sizeof(int)*amt, b, NULL);
k_c = clCreateBuffer(context,CL_MEM_WRITE_ONLY | CL_MEM_USE_HOST_PTR, sizeof(int)*amt, ret, NULL);

int* map_a = (int*) clEnqueueMapBuffer(c_q, k_a, CL_TRUE, CL_MAP_READ, 0, sizeof(int)*amt, 0, NULL, NULL, &error);
int* map_b = (int*) clEnqueueMapBuffer(c_q, k_b, CL_TRUE, CL_MAP_READ, 0, sizeof(int)*amt, 0, NULL, NULL, &error);
int* map_c = (int*) clEnqueueMapBuffer(c_q, k_c, CL_TRUE, CL_MAP_WRITE, 0, sizeof(int)*amt, 0, NULL, NULL, &error);
clFinish(c_q); 

其中 a bret 是 128 位对齐的 int 数组。 时间大约为 22.026186 毫秒,而使用 clEnqueueWriteBuffer 时为 198.604528 毫秒 但是,当我将代码更改为

k_a = clCreateBuffer(context,CL_MEM_READ_ONLY | CL_MEM_ALLOC_HOST_PTR, sizeof(int)*amt, NULL, NULL);
k_b = clCreateBuffer(context,CL_MEM_READ_ONLY | CL_MEM_ALLOC_HOST_PTR, sizeof(int)*amt, NULL, NULL);
k_c = clCreateBuffer(context,CL_MEM_WRITE_ONLY | CL_MEM_ALLOC_HOST_PTR, sizeof(int)*amt, NULL, NULL);

int* map_a = (int*)clEnqueueMapBuffer(c_q, k_a, CL_TRUE, CL_MAP_READ, 0, sizeof(int)*amt, 0, NULL, NULL, &error);
int* map_b = (int*)clEnqueueMapBuffer(c_q, k_b, CL_TRUE, CL_MAP_READ, 0, sizeof(int)*amt, 0, NULL, NULL, &error);
int* map_c = (int*)clEnqueueMapBuffer(c_q, k_c, CL_TRUE, CL_MAP_WRITE, 0, sizeof(int)*amt, 0, NULL, NULL, &error);

/** initiate map_a and map_b **/

时间增加到91.350065 毫秒

可能是什么问题?或者这根本就是个问题?

编辑: 这就是我在第二个代码中初始化数组的方式:

for (int i = 0; i < amt; i++)
{
    map_a[i] = i;
    map_b[i] = i;
}

现在我检查了一下,map_a 和 map_b 确实在程序末尾包含正确的元素,但 map_c 包含全 0。我这样做了:

clEnqueueUnmapMemObject(c_q, k_a, map_a, 0, NULL, NULL);
clEnqueueUnmapMemObject(c_q, k_b, map_b, 0, NULL, NULL);
clEnqueueUnmapMemObject(c_q, k_c, map_c, 0, NULL, NULL);

我的内核就是

__kernel void test(__global int* a, __global int* b, __global int* c)
{
    int i = get_global_id(0);
    c[i] = a[i] + b[i];
}   

最佳答案

我的理解是 CL_MEM_ALLOC_HOST_PTR 分配但不复制。第二个代码块是否真的将任何数据发送到设备上?

此外,当与 CL_MEM_USE_HOST_PTR 和 CL_MEM_COPY_HOST_PTR 一起使用时,clCreateBuffer 不应要求 clEnqueueWrite,因为缓冲区是使用 void *host_ptr 指向的内存创建的。

在 OpenCL 中使用“固定”内存应该是这样一个过程:

   int amt = 16*1024*1024;
   int Array[] = new int[amt];
   int Error = 0;

    //Note, since we are using NULL for the data pointer, we HAVE to use CL_MEM_ALLOC_HOST_PTR
    //This allocates memory on the devices
    cl_mem B1 = clCreateBuffer(context, CL_MEM_READ_WRITE | CL_MEM_ALLOC_HOST_PTR, sizeof(int)*amt, NULL, &Error); 

    //Map the Device memory to host memory, aka pinning it
    int *host_ptr = clEnqueueMapBuffer(queue, B1, CL_TRUE, CL_MAP_READ | CL_MAP_WRITE, 0, sizeof(int)*amt, 0, NULL, NULL, &Error); 

    //Copy from host memory to pinned host memory which copies to the card automatically`
    memcpy(host_ptr, Array, sizeof(int)*amt); 

    //Call your kernel and everything else and memcpy back the pinned back to host when
    //you are done

编辑:为了加快程序速度,您可以做的最后一件事是通过使用 CL_FALSE 而不是 CL_TRUE 来阻止内存读/写。只需确保在将数据复制回主机之前调用 clFinish(),以便清空命令队列并处理所有命令。

来源:OpenCL In Action

关于c++ - CL_MEM_ALLOC_HOST_PTR 比 CL_MEM_USE_HOST_PTR 慢,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17775738/

相关文章:

header - 如何在 opencl 内核中正确包含 header

c++ - 嵌入式文件作为 char 数组的编译器问题

c++ - “Warning: Comma within array index expression”,但逗号分隔函数参数

ios - 在创建新的 SCNNode 之前删除 SCNNode 不会释放内存

PHP加载大型csv文件 - 内存问题

c# - 附加到序列化集合

android - GPU 与 CPU 编程 : inconsistencies in processing times

c++ - 使用 Doxygen 从源文件生成代码

C++优先队列,逻辑错误,想不通

c++ - 创建 CvSVM vector 的 vector (数组)