GCC optimalizálás
Ez az útmutató bemutatja a lefordított kód optimalizálását biztonságos, értelmes CFLAGS és CXXFLAGS használatával. Általánosságban leírja az optimalizálás mögött meghúzódó elméletet is.
Az alapértelmezett CFLAGS változó értékei a make.conf fájlban állíthatók be a Gentoo rendszereken. A CFLAGS változó értékei külön, programcsomagonként is megadhatóak.
További információkért tekintse meg a CFLAGS és CXXFLAGS változókat a Gentoo kézikönyvben, valamint a safe safe CFLAGS cikkben. Továbbá, tekintse meg a GYIK-et.
Bevezetés
Mi a CFLAGS és CXXFLAGS változó?
A CFLAGS és a CXXFLAGS azon környezeti változók közé tartoznak, amelyeket hagyományosan a bináris programkódra fordító segédprogramnak a bekonfigurálására használnak egy programkódokat felépítő (legeneráló) rendszerben C és C++ forráskódok lefordításakor. Bár ezek a változók nincsenek szabványosítva, használatuk alapvetően mindenütt jelen van, és minden helyesen megírt build fájlnak értenie kell ezeket az extra vagy egyéni beállítások átadásához, amikor meghívja a bináris programkódra fordító segédprogramot. Nézze meg a GNU make információs oldalt a néhány gyakran használt változójának listájáért a kategóriában.
Mivel a legtöbb Gentoo rendszert alkotó programcsomagok forráskódjának nagy része C és C++ nyelven van megírva, ezért ezt a két változót az adminisztrátorok mindenképpen helyesen akarják beállítani, mivel ezek nagyban befolyásolják a rendszert a csomagfelétetés módját illetően.
Ezek használhatók egy program hibakeresési üzeneteinek csökkentésére, a hibafigyelmeztetési szintek növelésére, és természetesen az előállított bináris kód optimalizálására. A GCC kézikönyv tartalmazza a rendelkezésre álló opciók és azok céljainak teljes listáját.
Hogyan használják ezeket?
Általában a CFLAGS és CXXFLAGS az environmentben kerülnek beállításra, amikor egy configure scriptet indítanak vagy a automake program által generált makefile-okkal dolgoznak. Gentoo-alapú operációs rendszerekben állítsa be a CFLAGS és CXXFLAGS változókat a /etc/portage/make.conf fájlban. Az ebben a fájlban beállított változók exportálva lesznek az environmentbe azoknak a programoknak, amelyeket a portage indít el, így az összes szoftvercsomag ezekkel az opciókkal kerül lefordításra alapértelmezettként.
CFLAGS="-march=skylake -O2 -pipe"
CXXFLAGS="${CFLAGS}"
Noha a USE jelölőzászlókban lehetőség van a több sor használatára, a CFLAGS esetében ez problémákat okozhat, és okozni is fog olyan programokkal, mint például a cmake. Ügyeljen arra, hogy a CFLAGS deklarációja egyetlen sorban legyen, és minél kevesebb üres karaktert tartalmazzon, hogy elkerülje a problémákat. Példaként tekintse meg a bug #500034 hibabejegyzést.
Amint a fenti példában látható, a CXXFLAGS változó be van állítva, hogy használja az összes CFLAGS-ban szereplő opciót. Szinte minden rendszernek ilyen módon kell beállítva lennie. További opciók a CXXFLAGS-hoz kevésbé gyakoriak, és általában nem elég általánosan alkalmazhatók ahhoz, hogy érdemes legyen őket globálisan beállítani.
A Safe CFLAGS cikk segíthet a kezdőknek abban, hogy elkezdjék optimalizálni a rendszereiket.
Tévhitek
Noha a különböző CFLAGS által engedélyezett fordítóoptimalizálások hatékony módszert jelenthetnek kisebb és/vagy gyorsabb binárisok előállítására, ugyanakkor ronthatják a kód működését, növelhetik annak méretét, lassíthatják a futási idejét, vagy egyszerűen csak build hibát okozhatnak. A teljesítménynövekedés csökkenő hozadékának pontja meglehetősen gyorsan elérhető a CFLAGS használata során. Ne állítsa be őket önkényesen.
Emlékezzen arra, hogy a globális CFLAGS, amely a /etc/portage/make.conf fájlban van beállítva, a rendszer minden szoftvercsomagjára alkalmazva lesz, ezért a rendszergazdák általában csak általános, széles körben alkalmazható opciókat állítanak be. Az egyes szoftvercsomagok tovább módosítják ezeket az opciókat akár az ebuildben, akár maga az építési rendszer során, hogy előállítsák azokat a végleges zászlókészleteket, amelyeket a kódfordító hívásakor használnak.
Készen áll?
Tudatában a kapcsolódó kockázatoknak, vessen egy pillantást néhány észszerű, biztonságos optimalizálásra. Ezek jó szolgálatot tesznek, és elnyerik a fejlesztők tetszését a következő alkalommal, amikor egy problémát jelentenek a Bugzilla felületén. (A fejlesztők általában megkérik a felhasználót, hogy fordítsa újra a szoftvercsomagot minimális CFLAGS használatával, hogy megnézzék, vajon fennáll-e még a probléma. Ne feledje: Az agresszív jelölőzászlók tönkretehetik a programkódot!)
Optimalizálás
Alapok
A CFLAGS és CXXFLAGS célja, hogy a rendszerhez tökéletesen illeszkedő kódot hozzanak létre, amely lehetőség szerint hibátlanul működik, miközben egyszerű és gyors. Néha ezek a feltételek kölcsönösen kizárják egymást, ezért ez az útmutató azokra a kombinációkra fog összpontosítani, amelyekről ismert, hogy jól működnek. Ideális esetben ezek a legjobban elérhetők bármilyen CPU-architektúrához. Tájékoztató célból az agresszív jelölőzászló használat később kerül bemutatásra. A GCC kézikönyvben felsorolt összes opció (százak) nem kerül tárgyalásra, de az alapvető, leggyakoribb jelölőzászlók felülvizsgálatra kerülnek.
Amikor nem tudja, hogy egy jelölőzászló mit csinál, tekintse meg a GCC kézikönyv megfelelő fejezetét. Ha a kézikönyv megtekintése után is tanácstalan, akkor próbáljon meg egy keresőmotort, vagy nézze meg a GCC levelezési listákat.
-march
Az első és legfontosabb opció a -march
. Ez megadja a kódfordítónak, hogy milyen programkódot kell előállítania az operációs rendszer processzorarchitektúrájához (vagy arch); közli a GCC szoftverrel, hogy egy bizonyos típusú CPU-hoz készítsen kódot. A különböző CPU-k különböző képességekkel rendelkeznek, eltérő utasításkészleteket támogatnak, és más módon hajtják végre a programkódot. A -march
jelölőzászló utasítja a kódfordítóprogramot, hogy a rendszer CPU-jához illeszkedő specifikus kódot hozzon létre, annak minden képességével, tulajdonságával, utasításkészletével és sajátosságaival, feltéve, hogy a forráskód elő van készítve ezek használatára. Például az AVX utasítások előnyeinek kihasználásához a forráskódot ennek támogatására kell adaptálni.
A -march=
egy ISA kiválasztási opció. Ez közli a forráskódfordítóval, hogy használhatja az ISA utasításait. Intel/AMD64 platformon -march=native -O2
vagy alacsonyabb optimalizációs szint mellett a kód valószínűleg AVX utasításokat fog használni, de rövidebb SSE XMM regiszterekkel. GCC 12 előtti fordítóverziók használata esetén, az AVX YMM regiszterek teljes kihasználásához a -ftree-vectorize
vagy -O3
opciókat is alkalmazni kell[1].
Bár a /etc/portage/make.conf fájlban lévő CHOST változó meghatározza a használt általános architektúrát, a -march
jelölőzászlót továbbra is használni kell, hogy a programokat a rendszer specifikus processzorára lehessen optimalizálni. Az x86 és x86-64 CPU-knak (többek között) a -march
jelölőzászlót kell használniuk.
Milyen típusú CPU-ja van a rendszernek? Ennek kiderítéséhez futtassa a következő parancsot:
user $
cat /proc/cpuinfo
vagy akár telepítheti a app-portage/cpuid2cpuflags szoftvercsomagot, és hozzáadhatja a CPU-specifikus opciókat a /etc/portage/package.use/00cpuflags fájlhoz, amit az eszköz például a CPU_FLAGS_* változón keresztül végez el:
user $
cpuid2cpuflags
CPU_FLAGS_X86: aes avx avx2 f16c fma3 mmx mmxext pclmul popcnt sha sse sse2 sse3 sse4_1 sse4_2 sse4a ssse3
root #
echo "*/* $(cpuid2cpuflags)" > /etc/portage/package.use/00cpu-flags
Ha részletesebb információkra van szüksége, beleértve a march
és mtune
értékeket, akkor két parancs is használható.
- Az első parancs utasítja a kódfordítót, hogy ne végezzen semmilyen linkelést (
-c
), és ahelyett, hogy a--help
opciót használná a parancssori opciók tisztázására, most azt mutatja meg, hogy bizonyos opciók engedélyezve vagy letiltva vannak-e (-Q
). Ebben az esetben a megjelenített opciók azok, amelyek az adott célhoz engedélyezve vannak:user $
gcc -c -Q -march=native --help=target
- A második parancs megmutatja a fordító utasításait a fejlécfájl létrehozásához, de anélkül, hogy ténylegesen végrehajtaná a lépéseket, ehelyett a képernyőn jeleníti meg azokat (
-###
). A végső kimeneti sor az a parancs, amely tartalmazza az összes optimalizációs opciót és architektúraválasztást:user $
gcc -### -march=native /usr/include/stdlib.h
A
l2-cache-size
opció a processzor utolsó szintű gyorsítótárát (L2 vagy ha van, magasabb szintűt) jelöli.[2]cpu-type
- A glibc-hwcaps funkció (>=sys-libs/glibc-2.33) használható a
-march
meghatározására egy általánosabb processzorarchitektúrához (>=sys-devel/gcc-11 esetén):
user $
/lib64/ld-linux-x86-64.so.2 --help
... Subdirectories of glibc-hwcaps directories, in priority order: x86-64-v4 x86-64-v3 (supported, searched) x86-64-v2 (supported, searched) x86_64 (supported, searched)
Ebben a példában a CPU támogatja az x86-64-v3 psABI x86_64-et, amely a -march=x86-64-v3
használatára alkalmazható.
A
-mtune
esetében a -msse, -msse2, -msse3, -mmmx, -m3dnow referencia felsorolja a cpu-type
modelleket.Most akkor nézzük meg a -march
parancs működését. Ez a példa egy régebbi AMD Athlon 64 processzorra vonatkozik:
/etc/portage/make.conf
AMD64 példaCFLAGS="-march=athlon64"
CXXFLAGS="${CFLAGS}"
Itt van egy másik példa egy általánosan használt Intel processzorra:
/etc/portage/make.conf
Intel Core példaCFLAGS="-march=skylake"
CXXFLAGS="${CFLAGS}"
Ha a CPU típusa nem meghatározott, vagy a felhasználó nem tudja, hogy melyik beállítást válassza, akkor lehetséges a -march=native
beállítást használni. Amikor ezt a jelölőzászlót alkalmazzák, akkor a GCC megpróbálja felismerni a processzor típusát, és automatikusan beállítja a megfelelő jelölőzászlókat hozzá. Azonban ezt a beállítást nem szabad használni, ha a cél az, hogy a szoftvercsomagok különböző processzorok számára legyenek lefordítva!
Ha szoftvercsomagokat fordítunk le egy számítógépen azért, hogy azokat egy másik számítógépen futtassuk (például egy gyors számítógépet használunk egy régebbi, lassabb számítógéphez való szoftvercsomagok elkészítéséhez), akkor ne használjuk a -march=native
beállítást. A "native" azt jelenti, hogy az előállított bináris futtatható programkód csak az adott típusú processzoron fog futni. Az Intel Core processzoron a -march=native
beállítással létrehozott alkalmazások nem lesznek képesek futni egy régi Intel Atom processzoron.
Elérhetők továbbá a -mtune
és -mcpu
jelölőzászlók. Ezeket a jelölőzászlókat általában csak akkor használjuk, ha nincs elérhető -march
opció. Bizonyos processzorarchitektúrák megkövetelhetik a -mtune
vagy akár a -mcpu
használatát. Sajnos a GCC viselkedése nem túl következetes abban, hogy az egyes jelölőzászlók hogyan működnek egyik architektúráról a másikra.
Az x86 és x86-64 processzorokon a -march
kifejezetten az adott processzorra generál kódot, felhasználva annak elérhető utasításkészleteit és a megfelelő ABI-t. Nem lesz visszafelé kompatibilis régebbi/eltérő CPU-kkal. Fontolja meg a -mtune
használatát, amikor régebbi processzorok, például i386 és i486 számára generál futtatható bináris programkódot. A -mtune
általánosabb bináris kódot készít, mint a -march
. Bár optimalizálja a kódot egy adott processzor számára, de nem veszi figyelembe az elérhető utasításkészleteket és az ABI-t. Ne használja a -mcpu
parancsot x86 vagy x86-64 rendszereken, mivel ezeken az architektúrákon ez már elavult.
Kizárólag nem x86/x86-64 processzorok (például ARM, SPARC, Alpha és PowerPC) esetében lehet szükség a -mtune
vagy -mcpu
használatára a -march
helyett. Ezeken az architektúrákon a -mtune
/ -mcpu
néha ugyanúgy működik, mint a -march
(x86/x86-64 esetében), de más jelölőzászló névvel. Ismételten, a GCC viselkedése és a jelölőzászlók elnevezése nem következetes az architektúrák között, ezért mindenképpen tekintse meg a GCC kézikönyvet, hogy meghatározza, melyiket kell használni.
További javasolt
-march
/ -mtune
/ -mcpu
beállításokért olvassa el a megfelelő Gentoo Installation Handbook kézikönyv 5. fejezetét az adott architektúrára vonatkozóan. Ezenkívül olvassa el a GCC kézikönyv architektúra-specifikus opciók listáját, valamint részletesebb magyarázatokat a -march
, -mcpu
és -mtune
közötti különbségekről.Ne használja a
-march=native
vagy -mtune=native
beállításokat a CFLAGS vagy CXXFLAGS változókban a make.conf fájlban, amikor distcc szoftverrel fordít.-O
A
-O3
használata okozhat bizonyos szoftvercsomagoknál hibát akár a kódfordítás során, akár a futásidejű működésben, habár a -O3
megtartja a szabványos megfelelőséget, így minden meghibásodás vagy az alkalmazásban lévő nem definiált viselkedés eredménye, vagy (nagyon ritkán) a kódfordítóprogram hibája.Az összes olyan szoftvercsomag listázásához, amelyeket meghatározott CFLAGS/CXXFLAGS értékekkel fordítottak le, használható a következő parancs:
grep O3 /var/db/pkg///CFLAGS
A következő a -O
változó. Ez a változó az optimalizálás általános szintjét szabályozza. Ennek az értéknek a módosítása meghosszabbíthatja a kód fordításának az idejét, és lényegesen több memóriát használhat, különösen, ahogy az optimalizálás szintje nő.
Hét -O
beállítás létezik: -O0
, -O1
, -O2
, -O3
, -Os
, -Oz
és -Og
. Ezek közül csak egyet használjon a /etc/portage/make.conf fájlban. Van egy nyolcadik opció is, amelyet nem szabad rendszerszinten használni: -Ofast
- annak ellenére, hogy neve gyorsaságot sugall, megsérti a szabványos megfelelőséget, és veszélyes.
A -O0
kivételével a -O
beállítások mindegyike több további jelölőzászlót aktivál, ezért mindenképpen olvassa el a GCC kézikönyv optimalizációs opciókról szóló fejezetét, hogy megtudja, mely jelölőzászlók aktiválódnak az egyes -O
szinteken, valamint a fejezet néhány magyarázatot ad arról, hogy mit csinálnak.
Vizsgáljuk meg az egyes optimalizálási szinteket:
-O0
: Ez a szint (ami az "O" betűt követő nulla) teljesen kikapcsolja az optimalizálást, és ez az alapértelmezett beállítás, ha nincs megadva-O
szint a CFLAGS vagy CXXFLAGS változókban. Ez csökkenti a kódfordítási időt és javíthatja a hibakeresési információkat, de egyes alkalmazások nem fognak megfelelően működni, ha az optimalizálás nincs engedélyezve. Ezt az opciót nem ajánljuk, kivéve hibakeresési célokra.
-O1
: A legalapvetőbb optimalizálási szint. A kódfordítóprogram megpróbál gyorsabb, kisebb kódot előállítani anélkül, hogy sok kódfordítási időt venne igénybe. Ez alapvető, de mindig el kell végeznie a munkát.
-O2
: Egy lépés feljebb a-O1
szinthez képest. Az ajánlott optimalizálási szint, hacsak a rendszernek nincsenek speciális igényei. A-O2
néhány további jelölőzászlót aktivál azokon felül, amelyeket a-O1
már aktivált. A-O2
szinttel a kódfordítóprogram megpróbálja növelni a kód teljesítményét anélkül, hogy az méretbeli kompromisszumot jelentene, vagy túl sok kódfordítási időt igényelne.
-O3
: Engedélyezi a-O2
szintet, valamint olyan optimalizációkat engedélyez, amelyek drágák a kódfordítási idő és memóriahasználat szempontjából. A-O3
szinttel való kódfordítás valószínűleg javítja a teljesítményt (bár nem garantált). Történelmileg a-O3
előhozhatott fordítóprogram-hibákat, manapság azonban a-O3
szinttel kapcsolatos problémák szinte mindig nem definiált viselkedési esetek (UB), és a forráskódban van hiba, amit javítani kell. Egyes szoftvercsomagok még mindig hibásak a-O3
szinttel. A-O3
használata nem ajánlott, kivéve ha szoftvercsomagok tesztkészleteit futtatjuk.
-Ofast
: Új opció a GCC 4.7 verziójában, amely magába foglalja a -O3
szintet, valamint a -ffast-math
, -fno-protect-parens
, -fallow-store-data-races
, -fstack-arrays
és -fno-semantic-interposition
beállításokat. Ez az opció megsérti a szigorú szabványos megfelelőséget, és használata nem ajánlott. Ne alkalmazza rendszerszinten soha, és csak szoftvercsomagonként használja, ha a szoftvert már auditálták az opcióval való használatra.
-Os
: A bináris kód méretére optimalizál. Aktiválja az összes-O2
opciót, amely nem növeli a generált bináris kód méretét. Hasznos lehet olyan számítógépek esetében, amelyek rendkívül korlátozott adathordozó kapacitással rendelkeznek és/vagy kis gyorsítótár méretű processzorokat használnak.
-Oz
: A GCC 12.1 verziójában bevezetett opció, amely agresszívabban optimalizál a méretre, mint a-Os
. Megjegyzendő, hogy ez jelentősen rontja a futásidejű teljesítményt a-O2
szinthez képest, mivel növeli a végrehajtott utasítások számát, ha azok kevesebb byte értéket igényelnek a kódoláshoz.
-Og
: A GCC 4.8 verziójában egy új általános optimalizálási szint, a-Og
került bevezetésre. Ez kielégíti a gyors kódfordítási igényt és egy kiváló hibakeresési élményt biztosít, miközben észszerű futásidejű teljesítményt nyújt. Az általános fejlesztési élmény jobb lehet, mint az alapértelmezett-O0
optimalizálási szint. Fontos megjegyezni, hogy a-Og
nem jelenti a-g
-t, egyszerűen csak letiltja azokat az optimalizációkat, amelyek zavart okozhatnak a hibakeresésben.
Ahogy korábban említettem, a -O2
az ajánlott optimalizálási szint. Ha a szoftvercsomag fordítása sikertelen, és nem a -O2
szintet használja, akkor próbálja újraépíteni azzal az opcióval. Alternatív megoldásként állítsa a CFLAGS és CXXFLAGS értékeket egy alacsonyabb optimalizálási szintre, például -O1
vagy akár -O0 -g2 -ggdb
beállításokra (hiba jelentéséhez és lehetséges problémák ellenőrzéséhez).
-pipe
Egy gyakori jelölőzászló a -pipe
. Ez a jelölőzászló nincs hatással a generált programkódra, de gyorsabbá teszi a kódfordítási folyamatot. Arra utasítja a kódfordítóprogramot, hogy a kódfordítás különböző szakaszai során ideiglenes fájlok helyett csöveket használjon, ami több memóriát igényel. Alacsony memóriakapacitással rendelkező rendszereken előfordulhat, hogy a GCC működése leáll. Ilyen esetekben ne használja ezt a jelölőzászlót.
-ftree-vectorize
A -ftree-vectorize
egy optimalizációs opció (alapértelmezett -O2
és magasabb szinteken), amely megpróbálja vektorizálni az ismétlődéseket, ha lehetséges, a kiválasztott ISA alapján. Korábban azért nem volt alapértelmezett a -O2
szintnél, mert nem mindig javítja a kódot (lassabbá teheti, és általában növeli annak méretét). Ez igazán az ismétlésektől és egyéb tényezőktől függ. A GCC 12 óta alapértelmezettként engedélyezett a -O2
szinten alacsony költségű modellben (-fvect-cost-model=very-cheap
), hogy egyensúlyt teremtsen a kódméret és a sebesség előnyei között.
A költségmodell beállítható a -fvect-cost-model
opcióval. Az alternatív vektorizációs költségmodellek közé tartoznak: cheap
, dynamic
, és unlimited
. A dynamic
modell (alapértelmezett -O3
szinten) becsüli az ismétlődések költségét skalár és vektoralapú utasítások használatával, és eldönti, hogy a vektorizáció nyereséges-e fordítási vagy futásidei ellenőrzésekkel.
A cheap
modell hasonló a dynamic
-hoz, de kissé konzervatívabb. Nem lép érvénybe, ha az adatfüggőségek vagy igazítás futásidejű ellenőrzése meghaladja a paramétereket. Az unlimited
modell feltételezi, hogy a vektorizáció mindig nyereséges, átvált az automatikus vektorizációról az explicit vektorizációra, de rendszerszinten soha nem szabad alkalmazni, mivel ez jelentős kódtúlterhelést okoz.
-fomit-frame-pointer
Ez egy nagyon gyakori jelző, amelyet a generált kód méretének csökkentésére terveztek. Bekapcsolt állapotban van minden -O
szintnél (kivéve a -O0
szint) azon architektúrákon, ahol ez nem zavarja a hibakeresést (mint például x86-64), de szükség lehet az aktiválására. Ilyen esetben adja hozzá a jelölőzászlók közé.
Habár a GCC kézikönyv nem sorolja fel az összes architektúrát, az -O
opcióval ez aktiválható. Azonban x86-32 rendszereken explicit módon szükséges engedélyezni a -fomit-frame-pointer
opciót a GCC 4.6-os verziójáig, vagy bármely GCC verzió esetében, ha -Os
szintet használ. Viszont a -fomit-frame-pointer
használata nehezíti vagy lehetetlenné teszi a hibakeresést.
Fontos megjegyezni, hogy ez az opció nem engedélyezett alapértelmezés szerint Clang használata esetén. Érdemes azt is megjegyezni, hogy a keretmutatók megtartása előnyös lehet egy kódbázis profilozása során, és ilyen esetekben a felhasználóknak érdemes letiltaniuk ezt a funkciót a -fno-omit-frame-pointer
opció segítségével.
Ne kombinálja a
-fomit-frame-pointer
jelölőzászlót a hasonló -momit-leaf-frame-pointer
jelölőzászlóval. Az utóbbi használata nem ajánlott, mivel a -fomit-frame-pointer
már megfelelően elvégzi a feladatot. Ezen túlmenően kimutatták, hogy a -momit-leaf-frame-pointer
negatív hatással van a kód teljesítményére.-fno-semantic-interposition
Ez a jelölőzászló a kódgenerálási minőség javítására és nagyobb teljesítmény biztosítására szolgál (alapértelmezés szerint engedélyezett -Ofast
esetén). Az alapértelmezett viselkedés (-fsemantic-interposition
) az ELF szabványt követi, amely lehetővé teszi a szimbólumok interpozícióját a dinamikus linker által. Habár bizonyos esetekben ez hasznosnak tűnhet, megakadályozza, hogy a kódfordítóprogram kiterjedt kódelemzéseket és optimalizációkat végezzen (különösen a fordító nem próbál meg inline-olni, hacsak a függvények nem lettek kifejezetten inline-nak nyilvánítva).
A közhiedelemmel ellentétben ez a jelölőzászló globálisan engedélyezhető anélkül, hogy problémát okozna (kivéve, ha a szimbólumok interpozíciója szükséges, például különböző memóriakezelők használatakor rendszergazda könyvtárakkal), de azért nincs alapértelmezés szerint engedélyezve, hogy megfeleljen az ELF szabványnak. Ezzel szemben ez a jelölőzászló alapértelmezett részét képezi, ha Clang nyelvet használ.
-msse, -msse2, -msse3, -mmmx, -m3dnow
A GCC x86 és x86-64-specifikus jelölőzászlók listája összekapcsolja ezeket az utasításkészleteket a megfelelő
cpu-type
-jukkal.Az x86 és x86-64 architektúrák tartalmazhatják a Streaming SIMD Extensions (SSE), SSE2, SSE3, MMX és 3DNow! utasításkészleteket. Ezek elsősorban multimédiás, játék- és egyéb lebegőpontos számítási feladatokban hasznosak, bár számos egyéb matematikai fejlesztést is tartalmaznak. Ezek az utasításkészletek a modernebb processzorokban találhatók meg.
Ellenőrzi, hogy a processzor támogatja-e ezeket az utasításkészleteket, ha futtatja a következő parancsot: cat /proc/cpuinfo. A kimenet tartalmazza az összes támogatott további utasításkészletet. Fontos megjegyezni, hogy a pni csupán az SSE3 másik neve.
Általában ezeknek a jelölőzászlóknak nincs szükségük arra, hogy hozzáadjuk őket a /etc/portage/make.conf fájlhoz, amíg a rendszer a megfelelő -march
jelölést használja (például a -march=nocona
jelenti a -msse3
szintet). Néhány figyelemre méltó kivételt képeznek az újabb VIA és AMD64 processzorok, amelyek olyan utasításokat támogatnak, amelyeket a -march
nem tartalmaz (például SSE3). Az ilyen processzorok esetében, a szükséges további jelölőzászlókat engedélyezni kell, miután a /proc/cpuinfo segítségével ellenőriztük őket.
Graphite
A Graphite a hurok költségeket elemzi a graphite
GCC használatával, amikor a COMMON_FLAGS
beállítása tartalmazza a következő opciókat: -floop-block -fgraphite-identity -floop-parallelize-all
. További információért tekintse meg az Optimalizációs Opciók szakaszát.
Az Open Multi-Processing (OMP) lehetővé teszi utasítások generálását több szál és regiszter között a -fopenmp
opcióval. Ez csökkentheti a programok futási idejét, de növelheti a fordítás sikertelenségének valószínűségét. Amikor ugyanazt a programot legalább még egyszer le kell fordítani, akkor érdemes olyan opciókat használni, mint -fno-openmp
vagy -fopenmp-simd
. További információért tekintse meg a GCC Option Summary részét.
Keményítési optimalizációk
Bár lehetséges egy hardened profile használata, ez nem feltétlenül szükséges ahhoz, hogy néhány hardening zászlót hozzáadjunk a /etc/portage/make.conf fájlhoz egy másik profilban. Különösen egy asztali operációs rendszeren a pozíciófüggetlen kód (PIC) és a pozíciófüggetlen végrehajtható fájlok (PIE) rendszer szintű használata fordítási hibákat okozhat.
Ajánlott elolvasni a Szükséges-e bármilyen jelölőzászlót hozzáadni az LDFLAGS/CFLAGS-hoz a hardened buildelés bekapcsolásához? szakaszt a Hardened/FAQ részen belül az alapvető hardened CFLAGS/CXXFLAGS megszerzése érdekében.
A CFLAGS/CXXFLAGS módosítása problémákat okozhat, és egyes esetekben akár a rendszer használhatatlanná válását is eredményezheti. A teljes rendszer újraépítése a emerge -e @world paranccsal megoldhatja a helyzetet.
Egy egyébként nem hardened rendszer, például egy asztali profil használatakor történő hardening a GCC optimalizációjának is tekinthető, különösen az olyan biztonsági sebezhetőségek fényében, mint a Meltdown és a Spectre.
Néhány szoftvercsomag rendelkezik egyéni hardened
USE jelölőzászlókkal, amely lehetővé teszi a tesztelt biztonsági fejlesztések (például CFLAGS/CXXFLAGS) alkalmazását. Érdemes lehet ezt rendszerszinten beállítani a /etc/portage/make.conf fájlban.
A CFLAGS/CXXFLAGS optimalizálása túlcsordulás elleni védelem érdekében jó ötlet lehet, ha a biztonsági szempontok felülmúlják a sebesség optimalizálását. Ez például egy napi használatra szánt asztali rendszer esetében előfordulhat, míg például egy optimalizált játék PC esetében kontraproduktívnek tekinthető.
Egy másik intézkedés az Address Space Layout Randomization (ASLR), amely növelheti a biztonságot azáltal, hogy véletlenszerűen helyezi el az egyes funkciókat és puffereket a memóriában. Ez megnehezíti a támadási vektorok sikerét.
A PIE alapértelmezetten engedélyezve van, amikor biztonságosan alkalmazható a 17.0-s profilokban és az újabb verziókban[3]. A PIC is alapértelmezetten engedélyezve lehet azon architektúrák esetében, amelyeknél ez szükséges (mint például az AMD64). Nincs szükség arra, hogy manuálisan állítsa be a PIE-t vagy a PIC-t a CFLAGS-ban.
Sok ilyen jelölőzászlót most már a GCC toolchain belsőleg automatikusan alkalmaz a hardened profil alatt, és néhányat még a normál profil alatt is. Tekintse meg a táblázatot itt: Hardened/Toolchain.
Az alábbi táblázat a jelölőzászlók dokumentálására szolgál, nem pedig használati listaként, mivel az alapértelmezéseket máshol kezelik a Gentoo operációs rendszerben, és ezek rendszerszintű megadása esetleg nem működik megfelelően.
CFLAGS/CXXFLAGS | LDFLAGS | Funkció |
---|---|---|
-D_FORTIFY_SOURCE=2 (vagy -D_FORTIFY_SOURCE=3 )
|
Futásidejű túlcsordulás-észlelés. | |
-D_GLIBCXX_ASSERTIONS
|
Futásidejű határellenőrzés C++ karakterláncokhoz és tárolókhoz. | |
-fstack-protector-strong
|
Veremtúlcsordulás elleni védelem. | |
-fstack-clash-protection
|
Növelt megbízhatóságú veremtúlcsordulás-észlelés. | |
-fcf-protection
|
Vezérlési folyamat integritásvédelme. | |
-Wl,-z,now
|
Késleltetett kötés letiltása. | |
-Wl,-z,relro
|
Kizárólag olvasható szegmensek áthelyezés után. | |
-fpie
|
-Wl,-pie
|
Teljes ASLR végrehajtható fájlokhoz. |
-fpic -shared
|
Nincs szöveges áthelyezés a megosztott könyvtárakhoz. |
Optimalizációval kapcsolatos GYIK (Gyakran Ismételt Kérdések) leírások
GCC magasabb verziója jobb optimalizációkat kellene, hogy jelentsen?
Nem mindig, a szoftver visszalépés miatt, amikor a GCC korábbi verziójával elért optimalizálás már nem optimalizál. A visszalépések teljes listája megtalálható ezen a linken. Ha ez bekövetkezik, akkor kérjük, hogy jelentsen egy hibát a Gentoo bugzilla weboldalon és/vagy a GCC bugzilla weboldalon.
Létezik tökéletes optimalizáló/CFLAGS?
Nem, mert az megoldaná a megállási probléma kérdését, amely során megállapítható lenne, hogy egy program megáll-e vagy örökké fut [4]. Ez azt jelenti, hogy nincs tökéletes CFLAGS minden szoftvercsomaghoz. Még akkor is, ha ilyen CFLAGS létezne, a szoftvercsomagok idővel változnak.
Mi a helyzet magával a GCC optimalizálásával?
A gcc rendelkezik a pgo
és lto
USE jelölőzászlókkal, amelyek lehetővé teszik a Profilvezérelt Optimalizációt és a Linkelési Idő Optimalizációt. Ahhoz, hogy magát a gcc szoftvert építsük PGO-val és LTO-val:
/etc/portage/package.use/gcc
sys-devel/gcc pgo lto
A Gentoo operációs rendszerben a gcc háromlépcsős bootstrap folyamata zajlik, ami azt jelenti, hogy háromszor fordítja önmagát [5]. Az első szakaszban (stage1) a gcc egy régebbi gcc segítségével kerül fordításra. A második szakaszban (stage2) a gcc az első szakaszban (stage1) létrejött gcc segítségével kerül fordításra. A harmadik szakaszban (stage3) a gcc a második szakaszban (stage2) létrejött gcc segítségével kerül fordításra, és ezzel ellenőrizhető, hogy a második (stage2) és harmadik szakaszban (stage3) létrejött gcc ugyanaz-e. Ezt azért teszik, mert így alaposabb tesztelés történik, és jobb teljesítményt érnek el. Az lto
USE jelölőzászló hozzáadja a -flto jelölőzászlót a BOOT_CFLAGS paraméterekhez. A pgo
USE jelölőzászló hozzáadja a -fprofile-generate
jelölőzászlót a második szakaszban (stage2) lévő gcc szoftverhez, valamint a -fprofile-use -fprofile-reproducible=parallel-runs
jelölőzászlót a negyedik szakaszban (stage4) lévő gcc szoftverhez.
A gcc teljesítménye javulhat PGO használatával, bár ez akár meg is duplázhatja a kódfordítási időt.
De jobb teljesítményt érek el a -funroll-loops -fomg-optimize opciókkal!
Nem, az emberek csak azt hiszik, hogy így van, mert valaki meggyőzte őket arról, hogy minél több jelölőzászló az jó. Az agresszív jelölőzászlók rendszerszintű használata csak árt az alkalmazásoknak. Még a GCC kézikönyve is azt mondja, hogy a -funroll-loops
és a -funroll-all-loops
használata nagyobb kódot eredményezhet, és lassabb lehet. Ennek ellenére valamilyen okból ezek a jelölőzászlók, valamint a -ffast-math
, -fforce-mem
, -fforce-addr
és hasonló jelölőzászlók továbbra is nagyon népszerűek azok között, akik a legnagyobb dicsekvési jogot akarják megszerezni. Ha feltételezzük, hogy ezek a jelölőzászlók valóban előnyösek egyetlen alkalmazásra nézve, akkor az egész rendszerre történő általánosításuk nem bölcs dolog.
A lényeg az, hogy ezek veszélyesen agresszív jelölőzászlók. Nézzen körül alaposan a Gentoo Fórumokon és Bugzilla oldalán, hogy lássa, mit okoznak ezek a jelölőzászlók: Semmi jót!
Ezek a jelölőzászlók nem szükségesek globálisan a CFLAGS vagy CXXFLAGS paraméterekben. Kizárólag rontják a teljesítményt. Lehetséges, hogy azt a benyomást keltik, mintha egy csúcsteljesítményű, a legújabb technológiákat alkalmazó rendszert futtatnánk, de valójában semmi mást nem tesznek, mint hogy felduzzasztják a kódot és olyan hibákat eredményeznek, amelyeket INVALID vagy WONTFIX jelöléssel látnak el.
Az ilyen veszélyes jelölőzászlókra nincs szükség. Ne használja őket. Maradjon az alapoknál: -march
, -O
, és -pipe
.
M a helyzet a háromnál magasabb -O szintekkel?
Egyes felhasználók még jobb teljesítménnyel dicsekednek, amelyet -O4
, -O9
és hasonló jelölőzászlók használatával érnek el, de a valóság az, hogy a háromnál magasabb -O
szinteknek nincs hatásuk. A kódfordító elfogadhat olyan CFLAGS paramétereket, mint például -O4
, de valójában nem csinál velük semmit. Kizárólag a -O3
optimalizációkat hajtja végre, semmi többet.
Szüksége van bizonyítékra? Vizsgálja meg a forráskódot:
case OPT_LEVELS_3_PLUS:
enabled = (level >= 3);
break;
case OPT_LEVELS_3_PLUS_AND_SIZE:
enabled = (level >= 3 || size);
break;
Ahogy látható, minden háromnál magasabb értéket egyszerűen -O3
értékként kezel a rendszer.
Mi a helyzet a célgépen kívüli fordítással?
Egyes olvasók talán azon tűnődnek, hogy ha a kódfordítás nem a célgépen történik, hanem egy kifejezetten gyengébb processzorral vagy GCC alarchitektúrával, akkor az gyengébb optimalizálási eredményeket eredményez-e (egy natív fordításhoz képest). A válasz egyszerű: Nem. Függetlenül attól, hogy a kódfordítás melyik hardveren történik, és hogy a GCC mely CHOST számára készült, amennyiben ugyanazokat az argumentumokat használják (kivéve a -march=native
-t) és ugyanazt a GCC verziót használják (bár kisebb verziókülönbségek lehetnek), az eredményül kapott optimalizálások szigorúan ugyanazok maradnak.
Példaként, ha a Gentoo telepítve van egy olyan számítógépre, amelynek GCC CHOST paramétere i686-pc-linux-gnu, és egy Distcc szerver van beállítva egy másik számítógépen, amelynek GCC CHOST paramétere i486-linux-gnu, akkor nem kell attól tartani, hogy az eredmények kevésbé optimálisak lennének a távoli fordító és/vagy hardver szigorúan alacsonyabb al architektúrája miatt. Az eredmény ugyanolyan optimalizált lesz, mint egy natív fordítás, amennyiben ugyanazokat az opciókat adják meg mindkét kódfordítónak (és a -march
paraméter nem kapja meg a native
argumentumot). Ebben a konkrét esetben a célarchitektúrát kifejezetten meg kell adni, ahogyan azt a Distcc leírásában ki lett fejtve.
Az egyetlen különbség a két különböző al architektúrára célzott GCC verzió viselkedése között az implicit alapértelmezett argumentum a -march
paraméterhez, amelyet a GCC CHOST értékéből származtatnak, ha az nincs kifejezetten megadva a parancssorban.
Mi a helyzet a redundáns jelölőzászlókkal?
Gyakran előfordul, hogy a különböző -O
szinteken bekapcsolt CFLAGS és CXXFLAGS redundánsan vannak megadva a /etc/portage/make.conf fájlban. Néha ez tudatlanságból történik, de olykor azért, hogy elkerüljék a jelölőzászló szűrést vagy a jelölőzászlók lecserélését.
A jelölőzászlók szűrése/cseréje a Portage fa számos ebuild-jében megtörténik. Ez általában azért történik, mert bizonyos -O
szinteken a szoftvercsomagok nem fordíthatók le, vagy amikor a forráskód túlságosan érzékeny ahhoz, hogy bármilyen további jelölőzászlót használjanak. Az ebuild vagy kiszűr néhányat vagy az összes CFLAGS és CXXFLAGS jelölőzászlót, vagy lecserélheti a -O
szintet egy másikra.
A Gentoo Fejlesztői Kézikönyv ismerteti, hogy hol és hogyan működik a jelölőzászlók szűrése/cseréje.
Lehetséges megkerülni a -O
szűrést, ha redundánsan felsoroljuk az egy szinthez tartozó jelölőzászlókat, például -O3
, oly módon, hogy:
CFLAGS="-O3 -finline-functions -funswitch-loops"
Azonban ez nem okos megoldás. A CFLAGS szűrése nem véletlen történik! Ha jelölőzászlókat szűrnek, akkor az azt jelenti, hogy nem biztonságos azokkal a jelölőzászlókkal a szoftvercsomagot létrehozni. Egyértelmű, hogy nem biztonságos az egész rendszert -O3
szinten fordítani, ha az adott szint által bekapcsolt jelölőzászlók problémákat okoznak bizonyos szoftvercsomagokkal. Ezért ne próbálja "kijátszani" azokat a fejlesztőket, akik ezeket a szoftvercsomagokat karbantartják. Bízzon a fejlesztőkben. A jelölőzászlók szűrése és cseréje a rendszer és az alkalmazások stabilitásának biztosítása érdekében történik! Ha egy ebuild alternatív jelölőzászlókat határoz meg, akkor ne próbálja meg kijátszani azt.
A nem elfogadható jelölőzászlókkal történő szoftvercsomag létrehozás nagy valószínűséggel problémákhoz vezet. Amikor a problémákat a Bugzillán jelentik, a /etc/portage/make.conf fájlban használt jelölőzászlók jól láthatóak lesznek, és a fejlesztők arra kérik majd, hogy fordítsa újra ezeket a jelölőzászlók nélkül. Kerülje el az újrafordítás kellemetlenségét azáltal, hogy eleve nem használ redundáns jelölőzászlókat! Ne feltételezze automatikusan, hogy többet tud, mint a fejlesztők.
Mi a helyzet az LDFLAGS paraméterrel?
A Gentoo fejlesztői már beállították az alapvető, biztonságos LDFLAGS értékeket az alap profilokban, így azokat nem szükséges módosítani.
Használhatom-e a szoftvercsomagonkénti jelölőzászlókat?
A szoftvercsomag-specifikus jelölőzászlók használata bonyolítja a hibakeresést és támogatást. Ügyeljen arra, hogy megemlíti ennek a funkciónak a használatát a hibajelentésekben. Továbbá ügyeljen arra, hogy megemlíti az ezzel kapcsolatos módosításokat.
Részletes információ a szoftvercsomag-specifikus környezeti változók használatáról (beleértve a CFLAGS-t is) megtalálható a Gentoo Kézikönyv, "Szoftvercsomag-specifikus környezeti változók" fejezetében.
Profile Guided Optimization (PGO)
A Profilvezérelt Optimalizálás (PGO) lényege, hogy egy programot lefordítanak és profiloznak annak érdekében, hogy azonosítsák a leggyakrabban használt kódútvonalakat. Ez az elemzés alapján történnek az optimalizálások. Konkrétan a kódot -fprofile-generate
opcióval fordítják, amely hangolja a kódot. Ezt követően a kódot futtatják alkalmazásokkal, hogy begyűjtsék a profilinformációkat. Végül a profiladatokat felhasználva a kódot újra lefordítják -fprofile-use
opcióval. Ha manuálisan szeretne PGO-t engedélyezni szoftvercsomagokhoz, akkor tekintse meg ezt a linket.
A Firefox is támogatja a PGO-t, bár néha ez megszakíthatja a buildet.
Link Time Optimization (LTO)
Az LTO jelentősen megnöveli a kódfordítási időt, és ha akár csak egy objektumfájlt is megváltoztatnak a kódfordítás során, akkor az LTO újrafordítja az egész kódot. Folyamatban van a GCC fejlesztése az inkrementális LTO érdekében, de ez nem túl releváns a tiszta build-ek számára, amelyeket az ebuild-ek végeznek a Portage szoftvercsomag kezelőben.
A szoftvercsomagok még mindig átportolás alatt állnak az LTO támogatásához. Az LTO-t le kellhet tiltani a hibák jelentése előtt, mivel ez gyakori problémaforrás. Az -flto
jelölőzászlót használják, opcionálisan egy auto
argumentummal (ami érzékeli, hogy hány feladatot kell használni) vagy egy egész szám argumentummal (ami egy párhuzamosan végrehajtandó feladatok számát jelöli).
Az LTO cikk további információkat ad az LTO-ról a Gentoo operációs rendszeren.
További olvasnivaló a témában
- Configuring compile options (AMD64 Handbook)
- CPU_FLAGS_* — egy USE_EXPAND változó, amely az utasításkészleteket és egyéb CPU-specifikus jellemzőket tartalmazza.
- Safe CFLAGS — összefoglalja a Gentoo Linux CFLAGS "biztonságos" beállításait.
- RUSTFLAGS
Külső források
Az alábbi források némi segítséget nyújtanak az optimalizáció további megértéséhez:
Hivatkozások
- ↑ GNU GCC Bugzilla, AVX/AVX2 no ymm registers used in a trivial reduction. Lekérve: 2017/07/18.
- ↑ GNU GCC Bugzilla, 'gcc -marc=native' sets L2 cache size equal to L3 cache size on i7 and i5 CPU. Retrieved on 2022/08/14.
- ↑ Új 17.0-s profilok a Gentoo tárolóban
- ↑ https://en.wikipedia.org/wiki/Full-employment_theorem
- ↑ https://gcc.gnu.org/install/build.html
This page is based on a document formerly found on our main website gentoo.org.
The following people contributed to the original document:
They are listed here because wiki history does not allow for any external attribution. If you edit the wiki article, please do not add yourself here; your contributions are recorded on each article's associated history page.