kodtabla
Andras Tantos
andras_tantos at yahoo.com
Wed Mar 23 00:40:35 CET 2005
> Haliho!
Neked is!
>
> >> Az optimalizáció nem is csak fv.en belül optimalizál!!! Épp ez a
> >> lényeg! Az _egész_ forrásfájlban tud. Egy régebbi menürendszer
> >> kezelõ - adatbeviteli stb. programon így nyertem kb. 2 kByteot,
> >> mert a hasonló részeket (amik logikailag mások kicsit, ezért én
> >> külön obj-ba raktam õket) összevonta, miután egy fájlba kerültek.
> >> Ezt a több száz soros C programot (tele pointerrel - itt
> >> visszajön a topicindítás :-) - különbözõ nyelvek kezelésével)
> >> lehetett volna kézzel is optimalizálni, de megelégedtem a
> >> fordítóval.
> >>
> > Ez erdekes, egy sima C fordito a library fuggvenyekhez pl hozza sem
> > nyul. Meghivja egy call-lal, akkor is ha 6 byte hosszu.
>
> Ha ez probléma, akkor ne használj C library-t! Nem pont az a lényeg,
> hogy azért használunk vmit mert könnyebb, gyorsabb, egyszerûbb használni?
Nos, a helyzet a kovetkezo (tudtommal): a legregebbi forditok nem tudtak,
csak egy fv.-en belul optimalizalni. Sot, a meg regebbiek meg ezt se tudtak,
csak u.n. basic block-okon belul tudtak optimalizalni. Ezek durvan olyan
programreszletek, amikben nincs elagazas, es nincs olyan pont se, ahova a
program mashonnan ugrana. Ezeken belul sok mindent lehet csinalni, az alabbi
(EWAVR) listabol ezek azt hiszem mind basic-block-okon mukodnek:
- Common subexpression elimination-t
- Code motion (bizonyos elemei)-t
- Constant folding-ot
- Dead code elimination-t
A ket kovetkezo meg alapvetobb szinten van:
- Register Variables
- Peephole Optimizing
Ezek meg csak nem is a program logikai szerkezeten vegzett muveletek, hanem
vagy a program gepi kodra valo atirasa soran (register variables, ami a
register-allocator mukodesenek egyik mellektermeke) vagy mar magan a gepi
kodu programon vegzett atalakitasok.
Aztan vannak azok a muveletek, amik egy fv-en belul, de a basic-blockok
kozotti kapcsolatok figyelembevetelevel elvegezheto muveletek (ezekhez
tipikusan SSA vagy data-flow grafokat epitenek fel a forditok):
- Code motion (azt amit itt leirnak, mashol strenght-reduction-nak, vagy
hoisting-nak hivjak).
- Clustering of variables (bizonyos esetei)
- Data Overlaying (megintcsak bizonyos esetei, az, amit itt leirnak speciel
nem)
- Global Common Subexpression Elimination
- Loop Rotation
- Common Tail Merging
- Common Block Subroutines
- Case/Switch Optimizing
- Jump Negation-t
Es persze a fentiek maradekat is el lehet vegezni ezen a szinten is, azaz a
Constant folding-ot es a Dead code elimination-t.
A kovetkezo lepcso a teljes forditasi egyseg (ertsd C fajl az osszes
header-evel) vizsgalata. Itt lehet ujabb grafokat (tipikusan call-graph-ot)
epiteni es ezen tovabbi analiziseket vegezni. Ebbe a lepcsobe tartoznak a
kovetkezok:
- Clustering of variables (maradek esetei)
- Data Overlaying (amit itt leirnak)
- Function inlining
- Cross call (masok ezt outlining-nak hivjak, az inlining forditottja)
Es persze megint egy csomo minden elvegezheto ujra ezen a szinten is, pl:
- Common Block Subroutines
A klasszikus esetben ezen a szinten a fordito leteszi a lantot, es kiirja az
OBJ fajlt. A linker ezeket a fajlokat fogja osszerakni egy vegrahajthato
programma. A linker klasszikusan nem sok optimalizalast csinal, tipikusan
csak azt donti el, hogy mely OBJ-ektek kellenek, es melyek nem. Ezzel az a
problema, hogy ha csak egesz OBJ-eketen tud muveleteket vegezni, akkor sok
esetben olyan fuggvenyek is bekerulnek a kesz binary-ba, amiket senki nem
hiv, ezzel novelve a kod meretet. Ezert van az, hogy sok library-ben minden
egyes fuggveny kulon C fajlban van definialva. Igy egy buta linker is jo
munkat tud vegezni, de persze, ha megnezitek a fenti listat kiderul, hogy ez
kilovi a fodito harmadik csoportben felsorolt munkajat.
A megoldas az, hogy a linker fel tudja torni az obj fajokat, es ugynevezett
szegmenseket linkel ossze. Ekkor a fordito feladata, hogy minden egyes
fuggvenyt egy OBJ-ben a sajat kis szebmensebe tegye (es persze ezt meg lehet
tenni minden egyes globalis valtozoval is). Igy a linker mar jobb munkat tud
vegezni, es ami meg fontosabb nem teszi tonkre azt, amit a fordito mar
egyszer kitalalt. Ugyanakkor meg is neheziti a fordito munkajat, mert nem
tud olyan dolgokat kihasznalni, hogy ket (egy C fajlban deklaralt) fuggeny
egymashoz viszonyitott helyezete ismert, vagy hogy pl. ha az egyik benne van
a programban, akkor a masik is.
Korul belul ez az a pont, ahol a legtobb mai fordito all (kiveve egy-ket
PC-s forditot - VC++ es Intel C).
A kovetkezo lepes az, hogy a program teljes egeszet analizaljuk, es
forditasi egysegek (OBJ-ek) kozott is vegzunk optimalizalast. A problema
ezzel csupan az, hogy az osszes OBJ-et csak a linker latja, az meg nem
fordito. A megoldast idonkent 'whole program optimization'-nek, askor
'link-time code generation'-nek hivjak, de a lenyege az, hogy a linker
vissza tudja hivni a forditot valamilyen formaban.
Ha ezt a lepest is belerakjuk a kepbe, akkor a fenti optimalizalasokat, es
meg joparat el lehet vegezni a teljes programon is. A hatranya a megoldasnak
az irdatlan (forditoasi ideju) memoriaigeny es a lassu kodgeneralas.
Ami kimaradt:
Type-based alias analysis: ez minden egyes pontjan fontos a forditonak, egy
baj van vele: a C nem eleg erosen tipusos nyelv ahhoz, hogy ez az analizis
(ez meg nem optimalizacio, csak segitheti az optimalizalast) igazan hasznos
legyen. C++-ban sokkal fontosabb es hasznosabb.
Extended Index Access Optimizing: ez egy tipikusan eszkoz-specifikus
optimalizalas, es valoszinuleg egy basic-block-on belul csinaljak.
Es persze van egy csomo olyan optimalizalas, mi a felsoroasban nincs benne.
Egy kis izelito:
- Loop-unrolling
- Induction-variable merging
- Induction-variable splitting
- Tail-call elimination
- Vectorization
- Stack optimization
- Data alignment
- Stack alignment
- Intrinsic function inlining (memcpy-bol rep movsd es hasonlok)
stb. stb.
Es persze a minden optimalizalasnal ket nehez problema eldontese var a
forditora:
- Szabad-e meglepni a valtoztatast (azaz az eredeti es a modositott kod
ugyanugy mukodik minden *ervenyes* forraskodra)
- Erdemes-e meglepni a valtoztatast (azaz a modositott kod kisebb/gyorsabb-e
mint az eredeti)
>
> > Optimalizalasrol szo sincs. Hasonlo reszek keresese? Errol valami
> > doksit produkalj, de meg akkor sem hiszem el egeszen.
>
> Na, akkor lássuk:
> EWAVR 4.10, Compiler reference, p. 123
... sok szoveg torolve ...
>
> Ez volt az EW AVR, most nézzük a Keil-t 7.5, Optimizing C Compiler and
> Library Reference, p. 63:
... meg tobb szoveg torolve ...
> >>> Szóval teszem azt, nagyon sok hasonló vizsgálat van egy forrásban
> >>> (if (vmi rendkívül bonyolult) {} else {}) na, itt a fordító
> >>> észreveszi, hogy közös - hasonló a feltétel és kiteszi egy
> >>> szubrutinba. Ezt assemblyben k*rvanehéz megcsinálni, mert nem
> >>> veszed éeszre triviálisan a logikai hasonlóságokat. Ezek sokat
> >>> lehet nyerni.
>
> Mi ebben a durva? Menyiben tér el ez a fent idézett optimalizációs
> lehetõségektõl?
Semmi, es ezt raadasul aranylag egyszeru is megcsinalni (legalabbis bizonyos
eseteit). Itt a feltetel egy logikai kifelyezes, aminek a kiiertekelese
(vagy annak egy resze) kivonhato a sokszoros kiiertekeles ele - felteve,
hogy kozben nem ugrasz at ertekadast, ami megvaltoztathatja a kifelyezes
erteket. Teljesen altalanos 'global optimalization' muvelet, a 'hoisting'
kategoriaba esik. Aranylag ritkan szoktak kulon szubrutinba tenni: inkabb az
eredmenyt rakjak el egy atmeneti valtozoba/regiszterbe. A kulon szubrutinba
rakas az 'outlining' kategoria, es a baj vele az, hogy ritkan segit valoban
a programon (felteve, hogy sebessegre optimalizalunk).
Udv,
Tantos Andras
More information about the Elektro
mailing list