Back to index

glibc  2.9
profil.c
Go to the documentation of this file.
00001 /* Low-level statistical profiling support function.  Mostly POSIX.1 version.
00002    Copyright (C) 1996,1997,1998,2002,2004,2005,2006
00003        Free Software Foundation, Inc.
00004    This file is part of the GNU C Library.
00005 
00006    The GNU C Library is free software; you can redistribute it and/or
00007    modify it under the terms of the GNU Lesser General Public
00008    License as published by the Free Software Foundation; either
00009    version 2.1 of the License, or (at your option) any later version.
00010 
00011    The GNU C Library is distributed in the hope that it will be useful,
00012    but WITHOUT ANY WARRANTY; without even the implied warranty of
00013    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014    Lesser General Public License for more details.
00015 
00016    You should have received a copy of the GNU Lesser General Public
00017    License along with the GNU C Library; if not, write to the Free
00018    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
00019    02111-1307 USA.  */
00020 
00021 #include <sys/types.h>
00022 #include <unistd.h>
00023 #include <errno.h>
00024 #include <signal.h>
00025 #include <sys/time.h>
00026 #include <libc-internal.h>
00027 
00028 #ifndef SIGPROF
00029 
00030 #include <gmon/profil.c>
00031 
00032 #else
00033 
00034 static u_short *samples;
00035 static size_t nsamples;
00036 static size_t pc_offset;
00037 static u_int pc_scale;
00038 
00039 static inline void
00040 profil_count (void *pc)
00041 {
00042   size_t i = (pc - pc_offset - (void *) 0) / 2;
00043 
00044   if (sizeof (unsigned long long int) > sizeof (size_t))
00045     i = (unsigned long long int) i * pc_scale / 65536;
00046   else
00047     i = i / 65536 * pc_scale + i % 65536 * pc_scale / 65536;
00048 
00049   if (i < nsamples)
00050     ++samples[i];
00051 }
00052 
00053 /* Get the machine-dependent definition of `profil_counter', the signal
00054    handler for SIGPROF.  It calls `profil_count' (above) with the PC of the
00055    interrupted code.  */
00056 #include "profil-counter.h"
00057 
00058 /* Enable statistical profiling, writing samples of the PC into at most
00059    SIZE bytes of SAMPLE_BUFFER; every processor clock tick while profiling
00060    is enabled, the system examines the user PC and increments
00061    SAMPLE_BUFFER[((PC - OFFSET) / 2) * SCALE / 65536].  If SCALE is zero,
00062    disable profiling.  Returns zero on success, -1 on error.  */
00063 
00064 int
00065 __profil (u_short *sample_buffer, size_t size, size_t offset, u_int scale)
00066 {
00067   struct sigaction act;
00068   struct itimerval timer;
00069 #ifndef IS_IN_rtld
00070   static struct sigaction oact;
00071   static struct itimerval otimer;
00072 # define oact_ptr &oact
00073 # define otimer_ptr &otimer
00074 
00075   if (sample_buffer == NULL)
00076     {
00077       /* Disable profiling.  */
00078       if (samples == NULL)
00079        /* Wasn't turned on.  */
00080        return 0;
00081 
00082       if (__setitimer (ITIMER_PROF, &otimer, NULL) < 0)
00083        return -1;
00084       samples = NULL;
00085       return __sigaction (SIGPROF, &oact, NULL);
00086     }
00087 
00088  if (samples)
00089     {
00090       /* Was already turned on.  Restore old timer and signal handler
00091         first.  */
00092       if (__setitimer (ITIMER_PROF, &otimer, NULL) < 0
00093          || __sigaction (SIGPROF, &oact, NULL) < 0)
00094        return -1;
00095     }
00096 #else
00097  /* In ld.so profiling should never be disabled once it runs.  */
00098  //assert (sample_buffer != NULL);
00099 # define oact_ptr NULL
00100 # define otimer_ptr NULL
00101 #endif
00102 
00103   samples = sample_buffer;
00104   nsamples = size / sizeof *samples;
00105   pc_offset = offset;
00106   pc_scale = scale;
00107 
00108   act.sa_handler = (sighandler_t) &profil_counter;
00109   act.sa_flags = SA_RESTART;
00110   __sigfillset (&act.sa_mask);
00111   if (__sigaction (SIGPROF, &act, oact_ptr) < 0)
00112     return -1;
00113 
00114   timer.it_value.tv_sec = 0;
00115   timer.it_value.tv_usec = 1000000 / __profile_frequency ();
00116   timer.it_interval = timer.it_value;
00117   return __setitimer (ITIMER_PROF, &timer, otimer_ptr);
00118 }
00119 weak_alias (__profil, profil)
00120 
00121 #endif