OpenCL——Buffer和全局内存的区别
OpenCL - The difference between Buffer and global memory
在 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
是全局内存还是常量内存?我应该为 a
使用 __constant
限定符吗? cl_mem_flags(READ_ONLY
and READ_WRITE
)和内存限定符(global
and constant
)有什么联系?
__constant
限定符用于常量内存,一些卡在纹理缓存中获取它并从 __global 获得独立带宽,但大小非常有限。
__global __read_only * float
意味着,如果硬件认为合适,opencl 实现将尝试将其放入缓存(或使用其他数据路径),但它是 __global,因此仅受 vram 大小或其分数的限制,而不仅仅是 64kB(例如)对于 __constant。
这些限定符用于设备端优化。
在主机端优化时,您应该为其提供
CL_MEM_READ_ONLY
作为缓冲区创建的标志。这意味着设备只会从它读取(可能使用一些 DMA/pcie access/caching 优化)但可以使用 enqueuewrite 或 map unmap 操作从主机端写入(作为主机,如 C# C++ 代码,而不是设备) .
__constant
用于参数常量定义,不适用于要处理的数据。
如果您正在编写过滤器代码,则数据可以是 __global,过滤器掩码可以是 __constant,如果它不适合 __private 内存(具有最终带宽)或 __local 内存(比私有内存慢)因此访问掩码字节不会减少数据带宽。
现在回答你的问题:
" is a_buffer a global memory or constant memory? "
它在设备端(内核端)是全局的 因为你将它声明为 __global 但它可以在主机端(硬件)的任何地方。
编辑:对于主机端,取决于使用了哪些其他标志,例如,USE_HOST_PTR 使其可以从系统 RAM 直接访问并且只有一个设备端的虚拟缓冲区,没有它并且只有 CL_MEM_READ_WRITE 设备内存将有一个真实的缓冲区及其在 RAM 中的映射影子(作为 clenqueueread 或 clenqueueewrite 的子步骤)并且复制将首先访问这个影子然后上传到 GPU。
示例设备:4GB DDR3L 笔记本电脑中的 Intel(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 寄存器 space 每个线程或一半(由于编译器优化),然后由于溢出到全局内存而变慢。
在 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
是全局内存还是常量内存?我应该为 a
使用 __constant
限定符吗? cl_mem_flags(READ_ONLY
and READ_WRITE
)和内存限定符(global
and constant
)有什么联系?
__constant
限定符用于常量内存,一些卡在纹理缓存中获取它并从 __global 获得独立带宽,但大小非常有限。
__global __read_only * float
意味着,如果硬件认为合适,opencl 实现将尝试将其放入缓存(或使用其他数据路径),但它是 __global,因此仅受 vram 大小或其分数的限制,而不仅仅是 64kB(例如)对于 __constant。
这些限定符用于设备端优化。
在主机端优化时,您应该为其提供
CL_MEM_READ_ONLY
作为缓冲区创建的标志。这意味着设备只会从它读取(可能使用一些 DMA/pcie access/caching 优化)但可以使用 enqueuewrite 或 map unmap 操作从主机端写入(作为主机,如 C# C++ 代码,而不是设备) .
__constant
用于参数常量定义,不适用于要处理的数据。
如果您正在编写过滤器代码,则数据可以是 __global,过滤器掩码可以是 __constant,如果它不适合 __private 内存(具有最终带宽)或 __local 内存(比私有内存慢)因此访问掩码字节不会减少数据带宽。
现在回答你的问题:
" is a_buffer a global memory or constant memory? "
它在设备端(内核端)是全局的 因为你将它声明为 __global 但它可以在主机端(硬件)的任何地方。
编辑:对于主机端,取决于使用了哪些其他标志,例如,USE_HOST_PTR 使其可以从系统 RAM 直接访问并且只有一个设备端的虚拟缓冲区,没有它并且只有 CL_MEM_READ_WRITE 设备内存将有一个真实的缓冲区及其在 RAM 中的映射影子(作为 clenqueueread 或 clenqueueewrite 的子步骤)并且复制将首先访问这个影子然后上传到 GPU。
示例设备:4GB DDR3L 笔记本电脑中的 Intel(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 寄存器 space 每个线程或一半(由于编译器优化),然后由于溢出到全局内存而变慢。