Re: libc/1427: gprof does not profile threads <synopsis of the problem

Dan Kegel (dkegel@ixiacom.com)
Wed, 13 Mar 2002 15:17:38 -0800


http://bugs.gnu.org/cgi-bin/gnatsweb.pl?cmd=view%20audit-trail&database=default&pr=1427

IMHO gprof not working on Linux is getting to be
annoying for embedded developers adopting Linux.
The workaround is to have each new thread call setitimer.
Users can do this in their programs (see
http://sam.zoy.org/doc/programming/gprof.html )
but it's not well known for some reason. Perhaps everyone
figures if the workaround was so easy, it would have been fixed
in glibc long ago.

So let's break the logjam and fix glibc's linuxthreads' pthread_create to do
this.
Here's an untested patch that changes pthread_create
to sense (using sigaction) whether profiling is
active, and if so, arranges for the new thread to
transparantly call setitimer before calling the user's
thread main.

Comments welcome...
- Dan

--- glibc-2.2.4/linuxthreads/pthread.c.orig Wed Mar 13 12:01:42 2002
+++ glibc-2.2.4/linuxthreads/pthread.c Wed Mar 13 12:31:23 2002
@@ -637,15 +637,73 @@

/* Thread creation */

+/* profiling support: struct used to tell child thread how to call setitimer
*/
+typedef struct pthread_create_wrapper_s {
+ void *(*start_routine) (void *);
+ void *arg;
+
+ pthread_mutex_t lock;
+ pthread_cond_t wait;
+
+ struct itimerval itimer;
+} pthread_create_wrapper_t;
+
+/* profiling support: wrapper around child thread start routine to call
setitimer */
+static void *pthread_create_start_wrapper(void *data)
+{
+ /* Put user data in thread-local variables */
+ void *(*start_routine) (void *) = ((pthread_create_wrapper_t *)
data)->start_routine;
+ void *arg = ((pthread_create_wrapper_t *) data)->arg;
+
+ /* Turn on a profiling timer for this new thread. */
+ setitimer(ITIMER_PROF, &((pthread_create_wrapper_t *) data)->itimer, NULL);
+
+ /* Tell the calling thread that we don't need its data anymore */
+ __pthread_mutex_lock(&((pthread_create_wrapper_t *) data)->lock);
+ __pthread_cond_signal(&((pthread_create_wrapper_t *) data)->wait);
+ __pthread_mutex_unlock(&((pthread_create_wrapper_t *) data)->lock);
+
+ /* Call the real function */
+ return start_routine(arg);
+}
+
int __pthread_create_2_1(pthread_t *thread, const pthread_attr_t *attr,
void * (*start_routine)(void *), void *arg)
{
+ pthread_create_wrapper_t wrapper_data;
+ struct sigaction oact;
+ int profiling;
+
pthread_descr self = thread_self();
struct pthread_request request;
int retval;
if (__builtin_expect (__pthread_manager_request, 0) < 0) {
if (__pthread_initialize_manager() < 0) return EAGAIN;
}
+
+ /* profiling support:
+ * See if profiling is on.
+ * We know glibc uses sigaction for profiling,
+ * so it's safe to check sa_sigaction.
+ */
+ profiling = 0;
+ if (0 == sigaction(SIGPROF, 0, &oact)
+ && (oact.sa_sigaction != SIG_IGN)
+ && (oact.sa_sigaction != SIG_DFL)) {
+ profiling = 1;
+
+ /* Arrange for child thread to call setitimer so his cpu time will
+ * be profiled
+ */
+ wrapper_data.start_routine = start_routine;
+ start_routine = pthread_create_start_wrapper;
+ 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);
+ }
+
request.req_thread = self;
request.req_kind = REQ_CREATE;
request.req_args.create.attr = attr;
@@ -658,6 +716,18 @@
retval = THREAD_GETMEM(self, p_retcode);
if (__builtin_expect (retval, 0) == 0)
*thread = (pthread_t) THREAD_GETMEM(self, p_retval);
+
+ /* profiling support:
+ * Wait for child thread to call setitimer, then free resources
+ */
+ if (profiling) {
+ if (retval == 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 retval;
}
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/