Кланг проти GCC - що забезпечує кращі бінарні файли? [зачинено]


238

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

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


5
Все ще здається цінним питанням та відповідями, і багатьох цікавить.
YasserAsmi

9
@YasserAsmi: І дві метрики - слід пам’яті та швидкість виконання - далеко не довільні або підлягають «думці». Але, схоже, хвороба Physics.SE поширюється тут, і люди почали голосувати, щоб закрити, не читаючи тут деталей тексту запитань.
СФ.

12
запитання задає орієнтири та порівняння, відповідь дає і те й інше ... чому ця думка замість фактичного порівняння?
oemb1905

2
Не розумію, чому це питання було закрито. Незалежно від того, чи це базується на думці, чи на фактах, ми хочемо знати відповідь, і позначення її як закритої надає їй негативного відтінку, де її не повинно бути.
Тимофій Макобу

2
@TomZych: Якщо ви хочете знати ці фактори, задайте різні запитання. Цей дуже специфічний і однозначний - вимагає швидкості виконання та сліду пам’яті. Можливо, вас зацікавлять інші корисні для вас фактори, що не означає, що це питання недійсне, воно просто не відповідає вашим особистим інтересам. Це як ви програміст Java і хочете закрити кожне питання C #, оскільки це не говорить про Java.
СФ.

Відповіді:


239

Ось кілька сучасних, хоча і вузьких висновків шахти з 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. Інструмент, коан, є препроцесором та аналізатором вихідних файлів C / C ++ та таких коду: його обчислювальних спеціальних профілів для рекурсивно-десантного розбору та обробки файлів. Галузь розвитку (до якої відносяться ці результати) наразі містить близько 11 К LOC в приблизно 90 файлах. Зараз він кодується в C ++, який багатий поліморфізмом і шаблонами, але все ще замурований у багатьох патчах своїм не надто віддаленим минулим у злому разом С. Семантика переміщення не експлуатується явно. Він однонитковий. Я не доклав жодних серйозних зусиль для її оптимізації, в той час як "архітектура" залишається такою значною мірою ToDo.

Я використовував Clang до 3.2 лише в якості експериментального компілятора, оскільки, незважаючи на його високу швидкість компіляції та діагностику, його стандартна підтримка C ++ 11 відставала від сучасної версії GCC у відношенні коану. З 3.2 цей пробіл було закрито.

Мій тестовий запуск Linux для поточних процесів розробки коану приблизно 70 Кб вихідних файлів у суміші однофайлових тестових аналізаторів, стрес-тестів, що споживають 1000 тисяч файлів та сценарії тестів, що містять <1 К файли. Окрім звітності про результати тестування, джгут накопичує та відображає загальну кількість споживаних файлів та час роботи, що споживається в коані (він просто передає кожен командний рядок коану команді 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, при цьому всі рівні, крім компіляторів. З Кланг 3.2 мені більше не потрібна препроцесорна диференціація між кодовими трактами, які буде складати GCC та альтернативами Кланг. Я вбудований до тієї самої бібліотеки C ++ (GCC) у кожному конкретному випадку і провів усі порівняння послідовно в одному термінальному сеансі.

Типовим рівнем оптимізації для моєї версії є -O2. Я також успішно протестував збірки на -O3. Я перевіряв кожну конфігурацію 3 рази "назад до спини" і усереднював 3 результати з наступними результатами. Кількість у комірці даних - це середня кількість мікросекунд, що витрачається коаном, який виконується для обробки кожного з вхідних файлів ~ 70 К (читання, розбір та запис виводу та діагностика).

          | -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. При оптимізації -O2 GCC був швидшим, ніж Кланг, лише вусом
  4. При оптимізації -O3, Clang був важливіше швидшим за GCC.

Подальше цікаве порівняння двох укладачів з'явилося випадково незабаром після цих висновків. Coan вільно використовує розумні покажчики, і один з таких значних зусиль застосовується в обробці файлів. Цей тип смарт-покажчика в попередніх випусках був typedef'd заради диференціації компілятора, щоб бути, 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 мсек. на вхідний файл. При цій зміні вихідного коду відповідні результати були такими;

          | -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. Кланг перемагає GCC так само важливо на кожному рівні оптимізації.
  3. На продуктивність GCC лише незначно впливає зміна типу смарт-вказівника.
  4. На продуктивність Кланга -O2 важливо впливає зміна типу смарт-вказівника.

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

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

ОНОВЛЕННЯ: 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
  • Кланг б'є GCC з аналогічно важливим запасом на кожному рівні оптимізації.

Порівнюючи ці результати з результатами для GCC 4.7.2 та клаксом 3.2, видно, що GCC відступив приблизно чверть лідерства клангу на кожному рівні оптимізації. Але оскільки тест-додаток тим часом сильно розроблено, не можна впевнено віднести це до підходу в породженні коду GCC. (Цього разу я зазначив знімок програми, з якого були отримані таймінги, і можна використовувати його знову.)

ОНОВЛЕННЯ: GCC 4.8.2 v clang 3.4

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

У моєму первісному дописі зазначалося, що я не доклав жодних зусиль для оптимізації коану на швидкість. Це все ще було випадком обертів. 301. Однак після того, як я вбудував апарат для синхронізації в конусний тестовий джгут, кожен раз, коли я запускав тестовий набір, ефективність останніх змін дивилася мені в обличчя. Я бачив, що він часто дивно великий і що тенденція була більш круто негативною, ніж я відчував, що заслуговує на себе підвищення функціональності.

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

Ось тепер знайома матриця синхронізації для останніх двох компіляторів збірок версії 301:

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

І ось матриця для оборотів. 619.

коан - 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. При -O2 оптимізації складання 619 Кланг на 46% швидше, ніж його збірка 301: при -O3покращенні Кланг - 31%. Добре, але на кожному рівні оптимізації збірка 619 GCC є більш ніж удвічі швидшою, ніж її 301.

  • GCC більше, ніж повертає колишню перевагу Кланг. І на кожному рівні оптимізації GCC зараз б'є Clang на 17%.

  • Здатність Кланг у збірці 301 отримати більше важелів, ніж GCC від -O3оптимізації, зникла у складі 619. Жоден компілятор не отримує значимого значення з -O3.

Я був досить здивований цим переворотом статків, що підозрював, що, можливо, я випадково зробив собі мляву збірку кланг 3.4 (оскільки я створив це з джерела). Тож я повторно провів тест 619 із запасом мого дистрибутора Clang 3.3. Результати були практично такі ж, як і для 3,4.

Отже, що стосується реакції на поворот: Кланг зробив набагато краще, ніж GCC, зі швидкістю відкрутившись від мого коду С ++, коли я не давав йому допомоги. Коли я вирішив допомогти, GCC зробив набагато кращу роботу, ніж Кланг.

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

Чи є ваш кращий двійковий файл найшвидшим, або він найкращим чином компенсує дешево створений код? Або найкраще компенсує дорого створений код, який надає пріоритет ремонтопридатності та повторному використанню над швидкістю? Це залежить від природи та відносної ваги ваших мотивів виготовлення двійкових та обмежень, при яких ви це робите.

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


9
Чому брязкає швидше? наприклад, компілятор intel використовував спеціальності інтелектуальних чіпів. що clang використовує для отримання переваги? чи можна код переписати так, щоб gcc мав однакову продуктивність?
kirill_igum

27
@krill_igum GCC і clang - це різні (надзвичайно складні) програми, написані різними групами програмістів, щоб виконати одну і ту ж роботу: перевести вихідний код в об'єктний код. Майже неминуче один із них виконає цю роботу помірно краще, ніж інший у будь-якому обраному тесті в будь-який момент часу. Не повинно бути жодної спеціальної «речі», яку переможець «використовує», щоб «отримати перевагу», і оскільки обидві програми є відкритим кодом, вони не мають секретів одна від одної.
Майк Кінгхан

3
Можна використовувати kcachegrindдля точного визначення функцій, де створені виконувані файли відрізняються продуктивністю.

4
-1: Це скоріше роман (чи допис у блозі), ніж відповідь.
Джон Сондерс

60
@JohnSaunders: Що для однієї людини є детальною, глибокою відповіддю, для іншого - роман, недостойний їх уваги. Скажіть, що роз'єднує цих двох людей.
СФ.

48

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

Оскільки ви використовуєте найновіший Clang, це, можливо, трохи менш актуально. Знову ж таки, GCC 4.6 , мабуть, має деякі основні оптимізації для Core 2 та i7, мабуть.

Я думаю, що швидкість компіляції Кланг буде приємнішою для оригінальних розробників, і тоді, коли ви виштовхуєте код у світ, дистрибутив Linux / BSD / тощо. кінцеві користувачі будуть використовувати GCC для більш швидких бінарних файлів.


2
Тільки сьогодні я запускаю кілька орієнтирів щодо швидкості компіляції Clang, і це дуже невтішно для чистого C. Компіляція 35-C файлів із 270 KLOC-лямком була лише на 25% швидшою. Коли я бачу, наскільки швидкий tinycc на Linux, це поганий результат для нового письмового компілятора. Він стає кращим при використанні оптимізацій -O2 / -O3, але оскільки вони використовуються для випуску версії, продуктивність компілятора в цьому випадку не має значення.
Лотар

7
@mcandre Можливо, Ніцше-джоу був складений з Кланг, тоді як ти був складений з GCC.
Mateen Ulhaq

18

Те, що Кланг швидше збирає код, може бути не таким важливим, як швидкість отриманого двійкового файлу. Однак ось низка орієнтирів .


12
Насправді це і є. Під час розробки час компіляції (і споживання ресурсів за рахунок компіляції) набагато більше вузьке місце, ніж двійкові показники. Зрештою, ми компілюємо в режимі налагодження на цьому етапі. Лише тоді, коли настає етап тестування та доставки, ви переходите в режим випуску та намагаєтесь отримати якнайшвидший бінарний файл.
Маттьє М.

3
@ Matthieu M: Я клянусь, що відповідь сказала "може ..", ніби він викликає потенційну стурбованість. Я думаю, можливо, це варто було б згадати, оскільки це було, ви знаєте, пов'язане з ОП.
Дж. М. Бекер

Погодьтеся, хоча всі хороші моменти тут. Я б краще запустити 2-й або 3-й диск RAID 0, SSD або більшу і більш швидку оперативну пам’ять і отримати найкращу продуктивність .exe - за умови, що ці заходи зможуть вас зрівняти чи закрити. Також іноді корисно розробитись з більш ніж одним компілятором. Це може змусити вас знати про не портативні функції та помилки вловлювання, які в іншому випадку залишаються непоміченими, або призводять до непотрібного часу, намагаючись налагодити код, кращий компілятор попередив би / помилився.

Я спробував сьогодні порівнюючи критичний цілочисельний цільовий код, який я написав, і GCC біг набагато швидше (22S clang-llvm 25S), використовуючи обидва -O2 & -O3. Подумайте, що компілятори компілятора (gcc або clang) охоплюють більшість нестандартних функцій та статичних попереджень. У вашому власному великому проекті, не купуючи пакетний код іншого ppl, ви робите щось не так у своїй системі збирання, якщо час компіляції домінує у часі зв'язку. Є такі інструменти, як ccache.samba.org, які допомагають, якщо ви чистіть часто. Інша проблема із зміною компіляторів - це весь час вкладення коштів у тестування / перевірку, які викидаються.
Rob11311

code.google.com/p/distcc - це ще один проект, який може прискорити масове збирання разів, якщо ціла бібліотека потребує перекомпіляції через зміни структури даних або з метою перевірки / перевірки
Rob11311

11

Загальна різниця між GCC 4.8 та клаксом 3.3 щодо швидкості одержуваного двійкового файлу дуже мала. У більшості випадків код, що генерується обома компіляторами, виконує аналогічно. Жоден із цих двох компіляторів не домінує над іншим.

Орієнтовні показники, які говорять про наявність значного розриву в роботі між GCC та клаксом, збігаються.

На ефективність програми впливає вибір компілятора. Якщо розробник або група розробників використовує виключно GCC, тоді можна очікувати, що програма буде працювати швидше з GCC, ніж з clang, і навпаки.

З точки зору розробника, помітна відмінність між GCC 4.8+ та клаксом 3.3 полягає в тому, що GCC має параметр -Ogкомандного рядка. Цей параметр дозволяє оптимізувати, що не перешкоджає налагодженню, тому, наприклад, завжди можна отримати точні сліди стека. Відсутність цієї опції в clang ускладнює використання clang як оптимізуючого компілятора для деяких розробників.


Останнім часом (3.3 та 4.8) я не бачу навіть великої різниці між часом компіляції. (в "моїх" програмах із часом компіляції між 10 секундами і 30 секундами).
alfC

9

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


8

Особлива різниця, яку я зазначив у gcc 5.2.1 та clang 3.6.2, полягає в тому, що якщо у вас є критична петля, наприклад:

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

Тоді gcc буде при компілюванні -O3 або -O2, спекулятивно розкручує цикл вісім разів. Кланг взагалі не зніме його. Через спроби та помилки я виявив, що в моєму конкретному випадку з моїми програмними даними потрібна кількість розгортання - це п’ять, так що оверсайт GCC та підкреслення кланг. Однак перевитрати були більш згубними для продуктивності, тому gcc тут діяв набагато гірше.

У мене є не маю, чи розгортання різниці - це загальна тенденція чи просто щось, що було специфічним для мого сценарію.

Деякий час назад я написав декілька сміттєзбірників, щоб навчити себе більше про оптимізацію продуктивності в 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, і я не претендую на продуктивність компіляторів при компілюванні коду C ++.

На процесорі Ubuntu 15.10, x86.64 та процесорі AMD Phenom (tm) II X6 1090T.


4

В основному, відповідь така: це залежить. Існує велика кількість орієнтирів, орієнтованих на різні види застосування.

Мій орієнтир у моїй програмі: gcc> icc> clang.

Є рідкісні IO, але багато операцій з плаваючим процесором та структурою даних.

компілювати прапори -Wall -g -DNDEBUG -O3.

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

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.