public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
* Re: libc/1427: gprof does not profile threads <synopsis of the problem  (one li\ne)>
@ 2002-03-13 23:17 Dan Kegel
  2002-03-13 23:34 ` Ulrich Drepper
  0 siblings, 1 reply; 21+ messages in thread
From: Dan Kegel @ 2002-03-13 23:17 UTC (permalink / raw)
  To: darkeye, libc-gnats, gnats-admin, sam, Xavier.Leroy, linux-kernel

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;
 }

^ permalink raw reply	[flat|nested] 21+ messages in thread

end of thread, other threads:[~2002-03-16 18:21 UTC | newest]

Thread overview: 21+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2002-03-13 23:17 libc/1427: gprof does not profile threads <synopsis of the problem (one li\ne)> Dan Kegel
2002-03-13 23:34 ` Ulrich Drepper
2002-03-14  0:19   ` Dan Kegel
2002-03-14  1:28     ` libc/1427: gprof does not profile threads <synopsis of the problem Alan Cox
2002-03-14  1:08       ` Dan Kegel
2002-03-14  3:00         ` Alan Cox
2002-03-14  2:55           ` Jeff Garzik
2002-03-14  3:26             ` David Rees
2002-03-14 15:51               ` Dave McCracken
2002-03-14 15:58         ` Daniel Phillips
2002-03-14  7:08     ` libc/1427: gprof does not profile threads <synopsis of the problem (one li\ne)> Jakub Jelinek
2002-03-14 13:19       ` John Levon
2002-03-15 21:56       ` Dan Kegel
2002-03-16  0:19         ` Ulrich Drepper
2002-03-16  1:41           ` libc/1427: gprof does not profile threads <synopsis of the Alan Cox
2002-03-16  2:40           ` libc/1427: gprof does not profile threads <synopsis of the problem (one li\ne)> Erik Andersen
2002-03-16 13:12           ` Olaf Dietsche
2002-03-16 16:57           ` Daniel Egger
2002-03-14 16:07     ` Daniel Phillips
2002-03-14 16:25       ` Richard Gooch
2002-03-14 16:47         ` Daniel Phillips

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox