Mindent a Profiling-ról I.
Tegnap éjjel volt egy olyan élményem, ami keményen visszarepített kb. 2005-be, amikor még semmit sem tudtam erről az egész menedzser-dologról, hanem a kódolás volt a mindenem. (Más kérdés, hogy azóta is az maradt, de hát az ember tervez.. Na mindegy!
) Szóval anno, mikor 2005 környékén keményen dolgoztam a diplomamunkámon, etc. kedvenc témám volt a profiling, azóta szinte viszont nem foglalkoztam vele szinte egyáltalán. A válasz egyszerű: mert nem ilyesmivel dolgozom. Tudom, hogy hülyén hangzik, de bátran kijelenthetem, hogy nagyon sokszor nem üzleti érdek a performance, még az IT világban sem. Lehet WTF-elni, de így van! A dolog rém egyszerű:
– Működik? – kérdezi a megrendelő
– Igen, bár még… – kezdi a fejlesztő
– Akkor mikor kapom meg?!
– De még…
– Kész vagy nincs kész?
– … (Vigyed!)
Ugye sok embernek ismerős?
Más kérdés, hogy utólag persze megy a sírás, hogy lassú a rendszer, de akkor, miután nem akarja a nulláról telepíteni az egészet, jön az, hogy atomerőművet vesz alá, patch-eket követel, új verziót rendel, stb. A fejlesztő pedig örömmel leszállítja a jó öreg munka = bevétel = pénz = boldogság képlet miatt. (Mert márpedig igen, a pénz indirekt módon, de boldogít!)
Nos, ez az IT világ bizonyos területein működik, más területeken meg nem… Ezt a legegyszerűbben akkor lehet észrevenni, mikor a telekommunikációban, webfejlesztésben vagy egyéb, erősen megrendelői igények gyors (és nem maximalista) kielégítése köré orientált területen dolgozó egyszeri fejlesztő meglátja a 64k demót és egy rövid “Eztmeghogyarákba?!” felkiáltással reagálja le.
Mikor pedig valaki azt mondja, hogy profiler, debugger, runtime packer, optimizáció, akkor a fejét vakarja. Na várjunk… igen, talán az utóbbit hallotta. Az egyetemen volt valami a stringek összehasonlításával kapcsolatban, meg “a zordó-logenn” nevű misztikus cuccról is hallott. Vagy nem. Régen aki ezek nélkül élt, az nem volt programozó. Persze nem ő az, aki tehet róla. Ahogy írtam is: vannak az IT világban olyan területek, ahol az ilyesmi voodoo mágiának számít – sajnos. Ha értett is hozzá régen, hát közben már elfelejtette.
Tehát visszakanyarodva a bevezetőm elejéhez – tegnap éjszaka céges kódot profile-oztam, úri passzióból és eszembe jutott, hogy ez mennyire nem dívik újabban. A megrendelőnek minden azonnal kell, akkor is, ha félkész vacak. Ha akarná is az ember az ilyet, nem hagyják neki. Nincs idő rá! Menjen ki az a release! Na, itt döntöttem úgy, hogy azért is erről fogok cikket írni. Legyen ez az én tiltakozásom fejlesztőknek a corporate bullshit-be és a megrendelők követelődzésébe történő belefolytása ellen!
Mi az a profiling?
Meg sem próbálom kitalálni, miért így nevezték el ezt a hibakeresési technikát, biztos történelmi oka van. A lényeg, hogy ez egy olyan, opcionális lépése a fejlesztésnek, amely alapvetően nehezen felderíthető, performancia-hibák felderítésére szolgál. A profiling valahogy így illeszkedik a fejlesztési folyamatba:
- Implementáció – a kód megírása
- Fordítás és szintaxis-elemzés – a szintaxisbeli hibák megtalálása (tipikusan: pontosvessző-hiba, stb.)
- Statikus kódelemzés – egyszerűbb szemantikai hibák megtalálása (tipikusan: nem inicializált változók, létrehozott, de sosem használt változók, antipattern-ek, stb.)
- Unit-tesztelés – funkcionális tesztelés a bonyolultabb szemantikai hibák felderítésére (tipikusan: itt jövünk rá, hogy az algoritmus nem jó, a ciklus 0 helyett 1-től számol, stb.)
- Profiling – Na ez egy automatizált tesztelés, melynek célja performancia-veszteséggel járó szemantikai hibák megtalálása (tipikusan: miért ilyen lassú a render?!
) - Fix – guess what?
Az előző négy lépés valamelyikében feltárt hiba javítása!
Na most, nem kell Nobel-díjasnak lenni, hogy az ember tudja: a fejlesztés márpedig iteratív folyamat. Olyat még az életben nem látott senki, hogy valaki valamit megírt és az elsőre szintaktikailag, szemantikailag és minden egyéb értelemben tökéletes volt. Ha az ember igazán alapos, akkor egy esetleges fix után újra végignyomja az előtte már sikeresen letudott lépéseket. (Hiszen a fix is hozhat be bugot!)
A profiling alapvetőleg egy tág fogalom – több fajtája van, olyan is, amit jómagam sem használtam még az életben sem!
Amire a legtöbb fejlesztő a profiling említésekor gondol, az az ún “CPU profiling“, aminek az alapfeladata az úgynevezett hotspotok megtalálása, analízise és szükség esetén kiiktatása. Meglepő módon, az ezt végző tool neve a (CPU) profiler.
Nos, mi is az a hotspot? A kód olyan része, ahol a program/algoritmus/whatever a futásidő (vélhetően indokolatlanul) nagy részét eltölti. Csak egy példa: tegyük fel, hogy van egy programunk, amelyik konfigurációs fileból olvas be valamit, ami a működéséhez kell. Tegyük fel, hogy a profiling eredményeképp felfedezzük, hogy a futásidő 30%-át a program a beszédes nevű readConfigurationFile() függvényben tölti, ami mondjuk a tetejébe a 10 perces futás alatt 500 alkalommal lett felhívva. Nos, ilyenkor felmerül a kérdés: Miért? Vajon újra és újra felolvassa a file-t? (Láthatólag igen!) Tényleg szükséges ez? Vagy csak véletlen? Tegyük fel, hogy ez a program terveink szerint csak egyszer kellene, hogy felolvassa ezt a config file-t, majd egy gyors futással befejezné a működését. Miután viszont a file-felolvasás újra és újra megtörténik, a program futásideje megnő, vagyis “lassú lesz”. Miután egy hotspotról kiderül, hogy ilyen tipikusan értelmetlen, szuboptimális része a programnak, onnantól már nem hotspot, hanem bottleneck névre hallgat (hiszen belassítja a futást, mint az ital kiöntését az üveg nyaka!
) és alapvetőleg negatívumnak tekintendő.
A CPU profiling tehát alapvetőleg nem más, mint bottleneck vadászat. Ez a cikk erre koncentrál főleg. (Egy másik fontos profiling módszer a memory profiling, amelyik bottleneck-ek helyett memorí leak-ekről szól, vagyis olyan memóriaterületekről, amelyeket a program feleslegesen foglal le, vagy tart lefoglalva annak ellenére, hogy nincs szüksége rájuk).
Hogy azért ne legyen ennyire triviális a dolog, hangsúlyozni kell, hogy nem minden hotspot automatikusan bottleneck! Egy egyszerű OpenGL-es program meglepő módon tipikusan a render() metódusban fogja tölteni az ideje nagy részét. Ilyen esetben tovább kell bontanunk a dolgot: ok, az idő 80%-át a render() metódusban töltjük. És mivel hány százalékát töltjük a render() metódusban töltött időnek? Egy jó profiler tool erre bőven ad lehetőséget, megjelenítve számunkra az ún. call hierarchy-t, ami nem más, mint egy fastruktúra, mely azt mutatja, hogy melyik metódus melyik metódust hívta (és mennyi idő telt el a meghívás és a visszatérés között!).
Itt ismét bejön két fogalom a képbe…
Az inclusive time – vagyis az az idő, amennyit egy adott metódusban a program eltöltött, beleértve minden olyan metódusban eltöltött időt, amelyet ebből a metódusból hívtunk.
Az exclusive time – értelemszerűen az előbbi ellentéte, szigorúan a metódusban eltöltött idő.
Ez utóbbit szokták “self time”-nak is hívni. A kettő elkülönítése egyébként nem teljesen egzakt dolog, mert tipikusan attól függ, hogy az adott nyelvben mi számít atomi, beépített műveletnek. Gondoljunk pl. a standard output-ra. Van nyelv, ahol alap dolog, van olyan, ahol egy függvény – vagy akár egy objektum metódusa! Ez utóbbi esetben tipikusan nem számít bele az exclusive time-ba, míg az előbbiben tipikusan igen, pont mint az elepvető vezérlési szerkezetek, az if, else, for, while, stb. Vannak profiler-ek, amik megkülönböztetik a kettőt, vannak amelyek nem – mint mondtam, nem egzakt dolog – de sejthetjük: preferált az olyan tool, amelyik igen.
Hogyan működik?
Egy profiler működése alapvetően egyszerű egy, az azt használó fejlesztő szemszögéből. Ideális esetben semmi egyebet nem kell tennünk, mint futtatni az alkalmazásunkat, majd valamilyen módon megmondani a profilernek, hogy melyik process-t figyelje. Ezután a profiler mintákat gyűjt a futó processről, majd ebből számolja ki a felismert metódusokra az inclusive és exclusive time-ot, a hívások számát, etc. Ezt az adott profiler tool terminológiájától függően általában sampling-nak vagy instrumentation-nek hívják. A végén ideális esetben a kimenet valami ilyesmi (ismét csak alkalmazásfüggő), mi pedig ámulunk…
/folyt. köv./