在Kepler中,为了获得ILP,我们应该将操作数与共享内存分开算术运算吗?我不知道它是否(操作数是共享内存的算术运算)被分成两个操作,一个是从共享内存加载到寄存器然后在寄存器上进行操作,或者它是否是一个操作
因为在书中"编程大规模并行多处理器"关于数据预取的第6部分说加载到共享内存中由两部分组成(首先从全局内存到寄存器然后注册到共享内存)
e.g 这个陈述会产生ILP吗?
result1=opA[1]+opB[1]; // opA and opB in Shared mem, result1 in register
result2=opC[1]+opD[1];// opC and opD in Shared mem, result2 in register
或者我们应该像这样分解以制作ILP?
temp1=opA[1]; temp2=opB[1];
temp3=opC[1];temp4=opD[1];//temp variable in register
result1=temp1+temp2;
result2=temp3+temp4;
答案 0 :(得分:1)
在你的例子中,你不太可能看到改进,因为编译器可能会更好地处理这种情况(正如Robert Crovella在他的评论中所说)。
但是,有时候以这种方式预取可能有助于隐藏一些延迟。如果您使用向量类型将多个提取组合到一个提取中,从而更好地利用总线,您可能会看到改进。
一个非常简单的例子:
float4 temp1 = A[0];
float4 temp2 = A[1];
result1 = temp1.x + temp1.y + temp1.z + temp1.w;
num = result1 * 3.14159;
result2 = temp2.x * num + temp2.y * num + temp2.z + temp2.w * num;
这将导致result1
和num
的计算能够在temp2
的提取发生时进行,从而有助于隐藏部分提取延迟。
这真的不是一个很好的例子,但希望你能得到一般的想法。预取更适合的一种情况是当你在循环中做某事时。如果预取第一次循环迭代所需的第一组数据,则循环内容可以在为下一次迭代获取数据时执行,等等。
一个简单的例子:
float4 temp = A[0];
float sum = 0;
for( int i = 4; i < sizeA - 4; i+=4 ) {
sum = temp.x + temp.y + temp.z + temp.w;
temp = A[i];
}