Back to index

glibc  2.9
gmon.c
Go to the documentation of this file.
00001 /*-
00002  * Copyright (c) 1983, 1992, 1993
00003  *     The Regents of the University of California.  All rights reserved.
00004  *
00005  * Redistribution and use in source and binary forms, with or without
00006  * modification, are permitted provided that the following conditions
00007  * are met:
00008  * 1. Redistributions of source code must retain the above copyright
00009  *    notice, this list of conditions and the following disclaimer.
00010  * 2. Redistributions in binary form must reproduce the above copyright
00011  *    notice, this list of conditions and the following disclaimer in the
00012  *    documentation and/or other materials provided with the distribution.
00013  * 4. Neither the name of the University nor the names of its contributors
00014  *    may be used to endorse or promote products derived from this software
00015  *    without specific prior written permission.
00016  *
00017  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
00018  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00019  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00020  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
00021  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
00022  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
00023  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
00024  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00025  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
00026  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
00027  * SUCH DAMAGE.
00028  */
00029 #include <sys/param.h>
00030 #include <sys/time.h>
00031 #include <sys/gmon.h>
00032 #include <sys/gmon_out.h>
00033 #include <sys/uio.h>
00034 
00035 #include <errno.h>
00036 #include <stdio.h>
00037 #include <fcntl.h>
00038 #include <unistd.h>
00039 
00040 #include <stdio.h>
00041 #include <stdlib.h>
00042 #include <string.h>
00043 #include <unistd.h>
00044 #include <libc-internal.h>
00045 #include <not-cancel.h>
00046 
00047 #ifdef USE_IN_LIBIO
00048 # include <wchar.h>
00049 #endif
00050 
00051 /*  Head of basic-block list or NULL. */
00052 struct __bb *__bb_head attribute_hidden;
00053 
00054 struct gmonparam _gmonparam attribute_hidden = { GMON_PROF_OFF };
00055 
00056 /*
00057  * See profil(2) where this is described:
00058  */
00059 static int    s_scale;
00060 #define              SCALE_1_TO_1  0x10000L
00061 
00062 #define ERR(s) write_not_cancel (STDERR_FILENO, s, sizeof (s) - 1)
00063 
00064 void moncontrol (int mode);
00065 void __moncontrol (int mode);
00066 static void write_hist (int fd) internal_function;
00067 static void write_call_graph (int fd) internal_function;
00068 static void write_bb_counts (int fd) internal_function;
00069 
00070 /*
00071  * Control profiling
00072  *     profiling is what mcount checks to see if
00073  *     all the data structures are ready.
00074  */
00075 void
00076 __moncontrol (mode)
00077      int mode;
00078 {
00079   struct gmonparam *p = &_gmonparam;
00080 
00081   /* Don't change the state if we ran into an error.  */
00082   if (p->state == GMON_PROF_ERROR)
00083     return;
00084 
00085   if (mode)
00086     {
00087       /* start */
00088       __profil((void *) p->kcount, p->kcountsize, p->lowpc, s_scale);
00089       p->state = GMON_PROF_ON;
00090     }
00091   else
00092     {
00093       /* stop */
00094       __profil(NULL, 0, 0, 0);
00095       p->state = GMON_PROF_OFF;
00096     }
00097 }
00098 weak_alias (__moncontrol, moncontrol)
00099 
00100 
00101 void
00102 __monstartup (lowpc, highpc)
00103      u_long lowpc;
00104      u_long highpc;
00105 {
00106   register int o;
00107   char *cp;
00108   struct gmonparam *p = &_gmonparam;
00109 
00110   /*
00111    * round lowpc and highpc to multiples of the density we're using
00112    * so the rest of the scaling (here and in gprof) stays in ints.
00113    */
00114   p->lowpc = ROUNDDOWN(lowpc, HISTFRACTION * sizeof(HISTCOUNTER));
00115   p->highpc = ROUNDUP(highpc, HISTFRACTION * sizeof(HISTCOUNTER));
00116   p->textsize = p->highpc - p->lowpc;
00117   p->kcountsize = ROUNDUP(p->textsize / HISTFRACTION, sizeof(*p->froms));
00118   p->hashfraction = HASHFRACTION;
00119   p->log_hashfraction = -1;
00120   /* The following test must be kept in sync with the corresponding
00121      test in mcount.c.  */
00122   if ((HASHFRACTION & (HASHFRACTION - 1)) == 0) {
00123       /* if HASHFRACTION is a power of two, mcount can use shifting
00124         instead of integer division.  Precompute shift amount. */
00125       p->log_hashfraction = ffs(p->hashfraction * sizeof(*p->froms)) - 1;
00126   }
00127   p->fromssize = p->textsize / HASHFRACTION;
00128   p->tolimit = p->textsize * ARCDENSITY / 100;
00129   if (p->tolimit < MINARCS)
00130     p->tolimit = MINARCS;
00131   else if (p->tolimit > MAXARCS)
00132     p->tolimit = MAXARCS;
00133   p->tossize = p->tolimit * sizeof(struct tostruct);
00134 
00135   cp = calloc (p->kcountsize + p->fromssize + p->tossize, 1);
00136   if (! cp)
00137     {
00138       ERR("monstartup: out of memory\n");
00139       p->tos = NULL;
00140       p->state = GMON_PROF_ERROR;
00141       return;
00142     }
00143   p->tos = (struct tostruct *)cp;
00144   cp += p->tossize;
00145   p->kcount = (HISTCOUNTER *)cp;
00146   cp += p->kcountsize;
00147   p->froms = (ARCINDEX *)cp;
00148 
00149   p->tos[0].link = 0;
00150 
00151   o = p->highpc - p->lowpc;
00152   if (p->kcountsize < (u_long) o)
00153     {
00154 #ifndef hp300
00155       s_scale = ((float)p->kcountsize / o ) * SCALE_1_TO_1;
00156 #else
00157       /* avoid floating point operations */
00158       int quot = o / p->kcountsize;
00159 
00160       if (quot >= 0x10000)
00161        s_scale = 1;
00162       else if (quot >= 0x100)
00163        s_scale = 0x10000 / quot;
00164       else if (o >= 0x800000)
00165        s_scale = 0x1000000 / (o / (p->kcountsize >> 8));
00166       else
00167        s_scale = 0x1000000 / ((o << 8) / p->kcountsize);
00168 #endif
00169     } else
00170       s_scale = SCALE_1_TO_1;
00171 
00172   __moncontrol(1);
00173 }
00174 weak_alias (__monstartup, monstartup)
00175 
00176 
00177 static void
00178 internal_function
00179 write_hist (fd)
00180      int fd;
00181 {
00182   u_char tag = GMON_TAG_TIME_HIST;
00183   struct gmon_hist_hdr thdr __attribute__ ((aligned (__alignof__ (char *))));
00184 
00185   if (_gmonparam.kcountsize > 0)
00186     {
00187       struct iovec iov[3] =
00188         {
00189          { &tag, sizeof (tag) },
00190          { &thdr, sizeof (struct gmon_hist_hdr) },
00191          { _gmonparam.kcount, _gmonparam.kcountsize }
00192        };
00193 
00194       *(char **) thdr.low_pc = (char *) _gmonparam.lowpc;
00195       *(char **) thdr.high_pc = (char *) _gmonparam.highpc;
00196       *(int32_t *) thdr.hist_size = (_gmonparam.kcountsize
00197                                  / sizeof (HISTCOUNTER));
00198       *(int32_t *) thdr.prof_rate = __profile_frequency ();
00199       strncpy (thdr.dimen, "seconds", sizeof (thdr.dimen));
00200       thdr.dimen_abbrev = 's';
00201 
00202       writev_not_cancel_no_status (fd, iov, 3);
00203     }
00204 }
00205 
00206 
00207 static void
00208 internal_function
00209 write_call_graph (fd)
00210      int fd;
00211 {
00212 #define NARCS_PER_WRITEV    32
00213   u_char tag = GMON_TAG_CG_ARC;
00214   struct gmon_cg_arc_record raw_arc[NARCS_PER_WRITEV]
00215     __attribute__ ((aligned (__alignof__ (char*))));
00216   ARCINDEX from_index, to_index;
00217   u_long from_len;
00218   u_long frompc;
00219   struct iovec iov[2 * NARCS_PER_WRITEV];
00220   int nfilled;
00221 
00222   for (nfilled = 0; nfilled < NARCS_PER_WRITEV; ++nfilled)
00223     {
00224       iov[2 * nfilled].iov_base = &tag;
00225       iov[2 * nfilled].iov_len = sizeof (tag);
00226 
00227       iov[2 * nfilled + 1].iov_base = &raw_arc[nfilled];
00228       iov[2 * nfilled + 1].iov_len = sizeof (struct gmon_cg_arc_record);
00229     }
00230 
00231   nfilled = 0;
00232   from_len = _gmonparam.fromssize / sizeof (*_gmonparam.froms);
00233   for (from_index = 0; from_index < from_len; ++from_index)
00234     {
00235       if (_gmonparam.froms[from_index] == 0)
00236        continue;
00237 
00238       frompc = _gmonparam.lowpc;
00239       frompc += (from_index * _gmonparam.hashfraction
00240                * sizeof (*_gmonparam.froms));
00241       for (to_index = _gmonparam.froms[from_index];
00242           to_index != 0;
00243           to_index = _gmonparam.tos[to_index].link)
00244        {
00245          struct arc
00246            {
00247              char *frompc;
00248              char *selfpc;
00249              int32_t count;
00250            }
00251          arc;
00252 
00253          arc.frompc = (char *) frompc;
00254          arc.selfpc = (char *) _gmonparam.tos[to_index].selfpc;
00255          arc.count  = _gmonparam.tos[to_index].count;
00256          memcpy (raw_arc + nfilled, &arc, sizeof (raw_arc [0]));
00257 
00258          if (++nfilled == NARCS_PER_WRITEV)
00259            {
00260              writev_not_cancel_no_status (fd, iov, 2 * nfilled);
00261              nfilled = 0;
00262            }
00263        }
00264     }
00265   if (nfilled > 0)
00266     writev_not_cancel_no_status (fd, iov, 2 * nfilled);
00267 }
00268 
00269 
00270 static void
00271 internal_function
00272 write_bb_counts (fd)
00273      int fd;
00274 {
00275   struct __bb *grp;
00276   u_char tag = GMON_TAG_BB_COUNT;
00277   size_t ncounts;
00278   size_t i;
00279 
00280   struct iovec bbhead[2] =
00281     {
00282       { &tag, sizeof (tag) },
00283       { &ncounts, sizeof (ncounts) }
00284     };
00285   struct iovec bbbody[8];
00286   size_t nfilled;
00287 
00288   for (i = 0; i < (sizeof (bbbody) / sizeof (bbbody[0])); i += 2)
00289     {
00290       bbbody[i].iov_len = sizeof (grp->addresses[0]);
00291       bbbody[i + 1].iov_len = sizeof (grp->counts[0]);
00292     }
00293 
00294   /* Write each group of basic-block info (all basic-blocks in a
00295      compilation unit form a single group). */
00296 
00297   for (grp = __bb_head; grp; grp = grp->next)
00298     {
00299       ncounts = grp->ncounts;
00300       writev_not_cancel_no_status (fd, bbhead, 2);
00301       for (nfilled = i = 0; i < ncounts; ++i)
00302        {
00303          if (nfilled > (sizeof (bbbody) / sizeof (bbbody[0])) - 2)
00304            {
00305              writev_not_cancel_no_status (fd, bbbody, nfilled);
00306              nfilled = 0;
00307            }
00308 
00309          bbbody[nfilled++].iov_base = (char *) &grp->addresses[i];
00310          bbbody[nfilled++].iov_base = &grp->counts[i];
00311        }
00312       if (nfilled > 0)
00313        writev_not_cancel_no_status (fd, bbbody, nfilled);
00314     }
00315 }
00316 
00317 
00318 static void
00319 write_gmon (void)
00320 {
00321     struct gmon_hdr ghdr __attribute__ ((aligned (__alignof__ (int))));
00322     int fd = -1;
00323     char *env;
00324 
00325 #ifndef O_NOFOLLOW
00326 # define O_NOFOLLOW  0
00327 #endif
00328 
00329     env = getenv ("GMON_OUT_PREFIX");
00330     if (env != NULL && !__libc_enable_secure)
00331       {
00332        size_t len = strlen (env);
00333        char buf[len + 20];
00334        __snprintf (buf, sizeof (buf), "%s.%u", env, __getpid ());
00335        fd = open_not_cancel (buf, O_CREAT|O_TRUNC|O_WRONLY|O_NOFOLLOW, 0666);
00336       }
00337 
00338     if (fd == -1)
00339       {
00340        fd = open_not_cancel ("gmon.out", O_CREAT|O_TRUNC|O_WRONLY|O_NOFOLLOW,
00341                            0666);
00342        if (fd < 0)
00343          {
00344            char buf[300];
00345            int errnum = errno;
00346            __fxprintf (NULL, "_mcleanup: gmon.out: %s\n",
00347                      __strerror_r (errnum, buf, sizeof buf));
00348            return;
00349          }
00350       }
00351 
00352     /* write gmon.out header: */
00353     memset (&ghdr, '\0', sizeof (struct gmon_hdr));
00354     memcpy (&ghdr.cookie[0], GMON_MAGIC, sizeof (ghdr.cookie));
00355     *(int32_t *) ghdr.version = GMON_VERSION;
00356     write_not_cancel (fd, &ghdr, sizeof (struct gmon_hdr));
00357 
00358     /* write PC histogram: */
00359     write_hist (fd);
00360 
00361     /* write call-graph: */
00362     write_call_graph (fd);
00363 
00364     /* write basic-block execution counts: */
00365     write_bb_counts (fd);
00366 
00367     close_not_cancel_no_status (fd);
00368 }
00369 
00370 
00371 void
00372 __write_profiling (void)
00373 {
00374   int save = _gmonparam.state;
00375   _gmonparam.state = GMON_PROF_OFF;
00376   if (save == GMON_PROF_ON)
00377     write_gmon ();
00378   _gmonparam.state = save;
00379 }
00380 #ifndef SHARED
00381 /* This symbol isn't used anywhere in the DSO and it is not exported.
00382    This would normally mean it should be removed to get the same API
00383    in static libraries.  But since profiling is special in static libs
00384    anyway we keep it.  But not when building the DSO since some
00385    quality assurance tests will otherwise trigger.  */
00386 weak_alias (__write_profiling, write_profiling)
00387 #endif
00388 
00389 
00390 void
00391 _mcleanup (void)
00392 {
00393   __moncontrol (0);
00394 
00395   if (_gmonparam.state != GMON_PROF_ERROR)
00396     write_gmon ();
00397 
00398   /* free the memory. */
00399   free (_gmonparam.tos);
00400 }