source: trunk/libs/newlib/src/libgloss/rx/mcount.c @ 485

Last change on this file since 485 was 444, checked in by satin@…, 7 years ago

add newlib,libalmos-mkh, restructure shared_syscalls.h and mini-libc

File size: 11.9 KB
Line 
1/*-
2 * Copyright (c) 1983, 1992, 1993
3 *      The Regents of the University of California.  All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 * 4. Neither the name of the University nor the names of its contributors
14 *    may be used to endorse or promote products derived from this software
15 *    without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 */
29
30/* This file implements a subset of the profiling support functions.
31   It has been copied and adapted from mcount.c, gmon.c and gmon.h in
32   the glibc sources.
33   Since we do not have access to a timer interrupt in the simulator
34   the histogram and basic block information is not generated.  */
35
36#include <stdio.h>
37#include <stdlib.h>
38#include <string.h>
39#include <unistd.h>
40#include <fcntl.h>
41
42/* Fraction of text space to allocate for histogram counters here, 1/2.  */
43#define HISTFRACTION    2
44
45/* Fraction of text space to allocate for from hash buckets.
46   The value of HASHFRACTION is based on the minimum number of bytes
47   of separation between two subroutine call points in the object code.
48   Given MIN_SUBR_SEPARATION bytes of separation the value of
49   HASHFRACTION is calculated as:
50 
51        HASHFRACTION = MIN_SUBR_SEPARATION / (2 * sizeof (short) - 1);
52 
53   For example, on the VAX, the shortest two call sequence is:
54 
55        calls   $0,(r0)
56        calls   $0,(r0)
57 
58   which is separated by only three bytes, thus HASHFRACTION is
59   calculated as:
60 
61        HASHFRACTION = 3 / (2 * 2 - 1) = 1
62 
63   Note that the division above rounds down, thus if MIN_SUBR_FRACTION
64   is less than three, this algorithm will not work!
65 
66   In practice, however, call instructions are rarely at a minimal
67   distance.  Hence, we will define HASHFRACTION to be 2 across all
68   architectures.  This saves a reasonable amount of space for
69   profiling data structures without (in practice) sacrificing
70   any granularity.  */
71#define HASHFRACTION    2
72
73/* Percent of text space to allocate for tostructs.
74   This is a heuristic; we will fail with a warning when profiling
75   programs with a very large number of very small functions, but
76   that's normally OK.
77   2 is probably still a good value for normal programs.
78   Profiling a test case with 64000 small functions will work if
79   you raise this value to 3 and link statically (which bloats the
80   text size, thus raising the number of arcs expected by the heuristic).  */
81#define ARCDENSITY      3
82
83/* Always allocate at least this many tostructs.  This hides the
84   inadequacy of the ARCDENSITY heuristic, at least for small programs.  */
85#define MINARCS         50
86
87/* Maximum number of arcs we want to allow.
88   Used to be max representable value of ARCINDEX minus 2, but now
89   that ARCINDEX is a long, that's too large; we don't really want
90   to allow a 48 gigabyte table.
91   The old value of 1<<16 wasn't high enough in practice for large C++
92   programs; will 1<<20 be adequate for long?  FIXME  */
93#define MAXARCS         (1 << 20)
94
95#define SCALE_1_TO_1    0x10000L
96
97#define GMON_MAGIC      "gmon"  /* Magic cookie.  */
98#define GMON_VERSION    1       /* Version number.  */
99
100
101/* General rounding functions.  */
102#define ROUNDDOWN(x ,y) (((x) / (y)) * (y))
103#define ROUNDUP(x, y)   ((((x) + (y) - 1) / (y)) * (y))
104
105struct tostruct
106{
107  unsigned long selfpc;
108  unsigned long count;
109  unsigned long link;
110};
111
112/* Possible states of profiling.  */
113enum profiling_state
114{
115  GMON_PROF_OFF,
116  GMON_PROF_ON,
117  GMON_PROF_BUSY,
118  GMON_PROF_ERROR
119};
120
121/* The profiling data structures are housed in this structure.  */
122struct gmonparam
123{
124  enum profiling_state state;
125  unsigned short *     kcount;
126  unsigned long        kcountsize;
127  unsigned long *      froms;
128  unsigned long        fromssize;
129  struct tostruct *    tos;
130  unsigned long        tossize;
131  long                 tolimit;
132  unsigned long        lowpc;
133  unsigned long        highpc;
134  unsigned long        textsize;
135  unsigned long        hashfraction;
136  long                 log_hashfraction;
137};
138
139/* Raw header as it appears in the gmon.out file (without padding).
140   This header always comes first and is then followed by a series
141   records defined below.  */
142struct gmon_hdr
143{
144  char cookie[4];
145  char version[4];
146  char spare[3 * 4];
147};
148
149/* Types of records in this file.  */
150typedef enum
151{
152  GMON_TAG_TIME_HIST = 0,
153  GMON_TAG_CG_ARC = 1,
154} GMON_Record_Tag;
155
156struct gmon_cg_arc_record
157{
158  char tag;                             /* Set to GMON_TAG_CG_ARC.  */
159  char from_pc[sizeof (char *)];        /* Address within caller's body.  */
160  char self_pc[sizeof (char *)];        /* Address within callee's body.  */
161  char count[4];                        /* Number of arc traversals.  */
162};
163
164
165/* Forward declarations.  */
166void _mcount_internal (unsigned long);
167void _monstartup (unsigned long, unsigned long);
168void _mcleanup (void);
169
170static struct gmonparam _gmonparam;
171
172void
173_mcount_internal (unsigned long frompc)
174{
175  unsigned long      selfpc = frompc;
176  unsigned long *    frompcindex;
177  struct tostruct *  top;
178  struct tostruct *  prevtop;
179  struct gmonparam * p;
180  unsigned long      toindex;
181  int                i;
182
183  p = & _gmonparam;
184
185  /* Check that we are profiling and that we aren't recursively invoked.
186     NB/ This version is not thread-safe.  */
187  if (p->state != GMON_PROF_ON)
188    return;
189  p->state = GMON_PROF_BUSY;
190
191  /* Check that frompcindex is a reasonable pc value.
192     For example: signal catchers get called from the stack,
193     not from text space.  Too bad.  */
194  frompc -= p->lowpc;
195  if (frompc > p->textsize)
196    goto done;
197
198  i = frompc >> p->log_hashfraction;
199
200  frompcindex = p->froms + i;
201  toindex = * frompcindex;
202
203  if (toindex == 0)
204    {
205      /* First time traversing this arc.  */
206      toindex = ++ p->tos[0].link;
207      if (toindex >= p->tolimit)
208        /* Halt further profiling.  */
209        goto overflow;
210
211      * frompcindex = toindex;
212      top = p->tos + toindex;
213      top->selfpc = selfpc;
214      top->count = 1;
215      top->link = 0;
216      goto done;
217    }
218
219  top = p->tos + toindex;
220
221  if (top->selfpc == selfpc)
222    {
223      /* Arc at front of chain: usual case.  */
224      top->count ++;
225      goto done;
226    }
227
228  /* Have to go looking down chain for it.
229     Top points to what we are looking at,
230     prevtop points to previous top.
231     We know it is not at the head of the chain.  */
232  for (;;)
233    {
234      if (top->link == 0)
235        {
236          /* Top is end of the chain and none of the chain
237             had top->selfpc == selfpc.  So we allocate a
238             new tostruct and link it to the head of the
239             chain.  */
240          toindex = ++ p->tos[0].link;
241          if (toindex >= p->tolimit)
242            goto overflow;
243
244          top = p->tos + toindex;
245          top->selfpc = selfpc;
246          top->count = 1;
247          top->link = * frompcindex;
248          * frompcindex = toindex;
249          goto done;
250        }
251
252      /* Otherwise, check the next arc on the chain.  */
253      prevtop = top;
254      top = p->tos + top->link;
255
256      if (top->selfpc == selfpc)
257        {
258          /* There it is.  Increment its count
259             move it to the head of the chain.  */
260          top->count ++;
261          toindex = prevtop->link;
262          prevtop->link = top->link;
263          top->link = * frompcindex;
264          * frompcindex = toindex;
265          goto done;
266        }
267    }
268
269 done:
270  p->state = GMON_PROF_ON;
271  return;
272
273 overflow:
274  p->state = GMON_PROF_ERROR;
275  return;
276}
277
278void
279_monstartup (unsigned long lowpc, unsigned long highpc)
280{
281  char * cp;
282  struct gmonparam * p = & _gmonparam;
283
284  /* If the calloc() function has been instrumented we must make sure
285     that it is not profiled until we are ready.  */
286  p->state = GMON_PROF_BUSY;
287
288  /* Round lowpc and highpc to multiples of the density we're using
289     so the rest of the scaling (here and in gprof) stays in ints.  */
290  p->lowpc            = ROUNDDOWN (lowpc, HISTFRACTION * sizeof (* p->kcount));
291  p->highpc           = ROUNDUP (highpc, HISTFRACTION * sizeof (* p->kcount));
292  p->textsize         = p->highpc - p->lowpc;
293  p->kcountsize       = ROUNDUP (p->textsize / HISTFRACTION, sizeof (*p->froms));
294  p->hashfraction     = HASHFRACTION;
295  p->log_hashfraction = -1;
296  p->log_hashfraction = ffs (p->hashfraction * sizeof (*p->froms)) - 1;
297  p->fromssize        = p->textsize / HASHFRACTION;
298  p->tolimit          = p->textsize * ARCDENSITY / 100;
299
300  if (p->tolimit < MINARCS)
301    p->tolimit = MINARCS;
302  else if (p->tolimit > MAXARCS)
303    p->tolimit = MAXARCS;
304 
305  p->tossize          = p->tolimit * sizeof (struct tostruct);
306
307  cp = calloc (p->kcountsize + p->fromssize + p->tossize, 1);
308  if (cp == NULL)
309    {
310      write (2, "monstartup: out of memory\n", 26);
311      p->tos = NULL;
312      p->state = GMON_PROF_ERROR;
313      return;
314    }
315
316  p->tos = (struct tostruct *) cp;
317  cp += p->tossize;
318  p->kcount = (unsigned short *) cp;
319  cp += p->kcountsize;
320  p->froms = (unsigned long *) cp;
321
322  p->tos[0].link = 0;
323  p->state = GMON_PROF_ON;
324}
325
326
327static void
328write_call_graph (int fd)
329{
330#define NARCS_PER_WRITE 32
331
332  struct gmon_cg_arc_record raw_arc[NARCS_PER_WRITE]
333    __attribute__ ((aligned (__alignof__ (char *))));
334  unsigned long from_index;
335  unsigned long to_index;
336  unsigned long from_len;
337  unsigned long frompc;
338  int nfilled;
339
340  for (nfilled = 0; nfilled < NARCS_PER_WRITE; ++ nfilled)
341    raw_arc[nfilled].tag = GMON_TAG_CG_ARC;
342
343  nfilled = 0;
344  from_len = _gmonparam.fromssize / sizeof (*_gmonparam.froms);
345
346  for (from_index = 0; from_index < from_len; ++from_index)
347    {
348      if (_gmonparam.froms[from_index] == 0)
349        continue;
350
351      frompc = _gmonparam.lowpc;
352      frompc += (from_index * _gmonparam.hashfraction
353                 * sizeof (*_gmonparam.froms));
354
355      for (to_index = _gmonparam.froms[from_index];
356           to_index != 0;
357           to_index = _gmonparam.tos[to_index].link)
358        {
359          struct gmon_cg_arc_record * arc = raw_arc + nfilled;
360
361          memcpy (arc->from_pc, & frompc, sizeof (arc->from_pc));
362          memcpy (arc->self_pc, & _gmonparam.tos[to_index].selfpc, sizeof (arc->self_pc));
363          memcpy (arc->count,   & _gmonparam.tos[to_index].count, sizeof (arc->count));
364
365          if (++ nfilled == NARCS_PER_WRITE)
366            {
367              write (fd, raw_arc, sizeof raw_arc);
368              nfilled = 0;
369            }
370        }
371    }
372
373  if (nfilled > 0)
374    write (fd, raw_arc, nfilled * sizeof (raw_arc[0]));
375}
376
377#include <errno.h>
378
379static void
380write_gmon (void)
381{
382  struct gmon_hdr ghdr __attribute__ ((aligned (__alignof__ (int))));
383  int fd;
384
385  fd = open ("gmon.out", O_CREAT|O_TRUNC|O_WRONLY, 0666);
386  if (fd < 0)
387    {
388      write (2, "_mcleanup: could not create gmon.out\n", 37);
389      return;
390    }
391
392  /* Write gmon.out header: */
393  memset (& ghdr, '\0', sizeof (ghdr));
394  memcpy (ghdr.cookie, GMON_MAGIC, sizeof (ghdr.cookie));
395  * (unsigned long *) ghdr.version = GMON_VERSION;
396  write (fd, & ghdr, sizeof (ghdr));
397
398  /* We do not have histogram or basic block information,
399     so we do not generate these parts of the gmon.out file.  */
400 
401  /* Write call-graph.  */
402  write_call_graph (fd);
403
404  close (fd);
405}
406
407void
408_mcleanup (void)
409{
410  if (_gmonparam.state != GMON_PROF_ERROR)
411    {
412      _gmonparam.state = GMON_PROF_OFF;
413      write_gmon ();
414    }
415
416  /* Free the memory.  */
417  if (_gmonparam.tos != NULL)
418    {
419      free (_gmonparam.tos);
420      _gmonparam.tos = NULL;
421    }
422}
Note: See TracBrowser for help on using the repository browser.