【发布时间】:2016-12-14 21:24:22
【问题描述】:
在我的小性能问题调查中,我注意到一个有趣的堆栈分配功能,这里是测量时间的模板:
#include <chrono>
#include <iostream>
using namespace std;
using namespace std::chrono;
int x; //for simple optimization suppression
void foo();
int main()
{
const size_t n = 10000000; //ten millions
auto start = high_resolution_clock::now();
for (size_t i = 0; i < n; i++)
{
foo();
}
auto finish = high_resolution_clock::now();
cout << duration_cast<milliseconds>(finish - start).count() << endl;
}
现在都是foo() 实现,在每个实现中将总共分配500000 ints:
-
分配在一个块中:
void foo() { const int size = 500000; int a1[size]; x = a1[size - 1]; }结果:7.3 秒;
-
分配在两个块中:
void foo() { const int size = 250000; int a1[size]; int a2[size]; x = a1[size - 1] + a2[size - 1]; }结果:3.5 秒;
-
分配在四个块中:
void foo() { const int size = 125000; int a1[size]; int a2[size]; int a3[size]; int a4[size]; x = a1[size - 1] + a2[size - 1] + a3[size - 1] + a4[size - 1]; }结果:1.8 秒。
等等...我将它分成 16 个块并得到结果时间 0.38 秒。
请向我解释一下,为什么以及如何发生这种情况?
我使用了 MSVC 2013 (v120),发布版本。
UPD:
我的机器是x64平台。而且我是用Win32平台编译的。
当我使用 x64 平台编译它时,它在所有情况下都会产生大约 40 毫秒。
为什么平台选择会产生如此大的影响?
【问题讨论】:
-
盲目:除了可能的编译器优化。您看到的性能肯定会因 Cache Misses 而受损...通常,您应该在最高优化级别进行基准测试。 :-)
-
您的 PC 规格是什么?编译器版本和编译标志?
-
请不要发布非标准
void main的代码。 FTFY。 -
我一直在 Linux 上的 GCC 4.9.2 上查看它,它产生的结果正是您所期望的。在所有优化级别,使用您的代码分配单个数组
a1比分配四个数组a1...a4更快。在所有情况下,整个函数调用都需要不到 40 毫秒,而不是您所经历的几秒钟。上述所有时间之间的差异是微不足道的 - 最多大约 15 毫秒。 -
编译器编写者love UB,它提供了很多让代码运行得更快的方法。您正在读取一个从未写入的值。优化器注意到这一点,知道任何值都足够好,所以 only 读取 a1[0]。这反过来又允许消除 a2、a3 和 a4。这使得堆栈帧更小。这使得它在 _chkstk 上花费的时间更少。所以执行时间与
size的值成正比。
标签: c++ c performance stack allocation