Clang vs GCC-который производит лучшие двоичные файлы? [закрытый]

в настоящее время я использую GCC, но недавно я обнаружил Clang, и я размышляю о переключении. Однако есть один решающий фактор-качество (скорость, объем памяти, надежность) двоичных файлов, которые он производит-if gcc -O3может создавать двоичный файл, который работает на 1% быстрее или занимает на 1% меньше памяти, это прерыватель сделки.

Clang может похвастаться лучшей скоростью компиляции и более низким объемом памяти во время компиляции, чем GCC, но меня действительно интересуют критерии / сравнения результирующего скомпилированного программного обеспечения - не могли бы вы указать мне на некоторые или описать ваш опыт?

7 ответов


вот некоторые современные, хотя и узкие результаты моих исследований с GCC 4.7.2 и Clang 3.2 для C++.

обновление: GCC 4.8.1 v clang 3.3 сравнение прилагается ниже.

UPDATE: GCC 4.8.2 v clang 3.4 сравнение прилагается к этому.

я поддерживаю инструмент OSS, который построен для Linux как с GCC, так и с Clang, и с компилятором Microsoft для Windows. Инструмент, coan, является препроцессором и анализатор источника C / C++ файлы и кодовые линии таких: its вычислительные профили по рекурсивному разбору и обработке файлов. Сектор развития (к которому относятся эти результаты) содержит в настоящее время около 11K LOC в около 90 файлов. Он закодирован, теперь, в C++, который богат полиморфизмом и шаблонами, но все еще погрязший во многих заплатах своим не столь отдаленным прошлым в взломанном C. Семантика перемещения явно не используется. Он однопоточный. Я не приложили серьезных усилий для его оптимизации, в то время как "архитектура" остается так во многом Тодо.

я использовал Clang до 3.2 только в качестве экспериментального компилятора потому что, несмотря на свои главные скорость и диагностики компиляции, свое Стандартная поддержка C++11 отставала от современной версии GCC в уважение, проявляемое коаном. С 3.2 этот разрыв был закрыт.

мой тестовый жгут Linux для текущих процессов разработки coan примерно 70K исходные файлы в смеси однофайловых тестов анализатора, стресс тесты потребление 1000 файлов и тестов сценариев, потребляющих и фиксирует и суммирует цифры). Тайминги польщены тем, что любое количество тестов, которые занимают 0 измеримое время, будет все складывается до 0, но вклад таких тестов незначителен. Этот статистика времени отображается в конце make check такой:

coan_test_timer: info: coan processed 70844 input_files.
coan_test_timer: info: run time in coan: 16.4 secs.
coan_test_timer: info: Average processing time per input file: 0.000231 secs.

я сравнил производительность тестового жгута как между GCC 4.7.2 и Clang 3.2, все вещи равны, кроме компиляторов. Как лязг 3.2, Я больше не требую какого-либо препроцессорного дифференцирования между кодом тракты, которые GCC будет компилировать и лязгать альтернативы. Я строил для ... та же библиотека C++ (GCC) в каждом случае и выполняла все сравнения последовательно в том же терминальном сеансе.

в уровень оптимизации по умолчанию для моей сборки выпуска - O2. Я тоже успешно протестированные сборки at-O3. Я протестировал каждую конфигурацию 3 время спина к спине и усредненные результаты 3, со следующими результаты. Число в ячейке данных-среднее число микросекунды, потребляемые исполняемым файлом coan для обработки каждого из входные файлы ~70K (чтение, анализ и запись вывода и диагностики).

          | -O2 | -O3 |O2/O3|
----------|-----|-----|-----|
GCC-4.7.2 | 231 | 237 |0.97 |
----------|-----|-----|-----|
Clang-3.2 | 234 | 186 |1.25 |
----------|-----|-----|------
GCC/Clang |0.99 | 1.27|

любое конкретное приложение, скорее всего, будет иметь черты, которые играют несправедливо сильные и слабые стороны компилятора. Строгий бенчмаркинг использует разнообразные применения. С этим колодцем в разуме, примечательное особенности этих данных:

  1. -оптимизация O3 была незначительно вредна для GCC
  2. -оптимизация O3 была важна для Clang
  3. at-O2 оптимизация, GCC был быстрее, чем лязгали только усы
  4. at-O3 оптимизация, Clang был важно быстрее, чем ССЗ.

еще одно интересное сравнение двух компиляторов появилось случайно вскоре после этих открытий. Coan либерально использует умные указатели и один из них активно используется при обработке файлов. Это частности тип smart-pointer был typedef'D в предыдущих выпусках ради компилятор-дифференцирование, чтобы быть std::unique_ptr<X> если сконфигурированный компилятор имел достаточно зрелую поддержку для его использования в качестве это, и в противном случае std::shared_ptr<X>. Предубеждение к std::unique_ptr было глупо, так как эти указатели на самом деле были переданы вокруг, но!--10--> выглядел как вариант слесаря для замены std::auto_ptr в тот момент, когда варианты C++11 были для меня новыми.

в ходе экспериментальных построений для калибровки Clang 3.2 продолжалась потребность для этой и подобной дифференциации я непреднамеренно построил std::shared_ptr<X> когда я намеревался построить std::unique_ptr<X>, и с удивлением заметил, что полученный исполняемый файл, по умолчанию-O2 оптимизация, была самой быстрой Я видел, иногда достигая 184 мс. на входной файл. С этим изменения в исходный код, соответствующие результаты были таковы;

          | -O2 | -O3 |O2/O3|
----------|-----|-----|-----|
GCC-4.7.2 | 234 | 234 |1.00 |
----------|-----|-----|-----|
Clang-3.2 | 188 | 187 |1.00 |
----------|-----|-----|------
GCC/Clang |1.24 |1.25 |

пункты отметить следующие:

  1. ни один компилятор теперь не выигрывает от оптимизации-O3.
  2. Clang бьет GCC так же важно на каждом уровне оптимизации.
  3. производительность GCC незначительно зависит от типа смарт-указателя изменение.
  4. лязг-х-О2 на производительность существенно влияет тип smart-pointer изменение.

до и после изменения типа смарт-указателя Clang может создавать существенно более быстрая оптимизация исполняемого файла coan at-O3, и он может создайте одинаково быстрый исполняемый файл at - O2 и-O3, когда это тип указателя является лучшим -std::shared_ptr<X> - для работы.

очевидный вопрос, который я не компетентен комментировать, это почему Лязг должен уметь найти 25% - Ускорение O2 в моем приложении, когда сильно используемый тип смарт-указателя изменяется с уникального на общий, в то время как GCC безразличен к тому же изменению. И не знаю, стоит ли. cheer or boo открытие, что оптимизация Clang's-O2 укрывает такая огромная чувствительность к мудрости моего выбора smart-pointer.

обновление: GCC 4.8.1 v clang 3.3

соответствующие результаты теперь являются следующими:

          | -O2 | -O3 |O2/O3|
----------|-----|-----|-----|
GCC-4.8.1 | 442 | 443 |1.00 |
----------|-----|-----|-----|
Clang-3.3 | 374 | 370 |1.01 |
----------|-----|-----|------
GCC/Clang |1.18 |1.20 |

тот факт, что все четыре исполняемые файлы теперь возьмите гораздо больше среднего времени, чем раньше, чтобы обработать Файл 1 не не подумайте о производительности последних компиляторов. Это связано с тот факт, что более поздняя ветвь разработки тестового приложения взяла на себя много тем временем разбор изощренности и платит за это скоростью. Только коэффициенты значительное.

примечательные моменты теперь не являются захватывающе новыми:

  • GCC-это безразлично -О3 оптимизация
  • clang выгоды очень незначительно от-O3 оптимизации
  • clang бьет GCC по аналогично важному запасу на каждом уровне оптимизации.

сравнивая эти результаты с результатами для GCC 4.7.2 и clang 3.2, выделяется, что GCC отбросил около четверти лидерства clang на каждом уровне оптимизации. Но поскольку тестовое приложение было сильно разработано, тем временем нельзя уверенно приписывайте это догоняющему в генерации кода GCC. (На этот раз я отметил снимок приложения, из которого были получены тайминги и может использовать его снова.)

обновление: GCC 4.8.2 v clang 3.4

я закончил обновление для GCC 4.8.1 v Clang 3.3, сказав, что я бы придерживайтесь того же coan snaphot для дальнейших обновлений. Но я решил вместо того, чтобы проверить на этом снимке (REV. 301)и о последних разработках снимок у меня есть, который проходит его тестовый набор (REV. 619). Это дает результаты немного долготы, и у меня был другой мотив:--23-->

мое первоначальное сообщение отметило, что я не посвятил никаких усилий оптимизации coan для скорость. Так было и в 301-м откр. Однако, после того, как я построил приурочивая прибор в проводку испытания coan, каждый раз я бежал комплект испытания влияние последних изменений на производительность смотрело мне в лицо. Я видел это. он часто был удивительно большим и что тенденция была более резко отрицательной, чем Я чувствовал заслуживайте увеличения в функциональности.

к REV. 308 среднее время обработки на входной файл в наборе тестов имело Ну, более чем в два раза с момента первого размещения здесь. В этот момент я сделал Включите мою 10-летнюю политику не беспокоиться о производительности. В интенсиве Спейт изменений до 619 представление всегда было рассмотрением и a большое количество из них пошло исключительно на переписывание ключевых грузоносителей на принципиально быстрее линии (хотя и без использования каких-либо нестандартных возможности компилятора для этого). Было бы интересно увидеть реакцию каждого компилятора на это Разворот,

вот теперь знакомая матрица таймингов для последних двух сборок компиляторов REV. 301:

результаты coan-REV. 301

          | -O2 | -O3 |O2/O3|
----------|-----|-----|-----|
GCC-4.8.2 | 428 | 428 |1.00 |
----------|-----|-----|-----|
Clang-3.4 | 390 | 365 |1.07 |
----------|-----|-----|------
GCC/Clang | 1.1 | 1.17|

история здесь лишь незначительно изменилась с GCC-4.8.1 и Clang-3.3. Показывая ССАГПЗ немного лучше. Clang это мелочь хуже. Шум вполне мог объяснить это. Лязг все еще ... выходит вперед -O2 и -O3 поля, которые не будут иметь значения в большинстве заявки, но будет иметь значение для многих.

и вот матрица для REV. 619.

coan-REV. 619 результаты

          | -O2 | -O3 |O2/O3|
----------|-----|-----|-----|
GCC-4.8.2 | 210 | 208 |1.01 |
----------|-----|-----|-----|
Clang-3.4 | 252 | 250 |1.01 |
----------|-----|-----|------
GCC/Clang |0.83 | 0.83|

принимая 301 и 619 цифры бок о бок, несколько точек высказываются.

  • я стремился написать более быстрый код, и оба компилятора решительно оправдывают мое усилие. Но:

  • GCC оплачивает эти усилия гораздо щедрее, чем Clang. At -O2 оптимизация сборки 619 Clang на 46% быстрее, чем ее 301 сборка: at -O3 из Clang улучшение на 31%. Хорошо, но на каждом уровне оптимизации сборка GCC 619 более чем в два раза быстрее, чем его 301.

  • GCC больше, чем отменяет прежнее превосходство Clang. И при каждой оптимизации уровень GCC теперь бьет Clang by 17%.

  • способность Clang в сборке 301, чтобы получить больше рычагов, чем GCC от -O3 оптимизация ушел в сборку 619. Ни один компилятор не получает осмысленно от -O3.

так что касается реакции на разворот: на номера здесь, Clang сделал много лучше, чем GCC на скорости отжима из моего кода c++, когда я не давал ему помощь. Когда я решил помочь, GCC сделал гораздо лучшую работу, чем Clang.

я не поднимаю это наблюдение в принцип, но я беру урок, который "какой компилятор производит лучшие двоичные файлы?"это вопрос это, даже если вы укажете набор тестов, к которому ответ должен быть относительным, еще не ясный вопрос просто времени бинарники.

ваш лучший двоичный самый быстрый двоичный файл, или это тот, который лучше всего компенсирует дешево созданный код? Или лучше всего компенсирует дорого созданный код, который приоритизирует ремонтопригодность и повторное использование по скорости? Это зависит от природа и относительные веса ваших мотивов для создания двоичного кода, а также ограничения, при которых вы это делаете.

и в любом случае, если вы глубоко заботитесь о создании" лучших " двоичных файлов, то вы лучше продолжайте проверять, как последовательные итерации компиляторов доставляют на ваш идея "лучшего" над последовательными итерациями вашего кода.


Phoronix сделал несколько критерии об этом, но речь идет о версии моментального снимка Clang / LLVM от нескольких месяцев назад. Результаты заключаются в том, что все было более или менее толчком; ни GCC, ни Clang определенно не лучше во всех случаях.

поскольку вы используете последний Clang, это, возможно, немного менее актуально. Опять же, GCC 4.6 планируется иметь некоторые основных оптимизаций для Core 2 и i7, видимо.

Я думаю, что Clang быстрее скорость компиляции будет приятнее для оригинальных разработчиков, а затем, когда вы выталкиваете код в мир, дистрибутив Linux/BSD/etc. конечные пользователи будут использовать GCC для более быстрых двоичных файлов.


тот факт, что Clang компилирует код быстрее, может быть не так важен, как скорость результирующего двоичного файла. Однако вот серия тестов.


существует очень небольшая общая разница между GCC 4.8 и clang 3.3 с точки зрения скорости результирующего двоичного файла. В большинстве случаев код, сгенерированный обоими компиляторами, выполняет аналогично. Ни один из этих двух компиляторов не доминирует над другим.

критерии, говорящие о том, что существует значительный разрыв в производительности между GCC и clang, совпадают.

производительность программы зависит от выбора компилятора. Если разработчик или группа разработчиков исключительно используя GCC, можно ожидать, что программа будет работать немного быстрее с GCC, чем с clang, и наоборот.

С точки зрения разработчика, заметная разница между GCC 4.8+ и clang 3.3 заключается в том, что GCC имеет командная строка. Эта опция включает оптимизацию, которая не мешает отладке, поэтому, например, всегда можно получить точные трассировки стека. Отсутствие этого параметра в clang затрудняет использование clang в качестве оптимизирующего компилятора для некоторые разработчики.


единственный способ определить это-попробовать. FWIW я видел некоторые действительно хорошие улучшения, используя LLVM gcc 4.2 от Apple по сравнению с обычным gcc 4.2 (для кода x86-64 с довольно большим количеством SSE), но YMMV для разных кодовых баз. Предполагая, что вы работаете с x86/x86-64 и что вы действительно заботитесь о последних нескольких процентах, вы также должны попробовать ICC Intel, так как это часто может превзойти gcc - вы можете получить 30-дневную оценочную лицензию от intel.com и попробуй.


своеобразное различие, которое я отметил на gcc 5.2.1 и clang 3.6.2, это, если у вас есть критический цикл, например:

for (;;) {
    if (!visited) {
        ....
    }
    node++;
    if (!*node) break;
  }

тогда gcc будет, при компиляции с -O3 или -O2, изучающе разверните петлю восемь раз. Лязг не развернет его вообще. Через методом проб и ошибок я обнаружил, что в моем конкретном случае с моими данными программы, нужное количество отматываем пять так ССЗ недокус и Clang недокус. Однако, overshotting было более вредно к peformance поэтому ССЗ здесь все гораздо хуже.

Я идея если разворачивающаяся разница является общей тенденцией или что-то особенное в моем сценарии.

некоторое время назад я написал мало мусора коллекционеры!--14--> чтобы научить себя больше об оптимизации производительности и результаты я получил в мой достаточно ума, чтобы слегка благосклонно отнестись к лязгу. Тем более что мусор коллекция в основном о погоне за указателем и копировании памяти.

результаты это (цифры в секундах):

+---------------------+-----+-----+
|Type                 |GCC  |Clang|
+---------------------+-----+-----+
|Copying GC           |22.46|22.55|
|Copying GC, optimized|22.01|20.22|
|Mark & Sweep         | 8.72| 8.38|
|Ref Counting/Cycles  |15.14|14.49|
|Ref Counting/Plain   | 9.94| 9.32|
+---------------------+-----+-----+

Это все чистый код C, и я не претендую ни на один из компиляторов производительность при компиляции кода C++.

в Ubuntu 15.10, с архитектурой x86.64 и АМД процессоры Phenom(ТМ) II и процессор Х6 1090T.


в основном говоря, ответ: это зависит. Существует много ориентиров, ориентированных на различные виды применения.

мой бенчмарк в моем приложении: gcc > icc > clang.

есть редкие IO, но многие операции с плавающим процессором и структурой данных.

скомпилировать флаги is-Wall-g-DNDEBUG-O3.

https://github.com/zhangyafeikimi/ml-pack/blob/master/gbdt/profile/benchmark