Comments 26
Но ведь действительно, разве Go позиционируется, как замена Си, включая производительность?
Некорректно приводить сравнения, в которых действия выполняются меньше секунды. А вдруг это просто система лагнула?
0x0000555555554590 <+32>: add $0x1,%eax
0x0000555555554593 <+35>: pxor %xmm0,%xmm1
0x0000555555554597 <+39>: paddq %xmm2,%xmm0
0x000055555555459b <+43>: cmp $0x4c4b40,%eax
А у меня результат (gcc 8.2.1) выглядит так:
(gdb) disassemble main
Dump of assembler code for function main:
0x0000000000001040 <+0>: push %rbp
0x0000000000001041 <+1>: vmovdqa 0xfd7(%rip),%ymm0 # 0x2020
0x0000000000001049 <+9>: xor %eax,%eax
0x000000000000104b <+11>: vpxor %xmm3,%xmm3,%xmm3
0x000000000000104f <+15>: vmovdqa 0xfe9(%rip),%xmm4 # 0x2040
0x0000000000001057 <+23>: mov %rsp,%rbp
0x000000000000105a <+26>: and $0xffffffffffffffe0,%rsp
0x000000000000105e <+30>: xchg %ax,%ax
0x0000000000001060 <+32>: vextractf128 $0x1,%ymm0,%xmm1
0x0000000000001066 <+38>: vpaddq %xmm0,%xmm4,%xmm2
0x000000000000106a <+42>: vpaddq %xmm1,%xmm4,%xmm1
0x000000000000106e <+46>: add $0x1,%eax
0x0000000000001071 <+49>: vxorps %ymm0,%ymm3,%ymm3
0x0000000000001075 <+53>: vinsertf128 $0x1,%xmm1,%ymm2,%ymm0
0x000000000000107b <+59>: cmp $0x2625a0,%eax
0x0000000000001080 <+64>: jne 0x1060 <main+32>
0x0000000000001082 <+66>: lea 0xf7b(%rip),%rdi # 0x2004
0x0000000000001089 <+73>: vmovdqa %xmm3,%xmm0
0x000000000000108d <+77>: xor %eax,%eax
0x000000000000108f <+79>: vextractf128 $0x1,%ymm3,%xmm3
0x0000000000001095 <+85>: vpxor %xmm3,%xmm0,%xmm3
0x0000000000001099 <+89>: vpsrldq $0x8,%xmm3,%xmm0
0x000000000000109e <+94>: vpxor %xmm0,%xmm3,%xmm3
0x00000000000010a2 <+98>: vmovq %xmm3,%rsi
0x00000000000010a7 <+103>: vzeroupper
0x00000000000010aa <+106>: callq 0x1030 <printf@plt>
0x00000000000010af <+111>: xor %eax,%eax
0x00000000000010b1 <+113>: leaveq
0x00000000000010b2 <+114>: retq
End of assembler dump.
1. Не замедляет время компиляции.
2. Реализация не слишком сложная (maintainability).
3. Имеет примеры важного кода, который будет сильно ускоряться, кроме синтетики.
Я не утверждаю, что это бесполезные вещи, просто напоминаю, что приоритет у этого всего довольно низкий, а порог для включения этих оптимизаций в ядро Go довольно высокий. Как-то так.
Математический код и HPC может и получит буст от векторизации, но для gc по-моему это не самые частые пользователи. Возможно в будущем что-то изменится, но пока ситуация такая. Где-то ещё были разные связанные с этим proposal'ы, в том числе о введении примитивов для использования FMA инструкций, но под рукой списка нет, можете поискать на github трекере, если интересно.
Возможно LLVM-based компилятор будет лучше, но по-моему там пока ещё не достаточно всё зрелое.
LLVM успешно развернет и завекторизует.
Т.е. даже C# с бэкендом LLVM через mono-llvm или Unity Burst будет быстрее
PS: вообще я удивлен почему компиляторы не посчитали цикл в компайл тайме и не заменили константой — возможно через какой-нибудь llvm-souper/polly можно оптимизнуть
хотя если вместо ^ использовать &,+,* — то посчитает в компайл-тайме
Скомпилировал ваш Си код clang с -O2 -march=native (или -mcpu=haswell) — он развернул ваш цикл, распихал все инты по всем доступным AVX регистрам.
https://godbolt.org/z/iLkRS5
ЗЫ: даже без avx все равно будет быстрее — будет тот же анроллинг и все SSE регистры
real 0m0.003s
user 0m0.001s
sys 0m0.001s
Вы в итоге хотите сравнить циклы C vs Go а на деле сравниваете накладные расходы на запуск приложения, на гошный рантайм, на специфику работы printf.
Да и на самом деле смысл Go это больше про скорость разработки а не про тесты производительности с C.
Видимо в связи с тем, что штатный компилятор отлично оптимизирует запуск тредов (в моем случае на 4 ядра было создано 5 дополнительных тредов), приложение отрабатывает быстрее.
У меня одного эта фраза вызвала лёгкое недоумение?
Cи vs Go циклы и простая математика