Search code examples
cunixmemoryprofilingvalgrind

Profile per-function memory usage in C in Unix


In Unix , is there any way to get per-function total memory usage for a program written in C? That is, including local variables declared in that function (stack), malloc'd variables (heap) and static variables (bss and data).

I'm aware that Valgrind's Massif can retrieve information on the heap, but what about the other two?


Solution

  • As OP highlighted, each class of storage can be measured with different tool. In the old days (C90), this was relativel simple. Nowadays, much more complex ...

    Static Memory:

    Static memory (static or global), can be measured at the object file level (.o) using the size tool. This will include the memory for all static data in the file - potentially multiple functions. For example the function in o5 need 120+512 (data+bss)

    size o5.o
       text    data     bss     dec     hex filename
        757     512     120    1389     56d o5.o
    

    Automatic Variables

    Measuring automatic variables ("local") is more tricky. Before C99, allocation was fixed at compiled time (with the exception of the now alloca calls). It was possible to inspect the assembly generated code to find out how much stack space is allocated for a function. With C99, which allows VLA, this is no longer possible, for example

    void f(int n) {
        int a[n+3] ;   // Variable Length Array, size calculated at run time.
    }
    

    Also, with optimizations, many compiler are able to detect that two variables can share the same space, as they are not used at the same time. For example, most compilers can tell that x and y can share the same space.

    void f(int n) {
    
       for (int i=0 ; ... ; ... ) {
           int x[30] ;
       } ;
    
       for (int j=0 ; ... ; ... ) {
           int y[30] ;
       } ;
    }
    

    In theory, one can sample the stack size during run time, and try to determine 'typical' size of a function with VLA. For functions without VLA, ofter possible to extract the data from the generated assembly. Mileage will vary.

    Dynamic Variables

    For Dynamic memory allocations (malloc, and friends) - runtime tool are best set to capture how much memory is allocated. However, most tools will not be able to measure actual dynamic usage - they will usually perform analysis of the heap at a specific point of time, which could be more or less than what the function is actually using.