15.5_进一步优化
15.5 进一步优化
这里介绍2种进一步优化实现的代码:基于流处理器簇的内核函数调用(在流处理器簇1.x的架构中支持很多不同的乘法指令集,在这个计算的最内层循环中)以及内循环展开的内核程序。
15.5.1 基于流处理器簇的实现代码
流处理器簇1.x架构的硬件使用一个24位乘法器(对于内层的乘法计算是足够宽的),但2.x和3.x的硬件中使用的是32位乘法器。有时编译器可以检测到参与计算的整数的宽度,如果足够窄的话它便会使用1.x架构的24位乘法器来计算,但这似乎并不应该是内核函数corrShared_kernel()所需要考虑的事情。为了解决这个问题,我们可以在内核里声明一个模板类(C++语言特性)。
template <bool bSM1>
__global__void
__corrSharedSM_kernel( ... )内核函数的内循环则变为:
for (int j = 0; j < hTemplate; j++) {
for (int i = 0; i < wTemplate; i++) {
unsigned char I = LocalBlock[SharedIdx+i];
unsigned char T = g_Tpix[ idx++] + SumI += I;
}if(bSM1){ SumISq $+ =$ umul24(I,I); SumIT $+ =$ umul24(I,T); } else{ SumISq $+ =$ I\*I; SumIT $+ =$ I\*T; } } SharedIdx $+ =$ SharedPitch;主机端在调用内核函数时必须检测设备是否为1.x架构,如果是,则调用内核时bSM1=true。上述实例源代码出自corrSharedSM.cuh和corrSharedSMSums.cuh。
15.5.2 循环展开
由于每个线程都会存取共享内存中相邻字节,1.x架构的硬件中的内核函数的最内层循环不可避免的会产生四路存储体冲突。
如果我们将如下代码
for (int j = 0; j < hTemplate; j++) {
for (int i = 0; i < wTemplate; i++) {
unsigned char I = LocalBlock[SharedIdx+i];
unsigned char T = g_Tpix[ idx++] + SumI += I;
SumISq += I*I;
SumIT += I*T;
}
SharedIdx += SharedPitch;重写为
for { int j = 0; j < hTemplate; j++) }
for ( int i = 0; i < wTemplate/4; i++) {
corrSharedAccumulate<bSM1> (...) LocalBlock[SharedIdx+i*4+0],);
corrSharedAccumulate<bSM1> (...) LocalBlock[SharedIdx+i*4+1],);
corrSharedAccumulate<bSM1> (...) LocalBlock[SharedIdx+i*4+2],);
corrSharedAccumulate<bSM1> (...) LocalBlock[SharedIdx+i*4+3],);
}
SharedIdx += SharedPitch;其中corrSharedAccumulate()封装了模板类(C++特性)参数bSM1,代码如下
template <bool bsm1>
__device__void
corrSharedAccumulate(
int& SumI, int& SumISq, int& SumIT,
unsigned char I, unsigned char T)
{
SumI += I;
if (bsm1) {
SumISq += _umul24(I, I);
SumIT += _umul24(I, T);
}
else {
SumISq += I*I;
SumIT += I*T;
}
}虽然我们主要的目的是为了降低因字节存取而产生的存储体冲突,但也产生了另外一个效果,就是在流处理器簇为1.x的CUDA设备中内核函数运行的更快。