<?xml version="1.0" encoding="utf-8"?>
<page xmlns="http://projectmallard.org/1.0/" type="guide" style="task" id="massif" xml:lang="cs">
    <info>
      <link type="guide" xref="index#massif"/>
    
    <mal:credit xmlns:mal="http://projectmallard.org/1.0/" type="translator copyright">
      <mal:name>Marek Černocký</mal:name>
      <mal:email>marek@manet.cz</mal:email>
      <mal:years>2010, 2013</mal:years>
    </mal:credit>
  </info>
      <title>Using <app>Massif</app> for Profiling Memory Use in GNOME Software</title>

    <p>
        This article describes how to use the <app>Massif</app> heap profiler with GNOME applications. We describe how to invoke, interpret, and act on the output of <app>Massif</app>. The <app>Swell Foop</app> game is used as an example. </p>
   <section id="optimization-massif-TBL-intro">
        <title>Úvod</title>
        <p>
            <app>Massif</app> is a member of the <link href="http://valgrind.org/">valgrind</link> suite of memory-profiling tools. Its purpose is to give a detailed view of dynamic memory usage during the lifetime of the program. Specifically it records the memory use of the heap and the stack.
        </p>
        <p>
            The heap is the region of memory which is allocated with functions like malloc. It grows on demand and is usually the largest region of memory in a program. The stack is where all the local data for functions is stored. This includes the "automatic" variables in C and the return address for subroutines. The stack is typically a lot smaller and a lot more active than the heap. We won't consider the stack explicitly since <app>Massif</app> treats it as though it were just another part of the heap. <app>Massif</app> also gives information about how much memory is used to manage the heap.  </p>
        <p>
            <app>Massif</app> produces two output files: a graphical overview in a postscript file and a detailed breakdown in a text file.
        </p>
    </section>
    <section id="optimization-massif-TBL-using-massif">
        <title>Using <app>Massif</app> with GNOME</title>
        <p>
          <app>Massif</app> has very few options and for many programs does not need them. However for GNOME applications, where memory allocation might be buried deep in either glib or GTK, the number of levels down the call-stack Massif descends needs to be increased. This is achieved using the --depth parameter. By default this is 3; increasing it to 5 will guarantee the call-stack reaches down to your code. One or two more levels may also be desirable to provide your code with some context. Since the level of detail becomes quickly overwhelming it is best to start with the smaller depth parameter and only increase it when it becomes apparent that it isn't sufficient.
        </p>
        <p>
            It is also useful to tell <app>Massif</app> which functions allocate memory in glib. It removes an unnecessary layer of function calls from the reports and gives you a clearer idea of what code is allocating memory. The allocating functions in glib are g_malloc, g_malloc0, g_realloc, g_try_malloc, and g_mem_chunk_alloc. You use the --alloc-fn option to tell Massif about them.
        </p>
        <p>Váš příkazový řádek by pro předchozí měl vypadat nějak takto:</p>
        <code>
valgrind --tool=massif --depth=5  --alloc-fn=g_malloc --alloc-fn=g_realloc --alloc-fn=g_try_malloc \
         --alloc-fn=g_malloc0 --alloc-fn=g_mem_chunk_alloc swell-foop
        </code>
        <p>
            <app>Swell Foop</app> is the program we will be using as an example. Be warned that, since valgrind emulates the CPU, it will run <em>very</em> slowly. You will also need a lot of memory. </p>
    </section>
    <section id="optimization-massif-TBL-interpreting-results">
        <title>Interpretace výsledků</title>
        <p>
            The graphical output of <app>Massif</app> is largely self explanatory. Each band represents the memory allocated by one function over time. Once you identify which bands are using the most memory, usually the big thick ones at the top you will have to consult the text file for the details.
        </p>
        <p>Textový soubor je uspořádán do hierarchie oddílů, na začátku je seznam nejhorších uživatelů paměti v sestupném pořadí podle časoprostoru. Nasledují další oddíly, každý rozebírající výsledky do větších podrobností, jak se postupně zanořujete do zásobníku volání. Pro ilustraci použijeme výstup předchozího příkazu.</p>
        <figure>
            <title><app>Massif</app> output for the unoptimized version of the <app>Swell Foop</app> program.</title>
            <media type="image" src="figures/massif-before.png"/>
         </figure>
        <p>
            <link xref="optimization-massif-FIG-output-unoptimized"/>
            shows a typical postscript output from
            <app>Massif</app>. This is the result you would get from
            playing a single game of <app>Swell Foop</app> (version
            2.8.0) and then quitting. The postscript file will have a
            name like <file>massif.12345.ps</file> and the text file
            will be called <file>massif.12345.txt</file>. The number
            in the middle is the process ID of the program that was
            examined. If you actually try this example you will find
            two versions of each file, with slightly different
            numbers, this is because <app>Swell Foop</app> starts a
            second process and <app>Massif</app>
            follows that too. We will ignore this second process, it
            consumes very little memory.</p>
        <p>V horní části grafu vidíme velký žlutý pás označený gdk_pixbuf.new. Ten se zdá jako nejlepší kandidát na optimalizaci, ale nejdříve potřebujeme použít textový soubor, abychom našli co gdk_pixbuf_new volá. Začátek textového souboru vypadá nějak takto:</p>
        <code>
Příkaz: ./swell-foop 

== 0 ===========================
Funkce pro alokaci haldy zodpovídají za 90,40% měřeného časoprostoru

Voláno z:
  28.8% : 0x6BF83A: gdk_pixbuf_new (v /usr/lib/libgdk_pixbuf-2.0.so.0.400.9)

    6.1% : 0x5A32A5: g_strdup (v /usr/lib/libglib-2.0.so.0.400.6)

    5.9% : 0x510B3C: (uvnitř /usr/lib/libfreetype.so.6.3.7)

    3.5% : 0x2A4A6B: __gconv_open (v /lib/tls/libc-2.3.3.so)
        </code>
        <p>Řádek se znaky „=“ uvádí, jak hluboko v zásobníku sledování jsme zanoření, v tomto konkrétním případě jsem úplně nahoře. Následuje seznam nejnáročnějších uživatelů paměti v sestupném pořadí podle časoprostoru. Časoprostor je veličina představující jak moc paměti je použito a jako dlouho je použita. Odpovídá to ploše pásu v grafu. Tato část souboru nám říká, co již víme: nejvíce časoprostoru si zabrala funkce gdk_pisbuf_new. Abychom věděli, co gdk_pixbuf_new volá, musíme hledat v textovém souboru dále:</p>
        <code>
== 4 ===========================
Kontext zodpovídá za 28,8% měřeného časového prostoru
  0x6BF83A: gdk_pixbuf_new (v /usr/lib/libgdk_pixbuf-2.0.so.0.400.9)
  0x3A998998: (uvnitř /usr/lib/gtk-2.0/2.4.0/loaders/libpixbufloader-png.so)
  0x6C2760: (uvnitř /usr/lib/libgdk_pixbuf-2.0.so.0.400.9)
  0x6C285E: gdk_pixbuf_new_from_file (v /usr/lib/libgdk_pixbuf-2.0.so.0.400.9)

Voláno z:
  27.8% : 0x804C1A3: load_scenario (swell-foop.c:463)

    0.9% : 0x3E8095E: (uvnitř /usr/lib/libgnomeui-2.so.0.792.0)

  a 1 dalšího nedůležitého místa
        </code>
        <p>
            The first line tells us we are now four levels deep into the stack. Below it is a listing of the function calls that leads from here to gdk_pixbuf_new. Finally there is a list of functions that are at the next level down and call these functions. There are, of course, also entries for levels 1, 2, and 3, but this is the first level to reach right down through the GDK code to the <app>Swell Foop</app> code. From this listing, we can see instantly that the problem code is load_scenario.
        </p>
        <p>Nyní, když víme, která část našeho kódu používá všechen časoprostor, můžeme se na ni podívat a zjistit proč. Ukáže se, že load_scenario načítá pixbuf ze souboru a potom nikdy neuvolní paměť. Tím mám zjištěno, kde je v kódu problém a muže jej začít opravovat.</p>
    </section>
    <section id="optimization-massif-TBL-acting-on-results">
        <title>Využití výsledků</title>
        <p>Omezení spotřeby časoprostoru je dobré, ale existují dva způsoby jak jej zredukovat a nejsou rovnocenné. Buď můžete omezit množství alokované paměti nebo omezit dobu, po kterou je alokováno. Na chvíli si představte modelový systém, ve kterém běží jen dva procesy. Oba procesy využívají téměř všechnu fyzickou paměť a když ji vyčerpají celou, začne systém odkládat na disk a vše se zpomalí. Je zjevné, že když omezíme použití paměti rovnoměrně každým z obou procesů, mohou klidně běžet naráz, aniž by bylo potřeba odkládat na disk. Když místo toho omezíme čas, po který je paměť alokována, rovnoměrně u obou programů, mohou opět běžet v klidu současně, ale jen ve chvílích, kdy se nesejdou jejich největší požadavky na paměť. Proto je lepší omezit množství alokované paměti.</p>
        <p>
            Unfortunately, the choice of optimization is also
	    constrained by the needs of the program. The size of the
	    pixbuf data in <app>Swell Foop</app> is determined by the
	    size of the game's graphics and cannot be easily
	    reduced. However, the amount of time it spends loaded into
	    memory can be drastically reduced. <link xref="optimization-massif-FIG-output-optimized"/> shows the <app>Massif</app> analysis of <app>Swell Foop</app> after being altered to dispose of the pixbufs once the images have been loaded into the X server.
        </p>
        <figure>
            <title><app>Massif</app> output for the optimized <app>Swell Foop</app> program.</title>
           <media type="image" src="figures/massif-after.png"/>
            </figure>
        <p>Využití časoprostoru funkcí gdk_pixbuf_new představuje nyní tenčí pás, který jen zřídka povyskočí (je teď o šestnáct pozic níž a vyplněný purpurovou barvou). Jako bonus poklesl špičkový odběr paměti o 200 kB, protože špička se objeví před dalšími alokacemi paměti. Pokud běží naráz dva takové podobné procesy, je šance, že takové dvě paměťové špičky nastanou naráz, a tím vznikne riziko odkládání na disk, docela malá.</p>
        <p>
            Can we do better ? A quick examination of <app>Massif</app>'s text output reveals: g_strdup to be the new major offender.
        </p>
        <code>
Příkaz: ./swell-foop

== 0 ===========================
Funkce pro alokaci haldy zodpovídají za 87,6% měřeného časoprostoru

Voláno z:
    7.7% : 0x5A32A5: g_strdup (v /usr/lib/libglib-2.0.so.0.400.6)

    7.6% : 0x43BC9F: (uvnitř /usr/lib/libgdk-x11-2.0.so.0.400.9)

    6.9% : 0x510B3C: (uvnitř /usr/lib/libfreetype.so.6.3.7)

    5.2% : 0x2A4A6B: __gconv_open (v /lib/tls/libc-2.3.3.so)
        </code>
        <p>Když se na to podíváme blíže, uvidíme, že je volán na mnoha, opravdu mnoha místech.</p>
        <code>
== 1 ===========================
Kontext zodpovídá za 7,7% měřeného časového prostoru
  0x5A32A5: g_strdup (v /usr/lib/libglib-2.0.so.0.400.6)

Called from:
    1.8% : 0x8BF606: gtk_icon_source_copy (v /usr/lib/libgtk-x11-2.0.so.0.400.9)

    1.1% : 0x67AF6B: g_param_spec_internal (v /usr/lib/libgobject-2.0.so.0.400.6)

    0.9% : 0x91FCFC: (uvnitř /usr/lib/libgtk-x11-2.0.so.0.400.9)

    0.8% : 0x57EEBF: g_quark_from_string (v /usr/lib/libglib-2.0.so.0.400.6)

  a 155 dalších nedůležitých míst
        </code>
        <p>Nyní stojíme oproti klesající návratnost naší snahy o optimalizaci. Graf nám poradí jiný možný přístup: Pásy „ostatní“ a „správa haldy“ jsou docela velké. To nám říká, že je zde spousta malých alokací prováděných na různých místech. Odstranění něčeho takového může být obtížné, ale když je sloučíme do jediné alokace, může být větší a „správa haldy“ se tím zmenší.</p>
    </section>
    <section id="optimization-massif-TBL-caveats">
        <title>Upozornění</title>
        <p>Je zde pár věcí, na které je třeba si dávat pozor: Zaprvé, časové úseky jsou uváděny jako procentuální část, musíte je vztáhnout na celkovou velikost programu, abyste mohli usoudit, zda množství paměti stojí za sledování. Dobrý je k tomu graf s hodnotami v kilobajtech na svislé ose.</p>
        <p>
            Secondly, <app>Massif</app> only takes into account the memory used by your own program. Resources like pixmaps are stored in the X server and aren't considered by <app>Massif</app>. In the <app>Swell Foop</app> example we have actually only moved the memory consumption from client-side pixbufs to server-side pixmaps. Even though we cheated there are performance gains. Keeping the image data in the X server makes the graphics routines quicker and removes a lot of inter-process communication. Also, the pixmaps will be stored in a native graphics format which is often more compact than the 32-bit RGBA format used by gdk_pixbuf. To measure the effect of pixmaps, and other X resources use the <link href="http://www.freedesktop.org/Software/xrestop">xrestop</link> program.
        </p>
    </section>
</page>
