2008. december 31., szerda

StringBuilder appendelgetős

Szóval ezzel töltöttem a 2008-as év utolsó napját... Hmm, kisérleti project.

Ezt az elején hagyd ki bátran, mert tiszta marhaság saját XML-parsert írni.

Régebben írtam, hogy csináltam egy XML parsert ami NIO-hoz kicsit jobban passzol (azaz nem odadobunk neki egy IO streamet, hanem ahogy jönnek a byte-ok, úgy szépen darabonként dobáljuk a parsernek és amennyi értelmes dologot már beraktunk, arra meghívja a callback-et)

Az első nekifutás az java regexpekkel készült el, ez annyira ocsmányul lassú lett minden szempontból, hogy tulajdonképpen csak a java regexpek gyakorlására volt jó.

A második nekifutás az ma volt, megcsináltam kb korrekt finite state machine-nel, ami karakterenként parsel. A xerces, xpp3, "exmil" teljesítményversenyben az exmil majdnem minden esetben utolsóként szerepelt. Az xpp3 néha fele annyi idő alatt futott le, de még a xerces is helyenként lealázott.
Elővettem a netbeans profilerét (a mai napon néhány pirospontot elkönyvelhet a netbeans, te meg eclipse fiam üljle-egyes profilingból) és kitúrtam hogy mi viszi a legtöbb időt. A futási idő 90+ százalékában a StringBuilder-ben volt a proci. Ebből azt azt a merész következtetést vontam le, hogy a karakterek egymás után appendelgetése volt rossz ötlet.
Erre jött az az ötlet, hogy akkor esetleg nem karakterenként appendelgetek, hanem array-ként, így kihasználva a System.arrayCopy erejét. Persze mielött nekiszaladunk fejjel egy nagyobb módosításnak, elöbb mérünk...

A mérés elsőre nagyon meglepő választ hozott. Annyira meglepő volt, hogy biztos volt, hogy rossz :-) Azt szúrtam el a mérésben, hogy a StringBuildernek nem határoztam meg a kezdeti kapacitást. Az így alkotott kép elég cifra, és egyáltalán nem látszik belőle, hogy nőne a sebesség az arrayCopy-val. A probléma itt az, hogy a procidő túlnyomó részét ebben az esetben a memória allokációja és a régi adatok átmásolása okozza. (Bezzeg ha lenne java-ban realloc, mennyivel, gyorsabban menne, meg mennyivel bonyolultabb lenne programozni.)

A második mérésnél a StringBuildernek átpasszoltam a szükséges kapacitást előre, így nem kellett szegénynek átmásolgatnia egyenként. Meg is látszik az eredményen, és a kép is tiszta lett végre.


Szóval ez alapján, ha a kódomat átírom, hogy ne egyenként StringBufferbe minden darabját, hanem az elérhető mennyiségű adatból annyit dolgozzon fel, amennyit csak tud, akkor elméletileg a StringBuffer appendelgetésből származó többlet futásidőm harmadára vagy akár tizedére is csökkenhet. A többi kárára persze, mert ezt kicsit bonyibb lesz lekódolni.

Meglátjuk az újévben. Mellesleg az említett újévben 2 éves lesz ez a blogom, ebből az alkalomból felktettem egy értékelős szavazást oldalra, csak hogy én is tudjam kicsit hogy ti mit gondoltok arról amit én gondolok. Your feedback is wellcome. A szöveges feedback is.

Köszi, és boldog új évet!