Kód optimalizálás

Definíció és tulajdonságok

a kód optimalizálása A Kódmódosítás bármely módja a kód minőségének és hatékonyságának javítása érdekében. A program optimalizálható úgy, hogy kisebb méretűvé váljon, kevesebb memóriát fogyaszt, gyorsabban hajt végre, vagy kevesebb bemeneti/kimeneti műveletet hajt végre.

az optimalizálási módszereknek meg kell felelniük az alapvető követelményeknek, hogy az optimalizált programnak ugyanolyan kimenettel és mellékhatásokkal kell rendelkeznie, mint a nem optimalizált verziónak. Ezt a követelményt azonban figyelmen kívül lehet hagyni abban az esetben, ha az optimalizálás előnye a becslések szerint fontosabb, mint a program viselkedésében bekövetkező változás valószínű következményei.

az optimalizálás típusai és szintjei

az optimalizálást automatikus optimalizálók vagy programozók végezhetik. Az optimalizáló vagy egy speciális szoftver eszköz, vagy egy fordító beépített egysége (az úgynevezett optimalizáló fordító). A Modern processzorok optimalizálhatják a kódutasítások végrehajtási sorrendjét is.

az optimalizálások magas szintű és alacsony szintű optimalizálásokba vannak besorolva. A magas szintű optimalizálást általában a programozó végzi, aki absztrakt entitásokat (funkciókat, eljárásokat, osztályokat stb.) és szem előtt tartja a feladat általános keretét a rendszer tervezésének optimalizálása érdekében. A forráskód elemi szerkezeti blokkjainak szintjén végzett optimalizálások-hurkok, ágak stb. – általában magas szintű optimalizálásnak is nevezik, míg egyes szerzők külön (“középső”) szintre sorolják őket (N. Wirth?). Az alacsony szintű optimalizálást abban a szakaszban hajtják végre, amikor a forráskódot gépi utasításokká fordítják, és általában ebben a szakaszban alkalmazzák az automatizált optimalizálást. Az összeszerelő programozók azonban úgy vélik, hogy egyetlen gép sem képes erre jobban, bármilyen Tökéletes is, mint egy képzett programozó (mégis mindenki egyetért abban, hogy egy szegény programozó sokkal rosszabb lesz, mint egy számítógép).

mit kell optimalizálni

a kézi kódoptimalizálással egy másik problémával szembesülünk: nem csak azt kell tudni, hogy pontosan hogyan kell optimalizálni, hanem azt is, hogy a program melyik részét kell optimalizálni. Különböző okok miatt (lassú bemeneti műveletek, az emberi operátor és a számítógép működési sebességének különbsége stb.) a program végrehajtási idejének 90% – át a kód mindössze 10% – ának végrehajtására fordítják (ez az állítás meglehetősen spekulatív, a Pareto-elv meglehetősen kétséges alap, de A. Tanenbaum meggyőzően hangzik). Mivel az optimalizálás további időt vesz igénybe a program fejlesztésére fordított időtől eltekintve, jobb, ha a kód ezen időkritikus 10%-ának optimalizálására koncentrál, ahelyett, hogy megpróbálná optimalizálni az egész programot. Ezeket a kódrészleteket szűk keresztmetszeteknek nevezik, és speciális segédprogramokkal – profilozókkal – észlelhetők, amelyek mérni tudják a program különböző részeinek végrehajtási idejét.

a gyakorlatban azonban az optimalizálás általában a “kaotikus” programozás fázisa után történik (beleértve az olyan módszereket, mint a “Copy-Paste”, “később meglátjuk”, “ez így rendben van”), ezért az optimalizálás mint olyan keveréke, a refaktorálás és a hibajavítások: a “queer” konstrukciók egyszerűsítése, mint a strlen(path.c_str ()), logikai feltételek, mint (a.x != 0 && a.x != 0) stb. A profilozók kevés segítséget nyújtanak az ilyen optimalizálásban. Mindazonáltal ezeket a problémákat statikus elemző eszközökkel észlelheti, azaz szemantikai hibák keresésére tervezett eszközök, a forráskód mély elemzésére támaszkodva. Mint látható, a fent említett példa a furcsa állapot, nem hatékony kód jelenhet eredményeként hibák (mint a misprint példánkban, ahol a. x != 0 && a.y != 0 legyen helyette). Egy erős statikus analizátor észleli az ilyen kódrészleteket, és felhívja a figyelmet rájuk figyelmeztető üzenetek készítésével.

az optimalizálás jó és rossz eredményei

a programozásban szinte mindent a racionalitás szempontjából kell kezelni – az optimalizálás sem kivétel. Meg van győződve arról, hogy egy tapasztalatlan összeszerelő programozó által írt kód 3-5-ször lassabb, mint a fordító (Zubkov) által generált kód. Széles körben ismert Knuth mondata a korai alacsony szintű optimalizálásokról (például az operátorok vagy változók megtakarításának kísérleteiről): “a korai optimalizálás minden gonosz gyökere”.

a legtöbb programozó nem panaszkodik az optimalizáló által végrehajtott optimalizálásokra, amelyek közül néhány hagyományos és kötelező. Ilyen például a farokhívás optimalizálása funkcionális nyelvekben (a farokhívás a rekurzió speciális esete, amely hurokként ábrázolható).

azonban meg kell érteni, hogy a gépi kód szintjén végzett többszörös komplex optimalizálás a fordítás nagy lelassulását okozhatja. Az előny, amelyet lehetővé tesznek, túlságosan jelentéktelen lehet, összehasonlítva az Általános rendszertervezési optimalizálásokkal (Wirth). Azt is szem előtt kell tartani, hogy a modern nyelvek, minden szintaktikai és szemantikai “sallangjaikkal”, sok árnyalattal és finomsággal rendelkeznek, így egy programozó, aki nem ismeri őket, meglepődhet az optimalizálás eredményén.

vegyük például a C++ – t és az úgynevezett visszatérési érték optimalizálást, amikor a fordító elkerüli a függvény által visszaadott ideiglenes objektum másolását. Mivel a fordító kihagyja a másolást, ezt a módszert “Copy elision” – nek is nevezik. Tehát a következő kód:

#include <iostream> struct C { C() {} C(const C&) { std::cout << "A copy was made.\n"; }}; C f() { return C();} int main() { std::cout << "Hello World!\n"; C obj = f();}

több kimenettel is rendelkezhet:

Hello World!A copy was made.A copy was made.Hello World!A copy was made.Hello World!

bármilyen furcsának is tűnik, mindhárom változat érvényes, mert a nyelvi szabvány ilyen esetekben lehetővé teszi a másoló konstruktor hívásainak elhagyását, még akkor is, ha a konstruktornak mellékhatásai vannak (62.8 másolási osztály objektumok, 15.bekezdés).

következtetés

ezért mindig fontolóra kell vennünk a programkód optimalizálását speciális segédprogramok segítségével, ahol csak lehetséges, de ezt nagy gonddal kell megtenni, és készen kell állnunk arra, hogy időnként váratlan trükkök történjenek a fordítótól.

PVS-Studio

egy sor diagnosztika végre a statikus elemző PVS-Studio, amely lehetővé teszi, hogy megtalálja azokat a helyzeteket, ahol kódot lehet optimalizálni. A PVS-Studio azonban, mint bármely más statikus elemző, nem szolgálhat a profilozó eszközök helyettesítésére. Csak a dinamikus programelemzők képesek azonosítani a szűk keresztmetszeteket. A statikus analizátorok nem tudják, hogy milyen bemeneti adatokat kapnak a programok, és milyen gyakran hajtanak végre egy adott kóddarabot. Ezért mondjuk, hogy az elemző javasolja a kód néhány “mikrooptimalizálásának” végrehajtását, amelyek nem garantálják a teljesítménynövekedést.

a figyelembe vett hátrány ellenére a PVS-Studio analyzer jó kiegészítője a profilozó eszközöknek. Sőt, amikor a PVS-Studio figyelmeztetésekkel foglalkozik, az optimalizálással kapcsolatban a kód gyakran egyszerűbbé és rövidebbé válik. Ezt a hatást részletesebben a “Mikrooptimizációk feltárása Tizen-kód felhasználásával” című cikk tárgyalja.

Vélemény, hozzászólás?

Az e-mail-címet nem tesszük közzé.