Klassikalised vead koodi kiiruse mõõtmisel
09.09.2010 | Gunnar
Klassikalised vead koodi kiiruse mõõtmisel on vist aegumatud. Neid tehti eile, tehakse täna ja tehakse kindlasti ka homme. Et meie siin pisikeses Eestis teistest tublimad progejad saaks olla, siis võtan tagataskust välja mõned õpetussõnad, kuidas oma koodi pädevalt mõõta.
Et see blogi on konstruktiivne infokanal, siis annan muidugi näited ja lahendused ka iga punkti juurde, kuhu vaja. Esimesele ei anna, sest rippnimistust õige elemendi valimine ei tohiks seda blogi lugeval progejal üle jõu käia.
Debug konfiguratsiooni kasutamine
Silumisinfot sisaldav kood ei ole nii kiire, kui see, mis seda ei sisalda. Erinevad osad täidetavast koodist sisaldavad silumisinfot erineval määral ja see võib anda mõningatel juhtudel täiesti vale pildi sellest, mis täidetava koodi sisemuses toimub.
Release konfiguratsiooni kasutades saame kompilaatori poolt optimeeritud koodi, mis on kiireim, mida see pakkuda suudab (käesolevas katses oli kiiruste vahe debug ja release konfiguratsioonide vahel orienteeruvalt 4x).
Aega mõõdetakse kella pealt
Paljud mõõtjad ei tea, et kahe DateTime.Now võrdlemisel saadakse tulemuseks aeg, mille sisse läheb ka kõik muu tegevus, mida süsteem teeb.
Stopwatch klassi kasutades saame aga selle aja, mis uuritava koodi täitmiseks tegelikult kulus. See tähendab seda, et kui käesolev thread opsüsteemist tulenevalt vahepeal teiste threadide taga ootab, mille kord on tegutseda, siis sellised viivitused Stopwatchi aegades ei sisaldu.
Vale:
// jooksuta mõõdetavat koodi
var finish = DateTime.Now;
Console.WriteLine("Result: " + (finish - start));
Õige:
watch.Start();
// jooksuta mõõdetavat koodi
watch.Stop();
Console.WriteLine("Result: " + watch.ElapsedMilliseconds);
Mõõdetakse liiga paljusid tegevusi
Päris palju hakkab silma ka selliseid ämbreid, kus stopper käivitatakse kusagil suvalises kohas, mitte vahetult enne mõõdetavaid koodiridu. Sama kehtib stopperi peatamise kohta. Selle tulemusena võib mõni mõõtmisele tegelikult mittekuuluv koodirida lisada omalt poolt lõplikusse tulemusse päris väärika panuse.
Täpsemate ja puhtamate tulemuste saamiseks soovitab stopperi käima lüüa rida enne mõõdetavat koodi. Ja kinni löö see loomulikult esimese asjana peale mõõdetavat koodi. Siis on kindel (või peaaegu kindel), et mõõtmised ei sisalda liigset müra.
Lülita diagnostika mõõtmise ajaks välja
Igasugune diagnostika näiteks konsoolile või debug aknasse või logidesse kirjutamise näol lülita mõõtmise ajaks välja. Muidu sisaldavad su mõõtmised ka seda aega, mis kulus kirjutamisele. Failide korral võib mängu tulla näiteks kõvaketta koormus ja see omakorda võib tulemusi oluliselt moonutada.
Selline asi on ei-ei-ei-ei-ei!
{
Logger.Write("Processing customer " + customer.Name);
// tee midagi
}
Mõõda mitu korda
Kui mõõtmiseks mõeldud kood hästi organiseerida, siis pole seda keerukas tsüklis jooksutada. Tihti seda ei tehta ja nii leidub netis teinekord päris veidrad mõõtmistulemusi, kus koostöös eeltoodud vigadega saadakse ebapädevad tulemused.
Mõõda 10 korda või 100 korda või miljon korda ja arvuti ajakulude keskmine. Mõõtmiskordade arv vali selline, et kordi saaks piisav arv antud mõõtmise kohta ja mõõtmise järel ei pea liiga pikalt ootama.
Kokkuvõtteks
Eeltoodud vigade vältimisel saame koodi kiiruse ja jõudluse mõõtmisel oluliselt täpsemad tulemused. Kindlasti soovitan ma mõõtmisi läbi viia hoolikalt, sest iga lohakusviga võib meid viia valede tulemusteni ja sealt valede järeldusteni. Valed järeldused viivad meid omakorda eksiarvamusteni ja mitte just eriti jõudsalt töötava koodini. Hoolikad mõõtmised aga annavad meile väga kasulikku infot ja õpetavad meie käes olevaid vahendeid paremini tundma.
