在OpenCL中有效地交换内存缓冲区:实现
我遇到了与这里相同的问题:。我的第一个实现与问题中描述的相同,它在每个周期向设备写入/读取内存缓冲区。如前所述,这会引入无用的读/写缓冲区开销。下面的代码(内存开销)运行良好:在OpenCL中有效地交换内存缓冲区:实现,opencl,Opencl,我遇到了与这里相同的问题:。我的第一个实现与问题中描述的相同,它在每个周期向设备写入/读取内存缓冲区。如前所述,这会引入无用的读/写缓冲区开销。下面的代码(内存开销)运行良好: //THIS WORKS!!! f0_mem = clCreateBuffer( context, CL_MEM_READ_WRITE | CL_MEM_ALLOC_HOST_PTR, sizeof (int)*(capacity + 1), NULL
//THIS WORKS!!!
f0_mem = clCreateBuffer(
context,
CL_MEM_READ_WRITE | CL_MEM_ALLOC_HOST_PTR,
sizeof (int)*(capacity + 1),
NULL,
&err);
f1_mem = (..."the same as above"...);
m_d_mem = clCreateBuffer(..., CL_MEM_WRITE_ONLY | CL_MEM_ALLOC_HOST_PTR, sizeof (int)*capacity,...);
for (int k = 0; k < numelem; k++) {
sumK = sumK - weight[k];
cmax = 0;
cmax = max(capacity - sumK, weight[k]);
total_elements = (size_t) (capacity - cmax + 1);
if (k % 2 == 0) {
//clEnqueueWriteBuffer of cl_mem buffers
writeBufferToDevice(f0_mem, f1_mem, f0, f1);
setKernelArgs(f0_mem, f1_mem, weight[k], value[k], (int) total_elements);
} else {
//clEnqueueWriteBuffer of cl_mem buffers
writeBufferToDevice(f1_mem, f0_mem, f1, f0);
setKernelArgs(f1_mem, f0_mem, weight[k], value[k], (int) total_elements);
}
err = clEnqueueNDRangeKernel(queue, kernel, 1, NULL, global_work_items, NULL, 0, NULL, NULL);
//clEnqueueReadBuffer of cl_mem buffers
readBufferFromDevice(f0_mem, f1_mem, m_d_mem, f0, f1, m_d);
memcpy(M + k*capacity, m_d, sizeof (int)*capacity);
}
//这很有效!!!
f0_mem=clCreateBuffer(
上下文
CL_MEM_READ_WRITE|CL_MEM_ALLOC_HOST|PTR,
sizeof(int)*(容量+1),
无效的
&错误);
f1_mem=(…“同上”…);
m_d_mem=clCreateBuffer(…,CL_mem_WRITE_ONLY | CL_mem_ALLOC_HOST_PTR,sizeof(int)*容量,…);
for(int k=0;k
编辑:我的内核:
void kernel knapsack(global int *input_f, global int *output_f, global int *m_d, int cmax, int weightk, int pk, int maxelem){
int c = get_global_id(0)+cmax;
if(get_global_id(0) < maxelem){
if(input_f[c] < input_f[c - weightk] + pk){
output_f[c] = input_f[c - weightk] + pk;
m_d[c-1] = 1;
}
else{
output_f[c] = input_f[c];
}
}
}
void内核背包(全局int*input\f,全局int*output\f,全局int*m\d,int-cmax,int-weightk,int-pk,int-maxelem){
INTC=获取全局id(0)+cmax;
if(获取全局id(0)
在我尝试实施两个建议的解决方案后:
//ARGUMENTS SWAP
f0_mem = ...
f1_mem = ...
m_d_mem = ...
//clEnqueueWriteBuffer occurs hear
writeBufferToDevice( (cl_mem&) f0_mem, (cl_mem&) f1_mem, (cl_mem&) m_d_mem, (int*) f0, (int*) f1, (int*) m_d);
for (int k = 0; k < numelem; k++) {
/*
The same code block
*/
if (k % 2 == 0) {
setKernelArgs(f0_mem, f1_mem, weight[k], value[k], (int) total_elements);
} else {
setKernelArgs(f1_mem, f0_mem, weight[k], value[k], (int) total_elements);
}
err = clEnqueueNDRangeKernel(queue, kernel, 1, NULL, global_work_items, NULL, 0, NULL, NULL);
err = clEnqueueReadBuffer(queue, m_d_mem, CL_TRUE, 0, sizeof (int)*capacity, m_d, 0, NULL, NULL);
memcpy(M + k*capacity, m_d, sizeof (int)*capacity);
}
//参数交换
f0_mem=。。。
f1_mem=。。。
m_d_mem=。。。
//clEnqueueWriteBuffer
编写缓冲设备((cl_mem&)f0_mem,(cl_mem&)f1_mem,(cl_mem&)m_d_mem,(int*)f0,(int*)f1,(int*)m_d);
for(int k=0;k
第二个解决方案是这样实现的:
//TWO KERNELS
f0_mem = ...
f1_mem = ...
m_d_mem = ...
//clEnqueueWriteBuffer occurs hear
writeBufferToDevice( (cl_mem&) f0_mem, (cl_mem&) f1_mem, (cl_mem&) m_d_mem, (int*) f0, (int*) f1, (int*) m_d);
for (int k = 0; k < numelem; k++) {
/*
The same code block
*/
if (k % 2 == 0) {
setKernelArgs(f0_mem, f1_mem, weight[k], value[k], (int) total_elements);
clEnqueueNDRangeKernel(queue, kernel0, 1, NULL, global_work_items, NULL, 0, NULL, NULL);
} else {
setKernelArgs(kernel1, f1_mem, f0_mem, weight[k], value[k], (int) total_elements);
clEnqueueNDRangeKernel(queue, kernel1, 1, NULL, global_work_items, NULL, 0, NULL, NULL);
}
clEnqueueReadBuffer(queue, m_d_mem, CL_TRUE, 0, sizeof (int)*capacity, m_d, 0, NULL, NULL);
memcpy(M + k*capacity, m_d, sizeof (int)*capacity);
}
//两个内核
f0_mem=。。。
f1_mem=。。。
m_d_mem=。。。
//clEnqueueWriteBuffer
编写缓冲设备((cl_mem&)f0_mem,(cl_mem&)f1_mem,(cl_mem&)m_d_mem,(int*)f0,(int*)f1,(int*)m_d);
for(int k=0;k
这两种解决方案对我都不起作用(在我看来,根本不会发生交换!),我做错了什么
子问题:在最后两种解决方案中,在for循环之前,是否可以在不使用writeBufferToDevice(f0_mem、f1_mem、m_d_mem…)的情况下使用零填充内存缓冲区
这项工作基于这篇文章:
- 相关工作:
clFinish(命令)每次OpenCLAPI调用后,查看这是否会产生影响
除此之外,您还可以尝试第三种解决方案:在内核中交换指针。您需要将循环从CPU移动到GPU
inline void swap_pointers(__global double **A, __global double **B)
{
__global double *tmp = *A;
*A = *B;
*B = tmp;
}
__kernel void my_kernel(
__global double *pA,
__global double *pB,
...
)
{
for (int k = 0; k < numelem; k++)
{
// some stuff here
swap_pointers(&pA, &pB);
barrier(CLK_GLOBAL_MEM_FENCE | CLK_LOCAL_MEM_FENCE);
}
}
解决方案:
在将m_d复制到m之后的每个周期,m_d都应该重置,并使用背包::writeBuffer_m_d_ToDevice()写回m_d_mem buffer对象
不幸的是,clFinish(命令队列)没有任何区别。您的解决方案很好,但对我的项目不可行。我必须使用大块缓冲区,因此它们不能放入设备内存,或者传输时间太长。@NicoMkhatvari您能发布最小可编译版本来重现问题吗?。值得注意的是:决策矩阵和所选项目打印输出在“交换缓冲区”的情况下是错误的,但在原始代码中是正确的。很明显,您在某个地方弄乱了缓冲区顺序。我看你的CL代码没有问题。顺便说一句,对于第二种情况,循环中不需要setKernelArgs。这就是为什么要有2个内核,否则只需使用第一个案例。感谢setKernelArgs注释,你是对的。你说的混用缓冲区是什么意思,它们在内核计算期间不会重叠,因为它们是分开的(在每次迭代中,一个缓冲区用作输入,另一个用作输出),而且我还有线程c
clEnqueueReadBuffer(queue, m_d_mem, CL_TRUE, 0, sizeof (int)*capacity*numelem, m_d, 0, NULL, NULL);
ksack.readBuffer_m_d_FromDevice();
memcpy(M + k*capacity, m_d, sizeof (int)*capacity);
ksack.writeBuffer_m_d_ToDevice();//resets m_d_mem