CL_MEM_ALLOC_HOST_PTR slower than CL_MEM_USE_HOST_PTR
CL_MEM_ALLOC_HOST_PTR slower than CL_MEM_USE_HOST_PTR
所以我已经在OpenCL上玩了一段时间,并测试了主机和设备之间的内存传输速度。我使用的是英特尔OpenCL SDK,运行在带有集成图形的英特尔i5处理器上。然后我发现了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数组。与使用clEnqueueWriteBuffer
的198.604528ms相比,时间约为22.026186ms然而,当我将代码更改为时
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.350065ms
可能是什么问题?或者这是个问题?
编辑:这就是我在第二段代码中初始化数组的方式:
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_TR分配但不复制。第二个代码块是否真的将任何数据传输到设备上?
此外,当与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实际
通过正确的标志组合,您应该能够在Intel Integrated Graphics上实现"零拷贝"(即非常快速)映射/取消映射,因为它们都使用相同的内存,所以不需要"CPU到GPU"的拷贝(这就是"集成"的含义)。阅读有关内存的"英特尔OpenCL优化指南"部分。
- 为cl.exe(Visual Studio代码)指定命令行C++版本
- 当我编译webrtc服务器时,Windows上只支持clang-cl
- CLANG 编译器 说:变量"PTR"可能未初始化
- 在以唯一ptr为值的C++映射中,动态内存何时会被销毁
- 将 ptr 传递给 ptr 到 A 作为参数传递给 A 的函数是不好的做法吗?
- 为共享 ptr 向量实现复制 c'tor?
- 字符和整数中 **(ptr+1) 的值差异
- C++:在不中断共享的情况下通过引用传递共享 PTR?
- 使用 cl 构建代码并连接到 sqlite 库
- 如何将派生类从基 ptr 分配给 nlohmann::json
- 引用 std::shared:ptr 以避免引用计数
- MSYS2 MinGW64 在 Windows 上构建 GMP/MPFR 作为静态库,并将它们链接到使用 CL 编译的
- 为什么我不能在不进行任何转换的情况下将浮点数放入任何类型的 ptr 中?
- 在调用函数时,ptr** 和 ptr*& 之间是否有区别,或者首选C++?
- NMAKE:致命错误 U1077:cl.exe 和 nmake.exe 返回代码'0x2'
- 另一种类型的智能ptr,比如具有弱refs的unique_ptr
- Clang-CL 警告 strnicmp 已弃用,请使用 ISO C 并C++符合标准的名称_strnicmp
- 尝试打印出 *ptr++ 的值,以了解它是如何工作的
- 如何控制共享 ptr 引用计数?
- 在 OpenCL 库中找不到 cl::Error 类