我必须优化以下功能,以便它运行得更快:注意(这是一个较低的三角形转置)
void trans(int ** source, int** destination)
{
for (int i = 0 ; i < sizee ; i ++)
{
for (int j = i +1 ; j < sizee ; j ++)
{
destination[i][j]= source[j][i];
}
}
}
我理解对源的访问没有空间局部性,因为它是由列访问的,但我不明白我将如何实现它。任何帮助表示赞赏。谢谢。
编辑:我试过平铺,虽然运行时间得到改善,但优化的转置产生了错误的结果:#define b 2
for (int ii = 0 ; ii < sizee ; ii += b) {
for (int jj = ii +1 ; jj < sizee ; jj +=b) {
for(int i = ii; i < std::min(ii+b-1, sizee); i++)
{
for(int j = jj; j < std::min(jj+b-1, sizee); j++)
{
destination[i][j]= source[j][i];
}
}
}
}
答案 0 :(得分:1)
执行缓存友好转置算法的一种方法是平铺数据:
- for each square tile
- load a square tile from source into a temporary buffer
- transpose tile in-place
- write out transpose tile to its correct location in dest
选择图块大小,使其适合缓存。
为了进一步优化,您可以使用就地磁贴转置例程 - 您可以对其进行大量的微观优化。 8x8或16x16就地转置。
注意:当问题的原始版本不明显要求部分转置时,会提供此答案。我将在这里留下答案,因为它在下面有一些有用的评论。
答案 1 :(得分:0)
您可以从反转循环开始。将j
放在外面,i
放在内侧。原因如下:以下位置在内存中彼此相邻:
source[j][0];
source[j][1];
source[j][2];
source[j][3];
但这些地点不是:
source[0][i];
source[1][i];
source[2][i];
source[3][i];
当CPU完成将source[j][0]
读入寄存器时,您的L1缓存中有一整个缓存行数据。通过让您的读取在地址空间上线性地进行而不是分散来利用它。
您也可以unroll your loops。当你可以执行大量没有分支的指令时,CPU会喜欢它。
for (int j = i +1 ; j < sizee ; j += 8)
{
destination[i][j]= source[j][i];
destination[i][j+1]= source[j+1][i];
destination[i][j+2]= source[j+2][i];
destination[i][j+3]= source[j+3][i];
destination[i][j+4]= source[j+4][i];
destination[i][j+5]= source[j+5][i];
destination[i][j+6]= source[j+6][i];
destination[i][j+7]= source[j+7][i];
}
如果您的CPU有预取指令,那么您可以要求它在您完成当前内存块之前开始加载下一行数据。