Flagi optymalizujące kompilację

Artykuł opisujący flagi kompilatora GCC umożliwiające optymalizację aplikacji pod określony procesor i możliwości komputera

Kompilując pakiet w standardowej dystrybucji (tj. Nie gentoo i inne Source Based) ograniczamy się do ./configure, make i make install. W rzeczywistości kompilacja to bardzo obszerny temat i nawet w Fedorze czy MDK możemy optymalizować ustawienia GCC dotyczących kompilacji. Użytkownicy Gentoo zapewne znają wpis z etc/make.conf:
CFLAGS="-O2 -mcpu=pentium3 -pipe"
CXXFLAGS=${CFLAGS}
Są to flagi przekazywane GCC podczas kompilacji (w innych dystrybucjach siedzą one gdzie indziej). CFLAGS to flagi używane przy kompilacji kodu C. CXXFLAGS to flagi dla kodu C++. CPPFLAGS to flagi dla cpp - tzw. "preprocesora" kodu w C - i o tej zmiennej akurat można zapomnieć. A ostatni zawodnik - LDFLAGS - zawiera opcje przekazywane linkerowi, czyli temu programowi który łączy wszystkie cząstkowe produkty kompilatora (tzw. "object files", pliki z rozszerzeniem "*.o") w jeden wyjściowy obiekt - program lub bibliotekę.
Pierwsze opcje jakie warto ustawić to -march= lub -mtune= (dawniej -mcpu). Decydują one odpowiednio o zestawie używanych instrukcji oraz o ułożeniu wykonywanych instrukcji. Ludzie obeznani z asemblerem wiedzą o co chodzi, pozostałym musi wystarczyć świadomość, że w ten sposób wykorzystuje się specyficzne cechy danego procesora. Jeśli ustawi się opcję '-march= ', to opcja '-mcpu= ' jest ustawiana "automatycznie". Dostępne wartości (mogą ulegać zmianie):
i386, i486, i586, i686
pentium, pentium-mmx, pentiumpro, pentium2, pentium3, pentium4
k6, k6-2, k6-3
athlon, athlon-tbird, athlon-4, athlon-xp, athlon-mp
Pierwsza linijka zawiera wartości odnoszące się do poszczególnych generacji procesorów, np. i386 - 386DX i podobne rupiecie, i586 i686 to ogólnie pentiumy. Kolejne linijki zawierają wartości odnoszące się do konkretnego typu procesora. Jeżeli mamy np. penium3 to bierzemy wartość penium3 - wtedy uzyskamy kod najbardziej zoptymalizowany pod nasz sprzęt.
march kompiluje pakiet pod dany procesor co spowoduje że otrzymany kod będzie najbardziej do niego dopasowany, lecz nie będzie działał pod innymi procesorami. mtune powoduje dopasowanie do danego procesora ale w mniejszym stopniu, gdyż zachowuje kompatybilność z innymi procesorami.
Kolejną opcją jest coś w stylu "optymalizacji ogólnej" o możliwych wartościach:
-O, -O1, -O2, -O3, -Os, -O0
'-O' i '-O1' oznaczają to samo - bazowa optymalizacja, zarówno wielkości kodu, jak i jego szybkości. Kompromis pomiędzy osiągami kodu a czasem kompilacji (bo im silniejsza optymalizacja, tym kompilator potrzebuje więcej czasu i pamięci na wypracowanie "optymalnego" rozwiązania)
'-O2' to chyba najpopularniejsza opcja. Dosyć silna optymalizacja, silniejsza niż '-O1'.
'-O3' to najsilniejsza i najagresywniejsza z "automatycznych" optymalizacji. W odróżnieniu od '-O2' nie stara się już specjalnie utrzymać kodu w rozsądnych granicach "objętościowych", co oznacza że kod może się trochę rozpuchnąć. I opcja najbardziej chyba interesująca: '-Os'. W zasadzie jest to '-O2', tyle że z dodatkowymi "bonusikami" które mają na celu dodatkowo zredukowanie wielkość wynikowego kodu. Oferuje normalną optymalizację na poziomie 'O2', ale wynikowy kod może być (i zwykle będzie) pokaźnie mniejszy.

Inne opcje

'-pipe' - gcc będzie używać rurek zamiast plików tymczasowych przy wielu operacjach. Polecam, bo może to przyspieszyć niektóre kompilacje, a nie niesie z sobą żadnych złych skutków ubocznych (no, proces kompilacji zużyje nieco więcej pamięci, ale to nie są wartości o które trzeba się martwić). Opcja ta nie wpływa na jakość kodu wynikowego, ale warto ją mieć włączoną.
'-fomit-frame-pointer' - W skrócie: gcc użyje małej modyfikacji przy wywoływaniu funkcji, która pozwoli oszczędzić nieco czasu procesora (oraz pamięci i bajtów kodu). Kod wynikowy nie będzie się zapewne nadawał do uruchomienia pod debuggerem, ale kogo to obchodzi? Polecam włączyć tę opcję, bo niesie same korzyści. "NIE wolno" używać jej w CXXFLAGS (kompilacja C++) dla GCC 3.3.* i starszych.
-fno-exceptions -fno-rtti: Tylko dla kodu C++. Flagi te poprawiają wydajność i rozmiar otrzymanego kompilatu, lecz nie wszystkie aplikacje można z nimi skompilować. Nie zaleca się stosowania tych flag globalnie
-ftracer: zwiększa możliwości optymalizacyjne innych flag, nie zawsze jest stabilny i często działa odwrotnie niż powinien (pogarsza osiągi kompilatu).
-s: usuwa z kodu informacje dla debuggera. Zmniejszy to rozmiar kompilatu i czas kompilacji, lecz nie wpłynie bezpośrednio na wydajność kompilatu.

Z doświadczenia pracy na Gentoo mogę spokojnie powiedzieć że między systemem kompilowanym pod i386 a athlonem64 na tym samym sprzęcie różnica będzie niezauważalna, chyba że system wykonuje skomplikowane operacje. Dodawanie dodatkowych flag jak -ftracer, --ffast-math i innych zaowocuje niestabilnym systemem!
blog comments powered by Disqus

Kategorie

Strony