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!

2008. december 13., szombat

JHacks @ XWiki Screenshots

Próbálgattam ma Karenin snipsnap2xwiki projectjét a jhacks dumpon és gondoltam csinálok egy pár screenshotot biztatásként. Állapot elötte és utánna...

2008. december 9., kedd

Continuum

Rövid műsorajánlóval jelentkezünk korán reggel...

Szóval ajánlanám figyelmetekbe, hogy a continuum-hoz végre valahára megcsinálják a több agent-es build lehetőségét. Gondolom még sokat kell várni, amíg célba ér. Közben kijött a TeamCity 4.0, csili-vili dolgokkal, szóval munkában valószinűleg marad az...

2008. december 8., hétfő

Cache interszatyor

Nagy csend van nálam mostanában, rendesen el vagyok látva tennivalókkal. Hébe-hóba azért valami olyat is csinálok, ami valamennyire érdekes lehet. Például...

Szóval az alkalmazásunknak van egy halom backendje amiket igen frekventáltan használ (cms meg satöbbi), főleg (de nem kizárólag) web services alapú dolgok. Egy nagy közös jellegzetességük van: döglassú mind. Főleg a network delay sok, mert amikor meghívok egy remote objektumon egy metódust az általában egy még távolabbi metódust hív. Nem túl szerencsés, de ez van.
Erre persze már a kezdetek kezdetén gondoltak a fejlesztők, és egy tucat helyre betettek a hívás elé valamilyen cache-t.
Ez is megoldotta a teljesítmény problémákat, viszont az ilyen kód mennyisége igen szép volt sor-számban mérve, ezért keresni kezdtem más lehetőséget. Az igazából alapötlet volt, hogy a cache és a tulajdonképpeni kód az legyen egymástól elválasztva, azaz pl egy aop interceptor. Van a springmodules cucc, de abban nem találtam meg mindent kellene, úgyhogy összedobtam egy saját AOP interceptort, amit a read-only szolgáltatások elé be lehet szúrkálni a spring applicationcontext-ben.

Ilyeneket tud:
  • Persze független attól az komponenstől, amire ráhúzzuk.
  • Lehessen konfigurálni hogy mire lockoljon. Például egyes szolgáltatások teljesen befordulnak, ha egynél több kéréssel traktáljuk őket, úgyhogy konfigurálható hogy a hívás paramétereire, vagy az egész instance-re, vagy egyáltalán ne is lockoljon.
  • Felhasználók speciális felületen keresztül ki is törölhetik, hogy lássák a változtatásaik eredményét. Nagyon türelmetlen népek.
  • Konfigolható hogy melyik hívás eredménye meddig érvényes a memóriában.
  • Egy szál ellenőrzi a "már majdnem" elévült adatokat és frissíti - azaz újra hívja a döglassú backendet, így a néha végrehajtott frissítés nem blokkol le egy user request kiszolgálását és nem rajzol cikk-cakkokat a terhelési teszt egyébként kellemes eredményeire.
Balesetek:
  • Terhelési teszt közben történt is egy kis baleset: rosszul konfigoltam egy cache-t és megtekertem vele egy szolgáltatást, amiből csak egy van. Azaz live. Ez ilyen szent tehén rendszer, tilos hozzányúlni, szóval nem arattam vele osztatlan sikert.