- publishing free software manuals
Valgrind 3.3 - Advanced Debugging and Profiling for GNU/Linux applications
by J. Seward, N. Nethercote, J. Weidendorfer and the Valgrind Development Team
Paperback (6"x9"), 164 pages
ISBN 0954612051
RRP £12.95 ($19.95)

Get a printed copy>>>

8.2.3 The Output Graph

The next part is the graph that shows how memory consumption occurred as the program executed:


    KB
19.63^                                                            #
     |                                                            #
     |                                                            #
     |                                                            #
     |                                                            #
     |                                                            #
     |                                                            #
     |                                                           :#
     |                                                           :#
     |                                                           :#
   0-------------------------------------------------------------->ki
     0                                                        121.8

Number of snapshots: 25
 Detailed snapshots: [9, 14 (peak), 24]

Why is most of the graph empty, with only a couple of bars at the very end? By default, Massif uses “instructions executed” as the unit of time. For very short-run programs such as the example, most of the executed instructions involve the loading and dynamic linking of the program. The execution of ‘main’ (and thus the heap allocations) only occur at the very end. For a short-running program like this, we can use the ‘--time-unit=B’ option to specify that we want the time unit to instead be the number of bytes allocated/deallocated on the heap and stack(s).

If we re-run the program under Massif with this option, and then re-run ms_print, we get this more useful graph:


    KB
19.63^                                    #                        
     |                                    #  : .                   
     |                           :        #  : :  : .              
     |                           :        #  : :  : : :  .         
     |                 :         :        #  : :  : : :  : :  .    
     |             :   :         :        #  : :  : : :  : :  : : ,
     |        : @  :   :         :        #  : :  : : :  : :  : : @
     |   : :  : @  :   :         :        #  : :  : : :  : :  : : @
     | : : :  : @  :   :         :        #  : :  : : :  : :  : : @
     | : : :  : @  :   :         :        #  : :  : : :  : :  : : @
   0-------------------------------------------------------------->KB
     0                                                        29.48

Number of snapshots: 25
 Detailed snapshots: [9, 14 (peak), 24]

Each vertical bar represents a snapshot, i.e. a measurement of the memory usage at a certain point in time. The text at the bottom show that 25 snapshots were taken for this program, which is one per heap allocation/deallocation, plus a couple of extras. Massif starts by taking snapshots for every heap allocation/deallocation, but as a program runs for longer, it takes snapshots less frequently. It also discards older snapshots as the program goes on; when it reaches the maximum number of snapshots (100 by default, although changeable with the ‘--max-snapshots’ option) half of them are deleted. This means that a reasonable number of snapshots are always maintained.

Most snapshots are normal, and only basic information is recorded for them. Normal snapshots are represented in the graph by bars consisting of ‘:’ and ‘.’ characters.

Some snapshots are detailed. Information about where allocations happened are recorded for these snapshots, as we will see shortly. Detailed snapshots are represented in the graph by bars consisting of ‘@’ and ‘,’ characters. The text at the bottom show that 3 detailed snapshots were taken for this program (snapshots 9, 14 and 24). By default, every 10th snapshot is detailed, although this can be changed via the ‘--detailed-freq’ option.

Finally, there is at most one peak snapshot. The peak snapshot is a detailed snapshot, and records the point where memory consumption was greatest. The peak snapshot is represented in the graph by a bar consisting of ‘#’ and ‘,’ characters. The text at the bottom shows that snapshot 14 was the peak. Note that for tiny programs that never deallocate heap memory, Massif will not record a peak snapshot.

Some more details about the peak: the peak is determined by looking at every allocation, i.e. it is not just the peak among the regular snapshots. However, recording the true peak is expensive, and so by default Massif records a peak whose size is within 1% of the size of the true peak. See the description of the ‘--peak-inaccuracy’ option below for more details.

The following graph is from an execution of Konqueror, the KDE web browser. It shows what graphs for larger programs look like.


    MB
3.952^                                                         #.
     |                                                 , .. :@@#:
     |                                                ,@ :: :@@#::
     |                                           .@ :@@@ :: :@@#::
     |                                        ,: :@ :@@@ :: :@@#::
     |                                     @@:@: :@ :@@@ :: :@@#:::
     |            .:@@:   .: ::: ::: @  :::@@:@: :@ :@@@ :: :@@#:::
     |         @: ::@@:  ::: ::::::: @  :::@@:@: :@ :@@@ :: :@@#::.
     |       , @: ::@@:: ::: ::::::: @  :::@@:@: :@ :@@@ :: :@@#:::
     |, :::::@ @: ::@@:: ::: ::::::: @  :::@@:@: :@ :@@@ :: :@@#:::
   0-------------------------------------------------------------->Mi
     0                                                        626.4

Number of snapshots: 63
 Detailed snapshots: [3, 4, 10, 11, 15, 16, 29, 33, 34, 36, 39, 41,
                      42, 43, 44, 49, 50, 51, 53, 55, 56, 57 (peak)]

Note that the larger size units are KB, MB, GB, etc. As is typical for memory measurements, these are based on a multiplier of 1024, rather than the standard SI multiplier of 1,000. Strictly speaking, they should be written KiB, MiB, GiB, etc.

ISBN 0954612051Valgrind 3.3 - Advanced Debugging and Profiling for GNU/Linux applicationsSee the print edition