【问题标题】:Where is the bottleneck in this code?这段代码的瓶颈在哪里?
【发布时间】:2012-12-03 17:35:47
【问题描述】:

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

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

是否可以进行任何优化,例如矢量化或一些邪恶的内联来帮助这段代码?

我正在寻找三对角矩阵的特征解。 http://www.cimat.mx/~posada/OptDoglegGraph/DocLogisticDogleg/projects/adjustedrecipes/tqli.cpp.html

【问题讨论】:

  • 非顺序内存访问。期间。
  • 什么是i?有没有涉及它的循环?
  • i 上有外循环吗?
  • 您介意提出一个可以编译和试验的独立示例吗?
  • 尝试在循环外分配 fone 和 fzer,然后将它们设置在循环内。他们很可能会编译成两个推送然后弹出指令。您还可以使用指针来存储两个数组索引,这样您就不必每次都计算 kn+i 和 kn+i+1 两次。

标签: c++ c optimization gcc x86


【解决方案1】:

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

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

转置矩阵并以本机主要顺序访问它会使内存总线利用率增加四倍。由于这可能是您的代码的瓶颈,因此您可以期待大约相同顺序的加速。

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

【讨论】:

  • 您能否进一步扩展“在加载和存储的每 64 字节缓存行中,您的代码仅涉及 16 字节(或四分之一)”。我不明白为什么只有 16 个字节接触内存总线...
  • 嗯,在内存事务期间,CPU 从不加载或存储任何小于缓存行(64 字节)的内容。您的代码加载和存储 16 个连续字节:z[kn+i]、z[kn+i+1]。但是,CPU 不会加载 16 个字节,它会加载 64 个字节——包含数据的特定缓存行。在这 64 个字节中,有 48 个字节被加载和存储。它们占用了宝贵的总线资源,但您的代码无法利用。
【解决方案2】:

我认为您正在旋转某些东西(或者更确切地说,很多东西,以相同的角度(s 是 sin,c 是 cos))?

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

for (int k = (n-1) * n + i; k >= 0; k -= n)
{
    double fone=z[k+1];
    double fzer=z[k];
    z[k+1]=s*fzer+c*fone;
    z[k]  =c*fzer-s*fone;
}

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

【讨论】:

  • 我尝试了运行,并没有发现太大的不同。顺便说一句,我正在寻找三对角矩阵系统的特征值。
【解决方案3】:

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

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

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

【讨论】:

  • 模板化版本是什么意思,你的意思是我应该展开整个 for 循环(我也许可以这样做......)?还有整数是什么意思。
  • 您的矩阵包含 double 值。如果你能设法在没有 double-s 的情况下进行交易,它的工作速度会更快
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-11-08
  • 2021-07-08
  • 2019-01-11
  • 1970-01-01
  • 2017-07-17
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多