当我尝试测量算术运算的执行时间时,我遇到了非常奇怪的行为。包含for
在循环体中具有一个算术运算的循环的代码块的执行速度总是比相同的代码块慢,但在for
循环体中具有两个算术运算。这是我最终测试的代码:
#include <iostream>
#include <chrono>
#define NUM_ITERATIONS 100000000
int main()
{
// Block 1: one operation in loop body
{
int64_t x = 0, y = 0;
auto start = std::chrono::high_resolution_clock::now();
for (long i = 0; i < NUM_ITERATIONS; i++) {x+=31;}
auto end = std::chrono::high_resolution_clock::now();
std::chrono::duration<double> diff = end-start;
std::cout << diff.count() << " seconds. x,y = " << x << "," << y << std::endl;
}
// Block 2: two operations in loop body
{
int64_t x = 0, y = 0;
auto start = std::chrono::high_resolution_clock::now();
for (long i = 0; i < NUM_ITERATIONS; i++) {x+=17; y-=37;}
auto end = std::chrono::high_resolution_clock::now();
std::chrono::duration<double> diff = end-start;
std::cout << diff.count() << " seconds. x,y = " << x << "," << y << std::endl;
}
return 0;
}
我使用不同级别的代码优化 ( -O0
, -O1
, -O2
, -O3
) 和不同的在线编译器 (例如onlinegdb.com ) 在我的工作机器上、在我的 hame PC 和笔记本电脑上、在 RaspberryPi 和我同事的计算机上对此进行了测试。我重新排列了这两个代码块,重复了它们,更改了常量,更改了操作(+
、-
、<<
、=
等),更改了整数类型。但我总是得到类似的结果:循环中有一行的块比有两行的块慢:
1.05681 秒。x,y =
3100000000,0 0.90414 秒。x,y = 1700000000,-3700000000
我检查了https://godbolt.org/上的程序集输出,但一切看起来都像我预期的那样:第二个块在程序集输出中又多了一个操作。
三个操作总是按预期运行:它们比1慢,比4快。那么为什么两次操作会产生这样的异常呢?
编辑:
让我重复一遍:我的所有 Windows 和 Unix 机器上都有这样的行为,但代码没有优化。我查看了我执行的程序集(Visual Studio、Windows),我看到了我想在那里测试的指令。无论如何,如果循环被优化掉,我在剩下的代码中没有任何问题。我在问题中添加了优化通知以避免“不测量未优化代码”的答案,因为优化不是我所问的。问题实际上是为什么我的计算机执行两个操作比一个更快,首先是在这些操作没有被优化掉的代码中。在我的测试中,执行时间的差异是 5-25%(非常明显)。