maandag 1 september 2008

Team Coherence hack -> 10x sneller!

Op mijn huidige detacheringsplek gebruiken ze "Team Coherence" (http://www.teamcoherence.com) voor versie beheer en bug/issue tracking. Ze gebruiken dit pakket heel strict: bijvoorbeeld elke check-in moet een tracker melding hebben, een tracker heeft aantal stadia (waaronder controle door de aanvrager of indiener), versie labels, promotion levels, etc.

Op zich zijn ze tevreden over dit pakket. Het pakket heeft wel een poos een dip gehad, waarbij het niet meer onderhouden werd door de makers, maar nu wordt weer af en toe een update uitgebracht. Het grootste probleem echter wat ze hadden, was dat het pakket steeds trager werd: opstarten duurde maar liefst anderhalve minuut! Ook wisselen van views etc duurde dik een minuut.

Toen ik even niets te doen had (wachten op specs etc), heb ik even gekeken met Proces Explorer naar wat de oorzaak kon zijn. Nu blijkt dat hij veel geheugen acties doet (van 10Mb oplopend naar 65Mb en dan weer 36Mb), en veel kernel/system (rood) tijd gebruikt. Zie onder (er is trouwens getest op een HT systeem, vandaar niet meer dan 50% CPU):


1 thead (main thread) is druk bezig. Zie onder:



Als we nu de stack trace opvragen (en dit een paar keer doen), dan blijkt dat hij steeds bezig is met "GlobalRealloc".
Zie onder:


Ik weet dat het een Delphi 5 programma is, en Delphi gebruikt maar op 1 plek Global memory: TMemorystream.SetSize. Waarschijnlijk wordt steeds een paar bytes geschreven (stream.Write(s) oid), zodat het geheugenblok steeds met paar bytes vergroot moet worden. Nu doet Windows dit niet efficiënt: zelfs als na het huidige blok genoeg ruimte is, hij kopieert altijd naar een nieuw blok geheugen. En dit kost tijd, vooral als het heel vaak gebeurt. Vandaar de "rode" systeem CPU tijd.

Nu heb ik al wat ervaring met hacken gekregen met mijn profiler (http://code.google.com/p/asmprofiler) en detouring, dus ik heb ik een kleine dll geschreven die de GlobalRealloc overruled, en 1Mb extra reserveert. Als de nieuwe ruimte nog past in het oude, dan doet het niets, anders vraagt het door middel van de originele GlobalRealloc nieuw geheugen aan (met weer 1Mb extra):

function HookedGlobalReAlloc(hMem: HGLOBAL; dwBytes: SIZE_T; uFlags: UINT): HGLOBAL; stdcall;
begin
if GlobalSize(hMem) < id="pcex4"> Result := trampoline_GlobalReAlloc(hMem, dwBytes + (1000*1024), uFlags) //reserve 1Mb extra mem
else
Result := hMem; //do not realloc if needed size fits in current size, GlobalRealloc ALWAYS does a resize, even when it is not needed!
end;

Door middel van dll injection heb ik dit in Team Coherence geladen (zowel server als client), en nu duurt het opstarten maar 10 seconden! Dus 10x sneller!

P.S. ik heb dit ook aan de makers gestuurd, nog geen reactie tot nu toe...
P.S.2 de volgende keer zal ik demonstreren hoe ik de executable aangepast heb, zodat altijd mijn extra dll geladen wordt (dll injection dus niet meer nodig elke keer).

Geen opmerkingen: