Blame gmon/gmon.c

Packit 6c4009
/*-
Packit 6c4009
 * Copyright (c) 1983, 1992, 1993, 2011
Packit 6c4009
 *	The Regents of the University of California.  All rights reserved.
Packit 6c4009
 *
Packit 6c4009
 * Redistribution and use in source and binary forms, with or without
Packit 6c4009
 * modification, are permitted provided that the following conditions
Packit 6c4009
 * are met:
Packit 6c4009
 * 1. Redistributions of source code must retain the above copyright
Packit 6c4009
 *    notice, this list of conditions and the following disclaimer.
Packit 6c4009
 * 2. Redistributions in binary form must reproduce the above copyright
Packit 6c4009
 *    notice, this list of conditions and the following disclaimer in the
Packit 6c4009
 *    documentation and/or other materials provided with the distribution.
Packit 6c4009
 * 4. Neither the name of the University nor the names of its contributors
Packit 6c4009
 *    may be used to endorse or promote products derived from this software
Packit 6c4009
 *    without specific prior written permission.
Packit 6c4009
 *
Packit 6c4009
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
Packit 6c4009
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
Packit 6c4009
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
Packit 6c4009
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
Packit 6c4009
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
Packit 6c4009
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
Packit 6c4009
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
Packit 6c4009
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
Packit 6c4009
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
Packit 6c4009
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
Packit 6c4009
 * SUCH DAMAGE.
Packit 6c4009
 */
Packit 6c4009
#include <sys/param.h>
Packit 6c4009
#include <sys/time.h>
Packit 6c4009
#include <sys/gmon.h>
Packit 6c4009
#include <sys/gmon_out.h>
Packit 6c4009
#include <sys/uio.h>
Packit 6c4009
Packit 6c4009
#include <errno.h>
Packit 6c4009
#include <stdio.h>
Packit 6c4009
#include <fcntl.h>
Packit 6c4009
#include <unistd.h>
Packit 6c4009
#include <wchar.h>
Packit 6c4009
Packit 6c4009
#include <stdio.h>
Packit 6c4009
#include <stdlib.h>
Packit 6c4009
#include <string.h>
Packit 6c4009
#include <stddef.h>
Packit 6c4009
#include <unistd.h>
Packit 6c4009
#include <libc-internal.h>
Packit 6c4009
#include <not-cancel.h>
Packit 6c4009
Packit 6c4009
#ifdef PIC
Packit 6c4009
# include <link.h>
Packit 6c4009
Packit 6c4009
static int
Packit 6c4009
callback (struct dl_phdr_info *info, size_t size, void *data)
Packit 6c4009
{
Packit 6c4009
  if (info->dlpi_name[0] == '\0')
Packit 6c4009
    {
Packit 6c4009
      /* The link map for the executable is created by calling
Packit 6c4009
	 _dl_new_object with "" as filename.  dl_iterate_phdr
Packit 6c4009
	 calls the callback function with filename from the
Packit 6c4009
	 link map as dlpi_name.  */
Packit 6c4009
      u_long *load_address = data;
Packit 6c4009
      *load_address = (u_long) info->dlpi_addr;
Packit 6c4009
      return 1;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  return 0;
Packit 6c4009
}
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
/*  Head of basic-block list or NULL. */
Packit 6c4009
struct __bb *__bb_head attribute_hidden;
Packit 6c4009
Packit 6c4009
struct gmonparam _gmonparam attribute_hidden = { GMON_PROF_OFF };
Packit 6c4009
Packit 6c4009
/*
Packit 6c4009
 * See profil(2) where this is described:
Packit 6c4009
 */
Packit 6c4009
static int	s_scale;
Packit 6c4009
#define		SCALE_1_TO_1	0x10000L
Packit 6c4009
Packit 6c4009
#define ERR(s) __write_nocancel (STDERR_FILENO, s, sizeof (s) - 1)
Packit 6c4009
Packit 6c4009
void moncontrol (int mode);
Packit 6c4009
void __moncontrol (int mode);
Packit 6c4009
libc_hidden_proto (__moncontrol)
Packit 6c4009
static void write_hist (int fd, u_long load_address);
Packit 6c4009
static void write_call_graph (int fd, u_long load_address);
Packit 6c4009
static void write_bb_counts (int fd);
Packit 6c4009
Packit 6c4009
/*
Packit 6c4009
 * Control profiling
Packit 6c4009
 *	profiling is what mcount checks to see if
Packit 6c4009
 *	all the data structures are ready.
Packit 6c4009
 */
Packit 6c4009
void
Packit 6c4009
__moncontrol (int mode)
Packit 6c4009
{
Packit 6c4009
  struct gmonparam *p = &_gmonparam;
Packit 6c4009
Packit 6c4009
  /* Don't change the state if we ran into an error.  */
Packit 6c4009
  if (p->state == GMON_PROF_ERROR)
Packit 6c4009
    return;
Packit 6c4009
Packit 6c4009
  if (mode)
Packit 6c4009
    {
Packit 6c4009
      /* start */
Packit 6c4009
      __profil((void *) p->kcount, p->kcountsize, p->lowpc, s_scale);
Packit 6c4009
      p->state = GMON_PROF_ON;
Packit 6c4009
    }
Packit 6c4009
  else
Packit 6c4009
    {
Packit 6c4009
      /* stop */
Packit 6c4009
      __profil(NULL, 0, 0, 0);
Packit 6c4009
      p->state = GMON_PROF_OFF;
Packit 6c4009
    }
Packit 6c4009
}
Packit 6c4009
libc_hidden_def (__moncontrol)
Packit 6c4009
weak_alias (__moncontrol, moncontrol)
Packit 6c4009
Packit 6c4009
Packit 6c4009
void
Packit 6c4009
__monstartup (u_long lowpc, u_long highpc)
Packit 6c4009
{
Packit 6c4009
  int o;
Packit 6c4009
  char *cp;
Packit 6c4009
  struct gmonparam *p = &_gmonparam;
Packit 6c4009
Packit 6c4009
  /*
Packit 6c4009
   * round lowpc and highpc to multiples of the density we're using
Packit 6c4009
   * so the rest of the scaling (here and in gprof) stays in ints.
Packit 6c4009
   */
Packit 6c4009
  p->lowpc = ROUNDDOWN(lowpc, HISTFRACTION * sizeof(HISTCOUNTER));
Packit 6c4009
  p->highpc = ROUNDUP(highpc, HISTFRACTION * sizeof(HISTCOUNTER));
Packit 6c4009
  p->textsize = p->highpc - p->lowpc;
Packit 6c4009
  p->kcountsize = ROUNDUP(p->textsize / HISTFRACTION, sizeof(*p->froms));
Packit 6c4009
  p->hashfraction = HASHFRACTION;
Packit 6c4009
  p->log_hashfraction = -1;
Packit 6c4009
  /* The following test must be kept in sync with the corresponding
Packit 6c4009
     test in mcount.c.  */
Packit 6c4009
  if ((HASHFRACTION & (HASHFRACTION - 1)) == 0) {
Packit 6c4009
      /* if HASHFRACTION is a power of two, mcount can use shifting
Packit 6c4009
	 instead of integer division.  Precompute shift amount. */
Packit 6c4009
      p->log_hashfraction = ffs(p->hashfraction * sizeof(*p->froms)) - 1;
Packit 6c4009
  }
Packit 6c4009
  p->fromssize = p->textsize / HASHFRACTION;
Packit 6c4009
  p->tolimit = p->textsize * ARCDENSITY / 100;
Packit 6c4009
  if (p->tolimit < MINARCS)
Packit 6c4009
    p->tolimit = MINARCS;
Packit 6c4009
  else if (p->tolimit > MAXARCS)
Packit 6c4009
    p->tolimit = MAXARCS;
Packit 6c4009
  p->tossize = p->tolimit * sizeof(struct tostruct);
Packit 6c4009
Packit 6c4009
  cp = calloc (p->kcountsize + p->fromssize + p->tossize, 1);
Packit 6c4009
  if (! cp)
Packit 6c4009
    {
Packit 6c4009
      ERR("monstartup: out of memory\n");
Packit 6c4009
      p->tos = NULL;
Packit 6c4009
      p->state = GMON_PROF_ERROR;
Packit 6c4009
      return;
Packit 6c4009
    }
Packit 6c4009
  p->tos = (struct tostruct *)cp;
Packit 6c4009
  cp += p->tossize;
Packit 6c4009
  p->kcount = (HISTCOUNTER *)cp;
Packit 6c4009
  cp += p->kcountsize;
Packit 6c4009
  p->froms = (ARCINDEX *)cp;
Packit 6c4009
Packit 6c4009
  p->tos[0].link = 0;
Packit 6c4009
Packit 6c4009
  o = p->highpc - p->lowpc;
Packit 6c4009
  if (p->kcountsize < (u_long) o)
Packit 6c4009
    {
Packit 6c4009
#ifndef hp300
Packit 6c4009
      s_scale = ((float)p->kcountsize / o ) * SCALE_1_TO_1;
Packit 6c4009
#else
Packit 6c4009
      /* avoid floating point operations */
Packit 6c4009
      int quot = o / p->kcountsize;
Packit 6c4009
Packit 6c4009
      if (quot >= 0x10000)
Packit 6c4009
	s_scale = 1;
Packit 6c4009
      else if (quot >= 0x100)
Packit 6c4009
	s_scale = 0x10000 / quot;
Packit 6c4009
      else if (o >= 0x800000)
Packit 6c4009
	s_scale = 0x1000000 / (o / (p->kcountsize >> 8));
Packit 6c4009
      else
Packit 6c4009
	s_scale = 0x1000000 / ((o << 8) / p->kcountsize);
Packit 6c4009
#endif
Packit 6c4009
    } else
Packit 6c4009
      s_scale = SCALE_1_TO_1;
Packit 6c4009
Packit 6c4009
  __moncontrol(1);
Packit 6c4009
}
Packit 6c4009
weak_alias (__monstartup, monstartup)
Packit 6c4009
Packit 6c4009
Packit 6c4009
static void
Packit 6c4009
write_hist (int fd, u_long load_address)
Packit 6c4009
{
Packit 6c4009
  u_char tag = GMON_TAG_TIME_HIST;
Packit 6c4009
Packit 6c4009
  if (_gmonparam.kcountsize > 0)
Packit 6c4009
    {
Packit 6c4009
      struct real_gmon_hist_hdr
Packit 6c4009
      {
Packit 6c4009
	char *low_pc;
Packit 6c4009
	char *high_pc;
Packit 6c4009
	int32_t hist_size;
Packit 6c4009
	int32_t prof_rate;
Packit 6c4009
	char dimen[15];
Packit 6c4009
	char dimen_abbrev;
Packit 6c4009
      } thdr;
Packit 6c4009
      struct iovec iov[3] =
Packit 6c4009
	{
Packit 6c4009
	  { &tag, sizeof (tag) },
Packit 6c4009
	  { &thdr, sizeof (struct gmon_hist_hdr) },
Packit 6c4009
	  { _gmonparam.kcount, _gmonparam.kcountsize }
Packit 6c4009
	};
Packit 6c4009
Packit 6c4009
      if (sizeof (thdr) != sizeof (struct gmon_hist_hdr)
Packit 6c4009
	  || (offsetof (struct real_gmon_hist_hdr, low_pc)
Packit 6c4009
	      != offsetof (struct gmon_hist_hdr, low_pc))
Packit 6c4009
	  || (offsetof (struct real_gmon_hist_hdr, high_pc)
Packit 6c4009
	      != offsetof (struct gmon_hist_hdr, high_pc))
Packit 6c4009
	  || (offsetof (struct real_gmon_hist_hdr, hist_size)
Packit 6c4009
	      != offsetof (struct gmon_hist_hdr, hist_size))
Packit 6c4009
	  || (offsetof (struct real_gmon_hist_hdr, prof_rate)
Packit 6c4009
	      != offsetof (struct gmon_hist_hdr, prof_rate))
Packit 6c4009
	  || (offsetof (struct real_gmon_hist_hdr, dimen)
Packit 6c4009
	      != offsetof (struct gmon_hist_hdr, dimen))
Packit 6c4009
	  || (offsetof (struct real_gmon_hist_hdr, dimen_abbrev)
Packit 6c4009
	      != offsetof (struct gmon_hist_hdr, dimen_abbrev)))
Packit 6c4009
	abort ();
Packit 6c4009
Packit 6c4009
      thdr.low_pc = (char *) _gmonparam.lowpc - load_address;
Packit 6c4009
      thdr.high_pc = (char *) _gmonparam.highpc - load_address;
Packit 6c4009
      thdr.hist_size = _gmonparam.kcountsize / sizeof (HISTCOUNTER);
Packit 6c4009
      thdr.prof_rate = __profile_frequency ();
Packit 6c4009
      strncpy (thdr.dimen, "seconds", sizeof (thdr.dimen));
Packit 6c4009
      thdr.dimen_abbrev = 's';
Packit 6c4009
Packit 6c4009
      __writev_nocancel_nostatus (fd, iov, 3);
Packit 6c4009
    }
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
Packit 6c4009
static void
Packit 6c4009
write_call_graph (int fd, u_long load_address)
Packit 6c4009
{
Packit 6c4009
#define NARCS_PER_WRITEV	32
Packit 6c4009
  u_char tag = GMON_TAG_CG_ARC;
Packit 6c4009
  struct gmon_cg_arc_record raw_arc[NARCS_PER_WRITEV]
Packit 6c4009
    __attribute__ ((aligned (__alignof__ (char*))));
Packit 6c4009
  ARCINDEX from_index, to_index;
Packit 6c4009
  u_long from_len;
Packit 6c4009
  u_long frompc;
Packit 6c4009
  struct iovec iov[2 * NARCS_PER_WRITEV];
Packit 6c4009
  int nfilled;
Packit 6c4009
Packit 6c4009
  for (nfilled = 0; nfilled < NARCS_PER_WRITEV; ++nfilled)
Packit 6c4009
    {
Packit 6c4009
      iov[2 * nfilled].iov_base = &tag;
Packit 6c4009
      iov[2 * nfilled].iov_len = sizeof (tag);
Packit 6c4009
Packit 6c4009
      iov[2 * nfilled + 1].iov_base = &raw_arc[nfilled];
Packit 6c4009
      iov[2 * nfilled + 1].iov_len = sizeof (struct gmon_cg_arc_record);
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  nfilled = 0;
Packit 6c4009
  from_len = _gmonparam.fromssize / sizeof (*_gmonparam.froms);
Packit 6c4009
  for (from_index = 0; from_index < from_len; ++from_index)
Packit 6c4009
    {
Packit 6c4009
      if (_gmonparam.froms[from_index] == 0)
Packit 6c4009
	continue;
Packit 6c4009
Packit 6c4009
      frompc = _gmonparam.lowpc;
Packit 6c4009
      frompc += (from_index * _gmonparam.hashfraction
Packit 6c4009
		 * sizeof (*_gmonparam.froms));
Packit 6c4009
      for (to_index = _gmonparam.froms[from_index];
Packit 6c4009
	   to_index != 0;
Packit 6c4009
	   to_index = _gmonparam.tos[to_index].link)
Packit 6c4009
	{
Packit 6c4009
	  struct arc
Packit 6c4009
	    {
Packit 6c4009
	      char *frompc;
Packit 6c4009
	      char *selfpc;
Packit 6c4009
	      int32_t count;
Packit 6c4009
	    }
Packit 6c4009
	  arc;
Packit 6c4009
Packit 6c4009
	  arc.frompc = (char *) frompc - load_address;
Packit 6c4009
	  arc.selfpc = ((char *) _gmonparam.tos[to_index].selfpc
Packit 6c4009
			- load_address);
Packit 6c4009
	  arc.count  = _gmonparam.tos[to_index].count;
Packit 6c4009
	  memcpy (raw_arc + nfilled, &arc, sizeof (raw_arc [0]));
Packit 6c4009
Packit 6c4009
	  if (++nfilled == NARCS_PER_WRITEV)
Packit 6c4009
	    {
Packit 6c4009
	      __writev_nocancel_nostatus (fd, iov, 2 * nfilled);
Packit 6c4009
	      nfilled = 0;
Packit 6c4009
	    }
Packit 6c4009
	}
Packit 6c4009
    }
Packit 6c4009
  if (nfilled > 0)
Packit 6c4009
    __writev_nocancel_nostatus (fd, iov, 2 * nfilled);
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
Packit 6c4009
static void
Packit 6c4009
write_bb_counts (int fd)
Packit 6c4009
{
Packit 6c4009
  struct __bb *grp;
Packit 6c4009
  u_char tag = GMON_TAG_BB_COUNT;
Packit 6c4009
  size_t ncounts;
Packit 6c4009
  size_t i;
Packit 6c4009
Packit 6c4009
  struct iovec bbhead[2] =
Packit 6c4009
    {
Packit 6c4009
      { &tag, sizeof (tag) },
Packit 6c4009
      { &ncounts, sizeof (ncounts) }
Packit 6c4009
    };
Packit 6c4009
  struct iovec bbbody[8];
Packit 6c4009
  size_t nfilled;
Packit 6c4009
Packit 6c4009
  for (i = 0; i < (sizeof (bbbody) / sizeof (bbbody[0])); i += 2)
Packit 6c4009
    {
Packit 6c4009
      bbbody[i].iov_len = sizeof (grp->addresses[0]);
Packit 6c4009
      bbbody[i + 1].iov_len = sizeof (grp->counts[0]);
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  /* Write each group of basic-block info (all basic-blocks in a
Packit 6c4009
     compilation unit form a single group). */
Packit 6c4009
Packit 6c4009
  for (grp = __bb_head; grp; grp = grp->next)
Packit 6c4009
    {
Packit 6c4009
      ncounts = grp->ncounts;
Packit 6c4009
      __writev_nocancel_nostatus (fd, bbhead, 2);
Packit 6c4009
      for (nfilled = i = 0; i < ncounts; ++i)
Packit 6c4009
	{
Packit 6c4009
	  if (nfilled > (sizeof (bbbody) / sizeof (bbbody[0])) - 2)
Packit 6c4009
	    {
Packit 6c4009
	      __writev_nocancel_nostatus (fd, bbbody, nfilled);
Packit 6c4009
	      nfilled = 0;
Packit 6c4009
	    }
Packit 6c4009
Packit 6c4009
	  bbbody[nfilled++].iov_base = (char *) &grp->addresses[i];
Packit 6c4009
	  bbbody[nfilled++].iov_base = &grp->counts[i];
Packit 6c4009
	}
Packit 6c4009
      if (nfilled > 0)
Packit 6c4009
	__writev_nocancel_nostatus (fd, bbbody, nfilled);
Packit 6c4009
    }
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
Packit 6c4009
static void
Packit 6c4009
write_gmon (void)
Packit 6c4009
{
Packit 6c4009
    int fd = -1;
Packit 6c4009
    char *env;
Packit 6c4009
Packit 6c4009
    env = getenv ("GMON_OUT_PREFIX");
Packit 6c4009
    if (env != NULL && !__libc_enable_secure)
Packit 6c4009
      {
Packit 6c4009
	size_t len = strlen (env);
Packit 6c4009
	char buf[len + 20];
Packit 6c4009
	__snprintf (buf, sizeof (buf), "%s.%u", env, __getpid ());
Packit 6c4009
	fd = __open_nocancel (buf, O_CREAT|O_TRUNC|O_WRONLY|O_NOFOLLOW, 0666);
Packit 6c4009
      }
Packit 6c4009
Packit 6c4009
    if (fd == -1)
Packit 6c4009
      {
Packit 6c4009
	fd = __open_nocancel ("gmon.out", O_CREAT|O_TRUNC|O_WRONLY|O_NOFOLLOW,
Packit 6c4009
			      0666);
Packit 6c4009
	if (fd < 0)
Packit 6c4009
	  {
Packit 6c4009
	    char buf[300];
Packit 6c4009
	    int errnum = errno;
Packit 6c4009
	    __fxprintf (NULL, "_mcleanup: gmon.out: %s\n",
Packit 6c4009
			__strerror_r (errnum, buf, sizeof buf));
Packit 6c4009
	    return;
Packit 6c4009
	  }
Packit 6c4009
      }
Packit 6c4009
Packit 6c4009
    /* write gmon.out header: */
Packit 6c4009
    struct real_gmon_hdr
Packit 6c4009
    {
Packit 6c4009
      char cookie[4];
Packit 6c4009
      int32_t version;
Packit 6c4009
      char spare[3 * 4];
Packit 6c4009
    } ghdr;
Packit 6c4009
    if (sizeof (ghdr) != sizeof (struct gmon_hdr)
Packit 6c4009
	|| (offsetof (struct real_gmon_hdr, cookie)
Packit 6c4009
	    != offsetof (struct gmon_hdr, cookie))
Packit 6c4009
	|| (offsetof (struct real_gmon_hdr, version)
Packit 6c4009
	    != offsetof (struct gmon_hdr, version)))
Packit 6c4009
      abort ();
Packit 6c4009
    memcpy (&ghdr.cookie[0], GMON_MAGIC, sizeof (ghdr.cookie));
Packit 6c4009
    ghdr.version = GMON_VERSION;
Packit 6c4009
    memset (ghdr.spare, '\0', sizeof (ghdr.spare));
Packit 6c4009
    __write_nocancel (fd, &ghdr, sizeof (struct gmon_hdr));
Packit 6c4009
Packit 6c4009
    /* Get load_address to profile PIE.  */
Packit 6c4009
    u_long load_address = 0;
Packit 6c4009
#ifdef PIC
Packit 6c4009
    __dl_iterate_phdr (callback, &load_address);
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
    /* write PC histogram: */
Packit 6c4009
    write_hist (fd, load_address);
Packit 6c4009
Packit 6c4009
    /* write call-graph: */
Packit 6c4009
    write_call_graph (fd, load_address);
Packit 6c4009
Packit 6c4009
    /* write basic-block execution counts: */
Packit 6c4009
    write_bb_counts (fd);
Packit 6c4009
Packit 6c4009
    __close_nocancel_nostatus (fd);
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
Packit 6c4009
void
Packit 6c4009
__write_profiling (void)
Packit 6c4009
{
Packit 6c4009
  int save = _gmonparam.state;
Packit 6c4009
  _gmonparam.state = GMON_PROF_OFF;
Packit 6c4009
  if (save == GMON_PROF_ON)
Packit 6c4009
    write_gmon ();
Packit 6c4009
  _gmonparam.state = save;
Packit 6c4009
}
Packit 6c4009
#ifndef SHARED
Packit 6c4009
/* This symbol isn't used anywhere in the DSO and it is not exported.
Packit 6c4009
   This would normally mean it should be removed to get the same API
Packit 6c4009
   in static libraries.  But since profiling is special in static libs
Packit 6c4009
   anyway we keep it.  But not when building the DSO since some
Packit 6c4009
   quality assurance tests will otherwise trigger.  */
Packit 6c4009
weak_alias (__write_profiling, write_profiling)
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
Packit 6c4009
void
Packit 6c4009
_mcleanup (void)
Packit 6c4009
{
Packit 6c4009
  __moncontrol (0);
Packit 6c4009
Packit 6c4009
  if (_gmonparam.state != GMON_PROF_ERROR)
Packit 6c4009
    write_gmon ();
Packit 6c4009
Packit 6c4009
  /* free the memory. */
Packit 6c4009
  free (_gmonparam.tos);
Packit 6c4009
}