= Metingen = (''ook iets als "kwantitatieve software evaluatie"'') Om metingen op OpenAC zelf uit te kunnen voeren om zo een kwantitatief beeld te krijgen van de software, hebben we tools nodig om getallen te produceren op basis van de software. Deze pagina beschrijft sommige beschikbare en gebruikte tools. == Geheugengebruik == Het meest nauwkeurig voor geheugenmeting in Python onder Linux is [http://guppy-pe.sourceforge.net/#Heapy heapy], een tool om (interactief) de Python heap te onderzoeken. De handleiding voor heapy is nogal summier, maar er zit veel in de help binnen de module zelf. Met heapy kan je kijken hoeveel geheugen er gebruikt wordt, wat voor types het heeft, en ook zien welke veranderingen in het geheugen gebeuren als je bepaalde functionaliteit aanroept. === Installatie van Heapy === Instructies voor '''OpenSUSE''' - {{{zypper in python-devel}}} - Je moet guppy waarschijnlijk van source compileren: {{{ $ svn co https://guppy-pe.svn.sourceforge.net/svnroot/guppy-pe/trunk/guppy $ cd guppy $ python setup.py build $ sudo python setup.py install }}} Vervolgens kan je de (nogal basic) [https://guppy-pe.svn.sourceforge.net/svnroot/guppy-pe/trunk/guppy heapy tutorial] volgen. === Voorbeeldsessie Heapy === {{{ >>> from guppy import hpy; heap=hpy(); del hpy >>> heap.heap() Partition of a set of 26126 objects. Total size = 1889564 bytes. Index Count % Size % Cumulative % Kind (class / dict of class) 0 11935 46 728612 39 728612 39 str }}} Op dit moment -- met alleen Python gestart -- is er 1.8MB in gebruik, vooral strings. {{{ >>> heap.setref() >>> import logica [2012-03-17 01:04:19]:WARNING:openac:Functie doorvoer is deprecated bij callbacks maar zit nog in ModelBase >>> heap.heap() Partition of a set of 79843 objects. Total size = 6211716 bytes. Index Count % Size % Cumulative % Kind (class / dict of class) 0 37276 47 2880268 46 2880268 46 str 1 21661 27 846520 14 3726788 60 tuple }}} De ''setref()'' zorgt ervoor dat bij de volgende call we alleen nieuwe objecten zien. Het inlezen van module logica zorgt voor 6.2MB extra geheugen gebruik. {{{ >>> heap.setref() >>> logica.configuratie.lees() True >>> heap.heap() Partition of a set of 5493 objects. Total size = 461748 bytes. Index Count % Size % Cumulative % Kind (class / dict of class) 0 556 10 289120 63 289120 63 dict of include.primitieven.VrijObject 1 3767 69 134268 29 423388 92 str }}} Het inlezen van de configuratie van OpenAC gebruikt 461kB. Dat is misschien veel voor een bestand van 21kB grootte en 573 regels. We kunnen kijken hoe we bij al die nieuwe strings komen: {{{ >>> (heap.heap()&str).byvia Partition of a set of 3767 objects. Total size = 134276 bytes. Index Count % Size % Cumulative % Referred Via: 0 556 15 23704 18 23704 18 "['omschrijving']" 1 571 15 16000 12 39704 30 "['type']" 2 558 15 15656 12 55360 41 '.keys()[10]' 3 557 15 15608 12 70968 53 '.keys()[1]' }}} Hier zien we de weg (via) voor de strings die net zijn geladen. Daar zit niet zo veel verrassends in, behalve dat zo-te-zien er weinig sharing plaatsvindt. Een !VrijObject kost 520 bytes of meer (520 is de dict). Dat zie je met {{{(heap.heap()&dict).bysize}}}. Je kan ook met wat gefrobel ontdekken welke objecten het zijn: {{{ >>> v=heap.heap()&dict >>> v.byid Set of 711 objects. Total size = 326520 bytes. Index Size % Cumulative % Brief 0 1672 0.5 1672 0.5 dict of class: ..TestEnv ... >>> _.more ... }}} Op deze manier kunnen we bladeren door de objecten in de set ''v'' (dat zijn dicts die recent aan de heap zijn toegevoegd). De lijst byid kunnen we indexeren om een specifiek object te vinden: {{{ >>> v.byid[39] Set of 1 object. Total size = 520 bytes. Index Size % Cumulative % Owner Address 0 520 100.0 520 100.0 0x88a4d0c }}} Tot slot kunnen we ontdekken hoe we bij dit specifieke object kunnen komen: {{{ >>> v.byid[39].sp 0: heap.Root.i0_modules['logica.configuratie'].__dict__['variabelen'].__dict__['_data']['rapportage_export_folder'].__dict__ }}} Dus, ruwweg, hebben we hier {{{logica.configuratie.variabelen!['rapportage_export_folder']}}} te pakken -- of beter gezegd, de {{{__dict__}}} van het !VrijObject dat daardoor aangeduid wordt. === Tijdgebruik === De standaardmodule [http://docs.python.org/library/timeit.html timeit] kan gebruikt worden om reken-intensieve functies door te voeren en tijden uit te rekenen. Het werkt het beste op echte rekenfuncties in een aparte Python module; de functie kan een of meer parameters nemen die makkelijk in te voeren zijn op de command line. Als voorbeeld: {{{ import timeit print timeit.Timer( 't1.anonimiseer("hallo","tekst")','import t1') \ .repeat(number=10000) print timeit.Timer( 't2.anonimiseer("hallo","tekst")','import t2') \ .repeat(number=10000) }}} Je maakt een ''Timer'' object met een fragment programmacode die uitgevoerd wordt (zonder enige context, dus je kan geen variabelen hier gebruiken die je al gedefinieerd hebt, en geen reeds geimporteerde modules). Het tweede fragment wordt precies een keer uitgevoerd om een context te maken voor het eerste fragment -- bijvoorbeeld met imports. Het eerste fragment wordt ''number'' keer uitgevoerd (hier 10000) en de tijd die dat neemt wordt afgedrukt. Hiermee is makkelijk te zien hoe lang iets duurt of om de looptijd van twee verschillende implementaties te vergelijken.