我写了一个opencl代码片段,我想进一步改进:
global_size is 1920x1080
local size is kept NULL. I have left this to compiler.
__kernel void experiment(__read_only image2d_t YIn, __write_only image2d_t YOut)
{
uint4 best_suited=0;
uint4 temp =0;
int best_sum,ssum;
int2 coord_src = (int2)(get_global_id(0), 2*get_global_id(1)+1);
const sampler_t smp = CLK_FILTER_NEAREST | CLK_NORMALIZED_COORDS_FALSE | CLK_ADDRESS_CLAMP_TO_EDGE;
uint4 pixel1 = read_imageui(YIn, smp, coord_src + (int2)(-3,0));
uint4 pixel2 = read_imageui(YIn, smp, coord_src + (int2)(-2,0));
uint4 pixel3 = read_imageui(YIn, smp, coord_src + (int2)(-1,0));
uint4 pixel4 = read_imageui(YIn, smp, coord_src + (int2)( 0,0));
uint4 pixel5 = read_imageui(YIn, smp, coord_src + (int2)( 1,0));
uint4 pixel6 = read_imageui(YIn, smp, coord_src + (int2)( 2,0));
uint4 pixel7 = read_imageui(YIn, smp, coord_src + (int2)( 3,0));
/* Read luma pixels of next line */
uint4 pixel_nxt1 = read_imageui(YIn, smp, coord_src + (int2)(-3,2));
uint4 pixel_nxt2 = read_imageui(YIn, smp, coord_src + (int2)(-2,2));
uint4 pixel_nxt3 = read_imageui(YIn, smp, coord_src + (int2)(-1,2));
uint4 pixel_nxt4 = read_imageui(YIn, smp, coord_src + (int2)( 0,2));
uint4 pixel_nxt5 = read_imageui(YIn, smp, coord_src + (int2)( 1,2));
uint4 pixel_nxt6 = read_imageui(YIn, smp, coord_src + (int2)( 2,2));
uint4 pixel_nxt7 = read_imageui(YIn, smp, coord_src + (int2)( 3,2));
/* main loop: */
{
best_sum= abs_diff(pixel3.x,pixel_nxt4.x) + abs_diff(pixel4.x,pixel_nxt5.x) + abs_diff(pixel5.x,pixel_nxt6.x) -8;
best_suited.x = (pixel4.x+pixel_nxt2.x) >> 1;
sum = abs_diff(pixel2.x,pixel_nxt2.x) + abs_diff(pixel3.x,pixel_nxt6.x) + abs_diff(pixel4.x,pixel_nxt1.x);
if (sum < best_sum)
{
best_sum = sum;
best_suited.x = (pixel3.x+pixel_nxt3.x) >> 1;
sum = abs_diff(pixel1.x,pixel_nxt5.x) + abs_diff(pixel2.x,pixel_nxt6.x) + abs_diff(pixel3.x,pixel_nxt7.x) + 16;
if (sum < best_sum)
{
best_sum = sum;
best_suited.x = (pixel5.x+pixel_nxt1.x) >> 1;
}
}
sum = abs_diff(pixel4.x,pixel_nxt5.x) + abs_diff(pixel5.x,pixel_nxt2.x) + abs_diff(pixel6.x,pixel_nxt1.x);
if (sum < best_sum)
{
best_sum = sum;
best_suited.x = (pixel4.x+pixel_nxt3.x)>> 1;
sum = abs_diff(pixel5.x,pixel_nxt3.x) + abs_diff(pixel6.x,pixel_nxt4.x) + abs_diff(pixel7.x,pixel_nxt3.x);
if (sum < best_sum)
{
best_sum = sum;
best_suited.x = (pixel6.x+pixel_nxt2.x) >> 1;
}
}
}
/* Pix4(0,0) is the current pixel in below calculations */
write_imageui(YOut, coord_src, pixel4);
/* store the result: */
write_imageui(YOut, coord_src+(int2)(0,1),best_suited);
}
我尝试过以下事项: 1)abs_diff是内置函数,用位代码替换abs_diff没有任何改进。
2)使用英特尔Vtune分析其性能,并看到执行单元闲置30%的时间。 GPU内存读取速度为7.6GB /秒,写入速度为3.942GB /秒。三级缓存未命中数接近177x10 ^ 9,计算线程接近35 lacs。采样器瓶颈也是8.3%。
进一步思考: 1)我不知道读取本地内存中的数据是否对我有利。由于本地内存缓存线访问与访问英特尔架构上的L3缓存相同。通过图像api进行读取我已经访问了图像对象的高速缓冲存储器,即纹理存储器。如果我编写类似这样的代码,我能想到的唯一帮助就是减少采样器瓶颈: __local smem [256]; smem [get_local_id(0)= read_imageui(YIn,smp,coord_src);
2)我也不知道这里的最佳工作组规模应该是什么。
任何人都可以详细解释如何优化此代码吗?如何减少执行空闲时间,计算线程,L3缓存未命中以及增加GPU内存读写访问权限。如果你可以重新编写真正有用的代码。
答案 0 :(得分:0)
1)我猜测本地记忆可能会有所帮助。即使它在L3中出局,如果你在SLM中仔细安排你的负载而不是让所有的EU同时锤击L3,你将获得更少的缓存捶打。如果你有时间进行实验,那至少值得一试。
2)在没有SLM的情况下,我建议在英特尔BDW上使用大型工作组(256或16x16,具体取决于您的方式)。这对于工作量少得多的短内核更为重要。对于像你这样的大型内核,它可能无关紧要。
如果您使用SLM路由,那么我们需要一个工作组大小,以便切片上的所有线程尽可能多地使用(但不能更多)。经验法则是每个工作项64字节。我认为这假设是SIMD16编译,但由于我们无法控制你可能最终编译SIMD8。因此,每个工作项目也尝试128个字节。请参阅this IDF presentation中的幻灯片34和44。