如何做一个适当的缓存块矩阵转置?

时间:2019-04-02 04:54:18

标签: c caching matrix block transpose

我正在尝试在C语言中执行缓存阻止矩阵转置,但是我的代码有些麻烦。我的猜测是它与索引有关。你能告诉我我哪里出问题了吗?

我正在考虑这两种在网络上找到的算法:http://users.cecs.anu.edu.au/~Alistair.Rendell/papers/coa.pdfhttp://iosrjen.org/Papers/vol3_issue11%20(part-4)/I031145055.pdf

但是我还不能弄清楚如何正确地编写那些代码。

for (i = 0; i < N; i += block) {
    for (j = 0; j < i; j += block ) {

        for(ii=i;ii<i+block;ii++){
            for(jj=j;jj<j+block;jj++){

                temp1[ii][jj] = A2[ii][jj];
                temp2[ii][jj] = A2[jj][ii];

                A2[ii][jj] = temp1[ii][jj];
                A2[ii][jj] = temp2[ii][jj];
            }     
        }                                   
    }                       
}   

temp1temp2是大小块x填充有零的块的两个矩阵。 将值返回到for(转置矩阵的前后)时,我不确定是否必须再执行一次A2

我也尝试过:

for (i = 0; i < N; i += block) {
    for (j = 0; j < N; j += block ) {
    ii = A2[i][j];
    jj = A2[j][i];

        A2[j][i] = ii;
    A2[i][j] = jj;
    }                       
}

我期望比“朴素的”矩阵转置算法更好的性能:

for (i = 1; i < N; i++) {
    for(j = 0; j < i; j++) {

        TEMP= A[i][j];
        A[i][j]=A[j][i];
        A[j][i]=TEMP;

    }
}

2 个答案:

答案 0 :(得分:1)

执行阻塞矩阵转置的正确方法不是程序中的内容。多余的temp1和temp2数组将无用地填充您的缓存。您的第二个版本不正确。更多,您将执行过多的操作:元素被两次转置,对角元素被“转置”。

但是首先我们可以做一些简单(近似)的缓存行为分析。我假设您有一个双精度矩阵,并且缓存行是64字节(8个双精度)。

如果缓存可以完全包含矩阵,则阻塞实现等效于纯朴的实现。您只有强制性的高速缓存未命中才能获取矩阵元素。高速缓存未命中数将是N×N / 8,以处理N×N个元素,每个元素的平均未命中数为1/8。

现在,对于简单的实现,请看一下在缓存中处理了1行之后的情况。假设您的缓存足够大,那么您将在缓存中:
*整行A [0] [i]
*矩阵A [i] [0..7]

每隔一行的前8个元素

这意味着,如果高速缓存足够大,则可以处理连续的7行,而没有任何高速缓存未命中,而不是要获取行的高速缓存。因此,如果您的矩阵是N×N,则如果缓存大小大于〜2×N×8,那么您将只有8×N / 8(行)+ N(cols)= 2N个缓存未命中来处理8×N个元素,每个元素的平均未命中次数为1/4。从数字上讲,如果L1缓存大小为32k,则如果N <2k,则会发生这种情况。如果L2缓存为256k,则如果N <16k,数据将保留在缓存L2中。由于现代处理器中非常有效的预取,我认为L1中的数据和L2中的数据之间的区别不会真正可见。

如果矩阵很大,则在第一行的结尾之后,第二行的开头已从缓存中弹出。如果矩阵的一行完全填满缓存,则会发生这种情况。在这种情况下,缓存未命中的数量将变得更加重要。每行将有N / 8(获得该行)+ N(获得各列的第一个元素)缓存未命中,每个元素的平均未命中率为(9×N / 8)/N≈1。

因此您可以通过阻塞的实现来获得收益,但仅限于大型矩阵。

这是矩阵转置的正确实现。它避免了元素A [l] [m]的双重处理(当i = l和j = m或i = m和j = 1时),不转置对角线元素,并使用寄存器进行转置。

原始版本

for (i=0;i<N;i++)
  for (j=i+1;j<N;j++)
    {
       temp=A[i][j];
       A[i][j]=A[j][i];
       A[j][i]=temp;
    }

和被阻止的版本(我们假设矩阵大小是块大小的倍数)

for (ii=0;ii<N;ii+=block)
  for (jj=0;jj<N;jj+=block)
    for (i=ii;i<ii+block;i++)
      for (j=jj+i+1;j<jj+block;j++)
        {
           temp=A[i][j];
           A[i][j]=A[j][i];
           A[j][i]=temp;
        }

答案 1 :(得分:0)

我正在使用您的代码,但是当我将天真与阻塞算法进行比较时,我没有得到相同的答案。我把这个矩阵A放到下面的矩阵中:

A

2 8 1 8
6 8 2 4
7 2 6 5
6 8 6 5

2 6 1 6
8 8 2 4
7 2 6 5
8 8 6 5

矩阵大小为N = 4,块为2