Super-Simple gprof
Published 2011-1-25Goal
Get started with gprof.
Terms
- gprof- shows call graphs, processing time, etc for your application
- gprof-helper.so- This library must be prefix-loaded in order to correct innate problems with- gprof
- gmon.outis generated by your application, not by- gprof
- a.outsubstitute this with the name of your application whereever you see it in documentation
- gccmust use- -pgas a prefix (not suffix) compile option for both the compiler and linker
Example
Let's say we have a multi-threaded application called hello. This is how we get gprof info for it:
First compile it with -pg for gprof support:
CFLAGS="-pg"
LDFLAGS="-pg"
gcc ${CFLAGS} -o hello.o -c hello.c
gcc ${LDFLAGS} -o hello hello.o
Then compile the gprof-helper.c monkey-patch (hot-fix)
wget http://sam.zoy.org/writings/programming/gprof-helper.c
gcc -shared -fPIC gprof-helper.c -o gprof-helper.so -lpthread -ldl
Now load your application with the gprof fix pre-loaded and interpret the results with gprof
LD_PRELOAD=./gprof-helper.so hello
mv gmon.out hello.gmon.out
gprof hello hello.gmon.out > hello.gprof.results.txt
cat hello.gprof.results.txt
Note: If your application is a server, you must implement some sort of remote that can cause it to exit cleanly (return 0, not SIGINT, etc)
Appendix
I advise you to get gprof-helper.c from the original source:
"HOWTO: using gprof with multithreaded applications"
However, since it doesn't appear to be under active development (it's Jan 2011 now and the library hasn't been updated since Dec 2004) I provide it here for convenience.
gprof-helper.c:
/* gprof-helper.c -- preload library to profile pthread-enabled programs
 *
 * Authors: Sam Hocevar <sam at zoy dot org>
 *          Daniel Jönsson <danieljo at fagotten dot org>
 *
 *  This program is free software; you can redistribute it and/or
 *  modify it under the terms of the Do What ---- You Want To
 *  Public License as published by Banlu Kemiyatorn. See
 *  http://sam.zoy.org/projects/COPYING.WTFPL for more details.
 *
 * Compilation example:
 * gcc -shared -fPIC gprof-helper.c -o gprof-helper.so -lpthread -ldl
 *
 * Usage example:
 * LD_PRELOAD=./gprof-helper.so your_program
 */
#define _GNU_SOURCE
#include <sys/time.h>
#include <stdio.h>
#include <stdlib.h>
#include <dlfcn.h>
#include <pthread.h>
static void * wrapper_routine(void *);
/* Original pthread function */
static int (*pthread_create_orig)(pthread_t *__restrict,
                                  __const pthread_attr_t *__restrict,
                                  void *(*)(void *),
                                  void *__restrict) = NULL;
/* Library initialization function */
void wooinit(void) __attribute__((constructor));
void wooinit(void)
{
    pthread_create_orig = dlsym(RTLD_NEXT, "pthread_create");
    fprintf(stderr, "pthreads: using profiling hooks for gprof\n");
    if(pthread_create_orig == NULL)
    {
        char *error = dlerror();
        if(error == NULL)
        {
            error = "pthread_create is NULL";
        }
        fprintf(stderr, "%s\n", error);
        exit(EXIT_FAILURE);
    }
}
/* Our data structure passed to the wrapper */
typedef struct wrapper_s
{
    void * (*start_routine)(void *);
    void * arg;
    pthread_mutex_t lock;
    pthread_cond_t  wait;
    struct itimerval itimer;
} wrapper_t;
/* The wrapper function in charge for setting the itimer value */
static void * wrapper_routine(void * data)
{
    /* Put user data in thread-local variables */
    void * (*start_routine)(void *) = ((wrapper_t*)data)->start_routine;
    void * arg = ((wrapper_t*)data)->arg;
    /* Set the profile timer value */
    setitimer(ITIMER_PROF, &((wrapper_t*)data)->itimer, NULL);
    /* Tell the calling thread that we don't need its data anymore */
    pthread_mutex_lock(&((wrapper_t*)data)->lock);
    pthread_cond_signal(&((wrapper_t*)data)->wait);
    pthread_mutex_unlock(&((wrapper_t*)data)->lock);
    /* Call the real function */
    return start_routine(arg);
}
/* Our wrapper function for the real pthread_create() */
int pthread_create(pthread_t *__restrict thread,
                   __const pthread_attr_t *__restrict attr,
                   void * (*start_routine)(void *),
                   void *__restrict arg)
{
    wrapper_t wrapper_data;
    int i_return;
    /* Initialize the wrapper structure */
    wrapper_data.start_routine = start_routine;
    wrapper_data.arg = arg;
    getitimer(ITIMER_PROF, &wrapper_data.itimer);
    pthread_cond_init(&wrapper_data.wait, NULL);
    pthread_mutex_init(&wrapper_data.lock, NULL);
    pthread_mutex_lock(&wrapper_data.lock);
    /* The real pthread_create call */
    i_return = pthread_create_orig(thread,
                                   attr,
                                   &wrapper_routine,
                                   &wrapper_data);
    /* If the thread was successfully spawned, wait for the data
     * to be released */
    if(i_return == 0)
    {
        pthread_cond_wait(&wrapper_data.wait, &wrapper_data.lock);
    }
    pthread_mutex_unlock(&wrapper_data.lock);
    pthread_mutex_destroy(&wrapper_data.lock);
    pthread_cond_destroy(&wrapper_data.wait);
    return i_return;
}By AJ ONeal
Did I make your day?
 
    (you can learn about the bigger picture I'm working towards on my patreon page )
