在Opencl中,缓冲区是通过主机应用程序传递数据的渠道。
cl_mem clCreateBuffer (cl_context context, cl_mem_flags flags, size_t size,
void *host_ptr, cl_int *errcode_ret);
现在,如果我将缓冲区a_buffer
扩展为READ_ONLY
,则内核为:
__kernel void two_buffer_double(__global float* a)
{
int i = get_global_id(0);
float b = a[i] * 2;
}
我的问题是:a_buffer
是全局记忆还是常量记忆?我应该对__constant
使用a
限定符吗? cl_mem_flags(READ_ONLY
和READ_WRITE
)与内存限定符(global
和constant
)之间的联系是什么?
答案 0 :(得分:2)
__constant
限定符用于常量内存,有些卡在纹理缓存中获取并从__global获得独立带宽,但其大小非常有限。
__global __read_only * float
意味着,opencl实现会尝试将其放入缓存(或使用其他数据路径),如果硬件看起来合适,但它是__global,因此仅受vram大小或其分数的限制,而不仅仅是64kB(例如)__constant。
这些限定符用于设备端优化。
在主机端优化时,您应该为其提供
CL_MEM_READ_ONLY
作为缓冲区创建的标志。这意味着设备只会从中读取(可能使用某些DMA / pcie访问/缓存优化),但可以使用enqueuewrite或map unmap操作从主机端(如C#C ++代码,而不是设备)编写。
__constant
用于参数常量定义,不适用于要处理的数据。
如果您正在编写过滤器代码,则数据可能是__global,如果不能适合__private内存(具有最终带宽)或__本地内存(慢于私有),则过滤掩码可能是__constant,因此访问掩码字节不会减少数据带宽。
现在回答您的问题:
" a_buffer是全局内存还是常量内存? "
它是设备端(内核端)的全局,因为您将其声明为__global,但它可能位于主机端(硬件)的任何位置。
编辑:用于主机端,取决于使用哪些其他标志,例如,USE_HOST_PTR使其可以直接从系统RAM访问,并且设备端只有一个虚拟缓冲区,没有它和只有一个CL_MEM_READ_WRITE设备内存将有一个真正的缓冲区及其在RAM中的映射阴影(作为clenqueueread或clenqueuewrite的子步骤)和复制将首先访问此阴影然后上传到gpu。
示例设备:4GB DDR3L笔记本电脑中的英特尔(R)HD(TM)GRAPHICS 400:
Query value
CL_DEVICE_MAX_CONSTANT_BUFFER_SIZE 65536 bytes
CL_DEVICE_GLOBAL_MEM_CACHE_SIZE 262144 bytes
CL_DEVICE_GLOBAL_MEM_SIZE 1636414260 bytes
CL_DEVICE_GLOBAL_MEM_CACHE_TYPE CL_READ_WRITE_CACHE
CL_DEVICE_LOCAL_MEM_SIZE 65536(vs constant, benchmark it)
CL_DEVICE_LOCAL_MEM_TYPE CL_LOCAL(so is faster than global)
你不能查询私人内存大小,但对于中段游戏amd卡,它是每个线程组256kB。如果每组设置64个线程,它可以在每个线程使用4kB寄存器空间或其中一半(由于编译器优化),然后因为溢出到全局内存而变慢。