Hlavní navigace

Kompilujeme ze zdrojového kódu - optimalizace, výstup configure

Stanislav Brabec

Prvním krokem před vlastní konfigurací bývá výběr vhodné optimalizace. Dnes se na něj podíváme blíž. Poté spustíme skript configure a naučíme se číst jeho výpisy. Dozvíme se, co užitečného a důležitého nám program sděluje a na co dávat pozor.

Volby kompilátoru

Již v minulém dílu jsme se dotkli voleb kompilátoru, které můžeme předat proměnné CFLAGS, případně CXXFLAGS(pro C++). Dnes se zaměříme na volby optimalizace.

Typ procesoru

Gcc nabízí volby pro kompilaci pro různé procesory. Jsou jimi:

-march=typ_cpu: Tato volba nastaví kompilaci pro cílový procesor. Kód pak funguje na daném procesoru a jeho následnících.

-mcpu=typ_cpu: Tato volba nastavuje většinu parametrů pro daný procesor, ale vlastní tabulku instrukcí nemění. Lze tak vyrobit kód, který sice běží na i386, ale optimalizován je např. pro Pentium.

Nejnovější gcc-3.2 již podporuje výstup pro následující typy procesorů IA32 (Intel Architecture 32 bit): i386, i486, i586, i686, pentium, pentium-mmx, pentiumpro, pentium2, pentium3, pentium4, k6, k6–2, k6–3, athlon, athlon-tbird, athlon-4, athlon-xp a athlon-mp.

Naproti tomu nejvyšším IA32 systémem, který dnes GNU auto nástroje detekují, je i686-pc-linux-gnu. Pokud chceme lepší optimalizaci, musíme si pomoci proměnnou CFLAGS. Tou si musíme pomáhat i tehdy, je-li kompilátor implicitně nastaven na nižší typ procesoru.

Ladění

Pro ladění existuje volba -g. Ta zapne generování tabulek symbolů pro ladění. Ty se pak objeví v knihovnách i binárních souborech (pokud je nenainstalujeme pomocí make install-strip). Mnohé balíčky mají též –enable-debug jako volbu pro configure. Ta zapne nejen generování ladicích symbolů, ale přidá do kódu množství ladicích výpisů.

K samotnému ladění pak budeme potřebovat debugger (např. gdb), zřejmě i nějakou jeho grafickou nadstavbu a nejlépe i původní zdrojový kód.

Optimalizace

Optimalizace kompilátorů gcc se skládá z množství dílčích voleb, začínajících -f nebo -fno-. Najdete je v dokumentaci gcc, zkrácenou informaci pomocí gcc -v –help. Aby bylo nastavení optimalizace jednodušší, existuje ještě číselná škála voleb -O0 až -O3, které postupně zapínají více optimalizací a kompilují déle. V nových kompilátorech je navíc k dispozici -Os, která zapne pouze takové volby, jež nezpůsobují prodloužení kódu (optimalizace na velikost) – tedy optimalizace pro stroje s minimem paměti. Pokud chcete zjistit, které volby se kdy zapínají, odkazuji vás na zdrojové kódy gcc: gcc/toplev.c.

Standardní optimalizace, kterou auto nástroje pro GNU/Linux zapínají, je -O2.

Některé speciální volby však pomocí -O? nelze zapnout. Jsou to nastavení, která jsou jistým způsobem sporná – buď mohou způsobit extrémní zvětšení kódu, nebo generují méně přesný kód.

Volba -fomit-frame-pointer způsobí, že ve výsledném kódu nebude obsažen ukazatel rámce (ukazatel do struktur nadřazených objektů na zásobníku), pokud to není nutné (např. na IA32). Takový kód může být kratší a rychlejší, prakticky jej však nelze ladit. Pokud je takto zkompilována knihovna, mohou být problémy dokonce i při ladění aplikace, která ji používá. Některé aplikace mívají problémy s funkčností, jsou-li takto kompilovány (např. některé verzeMozilly).

Volba -funroll-all-loops, jak název napovídá, rozvine všechny smyčky se známým počtem opakování. Často to vede k velkému prodloužení kódu za cenu několika málo ušetřených strojových cyklů. Přesto se používá, zvlášť u multimediálních aplikací.

Volba -ffast-math zapne rychlé matematické rutiny namísto standardních IEEE nebo ISO. To může způsobit problémy matematickým a statistickým aplikacím, ale pro multimediální a 3D aplikace to znamená zvýšení rychlosti.

Volba -malign-double může zvýšit rychlost tím, že proměnné typu double a long long se budou číst z paměti během jediného cyklu. Způsobí však také zvětšení datových struktur a jejich binární nekomaptibilitu.

U kompilátorů C++ existuje možnost zmenšit paměťové nároky, pokud nebudeme používat RTTI (identifikaci typu proměnných za běhu) ani výjimky: -fno-rtti -fno-exceptions. Některé aplikace však na těchto vlastnostech staví, a pak při jejich kompilaci narazíme na podivné chyby. Stane-li se tak, nejdříve otestujeme, jak kompilace proběhne bez těchto voleb. Pozor, tyto volby mohou generovat mírně odlišné knihovny a kompilační chyba se může projevit až v aplikaci, která je použije.

U mizerně napsaných C++ aplikací občas pomůže -fpermissive, které z některých chybových hlášení udělá pouze varování.

S postupující kvalitou kompilátorů se ukazuje jedna nepříjemná věc – ne každou aplikaci lze moderním kompilátorem optimalizovat. Setkáme se dokonce s aplikacemi, které fungují pouze s -O0 (tedy jen bez optimalizace – např. starší verze recode). V 99 % to není chyba kompilátoru, ale programátora.

U některých aplikací se lze chybě vyhnout pomocí volby -fno-strict-aliasing, případně jiných voleb, které mohou poškodit kód špatně napsaného programu.

Ale -O0 s výhodou použijeme i jindy – pokud aplikaci teprve ladíme a chceme ji rychle zkompilovat.

Existují i opačné aplikace, které nelze kompilovat bez optimalizace. Jde především o použití inline funkcí, které neexistují v jiné podobě (např. inb a outb).

Pro ty, kdož experimentují s kompilátorem icc od Intelu, přidávám ještě tip na maximální optimalizaci pro něj: -O3 -axK -ipo.

Nejdokonalejší cestou, jak zajistit optimalizaci, je profilování. Aplikace je zkompilována s volbami pro profilování, spuštěna a používána. Při tom jsou vytvářeny profily, které sledují, jak často je daný kus kódu vyvoláván a jaký bývá častější výsledek testu při větvení. Poté je aplikace znovu zkompilována a na základě těchto informací vytvoří optimalizátor co nejlepší kód.

Spouštíme configure

Pokud spouštíme configure poprvé, budeme zřejmě zahlceni informacemi o přítomnosti a nepřítomnosti knihoven a hlavičkových souborů. Později zjistíte, že se nejedná o pouhý náhodný souhrn testů, ale že je v nich určitá pravidelnost a že skript má jisté fáze (jejich oddělení není nijak patrné, pouze se změní charakter testů).

Na zkoušku si spustíme konfiguraci kdelibs (ve skutečnosti jsem si část výsledků pro studijní účely vymyslel). Z důvodů uvedených v minulém dílu si vyberu instalaci do /opt/kde. Do souboru /etc/config.site jsem si zapsal vhodné hodnoty (viz minulý díl) a volání GNU-FHS. Skriptu configure předám –enable-final (kompilace po větších blocích – viz dokumentace KDE). Do CXXFLAGS nebudu přidávat -fno-rtti -fno-exceptions, neboť u kdelibs verze 3 to dělá samotný make.

export CONFIG_SITE=/et­c/config.site
export CFLAGS=„-march=athlon-4 -O3 -fomit-frame-pointer“
export CXXFLAGS=„-march=athlon-4 -O3 -fomit-frame-pointer“
./configure –prefix=/opt/kde –enable-shared –disable-static –enable-final –with-qtdir=/opt/qt3

Většina skriptů začíná obecným ověřením platformy. Testuje se, na jaké platformě pracujeme, zda fungují kompilátory a další základní programy, a jaké argumenty je možné jim předat.

configure: loading site script /etc/config.site
loading GNU-FHS site script
checking build system type… i686-pc-linux-gnu
checking host system type… i686-pc-linux-gnu
checking target system type… i686-pc-linux-gnu
checking for a BSD compatible install… /usr/bin/install -c
checking for -p flag to install… yes
checking whether build environment is sane… yes
checking for mawk… no
checking for gawk… gawk
checking whether make sets ${MAKE}… yes
checking for a BSD compatible install… /usr/bin/install -c -p
checking for style of include used by make… GNU
checking for gcc… gcc
checking for C compiler default output… a.out
checking whether the C compiler works… yes
checking whether we are cross compiling… no
checking for executable suffix…
checking for object suffix… o
checking whether we are using the GNU C compiler… yes
checking whether gcc accepts -g… no
checking dependency style of gcc… gcc3
checking how to run the C preprocessor… gcc -E
checking for g++… g++
checking whether g++ supports -fno-exceptions… yes
checking whether g++ supports -fno-check-new… yes
checking whether g++ supports -fexceptions… yes
 …

Pak se testují základní systémové knihovny pro různé systémy. Zde si všimnete, že některé testy pravidelně dopadnou negativně. Jsou to testy na základní knihovny některých nelinuxových UNIXů. Poté se testuje způsob lokalizace systému, základní hlavičkové soubory a vlastnosti datových struktur (jako kolik bajtů má long, funguje-li long long apod.).


checking for shl_load… no
checking for shl_load in -ldld… no
checking for dlopen… no
checking for dlopen in -ldl… yes
checking whether a program can dlopen itself… yes
checking whether a statically linked program can dlopen itself… yes
checking for msgfmt… /usr/bin/msgfmt
checking for gmsgfmt… /usr/bin/msgfmt
checking for xgettext… /usr/bin/xgettext
checking for ranlib… ranlib
checking for ANSI C header files… yes
checking for sys/types.h… yes
checking for sys/stat.h… yes
checking for stdlib.h… yes
checking for string.h… yes

checking for res_init… no
checking for killpg in -lucb… no
checking for int… yes
checking size of int… 4
checking for long… yes
checking size of long… 4
checking for char *… yes
checking size of char *… 4
checking for char… yes
checking size of char… 1

Tyto testy se pravidelně opakují v mnoha balících, jsou důkladně prověřeny a většinou fungují dobře.

Grafické aplikace si poté otestují X a přecházejí se ke specializovaným testům.

checking for X… libraries /usr/X11R6/lib, headers /usr/X11R6/include
checking for IceConnectionNumber in -lICE… yes
checking for libXext… yes

Nyní je potřeba zbystřit a sledovat, co skript hledá a zda to našel. Pokud se ve svém systému zatím neorientujete, bude to trochu náročnější. Ale časem, až získáte další poznatky, se orientace stává snazší.

V této části skript testuje přítomnost (nebo aktivizace) povinných a volitelných komponent. Pokud nenalezne některou z povinných komponent systému, většinou se zastaví, vypíše, co chybí, a dále nepokračuje. Jedná-li se o volitelnou součást, vypíše pouze nepřítomnost komponenty a pokračuje. Části balíku vyžadující její podporu pak budou vypnuté.

Hned na začátku vidíme problém:

checking for Xinerama… no

Protože vím, že Xinerama (rozšíření X pro více obrazovek) je v mém systému přítomno, začnu pátrat. Řešení je tentokrát jednoduché: podpora rozšíření Xinerama je standardně vypnutá a slovo no v tomto případě znamená, že test se vůbec neprováděl. Stačí předat skriptu –enable-xinerama. Spustím jej tedy znovu:

checking for Xinerama… yes

checking for libz… -lz
checking for libpng… -lpng -lz -lm
checking for libjpeg6b… no
checking for libjpeg… -ljpeg
checking for Qt… libraries /opt/qt3/lib, headers /opt/qt3/include using -mt
checking if Qt compiles without flags… no
checking for moc… /opt/qt3/bin/moc
checking for uic… /opt/qt3/bin/uic
checking whether uic supports -L … yes
checking whether uic supports -nounload … yes
checking if Qt needs -ljpeg… no

checking whether byte ordering is bigendian… no

checking for mkstemps… no

checking for vfork.h… no

Zde vidíme hned několik negativních odpovědí. Aby nás neznepokojovaly, budeme pro ně hledat vysvětlení.

První nás nemusí pálit – libjpeg6b je pouze jiné jméno libjpeg, použité na některých systémech. My mámelibjpeg (jak ukázal hned následující test), takže je vše v pořádku.

Další negativní hlášení – Qt se nedá zkompilovat bez přídavných argumentů. I to je v pořádku – qt3 jsem instaloval ručně do adresáře /opt/qt3 a tam kompilátor standardně nevidí.

Dále – Qt nepotřebuje -ljpeg. Opět je to logické – jpeg obrázky totiž v Qt čte zvláštní modul (toto chování je v Qt nastavitelné).

A že pořadí bajtů není bigendian? No, to není a na IA32 nikdy nebylo.

A co funkce mkstemps? Prohledáním dokumentace ke GNU C Library snadno zjistíme, že tam o ní není ani slovo:

fgrep mkstemps /usr/share/in­fo/libc.info*

To si ostatně můžeme potvrdit i prohledáním knihovny:

fgrep mkstemps /lib/libc.so.6

A nemáme hlavičkový soubor vfork.h? Nemáme. Prohledáním hlavičkových souborů zjistíme, že funkce vfork je definována jinde – v souboru unistd.h:

fgrep -r vfork /usr/include
/usr/include/u­nistd.h:extern __pid_t vfork (void) __THROW;

Takto sledujeme výstup a neshledáváme žádné skutečné problémy.


checking for FAMOpen in -lfam… no

Tak, a máme první problém. Na systému totiž FAM (File Alteration Monitor – monitor změn souboru) nebyl nainstalován. Z dokumentace zjistíme, že je to užitečná věc, bez níž musím dávat Obnovit, chci-li vidět změny v adresáři. FAM si tedy doinstaluji (včetně záplaty na jádro a spouštění démona při startu počítače) a opakuji konfiguraci:

checking for FAMOpen in -lfam (cached)… no

Hmm, výsledek je již v keši (config.cache):

ac_cv_lib_fam­_FAMOpen=${ac_cv_­lib_fam_FAMOpen=no}

Mohu tedy smazat tento řádek nebo celou keš a opakovat konfiguraci. A pokračovat…

checking for FAMOpen in -lfam… yes

checking whether OpenSSL uses rsaref… no
checking for easter eggs… none found

Nevím přesně, co je rsaref (předpokládám že jakási podpora šifry RSA), a nehodlám jej instalovat. Pouze si zapíšu do svého zápisníku, že budu-li někdy instalovat něco, co se takto jmenuje, budu rekompilovat i kdelibs.

Velikononí vajíčko? Nu, zde se jedná o škodolibost autorů. Je to zřejmě chyták na nezkušené, kteří začnou na disku a Internetu hledat program jménem Easter Egg.

A tak plyne výpis až k závěrečnému:

updating cache ../config.cache
configure: creating ./config.status
config.status: creating Makefile
config.status: creating config.h
config.status: config.h is unchanged

Good – your configure finished. Start make now

Vše proběhlo podle očekávání a nenarazili jsme na žádnou chybu. Ne vždy je to tak jednoduché. Ale o tom až příště…

Našli jste v článku chybu?

6. 9. 2002 11:15

Stanislav Brabec (neregistrovaný)

Tak to jste asi dělal špatně. Rozhodně funguje -O3. S jistými omezeními i -fomit-frame-pointer. Dále lze zmenšit knihovnu vyhozením informací o verzích, ale pak bude knihovna binárně nekompatibilní.
Je však třeba dávat pozor na verzi glibc a kompilátoru. Obecně platí - verze glibc musí být novější než verze gcc.
Pro kompilaci glibc s gcc-3.2 potřebujete patch.



5. 9. 2002 5:28

Karel Benák (neregistrovaný)

Pokud hodlate nekdo kompilovat glibc, mohu doporucit, nepouzivejte optimalizaci, protoze pak nefungujou takove prikazy, jako je ls, dir apod.

Podnikatel.cz: K EET. Štamgast už peníze na stole nenechá

K EET. Štamgast už peníze na stole nenechá

DigiZone.cz: Placené VoD a obsah zdarma

Placené VoD a obsah zdarma

Podnikatel.cz: Přehledná titulka, průvodci, responzivita

Přehledná titulka, průvodci, responzivita

Lupa.cz: Kdo pochopí vtip, může jít do ČT vyvíjet weby

Kdo pochopí vtip, může jít do ČT vyvíjet weby

DigiZone.cz: Dreambox DM900 Ultra HD přichází

Dreambox DM900 Ultra HD přichází

Podnikatel.cz: Zavře krám u #EET Malá pokladna a Teeta?

Zavře krám u #EET Malá pokladna a Teeta?

Podnikatel.cz: Chtějte údaje k dani z nemovitostí do mailu

Chtějte údaje k dani z nemovitostí do mailu

120na80.cz: Co všechno ovlivňuje ženskou plodnost?

Co všechno ovlivňuje ženskou plodnost?

Lupa.cz: Co se dá měřit přes Internet věcí

Co se dá měřit přes Internet věcí

Měšec.cz: Kdy vám stát dá na stěhování 50 000 Kč?

Kdy vám stát dá na stěhování 50 000 Kč?

Podnikatel.cz: Chaos u EET pokračuje. Jsou tu další návrhy

Chaos u EET pokračuje. Jsou tu další návrhy

Vitalia.cz: Spor o mortadelu: podle Lidlu falšovaná nebyla

Spor o mortadelu: podle Lidlu falšovaná nebyla

Vitalia.cz: Jsou čajové sáčky toxické?

Jsou čajové sáčky toxické?

Vitalia.cz: Znáte „černý detox“? Ani to nezkoušejte

Znáte „černý detox“? Ani to nezkoušejte

Podnikatel.cz: Podnikatelům dorazí varování od BSA

Podnikatelům dorazí varování od BSA

Vitalia.cz: I církev dnes vyrábí potraviny

I církev dnes vyrábí potraviny

DigiZone.cz: Rádio Šlágr má licenci pro digi vysílání

Rádio Šlágr má licenci pro digi vysílání

Lupa.cz: Propustili je z Avastu, už po nich sahá ESET

Propustili je z Avastu, už po nich sahá ESET

Vitalia.cz: „Připluly“ z Německa a možná obsahují jed

„Připluly“ z Německa a možná obsahují jed

Podnikatel.cz: EET: Totálně nezvládli metodologii projektu

EET: Totálně nezvládli metodologii projektu