如何在 OpenCL 中使用缓冲区分配和映射内存机制
How to use buffer allocation and mapping memory mechanism iin OpenCL?
我对使用 OpenCL 映射缓冲区的代码是否正确有点困惑。
我已经了解缓冲区/映射特定操作是在 OpenCL 环境中将映射(零拷贝(内存机制与 GPU 一起使用的最有效方法。
我不明白为什么res_nb
每次迭代都没有初始化为 0。在每次迭代中,res_nb
乘以 2
我知道我应该进行错误检查等等。
OpenCL 代码
__kernel void test(
__global uint* res_nb_g,
)
{
// atomicAdd will return the value which was stored at "res_nb_g" before "1" was added.
int i = atomic_add(res_nb_g, 1);
}
C 代码
cl_uint res_nb = 0;
cl_mem res_nb_g = clCreateBuffer(context, CL_MEM_READ_ONLY | CL_MEM_ALLOC_HOST_PTR | CL_MEM_COPY_HOST_PTR, sizeof(cl_uint), &res_nb, &clStatus);
clSetKernelArg(test_kernel, 0, sizeof(res_nb_g), &res_nb_g);
for (int run = 0; run < 10; run++) {
res_nb = *((cl_uint *)clEnqueueMapBuffer(clqueue, res_nb_g, CL_TRUE, CL_MAP_WRITE, 0, sizeof(cl_uint), 0, NULL, NULL, NULL));
res_nb = 0;
clEnqueueUnmapMemObject(clqueue, res_nb_g, &res_nb, 0, NULL, NULL);
clEnqueueNDRangeKernel(clqueue, test_kernel, 1, NULL, &g_work_size, &l_work_size, 0, NULL, NULL);
clFinish(clqueue);
res_nb = *((cl_uint *)clEnqueueMapBuffer(clqueue, res_nb_g, CL_TRUE, CL_MAP_READ, 0, sizeof(cl_uint), 0, NULL, NULL, &clStatus));
}
使用我的解决方案编辑:
cl_uint *res_nb = 0;
cl_mem res_nb_g = clCreateBuffer(context, CL_MEM_READ_WRITE | CL_MEM_ALLOC_HOST_PTR, sizeof(cl_uint), NULL, &clStatus);
clCheckError(clStatus);
clStatus = clSetKernelArg(test_kernel, 0, sizeof(res_nb_g), &res_nb_g);
clCheckError(clStatus);
for (cl_uint run = 0; run < nbruns; run++) {
res_nb = (cl_uint *)clEnqueueMapBuffer(clqueue, res_nb_g, CL_TRUE, CL_MAP_WRITE, 0, sizeof(cl_uint), 0, NULL, NULL, &clStatus);
clCheckError(clStatus);
*res_nb = 0;
clStatus = clEnqueueUnmapMemObject(clqueue, res_nb_g, res_nb, 0, NULL, NULL);
clCheckError(clStatus);
clStatus = clEnqueueNDRangeKernel(clqueue, test_kernel, 1, NULL, &g_work_size, &l_work_size, 0, NULL, NULL);
clCheckError(clStatus);
clFinish(clqueue); // Not necessary
res_nb = (cl_uint *)clEnqueueMapBuffer(clqueue, res_nb_g, CL_TRUE, CL_MAP_READ, 0, sizeof(cl_uint), 0, NULL, NULL, &clStatus);
clCheckError(clStatus);
// Edit: remark @ Andrew Savonichev
clStatus = clEnqueueUnmapMemObject(clqueue, res_nb_g, res_nb, 0, NULL, NULL);
clCheckError(clStatus);
}
首先,让我解释一下clEnqueueMapBuffer
的作用:它映射了一个设备缓冲区到主机地址空间,并返回指向此映射的指针记忆。确切地说,此指针必须传递给 clEnqueueUnmapMemObject
以便将更改提交回设备缓冲区。
res_nb = *((cl_uint *)clEnqueueMapBuffer(clqueue, res_nb_g, [...]);
在此行上,您可以立即取消引用指针并将值分配给本地变量。clEnqueueMapBuffer
返回的原始指针丢失。
clEnqueueUnmapMemObject(clqueue, res_nb_g, &res_nb, 0, NULL, NULL);
这条线可能会因CL_INVALID_VALUE
而失败,因为&res_nb
不是原始指针。它只是一个指向未知的局部变量的指针OpenCL 运行时。
res_nb = *((cl_uint *)clEnqueueMapBuffer(clqueue, res_nb_g, CL_TRUE, [...]);
这条线也有同样的问题,但它也没有相应的 clEnqueueUnmapMemObject
.即使缓冲区已映射为读取,您仍然必须调用clEnqueueUnmapMemObject
才能让运行时"释放"此映射记忆。
请参阅 openCL 中的 clEnqueueMapBuffer 和 clEnqueueUnmapMemObject规范以获取更多详细信息。
- 使用动态分配的数组会导致代码分析发出虚假的C6386缓冲区溢出警告
- 拥有映射的现代方法,该映射可以指向或引用已在堆栈上分配的不同类型的数据
- C++ 将元素分配给映射值时访问错误
- 如何分配适合容纳 T 类型对象的缓冲区(可能过度对齐、可能有运算符 new 等)
- char p[0]表示自动分配的缓冲区还是安全指针
- 有没有办法自动实现 sprintf 的缓冲区分配?
- D3D11:映射顶点缓冲区时E_OUTOFMEMORY
- 包含动态分配内存作为值的映射的取消定位速度有多快?
- 线程函数无法从堆上分配的缓冲区中读取字符
- 如何正确分配Fuse ReadDir()的缓冲区
- 将数据分配给了数组分配,但程序显示了以缓冲区超支的输出
- 如果可能,标准::映射分配是否静态
- 如何在 OpenCL 中使用缓冲区分配和映射内存机制
- 尝试为图像缓冲区分配内存时 ptr 值错误
- C++:通过从映射向量分配映射实例来填充映射的映射
- 动态分配映射指针值
- 静态数组缓冲区分配
- OpenCL缓冲区分配和映射最佳实践
- 在类成员中创建和分配映射
- 如何使用malloc分配映射键