Słyszałem z różnych źródeł (choć głównie od mojego kolegi), że kompilacja z poziomem optymalizacji -O3
g ++ jest w jakiś sposób „niebezpieczna” i ogólnie należy jej unikać, chyba że okaże się to konieczne.
Czy to prawda, a jeśli tak, to dlaczego? Czy powinienem się trzymać -O2
?
c++
optimization
g++
compiler-flags
Dunnie
źródło
źródło
-O3
jest to uważane za szczególnie wadliwe? Myślę, że może może pogorszyć nieokreślone zachowanie, ponieważ może robić dziwne i cudowne rzeczy w oparciu o pewne założenia, ale to byłaby twoja wina. Więc ogólnie powiedziałbym, że jest w porządku.-O2
włącza się-fstrict-aliasing
, a jeśli Twój kod przetrwa, prawdopodobnie przetrwa inne optymalizacje, ponieważ ludzie często się mylą. To powiedziawszy,-fpredictive-commoning
jest tylko włączone-O3
, a włączenie to może umożliwić błędy w twoim kodzie spowodowane nieprawidłowymi założeniami dotyczącymi współbieżności. Im mniej błędny jest twój kod, tym mniej niebezpieczna jest optymalizacja ;-)-Ofast
, wyłącza na przykład obsługę NaNs zgodną z IEEEOdpowiedzi:
We wczesnych dniach gcc (2.8 itd.) Oraz w czasach egcs i redhat 2.96-O3 bywał czasem dość błędny. Ale to już ponad dziesięć lat temu, a -O3 niewiele różni się od innych poziomów optymalizacji (w buggyness).
Zwykle jednak ujawnia przypadki, w których ludzie polegają na nieokreślonym zachowaniu, z powodu bardziej ścisłego polegania na regułach, a zwłaszcza narożnych przypadkach języka (języków).
Osobiście, od wielu lat prowadzę oprogramowanie produkcyjne w sektorze finansowym z opcją -O3 i nie spotkałem się jeszcze z błędem, którego nie byłoby, gdybym użył opcji -O2.
Według popularnego popytu, tutaj dodatek:
-O3, a zwłaszcza dodatkowe flagi, takie jak -funroll-loop (nie włączone przez -O3) mogą czasami prowadzić do generowania większej liczby kodów maszynowych. W pewnych okolicznościach (np. Na jednostce centralnej z wyjątkowo małą pamięcią podręczną instrukcji L1) może to spowodować spowolnienie z powodu całego kodu np. Jakiejś wewnętrznej pętli, która nie pasuje już do L1I. Zasadniczo gcc bardzo mocno stara się nie generować tak dużej ilości kodu, ale ponieważ zazwyczaj optymalizuje ogólny przypadek, może się to zdarzyć. Opcje szczególnie na to podatne (jak rozwijanie pętli) zwykle nie są zawarte w -O3 i są odpowiednio oznaczone na stronie podręcznika. W związku z tym ogólnie dobrym pomysłem jest użycie opcji -O3 do generowania szybkiego kodu i polegać tylko na opcji -O2 lub -Os (która próbuje zoptymalizować rozmiar kodu), gdy jest to właściwe (np. Gdy profiler wskazuje brak L1I).
Jeśli chcesz maksymalnie wykorzystać optymalizację, możesz dostosować gcc za pomocą --param kosztów związanych z niektórymi optymalizacjami. Dodatkowo zauważ, że gcc ma teraz możliwość umieszczania atrybutów w funkcjach, które kontrolują ustawienia optymalizacji tylko dla tych funkcji, więc gdy okaże się, że masz problem z -O3 w jednej funkcji (lub chcesz wypróbować specjalne flagi dla tej funkcji), nie musisz kompilować całego pliku ani nawet całego projektu za pomocą O2.
otoh wydaje się, że należy zachować ostrożność podczas używania opcji -Ofast, która stwierdza:
co prowadzi mnie do wniosku, że -O3 ma być w pełni zgodny ze standardami.
źródło
std::sort
funkcji jest mało prawdopodobne, aby pomoc. Użycie czegoś takiego jak stackoverflow.com/questions/109710/... pomogłoby lub może napisać źródło, aby skorzystać z posortowanej: skanuj, aż zobaczysz> = 128, a następnie zacznij sumowanie. Jeśli chodzi o rozdęty kod, tak, zamierzam przejść do zgłaszania go. : PZ mojego nieco szachowego doświadczenia, zastosowanie
-O3
do całego programu prawie zawsze powoduje spowolnienie (w stosunku do-O2
), ponieważ włącza agresywne rozwijanie i wstawianie pętli, które powoduje, że program nie mieści się już w pamięci podręcznej instrukcji. W przypadku większych programów może to być również prawdą w-O2
odniesieniu do-Os
!Zamierzonym sposobem użycia
-O3
jest, po profilowaniu programu, ręczne zastosowanie go do niewielkiej garści plików zawierających krytyczne pętle wewnętrzne, które faktycznie korzystają z tych agresywnych kompromisów między szybkością a szybkością. Nowsze wersje GCC mają tryb optymalizacji sterowany profilem, który może (IIUC) selektywnie stosować-O3
optymalizacje do gorących funkcji - skutecznie automatyzując ten proces.źródło
Opcja -O3 włącza droższe optymalizacje, takie jak wstawianie funkcji, oprócz wszystkich optymalizacji niższych poziomów „-O2” i „-O1”. Poziom optymalizacji „-O3” może zwiększyć szybkość wynikowego pliku wykonywalnego, ale może również zwiększyć jego rozmiar. W pewnych okolicznościach, gdy te optymalizacje nie są korzystne, ta opcja może faktycznie spowolnić program.
źródło
Tak, O3 jest błędny. Jestem programistą kompilatorów i podczas tworzenia własnego oprogramowania zidentyfikowałem wyraźne i oczywiste błędy gcc spowodowane przez generowanie przez O3 błędnych instrukcji montażu SIMD. Z tego, co widziałem, większość oprogramowania produkcyjnego jest dostarczana z O2, co oznacza, że O3 otrzyma mniej uwagi na testowanie i naprawianie błędów.
Pomyśl o tym w ten sposób: O3 dodaje więcej transformacji na O2, co dodaje więcej transformacji na O1. Statystycznie rzecz biorąc, więcej transformacji oznacza więcej błędów. Dotyczy to każdego kompilatora.
źródło
Ostatnio wystąpił problem z korzystaniem z optymalizacji z
g++
. Problem dotyczył karty PCI, w której rejestry (dla poleceń i danych) były reprezentowane przez adres pamięci. Mój sterownik zamapował adres fizyczny na wskaźnik w aplikacji i podał go wywoływanemu procesowi, który działał z nim w następujący sposób:Karta nie działała zgodnie z oczekiwaniami. Kiedy zobaczyłem zespół zrozumiałem, że kompilator napisał tylko
someCommand[ the last ]
dopciMemory
, pomijając wszystkie poprzednie zapisy.Podsumowując: bądź dokładny i uważny dzięki optymalizacji.
źródło
pciMemory
jakovolatile
.pciMemory
ponieważ wszystkie inne zapisy prawdopodobnie nie mają żadnego efektu. Optymalizator jest niesamowity, ponieważ może usunąć wiele bezużytecznych i czasochłonnych instrukcji.