İşte C ++ için GCC 4.7.2 ve Clang 3.2 ile dar bulgularım da olsa bazı güncel bilgiler.
GÜNCELLEME: GCC 4.8.1 v clang 3.3 karşılaştırma eklenmiştir.
GÜNCELLEME: Buna GCC 4.8.2 v clang 3.4 karşılaştırması eklenmiştir.
Linux için hem GCC hem de Clang ile ve Microsoft'un Windows için derleyicisi ile oluşturulmuş bir OSS aracı kullanıyorum. Coan aracı, C / C ++ kaynak dosyalarının ve codeline'larının ön işlemcisi ve analizcisidir: özyinelemeli iniş ayrıştırma ve dosya işleme üzerine hesaplama profili ana dalları. Geliştirme dalı (bu sonuçların ait olduğu) şu anda yaklaşık 90 dosyada yaklaşık 11K LOC içermektedir. Şimdi, polimorfizm ve şablonlar açısından zengin olan C ++ 'da kodlanmıştır ve yine de hack'lenmiş bir arada C kadar uzak olmayan geçmişiyle birçok yamada birleştirilmiştir. Hareket semantiği açıkça istismar edilmemiştir. Tek iş parçacıklı. Ben "mimarisi" büyük ölçüde ToDo kalır iken, onu optimize etmek için ciddi bir çaba sarf ettim.
Clang'ı 3.2'den önce sadece deneysel bir derleyici olarak kullandım, çünkü üstün derleme hızına ve teşhisine rağmen, C ++ 11 standart desteği, çağdaş GCC versiyonunu coan'ın kullandığı açılardan geride bıraktı. 3.2 ile bu boşluk kapatıldı.
Mevcut coan geliştirme süreçleri için Linux test kablo takımı, tek dosya ayrıştırıcı test senaryoları, 1000'lerce dosya tüketen stres testleri ve <1K dosya tüketen senaryo testlerinin bir karışımında yaklaşık 70K kaynak dosyası işler. Test sonuçları raporlamanın yanı sıra, kablo demeti, tüketilen toplam dosya ve tüketilen çalışma süresini biriktirir ve görüntüler (sadece her bir coan komut satırını Linux time
komutuna geçirir ve raporlanan sayıları toplar ve toplar ). Zamanlamalar, 0 ölçülebilir zaman alan herhangi bir sayıda testin 0'a kadar çıkacağı gerçeğiyle düzleştirilir, ancak bu tür testlerin katkısı ihmal edilebilir. Zamanlama istatistikleri aşağıdaki gibi görüntülenir 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.
Test kablo demeti performansını GCC 4.7.2 ve Clang 3.2 arasında karşılaştırdım, derleyiciler dışında her şey eşitti. Clang 3.2'den itibaren artık GCC'nin derleyeceği kod yolları ve Clang alternatifleri arasında herhangi bir önişlemci farklılaştırmasına gerek duymuyorum. Her durumda aynı C ++ kütüphanesine (GCC'ler) inşa ettim ve tüm karşılaştırmaları ardışık olarak aynı terminal oturumunda gerçekleştirdim.
Sürüm sürümüm için varsayılan optimizasyon düzeyi -O2'dir. Ayrıca derlemeleri -O3'te başarıyla test ettim. Her konfigürasyonu arka arkaya 3 kez test ettim ve aşağıdaki sonuçlarla 3 sonucun ortalamasını aldım. Bir veri hücresindeki sayı, ~ 70K girdi dosyalarının (okuma, ayrıştırma ve yazma ve tanılama) her birinin işlenmesi için yürütülebilir dosya tarafından tüketilen ortalama mikrosaniye sayısıdır.
| -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|
Herhangi bir özel uygulamanın, bir derleyicinin güçlü veya zayıf yönlerine haksızlık getiren özellikleri olması muhtemeldir. Titiz kıyaslama çeşitli uygulamalar kullanır. Bunu akılda tutarak, bu verilerin dikkate değer özellikleri şunlardır:
- -O3 optimizasyonu GCC'ye çok az zarar verdi
- -O3 optimizasyonu Clang için önemliydi
- -O2 optimizasyonunda, GCC sadece bir bıyıkla Clang'dan daha hızlıydı
- -O3 optimizasyonunda, Clang GCC'den önemli ölçüde daha hızlıydı.
İki derleyicinin daha ilginç bir karşılaştırması, bu bulgulardan kısa bir süre sonra kazayla ortaya çıktı. Coan liberal olarak akıllı işaretçiler kullanıyor ve bunlardan biri dosya işlemede yoğun bir şekilde kullanılıyor. Bu belirli akıllı işaretçi türü, derleyici farklılaşması uğruna önceki sürümlerde std::unique_ptr<X>
, yapılandırılmış derleyicinin bu şekilde kullanımı için yeterince olgun bir desteğe sahip olup olmadığı şeklinde tanımlanmıştır std::shared_ptr<X>
. std::unique_ptr
Bu işaretçiler aslında aktarıldığından, önyargı aptalcaydı, ancak C ++ 11 varyantlarının benim için yeni olduğu bir noktada std::unique_ptr
değiştirme için uygun seçenek gibi görünüyordu
std::auto_ptr
.
Clang 3.2'nin bu ve benzeri farklılığa olan ihtiyacını ölçmek için deneysel yapılar std::shared_ptr<X>
sırasında , istemeden inşa etmeyi düşündüğümde inşa
ettim std::unique_ptr<X>
ve varsayılan -O2 optimizasyonu ile elde edilen yürütülebilir dosyanın en hızlı I olduğunu gözlemlemekten şaşırdım. bazen 184 milisaniye ulaşarak girdi dosyası başına. Kaynak kodda yapılan bu bir değişiklikle karşılık gelen sonuçlar;
| -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 |
Burada dikkat edilmesi gereken noktalar:
- Her iki derleyici de artık -O3 optimizasyonundan faydalanmıyor.
- Clang, GCC'yi her optimizasyon seviyesinde olduğu kadar önemli bir şekilde atıyor.
- GCC'nin performansı yalnızca akıllı işaretçi türü değişikliğinden çok az etkilenir.
- Clang'ın -O2 performansı, akıllı işaretçi türü değişikliğinden önemli ölçüde etkilenir.
Akıllı işaretçi türü değişikliğinden önce ve sonra, Clang -O3 optimizasyonunda önemli ölçüde daha hızlı bir coan yürütülebilir dosyası oluşturabilir ve bu işaretçi tipi en iyisi olduğunda -O2 ve -O3'te eşit derecede daha hızlı bir yürütülebilir dosya oluşturabilir. std::shared_ptr<X>
- iş için.
Yorum yapmaya yetkin olmadığım açık bir soru neden
CCC'nin kayıtsız iken, yoğun olarak kullanılan akıllı işaretçi türü benzersizden paylaşıma değiştiğinde, Clang % 25 -O2'lik bir hız bulabilmesi gerektiğidir. aynı değişikliğe. Ayrıca Clang'ın -O2 optimizasyonunun akıllı işaretçi seçimlerimin bilgeliğine bu kadar büyük bir duyarlılığa sahip olduğu keşfini tezahürat etmem veya sevmem gerekip gerekmediğini de bilmiyorum.
GÜNCELLEME: GCC 4.8.1 v clang 3.3
Şimdi karşılık gelen sonuçlar:
| -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 |
Dört yürütülebilir şimdi 1 dosyayı işlemek için önceden çok daha büyük ortalama zaman alabilir gerçeği yapar değil son Derleyiciler performansı yansıtmak. Test uygulamasının daha sonraki geliştirme dalının bu arada çok sayıda ayrıştırma karmaşıklığı alması ve hızlı bir şekilde ödemesi nedeniyle. Sadece oranlar önemlidir.
Şimdi dikkat çeken noktalar tutkuyla yeni değil:
- GCC, -O3 optimizasyonuna kayıtsızdır
- clang -O3 optimizasyonundan çok az fayda sağlıyor
- clang GCC'yi her optimizasyon seviyesinde benzer şekilde önemli bir farkla yener.
Bu sonuçları GCC 4.7.2 ve clang 3.2 sonuçlarıyla karşılaştırarak, GCC'nin her optimizasyon seviyesinde clang liderliğinin yaklaşık dörtte birini geri çektiği göze çarpmaktadır. Ancak, test uygulaması bu arada büyük ölçüde geliştirildiğinden, GCC'nin kod oluşturma sürecindeki bir yakalama ile güvenle ilişkilendirilemez. (Bu kez, zamanlamaların alındığı uygulama anlık görüntüsünü not ettim ve tekrar kullanabilirsiniz.)
GÜNCELLEME: GCC 4.8.2 v clang 3.4
GCC 4.8.1 v Clang 3.3 güncellemesini bitirdim, daha fazla güncelleme için aynı coan snaphot'a yapışacağımı söyledim. Ama bunun yerine bu anlık görüntüyü (rev. 301) ve test paketini geçen revizyona (rev. 619) sahip olmaya karar verdim . Bu, sonuçlara biraz boylam verir ve başka bir nedenim vardı:
Orijinal gönderim, coan'ı hız için optimize etmek için hiçbir çaba sarf etmediğimi belirtti. Bu, rev. 301. Bununla birlikte, zamanlama aparatını coan test koşum takımı içine yerleştirdikten sonra, test takımını her çalıştırdığımda, en son değişikliklerin performans etkisi karşısında bana baktı. Sıklıkla şaşırtıcı derecede büyük olduğunu ve trendin işlevsellikteki kazanımlarla değerlendiğimi düşündüğümden daha dik olduğunu gördüm.
Rev. 308 Test takımındaki girdi dosyası başına ortalama işlem süresi, buradaki ilk kayıttan bu yana iki kattan fazla artmıştır. Bu noktada, 10 yıllık performansı rahatsız etmeme politikamda bir U dönüşü yaptım. 619'a kadar yapılan revizyonların yoğun bölümünde her zaman bir değerlendirme vardı ve bunların büyük bir kısmı sadece temel yük taşıyıcıları temelde daha hızlı hatlarda yeniden yazmaya gitti (ancak bunu yapmak için standart olmayan derleyici özellikleri kullanılmadan). Her derleyicinin bu U dönüşüne tepkisini görmek ilginç olurdu,
İşte rev.301'in en son iki derleyicisinin derlemeleri için şimdi bilindik zamanlama matrisi:
coan - rev.301 sonuçlar
| -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|
Buradaki hikaye sadece GCC-4.8.1 ve Clang-3.3'ten çok az değişti. GCC'nin gösterisi daha iyi bir önemsiz. Clang's bir önemsememek daha kötü. Gürültü bunu açıklayabilir. Clang hala öne çıkıyor -O2
ve -O3
çoğu uygulamada önemli olmayan ancak çok az önemli olan marjlar.
Ve işte rev için matris. 619.
coan - rev.619 sonuçlar
| -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 ve 619 figürlerini yan yana alarak birkaç nokta ortaya çıkıyor.
Daha hızlı kod yazmayı hedefliyordum ve her iki derleyici de çabalarımı net bir şekilde doğruladı. Fakat:
GCC bu çabaları Clang'dan çok daha cömertçe geri ödüyor. At -O2
optimizasyonu Clang en 619 build% 46 daha hızlı 301 yapı daha: En -O3
clang en iyileştirme 31% 'dir. İyi, ama her optimizasyon seviyesinde GCC'nin 619 yapısı 301'in iki katından daha hızlı.
GCC, Clang'ın eski üstünlüğünü tersine çevirir. Ve her optimizasyon seviyesinde GCC artık Clang'ı% 17 yeniyor.
Clang'ın 301 derlemesindeki -O3
optimizasyondan GCC'den daha fazla kaldıraç elde etme yeteneği 619 derlemesinde gitti. Her iki derleyici de anlamlı olarak kazanmaz -O3
.
Yanlışlıkla clang 3.4'ün kendisinin halsiz bir yapısını oluşturduğumdan şüphelendiğim bu servetlerin tersine çevrilmesinden yeterince şaşırdım (kaynağından inşa ettiğimden beri). Bu yüzden 619 testini distro hisse senedi Clang 3.3 ile tekrar çalıştırdım. Sonuçlar pratikte 3.4 ile aynıydı.
U-dönüşüne tepki ile ilgili olarak: Buradaki rakamlarda, Clang yardım vermiyorken C ++ kodumdan sıkma hızında GCC'den çok daha iyi yaptı. Aklıma yardım ettiğimde GCC, Clang'dan çok daha iyi bir iş çıkardı.
Bu gözlemi bir ilkeye yükseltmiyorum, ama “Hangi derleyici daha iyi ikili dosyaları üretir?” Dersini alıyorum. cevabın göreli olacağı test takımını belirtmiş olsanız bile, yine de sadece ikili dosyaları zamanlamanın kesin bir konusu değildir.
Daha iyi ikili en hızlı ikili mi, yoksa ucuz hazırlanmış kodu en iyi telafi eden mi? Ya da en iyi şekilde
, sürekliliği ve hızı yeniden kullanmayı önceliklendiren pahalı bir şekilde hazırlanmış kodu telafi eder? İkili üretmek için güdülerinizin ve altında yaptığınız kısıtlamaların niteliğine ve göreli ağırlıklarına bağlıdır.
Ve her halükarda, "en iyi" ikili dosyaları oluşturmayı derinden önemsiyorsanız, derleyicilerin birbirini takip eden yinelemelerinin, kodunuzun ardışık yinelemeleri üzerinden "en iyi" fikrinize nasıl ulaştığını daha iyi kontrol edebilirsiniz.