OpenCores
URL https://opencores.org/ocsvn/openrisc_me/openrisc_me/trunk

Subversion Repositories openrisc_me

[/] [openrisc/] [trunk/] [gnu-src/] [newlib-1.18.0/] [libgloss/] [rx/] [mcount.c] - Blame information for rev 258

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 207 jeremybenn
/*-
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
 
105
struct tostruct
106
{
107
  unsigned long selfpc;
108
  unsigned long count;
109
  unsigned long link;
110
};
111
 
112
/* Possible states of profiling.  */
113
enum 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.  */
122
struct 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.  */
142
struct 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.  */
150
typedef enum
151
{
152
  GMON_TAG_TIME_HIST = 0,
153
  GMON_TAG_CG_ARC = 1,
154
} GMON_Record_Tag;
155
 
156
struct 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.  */
166
void _mcount_internal (unsigned long);
167
void _monstartup (unsigned long, unsigned long);
168
void _mcleanup (void);
169
 
170
static struct gmonparam _gmonparam;
171
 
172
void
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
 
278
void
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
 
327
static void
328
write_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
 
379
static void
380
write_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
 
407
void
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
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.