2 * Copyright (c) 1991, 1998, 2001 The Regents of the University of California.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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 * 3. [rescinded 22 July 1999]
14 * 4. Neither the name of the University nor the names of its contributors
15 * may be used to endorse or promote products derived from this software
16 * without specific prior written permission.
18 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 static char sccsid
[] = "@(#)gmon.c 5.3 (Berkeley) 5/22/91";
40 #define GMON_PTR_SIZE 4
44 char *lpc
; /* base pc address of sample buffer */
45 char *hpc
; /* max pc address of sampled buffer */
46 int ncnt
; /* size of sample buffer (plus this header) */
48 char version
[4]; /* version number */
49 char profrate
[4]; /* profiling clock rate */
50 char spare
[3*4]; /* reserved */
53 #define GMONVERSION 0x00051879
56 * Histogram counters are unsigned shorts:
58 #define HISTCOUNTER unsigned short
61 * Fraction of text space to allocate for histogram counters here, 1/2:
63 #define HISTFRACTION 2
66 * Fraction of text space to allocate for from hash buckets. The
67 * value of HASHFRACTION is based on the minimum number of bytes of
68 * separation between two subroutine call points in the object code.
69 * Given MIN_SUBR_SEPARATION bytes of separation the value of
70 * HASHFRACTION is calculated as:
72 * HASHFRACTION = MIN_SUBR_SEPARATION / (2 * sizeof(short) - 1);
74 * For the VAX, the shortest two call sequence is:
79 * which is separated by only three bytes, thus HASHFRACTION is
82 * HASHFRACTION = 3 / (2 * 2 - 1) = 1
84 * Note that the division above rounds down, thus if MIN_SUBR_FRACTION
85 * is less than three, this algorithm will not work!
87 #define HASHFRACTION 1
90 * Percent of text space to allocate for tostructs with a minimum:
103 * A raw arc, with pointers to the calling site and the called site
104 * and a count. Everything is defined in terms of characters so
105 * as to get a packed representation (otherwise, different compilers
106 * might introduce different padding):
110 unsigned long raw_frompc
;
111 unsigned long raw_selfpc
;
116 * General rounding functions:
118 #define ROUNDDOWN(x,y) (((x)/(y))*(y))
119 #define ROUNDUP(x,y) ((((x)+(y)-1)/(y))*(y))
123 extern char *sbrk ();
127 * froms is actually a bunch of unsigned shorts indexing tos
129 static int profiling
= 3;
130 static unsigned short *froms
;
131 static struct tostruct
*tos
= 0;
132 static long tolimit
= 0;
133 static char *s_lowpc
= 0;
134 static char *s_highpc
= 0;
135 static unsigned long s_textsize
= 0;
140 /* see profil(2) where this is describe (incorrectly) */
141 #define SCALE_1_TO_1 0x10000L
143 #define MSG "No space for profiling buffer(s)\n"
157 struct rawarc rawarc
;
160 fd
= open ("gmon.out", O_WRONLY
|O_TRUNC
|O_CREAT
|O_BINARY
, 0666);
163 perror ("mcount: gmon.out");
167 fprintf (stderr
, "[mcleanup] sbuf 0x%x ssiz %d\n", sbuf
, ssiz
);
169 write (fd
, sbuf
, ssiz
);
170 endfrom
= s_textsize
/ (HASHFRACTION
* sizeof (*froms
));
171 for (fromindex
= 0; fromindex
< endfrom
; fromindex
++)
173 if (froms
[fromindex
] == 0)
177 frompc
= s_lowpc
+ (fromindex
* HASHFRACTION
* sizeof (*froms
));
178 for (toindex
= froms
[fromindex
]; toindex
!= 0;
179 toindex
= tos
[toindex
].link
)
183 "[mcleanup] frompc 0x%x selfpc 0x%x count %d\n",
184 frompc
, tos
[toindex
].selfpc
, tos
[toindex
].count
);
186 rawarc
.raw_frompc
= (unsigned long) frompc
;
187 rawarc
.raw_selfpc
= (unsigned long) tos
[toindex
].selfpc
;
188 rawarc
.raw_count
= tos
[toindex
].count
;
189 write (fd
, &rawarc
, sizeof rawarc
);
196 monstartup (lowpc
, highpc
)
207 * round lowpc and highpc to multiples of the density we're using
208 * so the rest of the scaling (here and in gprof) stays in ints.
211 ROUNDDOWN ((unsigned) lowpc
, HISTFRACTION
* sizeof (HISTCOUNTER
));
214 ROUNDUP ((unsigned) highpc
, HISTFRACTION
* sizeof (HISTCOUNTER
));
216 s_textsize
= highpc
- lowpc
;
217 monsize
= (s_textsize
/ HISTFRACTION
) + sizeof (struct phdr
);
218 buffer
= sbrk (monsize
);
219 if (buffer
== (char *) -1)
221 write (2, MSG
, sizeof (MSG
));
224 froms
= (unsigned short *) sbrk (s_textsize
/ HASHFRACTION
);
225 if (froms
== (unsigned short *) -1)
227 write (2, MSG
, sizeof (MSG
));
231 tolimit
= s_textsize
* ARCDENSITY
/ 100;
232 if (tolimit
< MINARCS
)
236 else if (tolimit
> 65534)
240 tos
= (struct tostruct
*) sbrk (tolimit
* sizeof (struct tostruct
));
241 if (tos
== (struct tostruct
*) -1)
243 write (2, MSG
, sizeof (MSG
));
251 ((struct phdr
*) buffer
)->lpc
= lowpc
;
252 ((struct phdr
*) buffer
)->hpc
= highpc
;
253 ((struct phdr
*) buffer
)->ncnt
= ssiz
;
254 monsize
-= sizeof (struct phdr
);
260 s_scale
= ((float) monsize
/ o
) * SCALE_1_TO_1
;
261 #else /* avoid floating point */
263 int quot
= o
/ monsize
;
267 else if (quot
>= 0x100)
268 s_scale
= 0x10000 / quot
;
269 else if (o
>= 0x800000)
270 s_scale
= 0x1000000 / (o
/ (monsize
>> 8));
272 s_scale
= 0x1000000 / ((o
<< 8) / monsize
);
276 s_scale
= SCALE_1_TO_1
;
280 /* These happen to be in the right place because of how crt0 works */
281 extern char __attribute__((far
)) _start
;
282 extern char __attribute__((far
)) _etext
;
285 __mep_mcount_2 (selfpc
, frompcindex
)
287 unsigned short *frompcindex
;
289 struct tostruct
*top
;
290 struct tostruct
*prevtop
;
292 static int initialized
= 0;
297 monstartup (&_start
, &_etext
);
301 * check that we are profiling
302 * and that we aren't recursively invoked.
310 * check that frompcindex is a reasonable pc value.
311 * for example: signal catchers get called from the stack,
312 * not from text space. too bad.
314 frompcindex
= (unsigned short *) ((long) frompcindex
- (long) s_lowpc
);
315 if ((unsigned long) frompcindex
> s_textsize
)
320 &froms
[((long) frompcindex
) / (HASHFRACTION
* sizeof (*froms
))];
321 toindex
= *frompcindex
;
325 * first time traversing this arc
327 toindex
= ++tos
[0].link
;
328 if (toindex
>= tolimit
)
332 *frompcindex
= toindex
;
334 top
->selfpc
= selfpc
;
340 if (top
->selfpc
== selfpc
)
343 * arc at front of chain; usual case.
349 * have to go looking down chain for it.
350 * top points to what we are looking at,
351 * prevtop points to previous top.
352 * we know it is not at the head of the chain.
354 for (; /* goto done */ ;)
359 * top is end of the chain and none of the chain
360 * had top->selfpc == selfpc.
361 * so we allocate a new tostruct
362 * and link it to the head of the chain.
364 toindex
= ++tos
[0].link
;
365 if (toindex
>= tolimit
)
370 top
->selfpc
= selfpc
;
372 top
->link
= *frompcindex
;
373 *frompcindex
= toindex
;
377 * otherwise, check the next arc on the chain.
380 top
= &tos
[top
->link
];
381 if (top
->selfpc
== selfpc
)
385 * increment its count
386 * move it to the head of the chain.
389 toindex
= prevtop
->link
;
390 prevtop
->link
= top
->link
;
391 top
->link
= *frompcindex
;
392 *frompcindex
= toindex
;
399 /* and fall through */
401 return; /* normal return restores saved registers */
404 profiling
++; /* halt further profiling */
405 # define TOLIMIT "mcount: tos overflow\n"
406 write (2, TOLIMIT
, sizeof (TOLIMIT
));