2004.08_Flagi sterujące optymalizacją w GCC_[Programowanie].pdf
(
394 KB
)
Pobierz
439034444 UNPDF
kompilacja programów
Flagi sterujące
optymalizacją w GCC
Grzegorz Niewęgłowski
i jego możliwości opty-
malizacji kodu, jak rów-
nież samej kompilacji,
krąży w środowisku linuksowym wiele
informacji, często sprzecznych. W poniż-
szym artykule przedstawię podstawowe
fakty dotyczące optymalizacji GCC.
Opcje sterujące optymalizacją
w GCC można z grubsza podzielić na
dwie grupy: optymalizację pod konkret-
ną architekturę oraz optymalizację szcze-
gółową, przy której decyduje się o takich
niuansach, jak redukowanie zbędnych
pętli w kodzie, usuwanie niewykorzy-
stanych zmiennych, sterowanie użyciem
rejestrów procesora itp. Takie opcje GCC
nazywa się zwykle
flagami.
Używanie
flag może mieć wpływ na stabilność
i poprawność działania programów ze
względu na błędy w programach lub
samym kompilatorze. Z tego powodu,
jeśli zauważysz jakieś błędne zachowa-
nia, spróbuj skompilować kod jeszcze raz,
bez własnych optymalizacji, a następnie
stopniowo dodawać poszczególne flagi,
aż znajdziesz winowajcę.
Flaga
-march
powoduje wykorzystanie
wszystkich cech specyficznych danego
modelu procesora, nawet jeśli zrywa to
kompatybilność ze starszymi modelami,
np. zezwala na tworzenie kodu używa-
jącego dodatkowych rejestrów procesora
czy rozszerzonych zestawów instrukcji,
np. MMX. Użycie flagi
-march
powoduje
od razu ciche włączenie bliźniaczej flagi
-mtune
. Ramka
Wybór architektury proce-
sora w GCC (3.4.0)
pokazuje zależność
Wybór architektury
procesora w GCC (3.4.0)
Procesor 386:
-march=i386
Procesor 486:
-march=i486
Procesor 586 (Pentium):
-march=i586
lub
-march=pentium
(te dwie opcje są równoznaczne)
WinChip:
-march=winchip-c6
,
-march=winchip2
Via C3:
-march=c3
,
-march=c3-2
Procesory Intel:
Pentium MMX:
-march=pentium-mmx
Pentium Pro (pierwsze i686):
-march=i686
lub
-march=pentium-
pro
(te dwie opcje są równoznaczne)
Procesor Pentium2:
-march=pentium2
Procesor Pentium3:
-march=pentium3
Procesor Pentium4:
-march=pentium4
Na płycie CD/DVD
Na płycie CD/DVD znajdują się
pakiety źródłowe nowego GCC.
Wybór typu procesora
Typ procesora wybiera się za pomocą
dwóch flag:
-mtune=
oraz
-march=
.
Flaga
-mtune
(znana również jako
-mcpu
) wybiera schemat kolejkowania
instrukcji procesora. Odpowiednio ukła-
dając kolejność napływania rozkazów do
procesora, można czasem przyspieszyć
ich realizację. Już procesory Pentium
potrafiły w pewnych sytuacjach wykony-
wać dwa rozkazy równolegle. Takie zmie-
nianie kolejności rozkazów nie zrywa
kompatybilności z innymi modelami
procesorów – one po prostu nie odniosą
z tego powodu żadnych korzyści.
Procesory AMD:
Procesor K6:
-march=k6
Procesor K6-2:
-march=k6-2
Procesor K6-3:
-march=k6-3
Zwykły Athlon:
-march=athlon
Athlon Thunderbird:
-march=athlon-
tbird
Athlon4:
-march=athlon-4
AthlonXP:
-march=athlon-xp
AthlonMP:
-march=athlon-mp
Rodzina AMD64 - do wyboru:
k8
,
opteron
,
athlon64
,
athlon-fx
O autorze
Autor od kilku lat używa Linuksa
jako jedynego systemu opera-
cyjnego. Aktywnie uczestniczy
w polskich grupach dyskusyj-
nych poświęconych Linuksowi,
jak również prowadzi nieduży
internetowy kącik dotyczący
zagadnień związanych z tym
systemem. Kontakt z autorem:
autorzy@linux.com.pl
50
sierpień 2004
W
okół kompilatora GCC
gcc
kompilacja programów
Nie ma sensu używanie
-O3
przy kompi-
lacji całego systemu. Pamiętajmy też, że
-O3
powoduje przyrost objętości kodu,
co może być fatalne dla procesorów
z niewielką pamięcią podręczną (
cache
),
takich jak Celerony czy Durony.
Czasem widuje się flagi typu
-O6
lub
nawet
-O99
. Nie są to żadne dodatkowe
tajne optymalizacje, bo aktualne GCC
nie obsługują niczego mocniejszego niż
-O3
. Podając wyższe wartości, GCC i tak
użyje
-O3
.
Jeśli w wywołaniu GCC podamy
kilka wartości
-Ox,
to GCC użyje tej
podanej najpóźniej.
Inne popularne lagi
GCC pozwala na drobiazgowe sterowanie
optymalizacją przy użyciu kilkudziesięciu
flag, z których jedynie kilka jest wartych
uwagi.
Rysunek 1.
Przykładowe zależności między optymalizacją a wielkością kompilatu
i wydajnością
-ffast-math
Ta flaga może spowodować (niezbyt
duże) przyspieszenie wykonywania nie-
których obliczeń matematycznych (np.
funkcji trygonometrycznych), ale dzieje
się to poprzez naginanie standardów
IEEE/ISO, dotyczących takich obliczeń.
Jeśli autor kodu zakładał pełną zgod-
ność funkcji matematycznych z wyżej
wymienionymi standardami, to kod
może zacząć produkować błędne wyniki.
Gdy to sam autor kodu zaleca używanie
tej flagi (np. umieszczając ją w pliku
Makefile
), to znaczy że zapewne można
z niej bezpiecznie korzystać, gdyż kod
był pisany tak, aby
-ffast-math
mu nie
zaszkodziło.
Włączanie jej globalnie dla wszyst-
kich budowanych pakietów to wielki
błąd, np. Perl, którego kiedyś skompilo-
wałem z
-ffast-math
, nie umiał przejść
przez zestaw testowy weryfikujący
poprawność kompilacji. Błędnie wyko-
nywał niektóre operacje arytmetyczne.
Tą flagą łatwo jest wywołać błędy trudne
do wykrycia.
pomiędzy modelem procesora a warto-
ścią
-march
.
Jeśli nie widzisz na liście swojego
procesora, to wybierz ten, który jest mu
technologicznie najbliższy, np. dla pierw-
szych Celeronów będzie to
pentium2
,
a dla AMD K5 będzie to
i586
. Proceso-
ry AMD Duron to w zasadzie zwykłe
Athlony, tyle że z okrojoną pamięcią
podręczną procesora (relacja między
Duronem a Athlonem jest podobna do tej
między Celeronem a Pentium), co znaczy,
że obowiązuje je zwykle
-march=athlon
.
Szczegółowe informacje o procesorze
zainstalowanym w danej maszynie znaj-
dują się w pliku
/proc/cpuinfo
.
Najczęściej używa się flagi
-O2
, włącza-
jącej najpopularniejszy zestaw optyma-
lizacji. Opcja
-O3
jest specjalna – po jej
włączeniu GCC używa prawie wszystkich
dostępnych trików, aby uzyskać szybszy
kod binarny, ale natura optymalizacji
wywoływanych przez
-O3
jest trudna do
przewidzenia i zmienia się w zależności
od konkretnego kompilowanego kodu.
Zwykle
-O3
spowoduje rozrośnięcie się
wynikowego kompilatu (skompilowany
program będzie zużywał więcej pamięci
operacyjnej), tylko czasem daje zauwa-
żalne przyspieszenie, a czasem może
nawet doprowadzić do spowolnienia
kodu. Z tego powodu to słabsze
-O2
jest
najpopularniejszą flagą, bo, w przeci-
wieństwie do
-O3
, oferuje rozsądny (oraz
przewidywalny) kompromis pomiędzy
wydajnością a rozmiarem kodu.
Bardzo interesująca jest opcja
-Os
.
Jest to specjalny wariant flagi
-O2
, zorien-
towany na generowanie mniejszego kodu
wykonywalnego. Włącza on prawie
wszystkie optymalizacje
-O2
i dodatkowo
używa kilku technik, aby zmniejszyć
wynikowy kompilat. Flaga
-Os
pozwala
zmniejszyć zapotrzebowanie na pamięć
operacyjną przy zachowaniu wydajności
bardzo zbliżonej do
-O2
.
Najrozsądniejszą opcją uniwersalną
jest
-Os
lub
-O2
. Z
-O3
korzystajmy tylko,
gdy mamy absolutną pewność, że da
to wymierny zysk (np. autor kodu tak
twierdzi albo samemu to sprawdziliśmy).
Wybór siły optymalizacji
GCC oferuje przytłaczająco wielką paletę
flag, z których możesz skorzystać. Aby
ułatwić ich stosowanie, powstały specjal-
ne zbiorcze opcje
-Ox
. Do wyboru mamy
-O0
,
-O1
,
-O2
,
-O3
i
-Os
. Użycie którejś
z flag
-O
powoduje włączenie określone-
go zestawu innych flag. Jak widać, flagi
-O
są numerowane od 0 do 3 (pomijając
-Os
) i te cyfry generalnie odpowiadają
sile optymalizacji. Im wyższa liczba, tym
mocniej GCC stara się zoptymalizować
kod (optymalizacje powodują też wydłu-
żenie procesu kompilacji). Opcja
-O0
wyłącza wszelką optymalizację i raczej
się jej nie używa. Opcja
-O1
włącza pod-
stawowe procedury przyspieszania kodu,
ale również rzadko widuje się ją w akcji.
-mfpmath=sse
To flaga przeznaczona dla procesorów
z zestawem instrukcji SSE (przede
wszystkim Pentium3, AMD Athlon lub
nowsze – w razie wątpliwości zajrzyj do
/proc/cpuinfo
i sprawdź, czy
sse
figuruje
w linii
lags:
). Dzięki tej fladze kod
będzie używał nowocześniejszych
i szybszych instrukcji SSE, zamiast
odwoływania się do antycznego już
www.lpmagazine.org
51
kompilacja programów
zmiennoprzecinkowego koprocesora
matematycznego i387 (wbudowanego
w każdy współczesny procesor x86).
Flaga ta może dać naprawdę solidny
przyrost wydajności w aplikacjach
zajmujących się obliczeniami matema-
tycznymi (np. programach do rende-
rowania grafiki 3D), więc jeśli masz
procesor obsługujący SSE, to nie zapom-
nij o niej.
Istnieje jeszcze specjalna wariacja tej
flagi:
-mfpmath=sse,387
. Sprawia ona, że
GCC generuje kod używający równocze-
śnie klasycznego koprocesora 387, jak
również nowej jednostki SSE. Teoretycz-
nie powoduje to dalsze przyspieszenie,
ale może zakłócić stabilność.
Posiadacze pierwszych Athlonów
(używających
-march=athlon
lub
-mar-
ch=athlon-tbird
) będą zapewne musieli
dodać jeszcze flagę
-msse
, gdyż dla tych
procesorów GCC nie włącza domyślnie
obsługi SSE (nie posiadały one jeszcze
pełnego zestawu instrukcji SSE).
-s
GCC, podczas normalnej kompilacji,
umieszcza w binarnych plikach wyni-
kowych dużo informacji dotyczących
nazw funkcji i zmiennych użytych
w kodzie źródłowym. Informacje te nie
są wykorzystywane przy normalnym
uruchamianiu binarki, ale pozwalają
użyć tzw.
debuggera
, czyli programu
do śledzenia wykonywania się kodu.
Pozwala to programistom wychwy-
tywać błędy w kodzie źródłowym
poprzez obserwowanie zawartości
zmiennych w trakcie wykonywania
się programu. Zwykły użytkownik, jak
łatwo się domyślić, nie analizuje kodu
w debuggerach. Dlatego istnieje flaga
-s
, która wyłącza wsparcie dla debug-
gera. Nie przyspieszy to działania
kompilatu, ale skróci czas potrzebny na
kompilację i znacząco zmniejszy wielkość
plików produkowanych przez kompi-
lator.
S
-O2 -fomit-frame-pointer -s -pipe"
CXXFLAGS="-march=athlon-xp
S
-O2 -fno-rtti -fno-exceptions -s -pipe"
Istnieje jeszcze zmienna CPPFLAGS. Nie-
którzy omyłkowo biorą ją za optymalizację
C++, ale to nieprawda. Owo CPP oznacza
bowiem
C PreProcessor
i nie ma nic wspól-
nego z optymalizacjami. Flagi dla C++ usta-
wia się poprzez zmienną CXXFLAGS.
Instrukcje MMX, SSE itp.
Czasem spotyka się zestawy flag typu
-march=athlon-xp -msse -mmmx -m3dnow
.
Zwykle jest to zbędne dublowanie flag,
bo odpowiednie dobranie wartości dla
-march
powinno automatycznie włączyć
wszystkie dodatkowe zestawy instrukcji.
Przykładowo, włączanie każdego pro-
cesora od Pentium2 w górę, włącza też
zestaw instrukcji MMX. Można się o tym
przekonać używając takich poleceń:
Przekazywanie lag do GCC
Do przekazywania flag kompilatorowi
zwykło używać się zmiennych środo-
wiskowych. Najważniejsze z nich to
CFLAGS i CXXFLAGS. Zmienna CFLAGS
odpowiada za flagi używane przy kom-
pilacji programów napisanych w C,
a CXXFLAGS steruje optymalizacją pro-
gramów C++. Zmienne te są odczytywa-
ne przez większość skryptów
./configure
,
więc po zdefiniowaniu globalnej zmien-
nej CFLAGS, kompilowane aplikacje
powinny zacząć używać podanych tam
optymalizacji.
Przykładowo, aby zdefiniować roz-
sądne flagi dla Athlona XP, można do
swojego
~/.bashrc
dodać następujące
wiersze:
-fomit-frame-pointer
Ta flaga optymalizuje niektóre funkcje
w kodzie źródłowym sprawiając, że
ich wywoływanie odbywa się szybciej.
Można spodziewać się po jej użyciu
przyrostu prędkości wykonywania kodu,
spadku jego wielkości oraz mniejsze-
go zużycia pamięci. Współpracuje ona
jednak tylko z kodem C, a jej użycie dla
kodu C++ ma prawie zawsze opłakane
skutki (większy niż normalnie, błędnie
działający kod).
touch pusty.c
gcc -S -v -Q pusty.c
GCC wyświetli m.in. fragment
options
enabled:
zawierający flagi, których kom-
pilator ma zamiar użyć. Jeśli teraz spróbu-
jesz wykonać:
gcc -S -v -Q pusty.c -march=athlon-xp
zobaczysz, że GCC po włączeniu
-march
=athlon-xp
automatycznie włączy
-mmmx
-m3dnow -msse
. Oczywiście, podawanie
tych opcji na siłę niczego nie popsuje, ale
warto pamiętać, że przy dobrze ustawio-
nym
-march
dodatki typu
-m3dnow
rzadko
kiedy są potrzebne.
Optymalizacje kompilatora są tematem
bardzo złożonym. Jak pokazuje ten arty-
kuł, można szybko stworzyć sobie całkiem
dobry i wydajny zestaw flag, jeśli zwróci
się uwagę na kluczowe elementy.
-fno-exceptions -fno-rtti
Te dwie flagi odnoszą się tylko do kodu
C++. Powodują wyłączenie pewnych
mechanizmów kompilatora, sprawiając,
że wynikowy kod binarny jest mniejszy
i szybszy. Niektóre programy C++ nie
dadzą się jednak z nią skompilować.
Najlepiej jest spróbować użyć tych flag
i ewentualnie wyłączyć je, jeśli kompila-
cja się nie powiedzie.
export CFLAGS="-march=athlon-xp -O2
S
S
-O2 -fno-rtti -fno-exceptions -s -pipe"
W Internecie:
Już w tym przykładzie widać, dlaczego
istnieją dwie osobne zmienne dla opty-
malizacji C/C++. C++ nie powinno nigdy
otrzymywać flagi
-fomit-frame-pointer
,
a kod C zignorowałby flagi
-fno-rtti
-fno-exceptions
. Z tego powodu zwykle
flagi dla C nie są identyczne z tymi dla
C++. W dystrybucji
Gentoo
flagi należy
zdefiniować w pliku
/etc/make.conf
,
w prawie identycznej postaci (pomijając
jedynie słowo
export
):
-pipe
GCC, kompilując jakiś plik, zapisuje
sobie pewne dane w plikach tymczaso-
wych. Po użyciu
-pipe
przestanie używać
plików tymczasowych, a zamiast nich
posłuży się rurkami (potokami). Nie ma
to wpływu na wynikowy kod, więc nie
jest to tak naprawdę flaga sterująca opty-
malizacją, ale może nieco przyspieszyć
samą kompilację.
• Skrypt samodzielnie generujący
zestaw lag na podstawie /proc/
cpuinfo:
http://www.iol.ie/~padraiga/scripts/
gcccpuopt
• Dokładna lista numerów Family/
Model/Stepping dla różnych proceso-
rów:
http://www.paradicesoftware.com/
specs/cpuid/index.htm
52
sierpień 2004
CFLAGS="-march=athlon-xp
-fomit-frame-pointer -s -pipe"
export CXXFLAGS="-march=athlon-xp
Plik z chomika:
SOLARIX33
Inne pliki z tego folderu:
2006.01_Koder plików w formacie OGG_[Programowanie].pdf
(722 KB)
2007.06_Piękno fraktali_[Programowanie].pdf
(1778 KB)
2008.11_GanttProject_[Programowanie].pdf
(1014 KB)
2007.04_USB Device Explorer_[Programowanie].pdf
(1134 KB)
2006.09_QT, PyQT – szybkie tworzenie baz danych_[Programowanie].pdf
(1319 KB)
Inne foldery tego chomika:
Administracja
Aktualnosci
Audio
Bazy Danych
Bezpieczenstwo
Zgłoś jeśli
naruszono regulamin