Optimizasyon seviyesi -O3 g ++ 'da tehlikeli midir?


233

Çeşitli kaynaklardan (çoğunlukla bir meslektaşımdan olsa da) duydum, -O3g ++ ' da bir optimizasyon seviyesi ile derlemenin bir şekilde' tehlikeli 'olduğunu ve gerekli olduğu kanıtlanmadıkça genel olarak kaçınılması gerektiğini duydum .

Bu doğru mu, eğer öyleyse neden? Sadece bağlı mıyım -O2?


38
Sadece tanımlanmamış davranışlara güveniyorsanız tehlikelidir. Ve o zaman bile, bir şeyi berbat eden optimizasyon seviyesi olsaydı şaşırırdım.
Seth Carnegie

5
Derleyici kodunuzu tam olarak derlemiş gibi davranan bir program üretmeye devam etmektedir. -O3Özellikle buggy olarak kabul edildiğini bilmiyorum. Belli varsayımlara dayanarak garip ve harika şeyler yapabileceği için belki de tanımsız davranışı "daha kötü" yapabilir, ancak bu sizin kendi hatanız olacaktır. Genel olarak, iyi olduğunu söyleyebilirim.
BoBTFish

5
Daha yüksek optimizasyon seviyelerinin derleyici hatalarına daha eğilimli olduğu doğrudur. Birkaç vakayı kendim vurdum, ancak genel olarak hala oldukça nadir.
Gizemli

21
-O2açılırsa -fstrict-aliasingve kodunuz bundan kurtulursa, muhtemelen diğer optimizasyonlardan da kurtulacaktır, çünkü bu, insanların tekrar tekrar yanlış yaptığı bir koddur. Bununla birlikte -fpredictive-commoning, sadece içerisindedir -O3ve eşzamanlılık hakkında yanlış varsayımlardan kaynaklanan kodunuzdaki hataları etkinleştirebilir. Kodunuz ne kadar az yanlışsa, o kadar az tehlikeli optimizasyon ;-)
Steve Jessop

6
@PlasmaHH, "daha katı" nın iyi bir açıklaması olduğunu düşünmüyorum, örneğin NaN'lerin -OfastIEEE uyumlu işlemesini kapatıyor
Jonathan Wakely

Yanıtlar:


223

Gcc'nin ilk günlerinde (2.8 vb.) Ve egcs zamanında ve redhat 2.96-O3 bazen oldukça buggy idi. Ancak bu on yıldan uzun bir süre önce ve -O3 diğer optimizasyon seviyelerinden çok farklı değil (buggyness'te).

Bununla birlikte, dil (ler) in kurallarına ve özellikle köşe vakalarına daha sıkı güvenmesi nedeniyle, insanların tanımlanmamış davranışa güvendiği vakaları ortaya çıkarma eğilimindedir.

Kişisel bir not olarak, yıllardır -O3 ile finansal sektörde üretim yazılımı kullanıyorum ve -O2 kullansaydım orada olmayacak bir hatayla karşılaşmadım.

Yoğun talep üzerine, burada bir ek:

-O3 ve özellikle -funroll-loop gibi ek bayraklar (-O3 tarafından etkinleştirilmez) bazen daha fazla makine kodu oluşturulmasına neden olabilir. Belirli koşullar altında (örneğin, son derece küçük L1 komut önbelleğine sahip bir CPU'da) bu, örneğin artık L1I'ye uymayan bazı iç döngülerin tüm kodlarından dolayı yavaşlamaya neden olabilir. Genellikle gcc çok fazla kod üretmemek için oldukça uğraşır, ancak genellikle genel durumu optimize ettiğinden, bu olabilir. Özellikle buna eğilimli seçenekler (loop unrolling gibi) normalde -O3'e dahil edilmez ve buna uygun olarak işaretlenir. Bu nedenle, hızlı kod oluşturmak için -O3 kullanmak genellikle uygun olduğunda (örneğin bir profil oluşturucu L1I'nin kaçırdığını gösterdiğinde) -O2 veya -Os'a (kod boyutu için optimize etmeye çalışır) düşmek için iyi bir fikirdir.

Eğer optimizasyonu uç noktalara taşımak istiyorsanız, - gcc'de bazı optimizasyonlarla ilişkili maliyetleri artırabilirsiniz. Ek olarak, gcc'nin artık yalnızca bu işlevler için optimizasyon ayarlarını kontrol eden işlevlere öznitelik koyma yeteneğine sahip olduğunu unutmayın, bu nedenle bir işlevde -O3 ile ilgili bir sorununuz olduğunu fark ettiğinizde (veya yalnızca bu işlev için özel bayraklar denemek istiyorsanız), tüm dosyayı, hatta tüm projeyi O2 ile derlemenize gerek yoktur.

otoh -Ofast kullanırken dikkatli olunması gerektiği anlaşılıyor:

-Ofast tüm -O3 optimizasyonlarını mümkün kılar. Ayrıca tüm standart uyumlu programlar için geçerli olmayan optimizasyonları etkinleştirir.

bu da -O3'ün tamamen standartlara uygun olması gerektiği sonucuna varmamı sağlıyor.


2
Ben sadece tam tersi bir şey kullanıyorum. Her zaman -Os veya -O2 kullanın (bazen O2 daha küçük bir yürütülebilir dosya oluşturur) .. Profillemeden sonra kodun daha fazla yürütme süresi alan ve tek başına% 20 daha fazla hız verebilen O3 kullanıyorum.
CoffeDeveloper

3
Bunu hız için yapıyorum. O3 çoğu zaman işleri yavaşlatır. Nedenini tam olarak bilmiyorum, Talimat önbelleğini kirlettiğinden şüpheleniyorum.
Kahve

4
@DarioOO Ben "kod bloat" yalvaran gibi yapmak için popüler bir şey gibi hissediyorum, ama neredeyse hiç kıyaslama ile destekli görmüyorum. Mimariye çok bağlıdır, ancak yayınlanan karşılaştırmaları her gördüğümde (örneğin phoronix.com/… ) O3'ün vakaların büyük çoğunluğunda daha hızlı olduğunu gösterir. Kod bloat aslında bir sorun olduğunu kanıtlamak için gereken profilleme ve dikkatli analiz gördüm ve genellikle sadece şablonlar aşırı bir şekilde kucaklayan insanlar için olur.
Nir Friedman

1
@NirFriedman: Derleyicinin satır içi maliyet modelinde hatalar olduğunda veya koştuğunuzdan tamamen farklı bir hedef için optimizasyon yaptığınızda bir sorun ortaya çıkar. İlginçtir, bu tüm optimizasyon seviyeleri için geçerlidir ...
PlasmaHH

1
@ PlazmaHH: genel durum için using-cmov sorununu çözmek zor olurdu. Genellikle sadece verilerinizi sıralamazsınız, bu nedenle gcc bir dalın öngörülebilir olup olmadığına karar vermeye çalışırken, std::sortişlev çağrılarını arayan statik analizin yardımcı olması pek olası değildir. Stackoverflow.com/questions/109710/… gibi bir şey kullanmak yardımcı olabilir veya sıralılıktan yararlanmak için kaynağı yazabilir:> = 128'i görene kadar tarayın, sonra toplamaya başlayın. Şişirilmiş koda gelince, evet bunu bildirmeye niyetleniyorum. : P
Peter Cordes

42

Biraz damalı deneyimimde, -O3tüm bir programa başvurmak neredeyse her zaman daha yavaş (göreceli olarak -O2) yapar, çünkü programı artık talimat önbelleğine sığmayan agresif döngü açma ve satır açma özelliğini açar . Daha büyük programlar için, bu -O2göreceli olarak da geçerli olabilir -Os!

Amaçlanan kullanım deseni -O3, programınızın profilini oluşturduktan sonra, bu agresif hıza yönelik boşluklardan gerçekten yararlanan kritik iç döngüler içeren küçük bir avuç dolusu dosyaya manuel olarak uygulamanızdır. GCC'nin daha yeni sürümlerinde, (IIUC) -O3optimizasyonları sıcak işlevlere seçici olarak uygulayabilen ve bu işlemi etkili bir şekilde otomatikleştirebilen profil kılavuzlu bir optimizasyon modu vardır .


10
"neredeyse her zaman"? "50-50" yapın ve bir anlaşma yapacağız ;-).
Hata Yok Tavşan

12

-O3 seçeneği, '-O2' ve '-O1' alt düzeylerinin tüm optimizasyonlarına ek olarak, fonksiyon satır içi gibi daha pahalı optimizasyonları da açar. '-O3' optimizasyon seviyesi, ortaya çıkan yürütülebilir dosyanın hızını artırabilir, ancak boyutunu da artırabilir. Bu optimizasyonların uygun olmadığı bazı durumlarda, bu seçenek aslında bir programı yavaşlatabilir.


3
Bazı "belirgin optimizasyonların" bir programı yavaşlatabileceğini anlıyorum, ancak GCC-O3'ün bir programı yavaşlattığını iddia eden bir kaynağınız var mı?
Mooing Duck

1
@MooingDuck: Bir kaynak gösterememe rağmen, oldukça küçük bir L1I önbelleğine sahip bazı eski AMD işlemcilerle (~ 10k talimatlar) böyle bir durumla karşılaştığımı hatırlıyorum. Eminim google ilgilenen için daha fazla var, ama özellikle döngü unrolling gibi seçenekler O3 bir parçası değildir ve bu boyutları çok artırır. -Os, yürütülebilir dosyayı en küçük yapmak istediğiniz kişidir. -O2 bile kod boyutunu artırabilir. Farklı optimizasyon seviyelerinin sonuçlarıyla oynamak için güzel bir araç gcc explorer.
PlazmaHH

@PlasmaHH: Aslında, küçük bir önbellek boyutu bir derleyicinin sıkışabileceği bir şey, iyi bir nokta. Bu gerçekten iyi bir örnek. Lütfen cevaba koyun.
Mooing Duck

1
PlazmaHH Pentium III 16KB kod önbelleğine sahipti. AMD'nin K6 ve üstü 32KB komut önbelleğine sahipti. P4'ler 96KB değerinde başladı. Core I7 aslında 32KB L1 kod önbelleğine sahip. Talimat kod çözücüleri günümüzde güçlüdür, bu nedenle L3'ünüz neredeyse her döngü için geri düşecek kadar iyidir.
doug65536

1
Bir döngüde çağrılan bir işlev olduğunda muazzam bir performans artışı görürsünüz ve döngüden önce gereksiz alt hesaplamanın ortadan kaldırılmasını ve işlevden gereksiz yeniden hesaplamanın kaldırılmasını sağlayabilir.
13:51, doug65536

8

Evet, O3 rahatsızlık verici. Derleyici geliştiriciyim ve kendi yazılımımı oluştururken O3 üreten buggy SIMD montaj talimatlarının neden olduğu net ve belirgin gcc hataları tespit ettim. Gördüğüm kadarıyla, çoğu üretim yazılımı O2 ile birlikte geliyor, bu da O3'ün wrt testi ve hata düzeltmelerine daha az dikkat edeceği anlamına geliyor.

Şöyle düşünün: O3, O2'nin üzerine daha fazla dönüşüm ekler ve bu da O1'in üzerine daha fazla dönüşüm ekler. İstatistiksel olarak konuşursak, daha fazla dönüşüm daha fazla hata anlamına gelir. Bu herhangi bir derleyici için geçerlidir.


3

Son zamanlarda optimizasyon ile ilgili bir sorun yaşadım g++. Sorun, kayıtların (komut ve veri için) bir bellek adresiyle temsil edildiği bir PCI kartla ilgiliydi. Sürücüm, fiziksel adresi uygulama içindeki bir işaretçiyle eşleştirdi ve çağrılan işleme verdi.

unsigned int * pciMemory;
askDriverForMapping( & pciMemory );
...
pciMemory[ 0 ] = someCommandIdx;
pciMemory[ 0 ] = someCommandLength;
for ( int i = 0; i < sizeof( someCommand ); i++ )
    pciMemory[ 0 ] = someCommand[ i ];

Kart beklendiği gibi davranmadı. Ben montaj görünce derleyici yalnızca yazdım anlaşılmaktadır someCommand[ the last ]içinepciMemory tüm önceki yazar atlayarak.

Sonuç olarak: optimizasyon ile doğru ve dikkatli olun.


38
Ancak buradaki nokta, programınızın tanımlanmamış bir davranışa sahip olmasıdır; iyimser yanlış bir şey yapmadı. Özellikle bildirmeniz gereken pciMemoryşekilde volatile.
Konrad Rudolph

11
Aslında UB değil, derleyici son yazma hariç pciMemoryhepsini yazmayı reddetme hakkına sahip çünkü diğer tüm yazmaların muhtemelen hiçbir etkisi yok. Bu iyimser için çok işe yaramaz ve zaman alıcı talimatlar kaldırabilir çünkü.
Konrad Rudolph

4
Bunu standart olarak buldum (10+ yıl sonra)) - Bellek eşlemeli bir giriş / çıkış bağlantı noktasına karşılık gelen bir nesneyi veya eşzamansız olarak kesen bir işlevle erişilen bir nesneyi tanımlamak için geçici bir bildirim kullanılabilir. Bu şekilde beyan edilen nesneler üzerindeki eylemler, bir uygulama tarafından '' optimize edilmez '' veya ifadeleri değerlendirme kurallarının izin verdiği durumlar dışında yeniden sıralanamaz.
borisbn

2
@borisbn Biraz konu dışı ama cihazınızın yeni bir komut göndermeden önce komutu aldığını nereden biliyorsunuz?
user877329 15:14

3
@ user877329 Cihazın davranışları tarafından gördüm, ama büyük bir
görevdi
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.