Я в настоящее время использую GCC, но я недавно обнаружил Clang, и я размышляю о переключении. Однако есть один решающий фактор - качество (скорость, объем памяти, надежность) двоичных файлов, которые он производит - если он gcc -O3
может производить двоичный файл, который работает на 1% быстрее или занимает на 1% меньше памяти, он нарушает условия сделки.
Clang может похвастаться лучшими скоростями компиляции и меньшим объемом памяти во время компиляции, чем GCC, но я действительно заинтересован в тестах / сравнениях итогового скомпилированного программного обеспечения - не могли бы вы указать мне некоторые или описать свой опыт?
optimization
gcc
compiler-construction
clang
benchmarking
Научная фантастика
источник
источник
Ответы:
Вот некоторые современные, хотя и узкие, мои выводы с GCC 4.7.2 и Clang 3.2 для C ++.
ОБНОВЛЕНИЕ: сравнение GCC 4.8.1 v clang 3.3, приложенное ниже.
ОБНОВЛЕНИЕ: сравнение с GCC 4.8.2 v clang 3.4 добавлено к этому.
Я поддерживаю инструмент OSS, созданный для Linux с GCC и Clang, а также с компилятором Microsoft для Windows. Этот инструмент, coan, является препроцессором и анализатором исходных файлов C / C ++ и таких строк кода: его профили вычислительных профилей для анализа рекурсивного спуска и обработки файлов. Ветвь разработки (к которой относятся эти результаты) в настоящее время содержит около 11K LOC в 90 файлах. Теперь он закодирован в C ++, который богат полиморфизмом и шаблонами, но во многих исправлениях его все еще пугает его не столь далекое прошлое во взломанной C. Семантика перемещения явно не используется. Это однопоточный. Я не прилагал серьезных усилий для его оптимизации, в то время как «архитектура» остается в значительной степени ToDo.
Я использовал Clang до 3.2 только в качестве экспериментального компилятора, потому что, несмотря на его превосходную скорость компиляции и диагностику, его стандартная поддержка C ++ 11 отстала от современной версии GCC по отношению к coan. С 3.2 этот пробел был закрыт.
Моя система тестирования Linux для текущей разработки коанов обрабатывает примерно 70 тыс. Исходных файлов в виде комбинации из одного файла парсера, стресс-тестов, потребляющих тысячи файлов, и сценариев, тестирующих файлы <1К. Наряду с отчетом о результатах теста, жгут собирает и отображает общее количество использованных файлов и время выполнения, использованное в coan (он просто передает каждую командную строку coan команде Linux,
time
а также записывает и суммирует сообщенные числа). Сроки польщены тем фактом, что любое количество тестов, которые занимают 0 измеримого времени, все в сумме составят 0, но вклад таких тестов незначителен. Временные характеристики отображаются в концеmake check
примерно так:Я сравнил производительность тестового жгута как между GCC 4.7.2 и Clang 3.2, при прочих равных, кроме компиляторов. Начиная с Clang 3.2, я больше не требую какого-либо препроцессорного разграничения между фрагментами кода, которые GCC будет компилировать, и альтернативами Clang. Я собрал одну и ту же библиотеку C ++ (GCC) в каждом случае и провел все сравнения последовательно в одном терминальном сеансе.
Уровень оптимизации по умолчанию для моей сборки выпуска -O2. Я также успешно протестировал сборки на -O3. Я протестировал каждую конфигурацию 3 раза подряд и усреднил 3 результата со следующими результатами. Число в ячейке данных - это среднее количество микросекунд, потребляемых исполняемым файлом coan для обработки каждого из входных файлов ~ 70K (чтение, анализ и запись и диагностика).
Любое конкретное приложение, скорее всего, будет иметь черты, которые несправедливо играют на сильные или слабые стороны компилятора. Строгий бенчмаркинг использует разнообразные приложения. Имея это в виду, заслуживающие внимания особенности этих данных:
Еще одно интересное сравнение двух компиляторов произошло случайно после этих результатов. Коан свободно использует умные указатели, и один из них активно используется при обработке файлов. Этот конкретный тип умного указателя был определен в предыдущих выпусках typedef с целью дифференциации компилятора, чтобы быть в том
std::unique_ptr<X>
случае, если настроенный компилятор имел достаточно развитую поддержку для его использования как такового, а в противном случае - какstd::shared_ptr<X>
. Смещение в сторонуstd::unique_ptr
было глупым, поскольку эти указатели фактически передавались, ноstd::unique_ptr
выглядело как более подходящий вариант для заменыstd::auto_ptr
в тот момент, когда варианты C ++ 11 были для меня новыми.В ходе экспериментальных сборок, чтобы измерить постоянную потребность Clang 3.2 в этом и аналогичном разграничении, я случайно построил,
std::shared_ptr<X>
когда собирался собиратьсяstd::unique_ptr<X>
, и с удивлением заметил, что полученный исполняемый файл с оптимизацией по умолчанию -O2 был самым быстрым. видел, иногда достигая 184 мсек. за входной файл. С этим одним изменением к исходному коду соответствующие результаты были такими;Примечания здесь:
До и после изменения типа интеллектуального указателя Clang может создать существенно более быстрый исполняемый файл coan при оптимизации -O3, и он может создать одинаково более быстрый исполняемый файл при -O2 и -O3, когда этот тип указателя является лучшим -
std::shared_ptr<X>
- для работы.Очевидный вопрос, который я не компетентен комментировать, заключается в том, почему Clang должен быть в состоянии найти ускорение на 25% -O2 в моем приложении, когда интенсивно используемый тип интеллектуального указателя изменяется с уникального на общий, в то время как GCC безразличен к тому же изменению. Также я не знаю, стоит ли мне приветствовать или поддерживать открытие, что оптимизация Clang -O2 таит в себе такую огромную чувствительность к мудрости моих умных указателей.
ОБНОВЛЕНИЕ: GCC 4.8.1 v clang 3.3
Соответствующие результаты сейчас:
Тот факт, что все четыре исполняемых файла теперь занимают намного большее среднее время, чем ранее, для обработки файла 1, не отражается на производительности последних компиляторов. Это связано с тем, что более поздняя ветвь разработки тестового приложения в то же время приобрела большую сложность в разборе и платит за это быстротой. Только отношения являются значительными.
Примечательно, что теперь это не новость:
Сравнивая эти результаты с результатами для 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, сказав, что я буду придерживаться того же снимка коана для дальнейших обновлений. Но вместо этого я решил протестировать этот снимок (версия 301) и последний имеющийся у меня снимок разработки, который проходит свой набор тестов (версия 619). Это дает результаты немного долготы, и у меня был другой мотив:
В моей первоначальной публикации отмечалось, что я не тратил усилий на оптимизацию коана по скорости. Это было все еще в случае с Rev. 301. Однако, после того, как я встроил устройство синхронизации в жгут для проверки коанов, каждый раз, когда я запускал набор тестов, влияние последних изменений на производительность меня поразило. Я видел, что он часто был удивительно большим и что тенденция была более крутой, чем я чувствовал, чтобы быть заслуженным ростом функциональности.
Рев. 308 среднее время обработки каждого входного файла в наборе тестов более чем удвоилось с момента первой публикации здесь. В этот момент я развернул свою 10-летнюю политику не беспокоиться о производительности. При интенсивном потоке пересмотров всегда учитывалось до 619 производительности, и большое количество из них было направлено исключительно на переписывание ключевых несущих нагрузки на принципиально более быстрых линиях (хотя без использования каких-либо нестандартных функций компилятора для этого). Было бы интересно увидеть реакцию каждого компилятора на этот разворот,
Вот уже знакомая нам временная матрица для двух последних сборок Rev.301:
Coan - Rev.301 результаты
История здесь только незначительно изменилась с GCC-4.8.1 и Clang-3.3. Показ GCC немного лучше. У Clang немного хуже. Шум вполне может объяснить это. Clang по-прежнему выходит вперед
-O2
и имеет-O3
маржу, которая не будет иметь значения в большинстве приложений, но будет иметь значение для многих.А вот и матрица для ред. 619.
Coan - rev.619 результаты
Принимая цифры 301 и 619 бок о бок, высказываются несколько моментов.
Я стремился написать более быстрый код, и оба компилятора решительно оправдывают мои усилия. Но:
GCC воздает эти усилия гораздо щедрее, чем Clang. При
-O2
оптимизации сборка 619 Clang на 46% быстрее, чем сборка 301: при-O3
улучшении Clang - 31%. Хорошо, но на каждом уровне оптимизации сборка 619 GCC более чем в два раза быстрее, чем его 301.GCC более чем отменяет прежнее превосходство Clang. И на каждом уровне оптимизации GCC теперь опережает Clang на 17%.
Способность Clang в сборке 301 получить больше рычагов, чем GCC от
-O3
оптимизации, исчезла в сборке 619. Ни один компилятор не извлекает значительную выгоду из-O3
.Я был достаточно удивлен этим изменением состояния, которое я подозревал, что я мог случайно сделать медленную сборку самого clang 3.4 (так как я собрал его из исходного кода). Таким образом, я повторно запустил тест 619 с запасом Clang 3.3 моего дистрибутива. Результаты были практически такими же, как и для 3.4.
Итак, что касается реакции на разворот: по числам, приведенным здесь, Clang добился гораздо больших успехов, чем GCC, по скорости выжимания из моего кода C ++, когда я не помогал. Когда я решил помочь, GCC проделал намного лучшую работу, чем Clang.
Я не превращаю это наблюдение в принцип, но извлекаю урок: «Какой компилятор создает лучшие двоичные файлы?» это вопрос, который, даже если вы указываете набор тестов, к которому ответ должен быть относительным, все еще не является четким вопросом просто синхронизации двоичных файлов.
Ваш лучший двоичный файл - самый быстрый двоичный файл, или это тот, который лучше всего компенсирует дешевый код? Или лучше всего компенсирует дорогостоящий код, который отдает предпочтение удобству обслуживания и повторному использованию по скорости? Это зависит от характера и относительных весов ваших мотивов для создания двоичного файла, а также от ограничений, при которых вы делаете это.
И в любом случае, если вы глубоко заботитесь о создании «лучших» двоичных файлов, вам лучше продолжать проверять, как последовательные итерации компиляторов воплощают вашу идею «лучших» по сравнению с последовательными итерациями вашего кода.
источник
kcachegrind
для определения функций, где сгенерированные исполняемые файлы отличаются по производительности.Phoronix сделал несколько тестов по этому поводу, но речь идет о снэпшот-версии Clang / LLVM, выпущенной несколько месяцев назад. Результатом было то, что вещи были более или менее толчком; ни GCC, ни Clang не являются окончательно лучше во всех случаях.
Так как вы использовали бы последний Clang, это может быть немного менее актуально. С другой стороны, в GCC 4.6 запланированы некоторые основные оптимизации для Core 2 и i7, по-видимому.
Я полагаю, что более быстрая скорость компиляции Clang будет лучше для оригинальных разработчиков, а затем, когда вы отправите код в мир, Linux distro / BSD / и т.д. конечные пользователи будут использовать GCC для более быстрых двоичных файлов.
источник
Тот факт, что Clang компилирует код быстрее, может быть не так важен, как скорость получающегося двоичного файла. Тем не менее, вот ряд тестов .
источник
Общая разница между GCC 4.8 и clang 3.3 очень мала с точки зрения скорости получаемого двоичного файла. В большинстве случаев код, сгенерированный обоими компиляторами, работает аналогично. Ни один из этих двух компиляторов не доминирует над другим.
Тесты, показывающие, что между GCC и clang существует значительный разрыв в производительности, совпадают.
На производительность программы влияет выбор компилятора. Если разработчик или группа разработчиков используют исключительно GCC, можно ожидать, что программа будет работать немного быстрее с GCC, чем с clang, и наоборот.
С точки зрения разработчика, заметное различие между GCC 4.8+ и clang 3.3 заключается в том, что в GCC есть
-Og
опция командной строки. Эта опция включает оптимизацию, которая не мешает отладке, поэтому, например, всегда можно получить точные трассировки стека. Отсутствие этой опции в clang затрудняет использование clang в качестве оптимизирующего компилятора для некоторых разработчиков.источник
Единственный способ определить это - попробовать. Я видел некоторые действительно хорошие улучшения при использовании Apple LLVM gcc 4.2 по сравнению с обычным gcc 4.2 (для кода x86-64 с довольно большим количеством SSE), но YMMV для разных кодовых баз. Предполагая, что вы работаете с x86 / x86-64 и действительно заботитесь о последних нескольких процентах, вам следует попробовать Intel ICC, поскольку это часто может превзойти gcc - вы можете получить 30-дневную пробную лицензию от intel.com и попробуй это.
источник
Особое отличие, которое я заметил в gcc 5.2.1 и clang 3.6.2, заключается в том, что если у вас есть критический цикл, такой как:
Тогда gcc при компиляции с
-O3
или-O2
умозрительно развернет цикл восемь раз. Clang не развернет его вообще. Методом проб и ошибок я обнаружил, что в моем конкретном случае с данными моей программы правильное количество развертываний равно пяти, поэтому gcc overshot и clang undershot. Тем не менее, overshot был более вредным для производительности, поэтому gcc показал себя намного хуже.Я понятия не имею, является ли разница в развертывании общей тенденцией или это что-то особенное для моего сценария.
Некоторое время назад я написал несколько сборщиков мусора, чтобы больше узнать об оптимизации производительности в C. И результатов, которые я получил, на мой взгляд, достаточно, чтобы немного отдать предпочтение clang. Тем более что сборка мусора в основном связана с погоней за указателями и копированием памяти.
Результаты (числа в секундах):
Это все чистый код C, и я не претендую на производительность любого из компиляторов при компиляции кода C ++.
В Ubuntu 15.10, x86.64 и процессоре AMD Phenom (tm) II X6 1090T.
источник
Собственно говоря, ответ: это зависит. Существует множество тестов, ориентированных на различные виды приложений.
Мой тест в моем приложении: gcc> icc> clang.
Есть редкие операции ввода-вывода, но многие операции с плавающей запятой процессора и структура данных.
флаги компиляции: -Wall -g -DNDEBUG -O3.
https://github.com/zhangyafeikimi/ml-pack/blob/master/gbdt/profile/benchmark
источник