问题描述
在 g++ 4.9.2 和 5.3.1 上,这段代码需要几秒钟的时间来编译并生成一个 52,776 字节的可执行文件:
On g++ 4.9.2 and 5.3.1, this code takes several seconds to compile and produces a 52,776 byte executable:
增加 size
似乎会线性增加编译时间和可执行文件的大小.我无法使用 clang 3.5 或 Visual C++ 2015 重现此行为.使用 -Os
没有区别.
Increasing size
seems to increase compilation time and executable size linearly. I cannot reproduce this behaviour with either clang 3.5 or Visual C++ 2015. Using -Os
makes no difference.
检查汇编代码发现a
的初始化被展开,生成4096 movl
指令:
Inspecting the assembly code reveals that the initialization of a
is unrolled, generating 4096 movl
instructions:
这仅在 T
具有非平凡构造函数并且使用 {}
初始化数组时才会发生.如果我执行以下任何操作,g++ 会生成一个简单的循环:
This only happens when T
has a non-trivial constructor and the array is initialized using {}
. If I do any of the following, g++ generates a simple loop:
- 删除
S::S()
; - 移除
S::S()
并在类中初始化S::f
; - 移除聚合初始化(
= {}
); - 不使用
-O2
编译.
- Remove
S::S()
; - Remove
S::S()
and initializeS::f
in-class; - Remove the aggregate initialization (
= {}
); - Compile without
-O2
.
我完全将循环展开作为一种优化,但我认为这不是一个很好的优化.在我将此报告为错误之前,有人可以确认这是否是预期的行为吗?
I'm all for loop unrolling as an optimization, but I don't think this is a very good one. Before I report this as a bug, can someone confirm whether this is the expected behaviour?
推荐答案
似乎有一个相关的错误报告,错误 59659 - 大的零初始化 std::array 编译时间过长.它被认为是 4.9.0 的固定",所以我认为这个测试用例要么是回归,要么是补丁未涵盖的边缘情况.值得一提的是,错误报告的两个测试用例1,2 在 GCC 4.9.0 和 5.3 上都对我表现出症状.1
There appears to be a related bug report, Bug 59659 - large zero-initialized std::array compile time excessive. It was considered "fixed" for 4.9.0, so I consider this testcase either a regression or an edgecase not covered by the patch. For what it's worth, two of the bug report's test cases1, 2 exhibit symptoms for me on both GCC 4.9.0 as well as 5.3.1
还有两个相关的错误报告:
There are two more related bug reports:
Bug 68203 - 使用 -std=c++ 的嵌套数组对结构的无限编译时间11
安德鲁平斯基 2015-11-04 07:56:57 UTC
Andrew Pinski 2015-11-04 07:56:57 UTC
这很可能是一个内存占用,它产生了大量的默认构造函数而不是对它们的循环.
This is most likely a memory hog which is generating lots of default constructors rather than a loop over them.
那个声称是这个的复制品:
That one claims to be a duplicate of this one:
错误 56671 - Gcc 使用大量内存和处理器能力以及大型 C++11 位集
乔纳森·韦克利 2016-01-26 15:12:27 UTC
Jonathan Wakely 2016-01-26 15:12:27 UTC
为这个 constexpr 构造函数生成数组初始化是问题:
Generating the array initialization for this constexpr constructor is the problem:
确实,如果我们将其更改为 S a[4096] {};
我们不会遇到问题.
Indeed if we change it to S a[4096] {};
we don't get the problem.
使用 perf
我们可以看到 GCC 大部分时间都花在了什么地方.第一:
Using perf
we can see where GCC is spending most of its time. First:
perf record g++ -std=c++11 -O2 test.cpp
然后性能报告
:
这对 GCC 开发人员以外的任何人都没有多大意义,但看到什么占用了如此多的编译时间仍然很有趣.
This won't mean much to anyone but GCC developers but it's still interesting to see what's taking up so much compilation time.
Clang 3.7.0 在这方面比 GCC 做得更好.在 -O2
编译时间不到一秒钟,生成一个小得多的可执行文件(8960 字节)和这个程序集:
Clang 3.7.0 does a much better job at this than GCC. At -O2
it takes less than a second to compile, produces a much smaller executable (8960 bytes) and this assembly:
另一方面,使用 GCC 5.3.1,在没有优化的情况下,编译速度非常快,但仍会生成 95328 大小的可执行文件.使用 -O2
编译将可执行文件大小减少到 53912,但编译时间需要 4 秒.我绝对会将这个报告给他们的 bugzilla.
On the other hand with GCC 5.3.1, with no optimizations, it compiles very quickly but still produces a 95328 sized executable. Compiling with -O2
reduces the executable size to 53912 but compilation time takes 4 seconds. I would definitely report this to their bugzilla.
这篇关于在 g++ 上进行聚合初始化的 std::array 生成大量代码的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持跟版网!