在尝试估计之间的性能差异时push_back
and std::inserter
我遇到了一个非常奇怪的性能问题。
让我们考虑以下代码:
#include <vector>
using container = std::vector<int>;
const int size = 1000000;
const int count = 1000;
#ifdef MYOWNFLAG
void foo(std::insert_iterator<container> ist)
{
for(int i=0; i<size; ++i)
*ist++ = i;
}
#endif
void bar(container& cnt)
{
for(int i=0; i<size; ++i)
cnt.push_back(i);
}
int main()
{
container cnt;
for (int i=0; i<count; ++i)
{
cnt.clear();
bar(cnt);
}
return 0;
}
在这种情况下,无论是否MYOWNFLAG
定义后,函数 foo 未被调用。然而,该标志的值会对性能产生影响:
$ g++ -g -pipe -march=native -pedantic -std=c++11 -W -Wall -Wextra -Werror -O3 -o bin/inserter src/inserter.cc && time ./bin/inserter
./bin/inserter 4,73s user 0,00s system 100% cpu 4,728 total
$ g++ -g -pipe -march=native -pedantic -std=c++11 -W -Wall -Wextra -Werror -O3 -o bin/inserter src/inserter.cc -DMYOWNFLAG && time ./bin/inserter
./bin/inserter 2,09s user 0,00s system 99% cpu 2,094 total
请注意,如果我更改原型foo
to use std::back_insert_iterator
我得到了类似的表现,就好像我没有设置标志一样。
编译器的优化发生了什么???
EDIT
我使用 gcc 4.9.2 20150304(预发布)
转载
- 由 Stefan 在 ideone 上转载
- 我在另一台机器上用 gcc 4.9.2 复制了
- 我没有在另一台带有 gcc 4.6.3 和标志 -std=c++0x 的机器上重现
首先,我将向您展示如何在没有垃圾函数的情况下实现这一目标的神奇技巧。然后我将向您展示垃圾函数为何有效。所以技巧:
原来无效(注意我的机器大约快两倍):
g++ -g -pipe -march=native -pedantic -std=c++11 -W -Wall -Wextra -Werror -O3 -o bin/inserter src/inserter.cc --param inline-unit-growth=200 && time ./bin/inserter
real 0m2.197s
user 0m2.200s
sys 0m0.000s
现在开始了(你的定义仍然处于非活动状态):
g++ -g -pipe -march=native -pedantic -std=c++11 -W -Wall -Wextra -Werror -O3 -o bin/inserter src/inserter.cc --param inline-min-speedup=2 && time ./bin/inserter
real 0m1.114s
user 0m1.100s
sys 0m0.010s
注意:区别在于看起来奇怪的论证--param inline-min-speedup=2
现在我简单介绍一下调查情况:
快和慢有什么区别?在慢速版本中,我们确实有无效的调用emplace_back_aux
inside bar()
,当您的 foo 未注释时,它会神奇地内联。所以我们可以得出结论,这个栏非常热门,而内联在这里至关重要。而且很可能所有这些错误都与内联有关。
现在有选项-fdump-ipa-inline-details
让我们看看内联转储。您将看到不同的时间/大小考虑因素。它很难阅读,我不想在这里粘贴所有细节。但研究此信息的一般结果是:GCC 认为,模块大小(百分比)的增长不值得估计加速。
-
该怎么办?两种可能性:
3.1.要么增加模块大小,要么增加未使用的总体加速估计foo
代码,即使用正确的类型(如 insert_iterator 来调用 emplace_back 并移动比率更大并达到内联限制)(请注意,这种方式非常不稳定 - 在具有改进的内联算法的其他编译器版本中,所有内容都可能会爆炸,并且您还需要真的很幸运能猜出代码来工作)。
3.2.或者移动内联限制。我对 GCC 提供的参数所说的是“请考虑以更少的加速内联甚至大的函数”。
那是。 GCC 内部还有很多其他参数以及您可以使用它们执行的其他技巧。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)