• Nem Talált Eredményt

fejezet - Esettanulmány: egy mau program felgyorsítása

In document A mau programozási nyelvVerziószám: (Pldal 186-190)

Szeretett mau programnyelvünk ugyebár lehetőséget nyújt bencsmarkok készítésére, azaz „megkukkolhatjuk”, egy-egy program vagy programrészlet mennyi idő alatt fut le. Ezt összevethetjük azzal, ugyanazon feladatot elvégző más programnyelven megírt programok mennyi ideig futnak.

Nos, az efféle összevetésre jó példa lehet, ha programot írunk arra, hogy ki­

számolja a pí értékét valamilyen pontossággal a Leibniz-formula szerint!

Mindenekelőtt készítsük el e program „legeredetibb”, C nyelvű változatát! A C ugyebár compiler típusú programnyelv, azaz lefordul binárisra, s így majdnem olyan gyors lesz, mintha „gépi kódban” írtuk volna meg azt. Lemérjük így mennyi ideig tart, s ez lesz az „etalon” amihez viszonyítunk majd azontúl! A sebességteszt egy Lenovo ThinkPad T530-as laptopon lett mérve, Core i7 processzorral, 16 giga RAM mellett, 64 bites Linux operációs rendszeren, a GCC 4.8.1-es fordító­

programja lett használva a fordításhoz. (A mau interpreter esetén is).

A C nyelvű program:

#include<stdio.h>

#include<stdlib.h>

#include<time.h>

int main(void) {

6 futtatás után a kijelzett időszükséglet átlaga:

27012

(Ez és minden további időadat e fejezetben ha mást nem írok mellé, milliomod másodpercet jelent).

Ha a fenti programot a -O2 optimalizációs flaggal fordítom, akkor 6 futás átlaga 24925 lesz. Ezt vesszük alapnak, mert a mau interpreter is -O2 -vel van fordítva.

Ez mintegy 8 százalékos javulást jelent e fenti program esetén.

Készítsük el a fenti feladatot ellátó program első változatát mau nyelven:

#!mau

// kiszámoljuk a pit a leibniz formulával.

#t@a; // inicializálunk egy időváltozót

#t@b; // inicializálunk egy másik időváltozót

#g@x=(#t@b)-(#t@a);

"Idő: " ?g @x; /;

#d@p = 4*#d@p;

"Pi/4 közelítés: " ?d @p; /;

A futási idők átlaga: 1002710. Az arány az etalonhoz képest:

1002710/24925 = 40.2291

Azaz, a mau program 40-szer lassabb. Hm... Fel kéne gyorsítani! Az első ötletünk az, hogy minek a 3 milliószor lefutó ciklus belsejébe minden sor után pontos­

vessző?! Nyilván az is idő amíg azt a plusz karaktert feldolgozza a program... Ki vele! Azokról a pontosvesszőkről beszélek, amiket a fenti programlistában kékes­

zöld színnel emeltem ki. Ezek után a mau program (átlagban) 970468 ideig fut.

Ez az előző változathoz képest 3.3% javulás! Nem azt mondom hogy világrengető siker, de már valami. Végeredményben e 3.5 százalékot csak 3 pontosvessző megspórolásával értük el, azaz durván 1% javulást jelent minden felesleges pontosvessző eliminálása! Megfontolandó tapasztalat...

Ezután az jut eszünkbe, hogy a nevezőt kettővel megnövelő programsort cseréljük ki 2 db inkrementáló utasításra! Ezesetben az ezek előtti sor végére vissza kell tenni a pontosvesszőt. A program ekkor így néz ki:

#!mau

// kiszámoljuk a pit a leibniz formulával.

#t@a; // inicializálunk egy időváltozót

#d@p=0; // Az osszegvaltozo

#L@n=1; // A nevezo

#L@s=1; // A szamlalo {| 3000000

#d@p=(@p)+(#L@s)/(#L@n);

++Ln ++Ln

#L@s=-@s

|}

#t@b; // inicializálunk egy másik időváltozót

#g@x=(#t@b)-(#t@a);

"Idő: " ?g @x; /;

#d@p = 4*#d@p;

"Pi/4 közelítés: " ?d @p; /;

A futásidők átlaga 766118. Ez az előzőnek csak 79%-a! Azért ez már nem semmi nyereség...

Ezután az ötlik az eszünkbe, hogy a két különálló inkrementáló utasítást cserél­

jük ki egyetlenre, ami rögvest kétszer inkrementál! Erről az utasításról van szó:

+2Ln

A futásidők átlaga ekkor: 745515, ami az előzőnek a 97.3%-a. Jó, hát nem világ­

rengető időnyereség, de sok kicsi sokra megy...

Ezután kicseréljük az előjelváltást egy „profi módszerre”, az előjelváltó gyorsutasí­

tásra! Ekkor a programunk így néz ki:

#!mau

// kiszámoljuk a pit a leibniz formulával.

#t@a; // inicializálunk egy időváltozót

#d@p=0; // Az osszegvaltozo

#L@n=1; // A nevezo

#L@s=1; // A szamlalo {| 3000000

#d@p=(@p)+(#L@s)/(#L@n);

+2Ln

±Ls

|}

#t@b; // inicializálunk egy másik időváltozót

#g@x=(#t@b)-(#t@a);

"Idő: " ?g @x; /;

#d@p = 4*#d@p;

"Pi/4 közelítés: " ?d @p; /;

Ennek a futásideje 444595, és hát ez az előzőnek csak 59.6%-a! Hm...! Vaskos, igen jelentős időnyereség...

No és hát ezt ha összevetjük azzal az állapottal amiből kiindultunk, azt kapjuk hogy annak a 44.3%-ánál járunk! Ezért érdemes volt dolgozni, optimalizálni, hiszen az időszükségletet lecsökkentettük kevesebb mint a felére!

Az „etalonnal” összevetve, most 17.83-szor vagyunk csak lassabbak, mint a „gépi kód”... És még ezen is gyorsíthatunk! Mert ezt a sort:

#d@p=(@p)+(#L@s)/(#L@n);

cseréljük ki erre:

#d@p+=(#L@s)/(#L@n);

Így az időszükséglet: 364682. Ez az előzőnek a 82%-a csak... És most már csak 14.6-szor vagyunk lassabbak, mint a C nyelvű változat, az etalon... Én amondó

vagyok, hogy ez már elfogadható! Ez „egy nagyságrendnyi” sebességkülönbség, ami teljesen érthető, hiszen mi nem compilerek vagyunk: a mau az egy INTER­

PRETER. Nyilvánvaló, ha megfeszülünk se tudjuk utolérni sebességben a compilereket.

Következő ötletünk az, hogy mi a csudának használunk L típusú változókat, amikor ezek értékét úgyis át kell konvertálni double-vá?! Legyen minden double.

Ehhez persze újra kell írni a C nyelvű programot is, hogy legyen új etalonunk.

Annak futásideje most 14644 lett, azaz az is sokkal gyorsabbá vált. A mi mau programunk első változata:

#!mau

// kiszámoljuk a pit a leibniz formulával.

#t@a; // inicializálunk egy időváltozót

#t@b; // inicializálunk egy másik időváltozót

#g@x=(#t@b)-(#t@a);

"Idő: " ?g @x; /;

#d@p = 4*#d@p;

"Pi/4 közelítés: " ?d @p; /;

Ennek futásideje: 1146300, s ez az etalonnak a 78-szorosa. Durva... Nem baj azért, lesz ám ez kisebb is...

Végezzük el rajta az összes módosítást, amit az előző, nem csak double típust használó mau progin elvégeztünk! Ekkor a programunk így fog kinézni:

#!mau

// kiszámoljuk a pit a leibniz formulával.

#t@a; // inicializálunk egy időváltozót

#t@b; // inicializálunk egy másik időváltozót

#g@x=(#t@b)-(#t@a);

"Idő: " ?g @x; /;

#d@p = 4*#d@p;

"Pi/4 közelítés: " ?d @p; /;

Ennek az időszükséglete pedig már csupán 465408. Az előző variáció 40.6%-a...

És ezt még tovább csőkkenthetjük! Használjunk a cikluson belül gyorsfüggvényt!

Ekkor a progi így néz ki:

#!mau

// kiszámoljuk a pit a leibniz formulával.

#t@a; // inicializálunk egy időváltozót

#t@b; // inicializálunk egy másik időváltozót

#g@x=(#t@b)-(#t@a);

"Idő: " ?g @x; /;

#d@p = 4*#d@p;

"Pi/4 közelítés: " ?d @p; /;

Ekkor az időszükséglet: 386190. Ez az előző 83%-a.

És most a függvényen belül a gyorsfüggvényes sort írjuk összevont utasításként!

A programunk most eképp fest:

#!mau

// kiszámoljuk a pit a leibniz formulával.

#t@a; // inicializálunk egy időváltozót

#d@p=0; // Az osszegvaltozo

#d@n=1; // A nevezo

#d@s=1; // A szamlalo {| 3000000

#d@p+=¤d/sn;

+2dn

±ds

|}

#t@b; // inicializálunk egy másik időváltozót

#g@x=(#t@b)-(#t@a);

"Idő: " ?g @x; /;

#d@p = 4*#d@p;

"Pi/4 közelítés: " ?d @p; /;

Ennek időátlaga pedig 331629.

Pillanatnyilag nincs jobb ötletem, hogyan lehetne tovább gyorsítani... Minden­

esetre ez az előző variációhoz képest is újabb 14% időspórolást jelent!

E végső eredmény a kiindulállapothoz képest (ami csak double típust használt) annak 28.9%-a, azaz KEVESEBB MINT EGYHARMADA! Az etalonhoz képest meg annak 22.6-szerese. Ez rosszabb mint a kevert típusokat használó változat etalonnal összevetett aránya, de csak mert úgy tűnik, a C nyelvű változat esetén nagyobb időnyereséget jelent ha nem kell a típusok közt konvertálgatni, mint ami előnyt ez a mau programban jelent. De így is megérte nekünk is kerülni a típuskonverziókat, mert ezen egytípusú utóbbi program végső változata a kevert típusú változat végső variánsával összevetve, mintegy 10%-kal gyorsabban fut, csak amiatt, mert nem kell a típusok közt konvertálgatni!

In document A mau programozási nyelvVerziószám: (Pldal 186-190)