Подтвердить что ты не робот

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

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

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

4b9b3361

Ответ 1

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

UPDATE: сравнение GCC 4.8.1 v clang 3.3, приведенное ниже.

ОБНОВЛЕНИЕ: GCC 4.8.2 v clang 3.4 сравнивается с этим.

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

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

Мой тестовый жгут для Linux для текущих процессов разработки 70K исходных файлов в виде комбинации тестовых файлов анализатора одного файла, стресс тесты, потребляющие 1000 файлов и сценарные тесты, 1K файлов. Помимо сообщения результатов испытаний, отображает итоговые значения потребляемых файлов и время, затрачиваемое на использование (он просто передает каждую командную строку coan команде Linux time и захватывает и суммирует сообщенные номера). Время пользы тем фактом, что любое количество тестов, принимающих 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, все равны, кроме компиляторов. Что касается Clang 3.2, Мне больше не требуется дифференциация препроцессора между кодом которые GCC будет компилировать, и альтернативы Clang. Я построил той же библиотеки С++ (GCC) в каждом случае и выполнял все сравнения последовательно в том же сеансе терминала.

Уровень оптимизации по умолчанию для моей версии сборки -O2. Я также успешно протестировал сборки на -O3. Я тестировал каждую конфигурацию 3 раз спина к спине и усреднил 3 результата, со следующими Результаты. Число в ячейке данных - это среднее число микросекунд, потребляемых исполняемым компьютером, для обработки каждого из входные файлы ~ 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|

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

  • Оптимизация
  • -O3 была незначительно вредной для GCC Оптимизация
  • -O3 была важна для Clang
  • При оптимизации -O2 GCC был быстрее, чем Clang, всего лишь усом
  • При оптимизации -O3 Clang был значительно быстрее, чем GCC.

Еще одно интересное сравнение двух компиляторов возникло случайно вскоре после этих выводов. Coan свободно использует умные указатели и один из них в значительной степени осуществляется при обработке файлов. Этот конкретный тип smart-pointer был типизирован в предыдущих выпусках ради компилятор-дифференцирование, чтобы быть std::unique_ptr<X>, если сконфигурированный компилятор имел достаточно зрелую поддержку для его использования в качестве это, и в противном случае a std::shared_ptr<X>. Предвзятость до std::unique_ptr была глупый, поскольку эти указатели фактически были перемещены, но std::unique_ptr выглядел как опция fitter для замены std::auto_ptr в момент, когда варианты С++ 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 |

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

  • Ни один компилятор теперь не приносит пользы от оптимизации -O3.
  • Clang превосходит GCC так же важно на каждом уровне оптимизации.
  • Производительность GCC незначительно зависит от типа смарт-указателя изменение.
  • Производительность Clang -O2 существенно зависит от типа смарт-указателя изменение.

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

Очевидный вопрос, который я не компетентен комментировать, Clang должен уметь находить ускорение 25% -O2 в моем приложении, когда сильно используемый тип интеллектуального указателя изменяется с уникального на общий, в то время как GCC безразличен к тому же изменению. Я также не знаю, должен ли я приветствовать или охарактеризовать открытие, что гавани оптимизации Clang-O2 такая огромная чувствительность к мудрости моих умных указателей.

UPDATE: 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 безразличен к оптимизации -O3
  • clang очень мало влияет на оптимизацию -O3.
  • clang превосходит GCC на аналогичном уровне на каждом уровне оптимизации.

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

UPDATE: GCC 4.8.2 v clang 3.4

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

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

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

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

coan - rev.301 results

          | -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. GCC, показывающий это мелочь лучше. Кланг хуже. Шум вполне мог объяснить это. Clang по-прежнему выходит за пределы -O2 и -O3, которые не имеют значения в большинстве приложений, но это будет иметь значение для многих.

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

coan - rev.619 results

          | -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. При -O2 оптимизация Clang 619 build на 46% быстрее, чем его сборка 301: at -O3 Clang's улучшение составляет 31%. Хорошо, но на каждом уровне оптимизации GCC 619 build более чем в 2 раза быстрее, чем 301.

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

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

Я был достаточно удивлен этим поворотом судьбы, что я подозревал, что я возможно, случайно сделал вялую сборку самого clang 3.4 (так как я построил это из источника). Таким образом, я повторил тест 619 с моим дистрибутивным запасом Clang 3.3. результаты были практически такими же, как и для 3.4.

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

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

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

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

Ответ 2

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

Поскольку вы будете использовать последний Clang, это может быть немного менее актуальным. С другой стороны, GCC 4.6, по-видимому, имеет некоторые

Ответ 3

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

Ответ 4

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

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

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

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

Ответ 5

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

Ответ 6

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

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

Тогда gcc будет при компиляции с -O3 или -O2 спекулятивно разверните цикл восемь раз. Кланг вообще не развит. Через проб и ошибок. Я обнаружил, что в моем конкретном случае с моими данными программы, правильное количество разворачивания - пять, поэтому gcc переборщил и clang перекус. Однако перегревание было более пагубным для gcc здесь намного хуже.

У меня нет идеи, если разница разворота - общая тенденция или просто что-то, что было характерно для моего сценария.

A назад я написал несколько мусора коллекционеров, чтобы больше научить меня о оптимизации производительности в C. И результаты, которые я получил, в моем достаточно ума, чтобы немного одобрить кланг. Тем более, что мусор сбор в основном связан с записью и копированием памяти.

Результаты (числа в секундах):

+---------------------+-----+-----+
|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-код, и я не претендую ни на компиляторы при компиляции кода на С++.

В Ubuntu 15.10, x86.64 и процессоре AMD Phenom (tm) II X6 1090T.

Ответ 7

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

Мой тест в моем приложении: gcc > icc > clang.

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

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

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