На g ++ 4.9.2 и 5.3.1 этот код компилируется за несколько секунд и создает исполняемый файл размером 52 776 байт:
#include <array>
#include <iostream>
int main()
{
constexpr std::size_t size = 4096;
struct S
{
float f;
S() : f(0.0f) {}
};
std::array<S, size> a = {}; // <-- note aggregate initialization
for (auto& e : a)
std::cerr << e.f;
return 0;
}
Увеличение size
кажется, увеличивает время компиляции и размер исполняемого файла линейно. Я не могу воспроизвести это поведение ни clang 3.5, ни Visual C ++ 2015. Использование -Os
не имеет значения.
$ time g++ -O2 -std=c++11 test.cpp
real 0m4.178s
user 0m4.060s
sys 0m0.068s
Проверка кода сборки показывает, что инициализация a
развернутый, генерирующий 4096 movl
инструкции:
main:
.LFB1313:
.cfi_startproc
pushq %rbx
.cfi_def_cfa_offset 16
.cfi_offset 3, -16
subq $16384, %rsp
.cfi_def_cfa_offset 16400
movl $0x00000000, (%rsp)
movl $0x00000000, 4(%rsp)
movq %rsp, %rbx
movl $0x00000000, 8(%rsp)
movl $0x00000000, 12(%rsp)
movl $0x00000000, 16(%rsp)
[...skipping 4000 lines...]
movl $0x00000000, 16376(%rsp)
movl $0x00000000, 16380(%rsp)
Это происходит только тогда, когда T
имеет нетривиальный конструктор, и массив инициализируется с помощью {}
, Если я сделаю любое из следующего, g ++ генерирует простой цикл:
S::S()
;S::S()
и инициализировать S::f
в классе;= {}
);-O2
,Я все за раскрутку цикла как оптимизацию, но я не думаю, что это очень хороший вариант. Прежде чем я сообщу об этом как об ошибке, может ли кто-нибудь подтвердить, является ли это ожидаемым поведением?
[править: я открыл новая ошибка для этого, потому что другие, кажется, не совпадают. Они были больше о долгом времени компиляции, чем о странном коде.]Похоже, есть сообщение об ошибке, Ошибка 59659 — слишком большое время компиляции с инициализированным нулем std :: array. Он считался «фиксированным» для 4.9.0, поэтому я рассматриваю этот тестовый случай как регрессию или граничный случай, не покрытый патчем. Для чего это стоит, два тестовых случая отчета об ошибке1, 2 проявлять симптомы для меня как на GCC 4.9.0, так и на 5.3.1
Есть еще два связанных сообщения об ошибках:
Эндрю Пински 2015-11-04 07:56:57 UTC
Скорее всего, это боров памяти, который генерирует много по умолчанию
конструкторы, а не петли над ними.
Тот утверждает, что является дубликатом этого:
Ошибка 56671 — Gcc использует большие объемы памяти и мощности процессора с большими битами C ++ 11
Джонатан Уэйкли 2016-01-26 15:12:27 UTC
Генерация инициализации массива для этого конструктора constexpr
эта проблема:constexpr _Base_bitset(unsigned long long __val) noexcept : _M_w{ _WordT(__val) } { }
Действительно, если мы изменим его на S a[4096] {};
у нас нет проблемы.
С помощью perf
мы можем видеть, где GCC проводит большую часть своего времени. Первый:
perf record g++ -std=c++11 -O2 test.cpp
затем perf report
:
10.33% cc1plus cc1plus [.] get_ref_base_and_extent
6.36% cc1plus cc1plus [.] memrefs_conflict_p
6.25% cc1plus cc1plus [.] vn_reference_lookup_2
6.16% cc1plus cc1plus [.] exp_equiv_p
5.99% cc1plus cc1plus [.] walk_non_aliased_vuses
5.02% cc1plus cc1plus [.] find_base_term
4.98% cc1plus cc1plus [.] invalidate
4.73% cc1plus cc1plus [.] write_dependence_p
4.68% cc1plus cc1plus [.] estimate_calls_size_and_time
4.11% cc1plus cc1plus [.] ix86_find_base_term
3.41% cc1plus cc1plus [.] rtx_equal_p
2.87% cc1plus cc1plus [.] cse_insn
2.77% cc1plus cc1plus [.] record_store
2.66% cc1plus cc1plus [.] vn_reference_eq
2.48% cc1plus cc1plus [.] operand_equal_p
1.21% cc1plus cc1plus [.] integer_zerop
1.00% cc1plus cc1plus [.] base_alias_check
Это не будет много значить ни для кого, кроме разработчиков GCC, но все еще интересно посмотреть, что занимает так много времени на компиляцию.
Clang 3.7.0 работает намного лучше, чем GCC. В -O2
компиляция занимает менее секунды, создает гораздо меньший исполняемый файл (8960 байт) и эту сборку:
0000000000400810 <main>:
400810: 53 push rbx
400811: 48 81 ec 00 40 00 00 sub rsp,0x4000
400818: 48 8d 3c 24 lea rdi,[rsp]
40081c: 31 db xor ebx,ebx
40081e: 31 f6 xor esi,esi
400820: ba 00 40 00 00 mov edx,0x4000
400825: e8 56 fe ff ff call 400680 <memset@plt>
40082a: 66 0f 1f 44 00 00 nop WORD PTR [rax+rax*1+0x0]
400830: f3 0f 10 04 1c movss xmm0,DWORD PTR [rsp+rbx*1]
400835: f3 0f 5a c0 cvtss2sd xmm0,xmm0
400839: bf 60 10 60 00 mov edi,0x601060
40083e: e8 9d fe ff ff call 4006e0 <_ZNSo9_M_insertIdEERSoT_@plt>
400843: 48 83 c3 04 add rbx,0x4
400847: 48 81 fb 00 40 00 00 cmp rbx,0x4000
40084e: 75 e0 jne 400830 <main+0x20>
400850: 31 c0 xor eax,eax
400852: 48 81 c4 00 40 00 00 add rsp,0x4000
400859: 5b pop rbx
40085a: c3 ret
40085b: 0f 1f 44 00 00 nop DWORD PTR [rax+rax*1+0x0]
С другой стороны, с GCC 5.3.1, без каких-либо оптимизаций, он компилируется очень быстро, но все равно создает исполняемый файл размером 95328. Компилирование с -O2
уменьшает размер исполняемого файла до 53912, но время компиляции занимает 4 секунды. я мог бы определенно сообщить об этом их bugzilla.
Других решений пока нет …