C++ 这段代码的瓶颈在哪里?

C++ 这段代码的瓶颈在哪里?,c++,c,optimization,gcc,x86,C++,C,Optimization,Gcc,X86,我有以下紧密的循环,它构成了我代码的串行瓶颈。理想情况下,我会将调用此函数的函数并行化,但这是不可能的 //n is about 60 for (int k = 0;k < n;k++) { double fone = z[k*n+i+1]; double fzer = z[k*n+i]; z[k*n+i+1]= s*fzer+c*fone; z[k*n+i] = c*fzer-s*fone; } //n大约是60 对于(int k=0;k

我有以下紧密的循环,它构成了我代码的串行瓶颈。理想情况下,我会将调用此函数的函数并行化,但这是不可能的

//n is about 60
for (int k = 0;k < n;k++) 
{
    double fone = z[k*n+i+1];
    double fzer = z[k*n+i];
    z[k*n+i+1]= s*fzer+c*fone;
    z[k*n+i] = c*fzer-s*fone;
}
//n大约是60
对于(int k=0;k
是否有任何优化,如矢量化或一些邪恶的内联,可以帮助这段代码


我正在寻找三对角矩阵的特征解

我想你是在旋转某个东西(或者更确切地说,很多东西,以相同的角度旋转(s是sin,c是cos))

倒计时总是很有趣的,并且在每次迭代中省去了变量比较,应该在这里工作。将计数器设为索引也可能节省一点时间(正如其他人所说,省去了一点算术)


这里没有什么戏剧性的东西,但如果没有其他东西,它看起来更整洁。

我想你是在旋转什么东西(或者更确切地说,很多东西,以相同的角度旋转(s是sin,c是cos))

倒计时总是很有趣的,并且在每次迭代中省去了变量比较,应该在这里工作。将计数器设为索引也可能节省一点时间(正如其他人所说,省去了一点算术)


这里没有什么特别的地方,但如果没有其他东西,它看起来会更整洁。

作为第一步,我会在这个循环中缓存指针:

//n is about 60
double *cur_z = &z[0*n+i]
for (int k = 0;k < n;k++) 
{
    double fone = *(cur_z+1);
    double fzer = *cur_z;
    *(cur_z+1)= s*fzer+c*fone;
    *cur_z = c*fzer-s*fone;
    cur_z += n;
}
//n大约是60
双*cur_z=&z[0*n+i]
对于(int k=0;k

其次,我认为制作这个函数的模板化版本更好。因此,如果矩阵包含整数值(因为FPU操作较慢),则可以获得良好的性能优势。

作为第一步,我将缓存此循环中的指针:

//n is about 60
double *cur_z = &z[0*n+i]
for (int k = 0;k < n;k++) 
{
    double fone = *(cur_z+1);
    double fzer = *cur_z;
    *(cur_z+1)= s*fzer+c*fone;
    *cur_z = c*fzer-s*fone;
    cur_z += n;
}
//n大约是60
双*cur_z=&z[0*n+i]
对于(int k=0;k

其次,我认为制作这个函数的模板化版本更好。因此,如果您的矩阵包含整数值,您可以获得良好的性能优势(因为FPU操作较慢)。

简短回答:将矩阵的内存布局从行主顺序更改为列主顺序

长答案: 看起来您正在访问按行主顺序存储的矩阵的第(i)列和第(i+1)列—可能是一个整体上不适合CPU缓存的大矩阵。基本上,在每次循环迭代中,CPU都必须等待RAM(以100个周期的顺序)。从理论上讲,经过几次迭代之后,地址预测应该开始,CPU应该在循环访问数据项之前推测性地加载数据项。这将有助于降低RAM延迟。但这仍然存在代码使用内存总线效率低下的问题:CPU和内存从不交换单个字节,只交换缓存线(当前处理器上为64字节)。在加载和存储的每64字节缓存线中,代码只涉及16字节(或四分之一)

转换矩阵并以本机主顺序访问它将使内存总线利用率提高四倍。因为这可能是代码的瓶颈,所以您可以预期大约相同顺序的加速


它是否值得,取决于算法的其余部分。其他部分当然会因为内存布局的更改而受损。

简短回答:将矩阵的内存布局从行主顺序更改为列主顺序

长答案: 看起来您正在访问按行主顺序存储的矩阵的第(i)列和第(i+1)列—可能是一个整体上不适合CPU缓存的大矩阵。基本上,在每次循环迭代中,CPU都必须等待RAM(以100个周期的顺序)。从理论上讲,经过几次迭代之后,地址预测应该开始,CPU应该在循环访问数据项之前推测性地加载数据项。这将有助于降低RAM延迟。但这仍然存在代码使用内存总线效率低下的问题:CPU和内存从不交换单个字节,只交换缓存线(当前处理器上为64字节)。在加载和存储的每64字节缓存线中,代码只涉及16字节(或四分之一)

转换矩阵并以本机主顺序访问它将使内存总线利用率提高四倍。因为这可能是代码的瓶颈,所以您可以预期大约相同顺序的加速


它是否值得,取决于算法的其余部分。由于内存布局的改变,其他部件当然会受到影响。

非顺序内存访问。句号。什么是
i
?是否有一个循环涉及到它?您是否有一个在
i
上的外部循环?您介意提出一个我们可以编译和实验的自包含示例吗?尝试在循环外部分配fone和fzer,然后在循环内部设置它们。最有可能的是,它们将编译成两个push和pop指令。您还可以使用指针存储两个数组索引,这样您就不必每次计算两次kn+i和kn+i+1。非顺序内存访问。句号。什么是
i
?是否有一个循环涉及到它?您是否有一个在
i
上的外部循环?您介意提出一个我们可以编译和实验的自包含示例吗?尝试在循环外部分配fone和fzer,然后在循环内部设置它们。最有可能的是,它们将编译成两个push和pop指令。您也可以使用指针来存储两个数组索引,这样您就不必每次都计算kn+i和kn+i+1两次。顺便说一下,我正在工作