1
/* gprof-helper.c -- preload library to profile pthread-enabled programs
3
* Authors: Sam Hocevar <sam at zoy dot org>
4
* Daniel Jönsson <danieljo at fagotten dot org>
6
* This program is free software; you can redistribute it and/or
7
* modify it under the terms of the Do What The Fuck You Want To
8
* Public License as published by Banlu Kemiyatorn. See
9
* http://sam.zoy.org/projects/COPYING.WTFPL for more details.
11
* Compilation example:
12
* gcc -shared -nostdlib -fPIC gprof-helper.c -o gprof-helper.so -lpthread -ldl
15
* LD_PRELOAD=./gprof-helper.so your_program
25
static void * wrapper_routine(void *);
27
/* Original pthread function */
28
static int (*pthread_create_orig)(pthread_t *__restrict,
29
__const pthread_attr_t *__restrict,
31
void *__restrict) = NULL;
33
/* Library initialization function */
36
pthread_create_orig = dlsym(RTLD_NEXT, "pthread_create");
37
fprintf(stderr, "pthreads: using profiling hooks for gprof\n");
38
if(pthread_create_orig == NULL)
40
char *error = dlerror();
43
error = "pthread_create is NULL";
45
fprintf(stderr, "%s", error);
50
/* Our data structure passed to the wrapper */
51
typedef struct wrapper_s
53
void * (*start_routine)(void *);
59
struct itimerval itimer;
63
/* The wrapper function in charge for setting the itimer value */
64
static void * wrapper_routine(void * data)
66
/* Put user data in thread-local variables */
67
void * (*start_routine)(void *) = ((wrapper_t*)data)->start_routine;
68
void * arg = ((wrapper_t*)data)->arg;
70
/* Set the profile timer value */
71
setitimer(ITIMER_PROF, &((wrapper_t*)data)->itimer, NULL);
73
/* Tell the calling thread that we don't need its data anymore */
74
pthread_mutex_lock(&((wrapper_t*)data)->lock);
75
pthread_cond_signal(&((wrapper_t*)data)->wait);
76
pthread_mutex_unlock(&((wrapper_t*)data)->lock);
78
/* Call the real function */
79
return start_routine(arg);
82
/* Our wrapper function for the real pthread_create() */
83
int pthread_create(pthread_t *__restrict thread,
84
__const pthread_attr_t *__restrict attr,
85
void * (*start_routine)(void *),
88
wrapper_t wrapper_data;
91
/* Initialize the wrapper structure */
92
wrapper_data.start_routine = start_routine;
93
wrapper_data.arg = arg;
94
getitimer(ITIMER_PROF, &wrapper_data.itimer);
95
pthread_cond_init(&wrapper_data.wait, NULL);
96
pthread_mutex_init(&wrapper_data.lock, NULL);
97
pthread_mutex_lock(&wrapper_data.lock);
99
/* The real pthread_create call */
100
i_return = pthread_create_orig(thread,
105
/* If the thread was successfully spawned, wait for the data
109
pthread_cond_wait(&wrapper_data.wait, &wrapper_data.lock);
112
pthread_mutex_unlock(&wrapper_data.lock);
113
pthread_mutex_destroy(&wrapper_data.lock);
114
pthread_cond_destroy(&wrapper_data.wait);