Flagi optymalizujące kompilację
14 July 2008
Comments
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ę.CXXFLAGS=${CFLAGS}
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.
pentium, pentium-mmx, pentiumpro, pentium2, pentium3, pentium4
k6, k6-2, k6-3
athlon, athlon-tbird, athlon-4, athlon-xp, athlon-mp
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!
RkBlog
Comment article