如何使用C优化矩阵初始化和转置以更快地运行

如何使用C优化矩阵初始化和转置以更快地运行,c,matrix,initialization,transpose,C,Matrix,Initialization,Transpose,该矩阵的维数为40000*40000。我应该考虑程序的空间和时间局部性,但我不知道如何优化这个代码。在我的电脑里花了50多秒,这对我们小组来说是不可接受的。现在块的大小是500。有人能帮我改进这个代码吗 void InitializeMatrixRowwise(){ int i,j,ii,jj; double x; x = 0.0; for (i = 0; i < DIMENSION; i += BLOCKSIZE) { f

该矩阵的维数为40000*40000。我应该考虑程序的空间和时间局部性,但我不知道如何优化这个代码。在我的电脑里花了50多秒,这对我们小组来说是不可接受的。现在块的大小是500。有人能帮我改进这个代码吗

void      InitializeMatrixRowwise(){
    int i,j,ii,jj;
    double x;
    x = 0.0;
    for (i = 0; i < DIMENSION; i += BLOCKSIZE)
    {
        for (j = 0; j < DIMENSION; j += BLOCKSIZE)
        {
            for (ii = i; ii < i+BLOCKSIZE && ii < DIMENSION; ii++)
            {
                for (jj = j; jj < j+BLOCKSIZE && jj < DIMENSION; jj++)
                {
                    if (ii >= jj)
                    {
                        Matrix[ii][jj] = x++;
                    }
                    else
                        Matrix[ii][jj] = 1.0;
                 }
             }
         }
     }
 }




void        TransposeMatrixRowwise(){
int column,row,i,j;
double temp;
for (row = 0; row < DIMENSION; row += BLOCKSIZE)
{
    for (column = 0; column < DIMENSION; column += BLOCKSIZE)
    {
        for (i = row; i < row + BLOCKSIZE && i < DIMENSION; i++)
        {
            for (j = column; j < column + BLOCKSIZE && j < DIMENSION; j++)
            {
                if (i > j)
                {
                    temp = Matrix[i][j];
                    Matrix[i][j] = Matrix[j][i];
                    Matrix[j][i] = temp;
                 }
             }
         }
     }
 }
 }
void initializeMatrix行(){
int i,j,ii,jj;
双x;
x=0.0;
对于(i=0;i=jj)
{
矩阵[ii][jj]=x++;
}
其他的
矩阵[ii][jj]=1.0;
}
}
}
}
}
void transportSematrix行(){
int列,行,i,j;
双温;
对于(行=0;行<维度;行+=块大小)
{
对于(列=0;列<维度;列+=块大小)
{
对于(i=row;ij)
{
温度=矩阵[i][j];
矩阵[i][j]=矩阵[j][i];
矩阵[j][i]=温度;
}
}
}
}
}
}

您的转置函数似乎比需要的复杂,因此可能比需要的慢。但是,我创建了两个版本的代码,在“全尺寸”(40k x 40k数组,具有500 x 500个块)上插入计时,一个使用转置函数,另一个使用更简单的算法:

static void TransposeMatrixRowwise(void)
{
    for (int row = 0; row < DIMENSION; row++)
    {
        for (int col = row + 1; col < DIMENSION; col++)
        {
            double temp = Matrix[row][col];
            Matrix[row][col] = Matrix[col][row];
            Matrix[col][row] = temp;
        }
    }
}
性能差异的原因几乎可以肯定是由于引用的位置。更复杂的算法一次处理两个独立的内存块,而更简单的算法处理的内存要多得多,导致更多的页面丢失,性能也会降低

因此,虽然您可能能够使用不同的块大小(它不需要与用于生成矩阵的块大小相同)来调整转置算法,但基于这些测量值毫无疑问 算法越复杂,效率越高

我还以1/10的比例进行了检查——4k x 4k矩阵,50 x 50块大小——以确保转置的输出是相同的(大约152 MiB的文本)。我没有用超过100倍的数据完整地保存数据。在1/10音阶的两个版本中,1/10音阶的成绩都显著好于1/100音阶,低于1/100音阶:

< Initialization: 0.068667
< Transposition: 0.063927
---
> Initialization: 0.081022
> Transposition: 0.039169
4005c4005
< Print transposition: 3.901960
---
> Print transposition: 4.040136
<初始化:0.068667
<换位:0.063927
---
>初始化:0.081022
>换位:0.039169
4005c4005
打印转置:4.0401136

JFTR:在运行macOS High Sierra 10.13.1、2.7 GHz Intel Core i7 CPU和16 GB 2133 MHz LPDDR3 RAM的2016 MacBook Pro上进行测试。编译器是GCC 7.2.0(自制)。浏览器正在运行(但大部分处于非活动状态),后台播放音乐,因此机器没有空闲,但我认为这不会显著影响数字。

您使用的编译器和标志是什么,可能的第一步是尝试一些基于编译器的优化,您可以查看的另一件事是确保整数存储在寄存器中,而不是缓存/内存中,可能需要使用内联ASM。您是否只需要在会话期间执行一次50秒以上的初始化,或者多次初始化?如果元素是
,则40k x 40k矩阵使用大约12.8 GiB,如果它们是
浮动的话,大约是一半。那是大的,;初始化这么多数据需要时间,即使假设您有足够的物理RAM,可以一次将所有数据都存储在内存中。当我使用40k x 40k、块大小为500 x 500的计时线束对您的代码执行计时测试时(在2016年MacBook Pro上,使用16 GiB 2133 MHz LPDDR3 RAM和2.7 GHz Intel Core i7),需要
Matrix(40000x40000块,500x500块)
/
初始化:10.597134
/
转置:22.087354
,或者不到33秒,这与您测量的完全相同。在块大小的子单元中工作的代码可能导致对内存的顺序访问更少,但通过其他机制获得相同的结果肯定不是那么容易尝试了一种方法,但结果不同。事实上,元素在需求方面必须加倍。是的,我认为改进的关键是引用的局部性。但我已经将代码从使用更简单算法的版本更改为这个版本,我不知道我还能做些什么来优化它。我无法在较小的规模下进行优化,因为dim这个矩阵的长度是固定的。你有其他优化的想法吗?
< Initialization: 0.068667
< Transposition: 0.063927
---
> Initialization: 0.081022
> Transposition: 0.039169
4005c4005
< Print transposition: 3.901960
---
> Print transposition: 4.040136