我有一个处理大图像的内核(OpenCL 1.1,数据类型是image2d_t)。有时我只想处理这个图像的区域。显而易见的解决方案是使用全局工作偏移。我希望这会产生性能提升,但到目前为止,我只能通过非零偏移获得更差的执行时间!
// Image is 4096x4096 pixels. Local work size is 8x8.
//
// Example A:
globalWorkSize = { 4096, 4096 };
globalWorkOffset = { 0, 0 };
// Execution time is 38 seconds
//
// Example B:
globalWorkSize = { 3296, 3296 };
globalWorkOffset = { 400, 400 };
// Execution time is 58 seconds <------------------ ?!
//
// Example C: Cropped image @ 3296x3296 pixels
globalWorkSize = { 3296, 3296 };
globalWorkOffset = { 0, 0 };
// Execution time is 28 seconds
有人可以解释为什么我会得到这些结果吗?
答案 0 :(得分:1)
Lubo Antonov认为数据访问对齐对性能很重要。但另一个参数是以跨步模式访问内存。
从x = 400和y = 400开始的你的例子是:
. = item
x = work item
c = memory channel
stride = 4096 between y_item=1 and y_item=2 and in this stride,
some of memory channels are left in "." areas and unused
unused channel
^
|
c c c c c c c c c c
. . . . . . . . . .
. x x x x x x x x x
. x x x x x x x x x
. x x x x x x x x x
. x x x x x x x x x
. x x x x x x x x x
. x x x x x x x x x
. x x x x x x x x x
. x x x x x x x x x
. x x x x x x x x x
当然,前400个未使用像素中有更多通道,但其中一些通道的数量少于“x”工作区中的其他通道。例如,通道2,3,4,5,6,7在“x”中被访问了20次,但是通道1被访问了25次,这迫使对其进行比其他通道更加序列化的访问。
如果跨步区域具有与非跨步区域不同的存储器通道数量,则高速2次跨步存储器访问使用较少的存储器通道/存储体并降低性能。
Z-ordering支持硬件性能的优势也可能在工作区的左边缘被打破。
如果每个扫描线不是gpu中计算单元数量的精确倍数,则同一计算单元可能无法从L1缓存中的最后一个扫描线获取缓存数据(请记住Z-ordering访问和邻居访问,如高斯过滤器)
c = compute unit, S=selected compute unit for observation
kernel is accessing neighbour pixels too, for filtering, for example
gpu has 10 compute units
strided: L1 cache not hit
..........
.cccSccccc
.ccccScccc
.cccccSccc
.ccccccScc
.cccccccSc
.ccccccccS
non-strided: pixel[y-1] is already in L1, cache hit, more performance
..........
cccScccccc
cccScccccc
cccScccccc
cccScccccc
cccScccccc
但这并不能保证,只是一个关于工作项的本能被分配用于最大的核心职业,其中每个核心的gpu通过迭代工作分配而不是这样分别加载:首先填充然后填充第二个然后填充第三个等等....填充第一个核心将有利于核心效率,但是其他核心未被占用会破坏拥有更多核心的优势。这也需要一个远程过滤内核。 5x5滤波器仅受益于边缘像素,而51x51滤波器将包含多个工作组。
答案 1 :(得分:1)
尽管使用图像似乎是正确的选择,但它可能并非总是如此。
如果你不需要在像素之间进行插值而不需要边框颜色处理,那么在图像上使用缓冲区可能会更好。
即使你有更多的颜色来处理你,也可以有单独的内核处理边缘区域和缓冲区可能会提供更好的整体性能。
使用图像获得更好性能的原因来自于从内存一次加载多个像素的能力,在某些架构中,指令一次可以加载128位。
并提出实际问题, 我的猜测是hw会使用offset和work id来计算每个像素的实际坐标。