优化下三角矩阵转置

时间:2012-11-30 17:15:32

标签: c optimization

我必须优化以下功能,以便它运行得更快:注意(这是一个较低的三角形转置)

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];
            }
        }
    } 
}

2 个答案:

答案 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有预取指令,那么您可以要求它在您完成当前内存块之前开始加载下一行数据。