所以我现在一直在玩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
b
和ret
是128位对齐的int数组。
时间大约是 22.026186 ms ,相比之下 198.604528 ms使用clEnqueueWriteBuffer
但是,当我将代码更改为
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 ms
可能是什么问题?或者这是一个问题吗?
编辑: 这是我在第二个代码中初始化数组的方法:
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];
}
答案 0 :(得分:1)
我的理解是CL_MEM_ALLOC_HOST_PTR分配但不复制。第二个代码块是否实际上将任何数据传送到设备上?
此外,clCreateBuffer与CL_MEM_USE_HOST_PTR和CL_MEM_COPY_HOST_PTR一起使用时不应该需要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(),以便清空命令队列并处理所有命令。
答案 1 :(得分:0)
使用正确的标志组合,你应该能够在英特尔集成显卡上实现“零拷贝”(即非常快)的map / unmap,因为它们都不需要“CPU到GPU”复制,因为它们都使用了相同的记忆(这就是“综合”的含义)。阅读内存中的Intel OpenCL Optimization Guide部分。