Kernel OpenCL-为什么使用只读或只写缓冲区

Kernel OpenCL-为什么使用只读或只写缓冲区,kernel,buffer,opencl,flags,pyopencl,Kernel,Buffer,Opencl,Flags,Pyopencl,在OpenCL中,将缓冲区标记为READ_ONLY或WRITE_ONLY是否有任何性能优势 这个内核是我经常看到的(a是只读,b是只写): 这个内核似乎更好,因为它使用更少的全局内存(a是读写): READ\u ONLY和WRITE\u ONLY标志是否仅用于帮助调试和捕获错误?这取决于 READ\u ONLY\u global内存位置存储在“全局/恒定内存数据缓存”中,它比GPU(请参阅)上的普通缓存或RAM快得多,在CPU上则无所谓 我不知道WRITE_的任何优点,也许它也有帮助,因为GPU

OpenCL
中,将缓冲区标记为
READ_ONLY
WRITE_ONLY
是否有任何性能优势

这个
内核
是我经常看到的(a是
只读
,b是
只写
):

这个
内核
似乎更好,因为它使用更少的全局内存(a是
读写
):

READ\u ONLY
WRITE\u ONLY
标志是否仅用于帮助调试和捕获错误?

这取决于

READ\u ONLY\u global
内存位置存储在“全局/恒定内存数据缓存”中,它比GPU(请参阅)上的普通缓存或RAM快得多,在CPU上则无所谓

我不知道WRITE_的任何优点,也许它也有帮助,因为GPU知道它可以流式输出数据,而无需缓存


如果您不确定,就去测量它。

要直接回答您的问题,我会说:不,这些标志的存在不仅仅是为了帮助调试和捕获错误。但是,很难给出任何实现如何使用这些标志以及它们如何影响性能的参考

我的理解是(遗憾的是,没有任何文档支持)在使用这些标志时,您会对缓冲区的使用方式施加更多限制,因此您可以帮助运行时/驱动程序/编译器做出一些可能会提高性能的假设。例如,我设想,在内核使用只读缓冲区时,不必担心内存的一致性,因为工作项不应该写入其中。因此,可以跳过一些检查……不过在Opencl中,您应该自己使用屏障等来处理这些检查

还请注意,自从OpenCL1.2以来,还引入了一些其他标志,这些标志与主机需要如何访问缓冲区有关。有:

CL_MEM_HOST_NO_ACCESS,
CL_MEM_HOST_{READ, WRITE}_ONLY,
CL_MEM_{USE, ALLOC, COPY}_HOST_PTR
我猜它必须再次帮助实施opencl的人员提高性能,但我想我们需要一些AMD或NVIDIA专家的意见

请注意,到目前为止,我所说的都是我的想法,并不是基于任何严肃的文档(我没有找到任何)


另一方面,我可以肯定地告诉您,标准并没有像@Quonux所说的那样强制只读缓冲区位于常量空间中。有些实现可能是为了小缓冲区而这样做的。不要忘记,恒定空间内存很小,因此只读缓冲区可能太大而无法容纳。确保缓冲区位于常量空间内存中的唯一方法是在内核代码中使用常量关键字,如前所述。当然,在主机端,如果要使用常量缓冲区,必须使用只读标志。

注意,实际上有两种类型。在分配缓冲区时,您有
CL\u MEM\u READ\u
CL\u WRITE\u-ONLY
CL\u MEM\u READ\u-WRITE
,但是您也有
\u READ\u
\u WRITE\u-ONLY
来装饰内核代码中的指针

这些可以用于优化和错误检查。让我们先看看表演。如果遇到只写缓冲区,则不需要缓存写操作(如直写缓存),从而为读取节省更多缓存。这在很大程度上取决于GPU硬件,至少NVIDIA硬件具有实际实现这一点所需的指令(
.cs
.lu
修饰符)。你可以参考他们的。我没有看到编译器实际执行此优化的任何证据,例如:

\uuuuu内核void Memset4(\uuuu全局\uuuu写\uu仅无符号int*p\u dest,
常量无符号整数n_dword_num)
{
无符号整数i=获取全局id(0);
如果(i
编译为:

st.global.u32 [%r10], %r11; // no cache operation specified
这是有道理的,因为CUDA没有这些限定符的等价物,所以编译器很可能会默默地忽略这些限定符。但把他们放在那里也没什么坏处,我们将来可能会更幸运。在CUDA中,通过使用函数和使用编译器标志选择加入/退出缓存L1中的全局内存传输(
-Xptxas-dlcm=cg
),可以公开其中一些功能。如果您发现绕过缓存产生了一个主要优势,那么也可以始终使用
asm

至于错误检查,在内核声明中使用
const
说明符可以很容易地避免写入只读缓冲区。在纯“C”中,不允许从只写缓冲区读取数据是不可能的

将这些缓冲区映射到主机内存时,会发生另一种可能的优化。映射
CL\u MEM\u READ\u
缓冲区时,映射的区域可能未初始化,因为主机只会写入该内存,而设备只会读取它。类似地,当取消映射
CL_MEM_WRITE_ONLY
缓冲区时,驱动程序不需要将(可能由主机修改的)内容从主机内存复制到设备内存。我没有测量这个

作为补充说明,我尝试使用:

inline unsigned int n\u StreamingLoad(\uuu global\uu只读常量unsigned int*p\u src)
{
#英伟迪亚酒店
无符号整数n_结果;
asm(“ld.global.cs.u32%r0,[%r1];”:“=r”(n_结果):“r”(p_src));
返回n_结果;
#else//NVIDIA
return*p_src;//泛型
#endif//NVIDIA
}
内联void StreamingWrite(\uuuuu global\uuuu write\u only unsigned int*p\u dest,const unsigned int n\u value)
{
#英伟迪亚酒店
asm(“st.global.cs.u32[%r0],%r1;”:“r”(p_dest),“r”(n_值):“内存”);
#else//NVIDIA
*p_dest=n_值;//通用
#endif//NVIDIA
}
即使在带有
sm35
设备(在GTX 780和K40上测试)的简单memcpy内核上,也能为您提供大约15 GB/sec的额外带宽。在CL_MEM_HOST_NO_ACCESS, CL_MEM_HOST_{READ, WRITE}_ONLY, CL_MEM_{USE, ALLOC, COPY}_HOST_PTR
st.global.u32 [%r10], %r11; // no cache operation specified