Megosztás a következőn keresztül:


Optimalizálási ajánlott eljárások

Ez a dokumentum a C++ programok Visual Studióban való optimalizálásának ajánlott eljárásait ismerteti.

A Fordító és a Linker beállításai

Profilvezérelt optimalizálás

A Visual Studio támogatja a profilalapú optimalizálást (PGO). Ez az optimalizálás az alkalmazás egy rendszerezett verziójának betanítási végrehajtásából származó profiladatokat használja az alkalmazás későbbi optimalizálásának hajtóerejéhez. A PGO használata időigényes lehet, ezért előfordulhat, hogy nem minden fejlesztő használ ilyet, de azt javasoljuk, hogy a termék végleges kiadási buildjéhez használja a PGO-t. További információ: Profile-Guided optimalizálás.

Emellett a teljes programoptimalizálás (más néven Link Time Code Generation) és /O1 az /O2 optimalizálás is javult. Általánosságban elmondható, hogy egy ilyen lehetőséggel összeállított alkalmazás gyorsabb lesz, mint ugyanaz az alkalmazás, amely egy korábbi fordítóval van lefordítva.

További információt a (Teljes programoptimalizálás) és a (Méret minimalizálása, Sebesség maximalizálása) című témakörben talál/GL./O1/O2

A használni kívánt optimalizálási szint

Ha egyáltalán lehetséges, a végleges kiadási buildeket profilvezérelt optimalizálással kell összeállítani. Ha a PGO-val nem lehet építeni, akár a rendszerezett buildek futtatásához szükséges infrastruktúra hiánya, akár a forgatókönyvekhez való hozzáférés hiánya miatt, javasoljuk a teljes programoptimalizálással való építést.

A /Gy kapcsoló is nagyon hasznos. Minden függvényhez külön COMDAT-t hoz létre, nagyobb rugalmasságot biztosítva a csatolónak a nem hivatkozott COMDAT-ok eltávolításához és a COMDAT-összecsukáshoz. A használat /Gy egyetlen hátránya, hogy hibakereséskor problémákat okozhat. Ezért általában ajánlott használni. További információ: /Gy (Function-Level csatolás engedélyezése).

A 64 bites környezetekben való csatoláshoz ajánlott a /OPT:REF,ICF linker lehetőséget használni, és 32 bites környezetekben /OPT:REF ajánlott. További információ: /OPT (Optimalizálás).

Emellett kifejezetten ajánlott hibakeresési szimbólumok létrehozása, még optimalizált kiadási buildek esetén is. Ez nem befolyásolja a létrehozott kódot, és sokkal egyszerűbbé teszi az alkalmazás hibakeresését, ha szükséges.

Lebegőpontos kapcsolók

A /Op fordítóbeállítás el lett távolítva, és a következő négy fordítóbeállítással bővült a lebegőpontos optimalizálás:

Lehetőség Leírás
/fp:precise Ez az alapértelmezett javaslat, amelyet a legtöbb esetben érdemes használni.
/fp:fast Ajánlott, ha a teljesítmény rendkívül fontos, például játékokban. Ez a leggyorsabb teljesítményt eredményezi.
/fp:strict Ajánlott, ha pontos lebegőpontos kivételekre és IEEE-viselkedésre van szükség. Ez a leglassabb teljesítményt eredményezi.
/fp:except[-] Használható együtt /fp:strict vagy /fp:precise, de nem /fp:fast.

További információt a (Floating-Point viselkedésének megadása) című témakörben talál/fp.

Optimalizálási declspecs

Ebben a szakaszban két olyan declspecet tekintünk meg, amelyeket a programokban a teljesítmény javítására használhatunk: __declspec(restrict) és __declspec(noalias).

A restrict deklaráció csak olyan függvénydeklarációkra alkalmazható, amelyek mutatót adnak vissza, például __declspec(restrict) void *malloc(size_t size);

A restrict declspec olyan függvényeken használatos, amelyek nem megadott mutatókat adnak vissza. Ez a kulcsszó a C-Runtime Library implementációjához malloc használatos, mivel soha nem ad vissza olyan mutatóértéket, amely már használatban van az aktuális programban (kivéve, ha illegális műveletet végez, például a memória felszabadítása után).

A restrict declspec további információkat nyújt a fordítónak a fordítóoptimalizálások elvégzéséről. A fordítók számára az egyik legnehezebb feladat meghatározni, hogy mely mutatók mutatnak ugyanarra a memóriacímre, és ennek az információnak a használata nagyban segíti a fordítót.

Érdemes kiemelni, hogy ez a fordító ígérete, nem pedig olyasmi, amit a fordító ellenőrizni fog. Ha a program nem megfelelően használja ezt restrict a declspec-et, előfordulhat, hogy a program helytelenül viselkedik.

További információért lásd restrict.

A noalias declspec csak a függvényekre alkalmazható, és azt jelzi, hogy a függvény félig tiszta függvény. A félig tiszta függvény olyan függvény, amely csak a helyi elemekre, argumentumokra és az argumentumok első szintű indirektjeire hivatkozik vagy módosítja azokat. Ez a declspec ígéretet jelent a fordító számára, és ha a függvény globális vagy másodszintű indirekt mutatóargumentumokra hivatkozik, akkor a fordító olyan kódot hozhat létre, amely megszakítja az alkalmazást.

További információért lásd noalias.

Optimalizálási pragmák

A kód optimalizálásához számos hasznos pragma is rendelkezésre áll. Elsőként a következőt fogjuk megvitatni #pragma optimize:

#pragma optimize("{opt-list}", on | off)

Ez a pragma lehetővé teszi egy adott optimalizálási szint függvényenkénti beállítását. Ez ideális azokhoz a ritka esetekhez, amikor az alkalmazás összeomlik, amikor egy adott függvényt optimalizálással állít össze. Ezzel kikapcsolhatja az optimalizálást egyetlen függvény esetében:

#pragma optimize("", off)
int myFunc() {...}
#pragma optimize("", on)

További információért lásd optimize.

Az inlining az egyik legfontosabb optimalizálás, amelyet a fordító végez, és itt néhány olyan pragmáról beszélünk, amelyek segítenek módosítani ezt a viselkedést.

#pragma inline_recursion hasznos annak megadásához, hogy szeretné-e, hogy az alkalmazás képes legyen egy rekurzív hívást inline-olni. Alapértelmezés szerint ki van kapcsolva. A kis függvények sekély rekurziója esetén ezt bekapcsolhatja. További információért lásd inline_recursion.

Egy másik hasznos pragma az inlinelés mélységének korlátozására a #pragma inline_depth. Ez általában olyan helyzetekben hasznos, amikor egy program vagy függvény méretét szeretné korlátozni. További információért lásd inline_depth.

__restrict és __assume

A Visual Studióban néhány olyan kulcsszó található, amelyek segíthetnek a teljesítményben: __restrict és __assume.

Először is meg kell jegyezni, hogy két __restrict__declspec(restrict) különböző dolog. Bár némileg rokonok, szemantikájaik különböznek. __restrict típus-minősítő, például const vagy volatile, de kizárólag mutatótípusokhoz.

A módosított __restrict mutatót __restrict mutatónak nevezzük. A __restrict mutató olyan mutató, amely csak a __restrict mutatón keresztül érhető el. Más szóval egy másik mutató nem használható a __restrict mutató által mutatott adatok eléréséhez.

__restrict a Microsoft C++ optimalizáló hatékony eszköze lehet, de nagy körültekintéssel használja. Helytelen használat esetén az optimalizáló olyan optimalizálásokat hajthat végre, amelyek megszakítják az alkalmazást.

Ezzel __assumea fejlesztő meg tudja mondani a fordítónak, hogy feltételezéseket tegyen bizonyos változók értékéről.

Például __assume(a < 5); azt mondja az optimalizálónak, hogy a kód ezen sorában a változó a kisebb, mint 5. Ez ismét ígéret a fordítónak. Ha a a ebben a programban ezen a ponton valóban 6, akkor a fordító optimalizálása után a program viselkedése lehet, hogy nem az lesz, amit várna. __assume az utasítások és/vagy feltételes kifejezések váltása előtt a legcélrasztosabb.

Bizonyos korlátozások a következőkre __assumevonatkoznak: . Először is, a __restrict csupán egy javaslatként van megadva, így a fordító szabadon figyelmen kívül hagyhatja. __assume Emellett jelenleg csak az állandókkal szembeni változó egyenlőtlenségekkel működik. Nem propagálja a szimbolikus egyenlőtlenségeket, például feltételezi(a < b).

Belső támogatás

Az intrinsics függvényhívások, amelyekben a fordító belső ismeretekkel rendelkezik a hívásról, és ahelyett, hogy függvényt hívna meg egy könyvtárban, a függvény kódját bocsátja ki. Az intrin.h< fejlécfájl >tartalmazza az összes elérhető belső elemet az egyes támogatott hardverplatformokhoz.

Az intrinsics lehetővé teszi a programozó számára, hogy az assembly nyelv használata nélkül mélyebben belemenjen a kódban. Az intrinsics használatának számos előnye van:

  • A kód hordozhatóbb. Az intrinsics számos része több CPU-architektúrán is elérhető.

  • A kód könnyebben olvasható, mivel a kód továbbra is C/C++-ban van megírva.

  • A kód a fordítóoptimalizálás előnyeit élvezi. Ahogy a fordító egyre jobb lesz, az intrinsics kódgenerációja javul.

További információ: Compiler Intrinsics.

Kivételek

A kivételek használata teljesítménycsökkenéssel jár. Bizonyos korlátozások akkor lépnek fel, ha olyan próbablokkokat használ, amelyek gátolják a fordítót bizonyos optimalizálások végrehajtásában. Az x86-platformokon további teljesítménycsökkenés tapasztalható a próbablokkok miatt, mivel a kódfuttatás során létre kell hoznia további állapotinformációkat. A 64 bites platformokon a kipróbálási blokkok nem csökkentik annyira a teljesítményt, de ha kivételt vetnek ki, a kezelő megkeresése és a verem visszatekerése költséges lehet.

Ezért javasolt elkerülni a try/catch blokkok bevezetését olyan kódba, amelynek valóban nincs rá szüksége. Ha kivételeket kell használnia, ha lehetséges, használjon szinkron kivételeket. További információ: Strukturált kivételkezelés (C/C++).

Végül pedig csak kivételes esetekben kivételeket kell kivenni. Az általános vezérlési folyamat kivételeinek használata valószínűleg a teljesítmény romlását eredményezi.

Lásd még