C++ 'small' 优化行为异常

标签 c++ optimization

我正在尝试对我的一个项目进行“小规模”优化。

有一系列单独很小的数组访问,但分析表明这些数组访问是我的程序的绝大多数时间花费的地方。所以,是时候让事情变得更快了,因为程序大约需要一个小时才能运行。

我已经移动了以下类型的访问权限:

const float theValOld1 = image(x, y, z);
const float theValOld2 = image(x, y+1, z);
const float theValOld3 = image(x, y-1, z);
const float theValOld4 = image(x-1, y, z);

等等,用于围绕当前像素进行 28 次访问。

图像变为
float image(const int x, const int y, const int z) const {
     return data[z*xsize*ysize + y*xsize + x];
}

我已经把它换成了
const int yindex = y*xsize;
const int zindex = z*xsize*ysize;
const float* thePtr = &(data[z*xsize*ysize + y*xsize + x]);
const float theVal1 = *(thePtr);
const float theVal2 = *(thePtr + yindex);
const float theVal3 = *(thePtr - yindex);
const float theVal4 = *(thePtr - 1);

等等,对于相同数量的操作。

我希望,如果编译器非常棒,这种变化不会对速度产生任何影响。如果编译器不是很棒,那么我会说第二个版本应该更快,因为我避免了 [] thunk 附带的隐式指针添加,以及删除 y 和 z 的乘法堕落。

为了让它更加不平衡,我将 z 操作移到了它们自己的部分,只有在 zindex != 0 时才会被命中,因此有效地,第二个版本只有 9 次访问。因此,根据该指标,第二个版本肯定应该更快。

为了衡量性能,我使用了 QueryPerformanceCounter。

对我来说奇怪的是操作顺序很重要!

如果我按照描述保留操作并比较时间(以及结果,以确保优化后计算出相同的值),那么旧代码每像素需要大约 45 个滴答,而新代码每像素需要 10 个滴答.如果我颠倒这些操作,那么旧代码每像素大约需要 14 个滴答,而新代码每像素大约需要 30 个滴答(其中有很多噪音,这些是大约 100 个像素的平均值)。

为什么顺序很重要?是否有缓存或正在发生的事情?变量都被命名为不同的东西,所以我认为这无关紧要。如果发生了一些缓存,有什么办法可以从一个像素到另一个像素利用它吗?

推论:为了比较速度,我认为正确的方法是彼此独立运行两个版本,然后比较不同运行的结果。我想让这两个比较彼此相邻是有道理的,但显然这里发生了一些事情阻止了这种情况。有没有办法挽救这种并排运行以从单次运行中获得合理的速度比较,以便我可以确保结果(轻松)相同?

编辑:澄清。

我在同一个函数中有新旧代码,所以我可以确保结果是相同的。

如果我先运行旧代码,然后运行新代码,则新代码比旧代码运行得更快。
如果我先运行新代码,然后运行旧代码,旧代码的运行速度会比新代码快。

z 命中是数学所必需的,并且 if 语句无法删除,并且两者都存在。对于新代码,我刚刚将更多特定于 z 的代码移到了 z 部分,并且我使用的测试代码是 100% 2D。当我转向 3D 测试时,我相信我会看到更多分支的效果。

最佳答案

您可能(可能)遇到某种预读或缓存线边界问题。一般来说,当您加载单个值并且它不是“热的”(在缓存中)时,CPU 将拉入缓存行(32、64 或 128 字节非常典型,具体取决于处理器)。对同一行的后续读取将快得多。

如果您更改操作顺序,您可能只会看到由于加载和驱逐线路的方式而造成的停顿。

解决此类问题的最佳方法是打开“拆卸” View 并花一些时间阅读处理器的引用手册。

如果幸运的话,代码重新排序导致的更改将是显而易见的(编译器可能会生成额外的指令或分支)。不太幸运的是,它会在处理器的某个地方出现停顿——在解码管道期间或由于内存获取......

一个可以计算停顿和缓存未命中数的好的分析器在这里也可能有所帮助(例如,AMD 有 CodeAnalyst )。

如果你不是在时间紧迫的情况下,那么深入了解一下真的很值得——至少,你最终可能会学到一些你以前不知道的东西,比如你的 CPU、机器架构、编译器、库等工作。 (在研究 disasm 时,我几乎总是会“呵呵”。)

关于C++ 'small' 优化行为异常,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1219671/

相关文章:

c++ - 在 C 和 C++ 编程中使用哪个更好?

c++ - 针对 C++ 用户的 Visual Studio 2010 与 2012 编译时性能和稳定性比较

c++ - 奇怪的段错误 11

c++ - 将 boost::asio::async_wait_until 与 boost::asio::streambuf 一起使用

c++ - C++中成员函数的内存分配

php - 在php5中使用内联字符串与连接的速度差异?

c# - 找不到网络优化 css 包 (404)

java - 如何减少 JSF 中的 javax.faces.ViewState

c++ - 如果一个类继承自纯基类,那么默认析构函数是什么?

algorithm - 混淆会使我的程序更加优化