Blame optimization-guide/sv/massif.page

Packit 1470ea
Packit 1470ea
<page xmlns="http://projectmallard.org/1.0/" type="guide" style="task" id="massif" xml:lang="sv">
Packit 1470ea
    <info>
Packit 1470ea
      <link type="guide" xref="index#massif"/>
Packit 1470ea
    
Packit 1470ea
    <mal:credit xmlns:mal="http://projectmallard.org/1.0/" type="translator copyright">
Packit 1470ea
      <mal:name>Anders Jonsson</mal:name>
Packit 1470ea
      <mal:email>anders.jonsson@norsjovallen.se</mal:email>
Packit 1470ea
      <mal:years>2015</mal:years>
Packit 1470ea
    </mal:credit>
Packit 1470ea
  </info>
Packit 1470ea
      <title>Använda <app>Massif</app> för att profilera minnesanvändning i GNOME-program</title>
Packit 1470ea
Packit 1470ea
    

Denna artikel beskriver hur heap-profileraren <app>Massif</app> kan användas med GNOME-program. Vi beskriver hur du kan köra, tolka och reagera på utdata från <app>Massif</app>. Spelet <app>Swell Foop</app> används som ett exempel.

Packit 1470ea
   <section id="optimization-massif-TBL-intro">
Packit 1470ea
        <title>Introduktion</title>
Packit 1470ea
        

<app>Massif</app> är en medlem av <link href="http://valgrind.org/">valgrind</link>-sviten av verktyg för minnesprofilering. Dess syfte är att ge en detaljerad överblick över dynamisk minnesanvändning under programmets livstid. Specifikt lagrar det minnesanvändningen för heapen och stacken.

Packit 1470ea
        

Heapen är minnesregionen som allokeras med funktioner som malloc. Den växer enligt efterfrågan och är vanligen den största minnesregionen i ett program. Stacken är där alla lokala data för funktioner lagras. Detta inkluderar de ”automatiska” variablerna i C och returadressen för subrutiner. Stacken är vanligen mycket mindre och mycket mer aktiv än heapen. Vi kommer inte explicit tänka närmare på stacken eftersom <app>Massif</app> behandlar den som att den bara vore en annan del av heapen. <app>Massif</app> ger också information om hur mycket minne som används för att hantera heapen.

Packit 1470ea
        

<app>Massif</app> skapar två utdatafiler: en grafisk överblick i en postscript-fil och en detaljerad sammanställning i en textfil.

Packit 1470ea
    </section>
Packit 1470ea
    <section id="optimization-massif-TBL-using-massif">
Packit 1470ea
        <title>Använda <app>Massif</app> med GNOME</title>
Packit 1470ea
        

<app>Massif</app> har väldigt få flaggor och behöver dem inte för många program. För GNOME-program, där minnesallokering kan vara gömd djupt nere i antingen glib eller GTK, kan dock antalet nivåer som Massif går ner för anropsstacken behöva ökas. Detta uppnås med parametern --depth. Denna är som standard 3. Att öka den till 5 garanterar att anropsstacken når ner till din kod. En eller två ytterligare nivåer kan också vara önskvärda för att tillhandahålla mer sammanhang till din kod. Eftersom detaljnivån snabbt blir överväldigande är det bäst att börja med den mindre djupparametern och endast öka den då det blir uppenbart att den är otillräcklig.

Packit 1470ea
        

Det är också användbart att berätta för <app>Massif</app> vilka funktioner som allokerar minne i glib. Det tar bort ett onödigt lager av funktionsanrop från rapporterna och ger dig en tydligare bild av vilken kod som allokerar minne. De allokerande funktionerna i glib är g_malloc, g_malloc0, g_realloc, g_try_malloc och g_mem_chunk_alloc. Du använder flaggan --alloc-fn för att informera Massif om dem.

Packit 1470ea
        

Din kommandorad bör därför se ut något i stil med:

Packit 1470ea
        
Packit 1470ea
valgrind --tool=massif --depth=5  --alloc-fn=g_malloc --alloc-fn=g_realloc --alloc-fn=g_try_malloc \
Packit 1470ea
         --alloc-fn=g_malloc0 --alloc-fn=g_mem_chunk_alloc swell-foop
Packit 1470ea
        
Packit 1470ea
        

<app>Swell Foop</app> är programmet vi kommer använda som ett exempel. Var redo på att eftersom valgrind emulerar processorn så kommer det köra väldigt långsamt. Du kommer också behöva mycket minne.

Packit 1470ea
    </section>
Packit 1470ea
    <section id="optimization-massif-TBL-interpreting-results">
Packit 1470ea
        <title>Tolka resultaten</title>
Packit 1470ea
        

Grafiskt utdata för <app>Massif</app> är i stort självförklarande. Varje band representerar minnet allokerat av en funktion över tid. Då du väl identifierat vilka band som använder mest minne, oftast de tjocka banden högst upp, kommer du att behöva läsa textfilen för detaljer.

Packit 1470ea
        

Textfilen är arrangerad som en hierarki av avsnitt, högst upp är en lista över de värsta minnesanvändarna arrangerade i ordning efter sjunkande utrymmestid. Under detta är vidare avsnitt som vardera delar upp resultaten i större detalj allt efter att du fortsätter ner för anropsstacken. För att illustrera detta kommer vi visa utdata för kommandot ovan.

Packit 1470ea
        <figure>
Packit 1470ea
            <title>Utdata från <app>Massif</app> för den ej optimerade versionen av programmet <app>Swell Foop</app>.</title>
Packit 1470ea
            <media type="image" src="figures/massif-before.png"/>
Packit 1470ea
         </figure>
Packit 1470ea
        

Bilden ovan visar typiskt postscript-utdata från <app>Massif</app>. Detta är resultatet du skulle få av att spela en omgång <app>Swell Foop</app> (version 2.8.0) och sedan avsluta. Postscript-filen kommer ha ett namn som <file>massif.12345.ps</file> och textfilen kommer att kallas <file>massif.12345.txt</file>. Numret i mitten är process-ID:t för programmet som undersöktes. Om du faktiskt prövar detta exempel kommer du hitta två versioner av varje fil, med något olika nummer, detta beror på att <app>Swell Foop</app> startar en andra process och <app>Massif</app> följer den också. Vi kommer ignorera denna andra process, den förbrukar mycket lite minne.

Packit 1470ea
        

Högst upp på grafen ser vi ett stort gult band märkt gdk_pixbuf_new. Detta verkar vara en ideal kandidat för optimering, men vi kommer behöva använda textfilen för att få reda på vad som anropar gdk_pixbuf_new. Början på textfilen kommer se ut något i stil med detta:

Packit 1470ea
        
Packit 1470ea
Command: ./swell-foop
Packit 1470ea
Packit 1470ea
== 0 ===========================
Packit 1470ea
Heap allocation functions accounted for 90.4% of measured spacetime
Packit 1470ea
Packit 1470ea
Called from:
Packit 1470ea
  28.8% : 0x6BF83A: gdk_pixbuf_new (in /usr/lib/libgdk_pixbuf-2.0.so.0.400.9)
Packit 1470ea
Packit 1470ea
    6.1% : 0x5A32A5: g_strdup (in /usr/lib/libglib-2.0.so.0.400.6)
Packit 1470ea
Packit 1470ea
    5.9% : 0x510B3C: (within /usr/lib/libfreetype.so.6.3.7)
Packit 1470ea
Packit 1470ea
    3.5% : 0x2A4A6B: __gconv_open (in /lib/tls/libc-2.3.3.so)
Packit 1470ea
        
Packit 1470ea
        

Raden med ”=”-tecknen indikerar hur långt ner för stackspåret vi är, i detta fall på toppen. Efter detta listar det de tyngsta användarna av minne ordnade efter sjunkande utrymmestid. Utrymmestid är produkten av mängden minne som används och hur länge det användes. Det motsvarar arean av banden i grafen, Denna del av filen talar om för oss vad vi redan vet: att den mesta utrymmestiden ägnas åt gdk_pixbuf_new. För att ta reda på vad som anropade gdk_pixbuf_new måste vi söka längre ner i textfilen:

Packit 1470ea
        
Packit 1470ea
== 4 ===========================
Packit 1470ea
Context accounted for 28.8% of measured spacetime
Packit 1470ea
  0x6BF83A: gdk_pixbuf_new (in /usr/lib/libgdk_pixbuf-2.0.so.0.400.9)
Packit 1470ea
  0x3A998998: (within /usr/lib/gtk-2.0/2.4.0/loaders/libpixbufloader-png.so)
Packit 1470ea
  0x6C2760: (within /usr/lib/libgdk_pixbuf-2.0.so.0.400.9)
Packit 1470ea
  0x6C285E: gdk_pixbuf_new_from_file (in /usr/lib/libgdk_pixbuf-2.0.so.0.400.9)
Packit 1470ea
Packit 1470ea
Called from:
Packit 1470ea
  27.8% : 0x804C1A3: load_scenario (swell-foop.c:463)
Packit 1470ea
Packit 1470ea
    0.9% : 0x3E8095E: (within /usr/lib/libgnomeui-2.so.0.792.0)
Packit 1470ea
Packit 1470ea
  and 1 other insignificant place
Packit 1470ea
        
Packit 1470ea
        

Den första raden säger oss att vi är fyra nivåer ner i stacken. Under den är en lista över de funktionsanrop som leder härifrån till gdk_pixbuf_new. Slutligen finns det en lista över funktioner som är på nästa nivå neråt och anropar dessa funktioner. Det finns förstås även poster för nivå 1, 2 och 3, men detta är den första nivån som når rakt genom GDK-koden till <app>Swell Foop</app>-koden. Från denna lista kan vi omedelbart se att problemkoden är load_scenario.

Packit 1470ea
        

Nu när vi vet vilken del av vår kod som använder all utrymmestid kan vi titta på den och ta reda på varför. Det visar sig att load_scenario läser in en pixbuf från fil och sedan aldrig frigör det minnet. Eftersom vi har identifierat problemkoden så kan vi fixa den.

Packit 1470ea
    </section>
Packit 1470ea
    <section id="optimization-massif-TBL-acting-on-results">
Packit 1470ea
        <title>Agera på resultaten</title>
Packit 1470ea
        

Att reducera användning av utrymmestid är bra, men det finns två sätt att minska det och de är inte likvärdiga. Du kan antingen minska mängden minne som allokeras, eller minska tidsperioden som det är allokerat. Tänk dig nu ett modalt system där bara två processer körs. Båda processerna använder upp nästan allt fysiskt RAM-minne, och om de någonsin överlappar kommer systemet använda växlingsutrymme och allt kommer att sakta ner. Uppenbarligen kan de samexistera utan behov att använda växlingsutrymme om vi minskar minnesanvändningen för varje process med en faktor två. Om vi istället minskar tiden minne är allokerat kan programmen samexistera, men bara så länge deras perioder av hög minnesanvändning inte överlappar. Det är därför bättre att minska mängden allokerat minne.

Packit 1470ea
        

Dessvärre begränsas valet av optimering även av programmets behov. Storleken på pixbuf-data i <app>Swell Foop</app> avgörs av storleken på spelets grafik och kan inte minskas på något lätt sätt. Tidsperioden som det är inläst i minne kan dock minskas drastiskt. Bilden nedan visar analysen <app>Massif</app> har gjort av <app>Swell Foop</app> efter att programmet ändrats för att göra sig av med pixbufar då bilderna har lästs in i X-servern.

Packit 1470ea
        <figure>
Packit 1470ea
            <title><app>Massif</app>-utdata för det optimerade <app>Swell Foop</app>-programmet.</title>
Packit 1470ea
           <media type="image" src="figures/massif-after.png"/>
Packit 1470ea
            </figure>
Packit 1470ea
        

Användningen av utrymmestid för gdk_pixbuf_new är nu ett tunt band som endast tillfälligt når toppar (det är nu det sextonde bandet uppifrån och har färgen magenta). Som en bonus minskar minnesanvändningstoppen med 200 kB efter det att toppen inträffat innan annat minne allokeras. Om två processer som denna körs samtidigt är risken att topparna inträffar samtidigt, och därmed risken att växlingsutrymme behöver användas, ganska låg.

Packit 1470ea
        

Kan vi göra bättre? En snabb undersökning av textutdata från <app>Massif</app> visar att g_strdup nu är den största minnestjuven.

Packit 1470ea
        
Packit 1470ea
Command: ./swell-foop
Packit 1470ea
Packit 1470ea
== 0 ===========================
Packit 1470ea
Heap allocation functions accounted for 87.6% of measured spacetime
Packit 1470ea
Packit 1470ea
Called from:
Packit 1470ea
    7.7% : 0x5A32A5: g_strdup (in /usr/lib/libglib-2.0.so.0.400.6)
Packit 1470ea
Packit 1470ea
    7.6% : 0x43BC9F: (within /usr/lib/libgdk-x11-2.0.so.0.400.9)
Packit 1470ea
Packit 1470ea
    6.9% : 0x510B3C: (within /usr/lib/libfreetype.so.6.3.7)
Packit 1470ea
Packit 1470ea
    5.2% : 0x2A4A6B: __gconv_open (in /lib/tls/libc-2.3.3.so)
Packit 1470ea
        
Packit 1470ea
        

Om vi tittar närmare ser vi dock att det anropas från många, många ställen.

Packit 1470ea
        
Packit 1470ea
== 1 ===========================
Packit 1470ea
Context accounted for  7.7% of measured spacetime
Packit 1470ea
  0x5A32A5: g_strdup (in /usr/lib/libglib-2.0.so.0.400.6)
Packit 1470ea
Packit 1470ea
Called from:
Packit 1470ea
    1.8% : 0x8BF606: gtk_icon_source_copy (in /usr/lib/libgtk-x11-2.0.so.0.400.9)
Packit 1470ea
Packit 1470ea
    1.1% : 0x67AF6B: g_param_spec_internal (in /usr/lib/libgobject-2.0.so.0.400.6)
Packit 1470ea
Packit 1470ea
    0.9% : 0x91FCFC: (within /usr/lib/libgtk-x11-2.0.so.0.400.9)
Packit 1470ea
Packit 1470ea
    0.8% : 0x57EEBF: g_quark_from_string (in /usr/lib/libglib-2.0.so.0.400.6)
Packit 1470ea
Packit 1470ea
  and 155 other insignificant places
Packit 1470ea
        
Packit 1470ea
        

Vi möter nu avtagande resultat för våra optimeringsförsök. Grafen tipsar om en annan möjlig infallsvinkel: både bandet ”other” och ”heap admin” är ganska stort. Detta säger oss att det finns många små allokeringar som görs från olika ställen. Att eliminera dessa blir svårt, men om de kunde grupperas skulle individuella allokeringar kunna vara större och kostnaden för ”heap admin” kunna minskas.

Packit 1470ea
    </section>
Packit 1470ea
    <section id="optimization-massif-TBL-caveats">
Packit 1470ea
        <title>Förbehåll</title>
Packit 1470ea
        

Det finns några saker att vara uppmärksam på: den första är att utrymmestid endast rapporteras som en procentsats, du måste jämföra den med programmets totala storlek för att avgöra om mängden minne är värd titta närmare på. Grafen är med sin vertikala kilobyteaxel bra för detta.

Packit 1470ea
        

Den andra saken är att <app>Massif</app> endast räknar in minne använt av ditt eget program. Resurser som pixmappar lagras i X-servern och räknas inte av <app>Massif</app>. I <app>Swell Foop</app>-exemplet har vi faktiskt bara förflyttat minnesförbrukningen från pixbufar på klientsidan till pixmappar på serversidan. Även om vi fuskade uppstår det prestandavinster. Att behålla bilddata i X-servern gör grafikrutinerna snabbare och tar bort mycket kommunikation mellan processer. Pixmapparna kommer också lagras i ett inhemskt grafikformat vilket ofta är mer kompakt än det 32-bitars RGBA-format som används av gdk_pixbuf. För att mäta effekten av pixmappar och andra X-resurser kan du använda programmet <link href="http://www.freedesktop.org/Software/xrestop">xrestop</link>.

Packit 1470ea
    </section>
Packit 1470ea
</page>