Saya telah mendengar dari berbagai sumber (meskipun sebagian besar dari kolega saya), bahwa kompilasi dengan level optimisasi -O3
dalam g ++ entah bagaimana 'berbahaya', dan harus dihindari secara umum kecuali terbukti perlu.
Apakah ini benar, dan jika demikian, mengapa? Haruskah saya bertahan -O2
?
c++
optimization
g++
compiler-flags
Dunnie
sumber
sumber
-O3
dianggap sangat buggy? Saya pikir mungkin itu dapat membuat perilaku yang tidak terdefinisi "lebih buruk" karena dapat melakukan hal-hal aneh dan indah berdasarkan asumsi tertentu, tetapi itu akan menjadi kesalahan Anda sendiri. Jadi secara umum, saya akan mengatakan itu baik-baik saja.-O2
menyala-fstrict-aliasing
, dan jika kode Anda bertahan maka mungkin akan bertahan optimasi lain, karena itu salah bahwa orang salah lagi. Yang mengatakan,-fpredictive-commoning
hanya dalam-O3
, dan memungkinkan yang memungkinkan bug dalam kode Anda disebabkan oleh asumsi yang salah tentang konkurensi. Semakin sedikit salah kode Anda, optimisasi yang kurang berbahaya adalah ;-)-Ofast
, mematikan penanganan yang sesuai dengan IEEE misalnyaJawaban:
Pada hari-hari awal gcc (2,8 dll) dan pada masa egcs, dan redhat 2,96 -O3 kadang-kadang cukup buggy. Tapi ini lebih dari satu dekade yang lalu, dan -O3 tidak jauh berbeda dari tingkat optimisasi lainnya (dalam buggyness).
Namun, ia cenderung mengungkapkan kasus-kasus di mana orang mengandalkan perilaku yang tidak terdefinisi, karena lebih mengandalkan aturan, dan terutama kasus sudut, dari bahasa.
Sebagai catatan pribadi, saya menjalankan perangkat lunak produksi di sektor keuangan selama bertahun-tahun sekarang dengan -O3 dan belum menemukan bug yang tidak akan ada di sana jika saya akan menggunakan -O2.
Dengan permintaan populer, berikut tambahan:
-O3 dan terutama flag-flag tambahan seperti -funroll-loop (tidak diaktifkan oleh -O3) terkadang dapat menyebabkan lebih banyak kode mesin yang dihasilkan. Dalam keadaan tertentu (misalnya pada cpu dengan cache instruksi L1 sangat kecil) ini dapat menyebabkan perlambatan karena semua kode misalnya beberapa loop batin sekarang tidak pas lagi ke L1I. Umumnya gcc berusaha cukup keras untuk tidak menghasilkan kode begitu banyak, tetapi karena biasanya mengoptimalkan kasus generik, ini bisa terjadi. Opsi yang cenderung rentan terhadap hal ini (seperti loop terbuka) biasanya tidak termasuk dalam -O3 dan ditandai sesuai di halaman manual. Karena itu umumnya merupakan ide yang baik untuk menggunakan -O3 untuk menghasilkan kode cepat, dan hanya kembali ke -O2 atau -Os (yang mencoba untuk mengoptimalkan ukuran kode) saat yang tepat (misalnya ketika profiler menunjukkan L1I meleset).
Jika Anda ingin mengambil optimasi ke ekstrem, Anda dapat men-tweak dalam gcc melalui --param biaya yang terkait dengan optimasi tertentu. Selain itu perhatikan bahwa gcc sekarang memiliki kemampuan untuk menempatkan atribut pada fungsi yang mengontrol pengaturan optimisasi hanya untuk fungsi-fungsi ini, jadi ketika Anda menemukan Anda memiliki masalah dengan -O3 dalam satu fungsi (atau ingin mencoba flag khusus untuk fungsi itu), Anda tidak perlu mengkompilasi seluruh file atau bahkan seluruh proyek dengan O2.
otoh tampaknya harus diperhatikan saat menggunakan -Ofast, yang menyatakan:
yang membuat saya menyimpulkan bahwa -O3 dimaksudkan untuk sepenuhnya memenuhi standar.
sumber
std::sort
fungsi tidak mungkin membantu. Menggunakan sesuatu seperti stackoverflow.com/questions/109710/… akan membantu, atau mungkin menulis sumber untuk mengambil keuntungan dari pengurutan: pindai hingga Anda melihat> = 128, kemudian mulai menjumlahkan. Adapun kode kembung, ya saya bermaksud untuk melaporkannya. : PDalam pengalaman saya yang agak kotak-kotak, menerapkan
-O3
ke seluruh program hampir selalu membuatnya lebih lambat (relatif terhadap-O2
), karena itu diaktifkan pada loop agresif membuka gulungan dan inlining yang membuat program tidak lagi sesuai dengan cache instruksi. Untuk program yang lebih besar, ini juga berlaku untuk-O2
relatif-Os
!Pola penggunaan yang dimaksudkan
-O3
adalah, setelah membuat profil program Anda, Anda menerapkannya secara manual ke segelintir kecil file yang berisi loop internal kritis yang sebenarnya mendapat manfaat dari pengorbanan ruang-untuk-kecepatan yang agresif ini. Versi GCC yang lebih baru memiliki mode optimasi berpandu profil yang dapat (IIUC) secara selektif menerapkan-O3
optimasi ke fungsi-fungsi panas - mengotomatiskan proses ini secara efektif.sumber
Opsi -O3 mengaktifkan pengoptimalan yang lebih mahal, seperti fungsi inlining, selain semua pengoptimalan level bawah '-O2' dan '-O1'. Level optimisasi '-O3' dapat meningkatkan kecepatan yang dapat dieksekusi, tetapi juga dapat meningkatkan ukurannya. Dalam beberapa keadaan di mana optimasi ini tidak menguntungkan, opsi ini mungkin sebenarnya membuat program lebih lambat.
sumber
Ya, O3 adalah buggier. Saya seorang pengembang kompiler dan saya telah mengidentifikasi bug gcc yang jelas dan jelas disebabkan oleh O3 yang menghasilkan instruksi perakitan SIMD buggy ketika membangun perangkat lunak saya sendiri. Dari apa yang saya lihat, sebagian besar perangkat lunak produksi menyertakan O2 yang berarti O3 akan kurang mendapat perhatian pengujian pengujian dan perbaikan bug.
Pikirkan seperti ini: O3 menambahkan lebih banyak transformasi di atas O2, yang menambahkan lebih banyak transformasi di atas O1. Secara statistik, lebih banyak transformasi berarti lebih banyak bug. Itu berlaku untuk kompiler mana pun.
sumber
Baru-baru ini saya mengalami masalah menggunakan optimasi dengan
g++
. Masalahnya terkait dengan kartu PCI, di mana register (untuk perintah dan data) diwakili oleh alamat memori. Driver saya memetakan alamat fisik ke sebuah pointer di dalam aplikasi dan memberikannya ke proses yang dipanggil, yang bekerja dengannya seperti ini:Kartu tidak bertindak seperti yang diharapkan. Ketika saya melihat perakitan aku mengerti bahwa compiler hanya menulis
someCommand[ the last ]
ke dalampciMemory
, menghilangkan semua menulis sebelumnya.Kesimpulannya: akurat dan penuh perhatian dengan optimasi.
sumber
pciMemory
sebagaivolatile
.pciMemory
karena semua penulisan yang lain terbukti tidak berpengaruh. Untuk pengoptimal itu luar biasa karena dapat menghapus banyak instruksi yang tidak berguna dan memakan waktu.