Cygwin: dirent.h: fix a comment
[newlib-cygwin.git] / libgloss / mep / mep-gmon.c
blob72d6369a3e990e2ebca80b3db8e94c4f0af7c239
1 /*-
2 * Copyright (c) 1991, 1998, 2001 The Regents of the University of California.
3 * All rights reserved.
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 * 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
28 * SUCH DAMAGE.
31 #ifndef lint
32 static char sccsid[] = "@(#)gmon.c 5.3 (Berkeley) 5/22/91";
33 #endif /* not lint */
35 #include <fcntl.h>
36 #include <unistd.h>
37 #include <stdlib.h>
38 #include <stdio.h>
40 #define GMON_PTR_SIZE 4
42 struct phdr
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:
76 * calls $0,(r0)
77 * calls $0,(r0)
79 * which is separated by only three bytes, thus HASHFRACTION is
80 * calculated as:
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:
92 #define ARCDENSITY 2
93 #define MINARCS 50
95 struct tostruct
97 char *selfpc;
98 int count;
99 unsigned short link;
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):
108 struct rawarc
110 unsigned long raw_frompc;
111 unsigned long raw_selfpc;
112 int raw_count;
116 * General rounding functions:
118 #define ROUNDDOWN(x,y) (((x)/(y))*(y))
119 #define ROUNDUP(x,y) ((((x)+(y)-1)/(y))*(y))
122 #ifdef __alpha
123 extern char *sbrk ();
124 #endif
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;
137 static int ssiz;
138 static char *sbuf;
139 static int s_scale;
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"
145 #ifndef O_BINARY
146 #define O_BINARY 0
147 #endif
149 static void
150 moncleanup ()
152 int fd;
153 int fromindex;
154 int endfrom;
155 char *frompc;
156 int toindex;
157 struct rawarc rawarc;
159 profiling = 1;
160 fd = open ("gmon.out", O_WRONLY|O_TRUNC|O_CREAT|O_BINARY, 0666);
161 if (fd < 0)
163 perror ("mcount: gmon.out");
164 return;
166 #ifdef DEBUG
167 fprintf (stderr, "[mcleanup] sbuf 0x%x ssiz %d\n", sbuf, ssiz);
168 #endif /* DEBUG */
169 write (fd, sbuf, ssiz);
170 endfrom = s_textsize / (HASHFRACTION * sizeof (*froms));
171 for (fromindex = 0; fromindex < endfrom; fromindex++)
173 if (froms[fromindex] == 0)
175 continue;
177 frompc = s_lowpc + (fromindex * HASHFRACTION * sizeof (*froms));
178 for (toindex = froms[fromindex]; toindex != 0;
179 toindex = tos[toindex].link)
181 #ifdef DEBUG
182 fprintf (stderr,
183 "[mcleanup] frompc 0x%x selfpc 0x%x count %d\n",
184 frompc, tos[toindex].selfpc, tos[toindex].count);
185 #endif /* DEBUG */
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);
192 close (fd);
195 static void
196 monstartup (lowpc, highpc)
197 char *lowpc;
198 char *highpc;
200 int monsize;
201 char *buffer;
202 register int o;
204 atexit (moncleanup);
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.
210 lowpc = (char *)
211 ROUNDDOWN ((unsigned) lowpc, HISTFRACTION * sizeof (HISTCOUNTER));
212 s_lowpc = lowpc;
213 highpc = (char *)
214 ROUNDUP ((unsigned) highpc, HISTFRACTION * sizeof (HISTCOUNTER));
215 s_highpc = highpc;
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));
222 return;
224 froms = (unsigned short *) sbrk (s_textsize / HASHFRACTION);
225 if (froms == (unsigned short *) -1)
227 write (2, MSG, sizeof (MSG));
228 froms = 0;
229 return;
231 tolimit = s_textsize * ARCDENSITY / 100;
232 if (tolimit < MINARCS)
234 tolimit = MINARCS;
236 else if (tolimit > 65534)
238 tolimit = 65534;
240 tos = (struct tostruct *) sbrk (tolimit * sizeof (struct tostruct));
241 if (tos == (struct tostruct *) -1)
243 write (2, MSG, sizeof (MSG));
244 froms = 0;
245 tos = 0;
246 return;
248 tos[0].link = 0;
249 sbuf = buffer;
250 ssiz = monsize;
251 ((struct phdr *) buffer)->lpc = lowpc;
252 ((struct phdr *) buffer)->hpc = highpc;
253 ((struct phdr *) buffer)->ncnt = ssiz;
254 monsize -= sizeof (struct phdr);
255 if (monsize <= 0)
256 return;
257 o = highpc - lowpc;
258 if (monsize < o)
259 #if 0
260 s_scale = ((float) monsize / o) * SCALE_1_TO_1;
261 #else /* avoid floating point */
263 int quot = o / monsize;
265 if (quot >= 0x10000)
266 s_scale = 1;
267 else if (quot >= 0x100)
268 s_scale = 0x10000 / quot;
269 else if (o >= 0x800000)
270 s_scale = 0x1000000 / (o / (monsize >> 8));
271 else
272 s_scale = 0x1000000 / ((o << 8) / monsize);
274 #endif
275 else
276 s_scale = SCALE_1_TO_1;
277 profiling = 0;
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;
284 void
285 __mep_mcount_2 (selfpc, frompcindex)
286 char *selfpc;
287 unsigned short *frompcindex;
289 struct tostruct *top;
290 struct tostruct *prevtop;
291 long toindex;
292 static int initialized = 0;
294 if (!initialized)
296 initialized = 1;
297 monstartup (&_start, &_etext);
301 * check that we are profiling
302 * and that we aren't recursively invoked.
304 if (profiling)
306 goto out;
308 profiling++;
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)
317 goto done;
319 frompcindex =
320 &froms[((long) frompcindex) / (HASHFRACTION * sizeof (*froms))];
321 toindex = *frompcindex;
322 if (toindex == 0)
325 * first time traversing this arc
327 toindex = ++tos[0].link;
328 if (toindex >= tolimit)
330 goto overflow;
332 *frompcindex = toindex;
333 top = &tos[toindex];
334 top->selfpc = selfpc;
335 top->count = 1;
336 top->link = 0;
337 goto done;
339 top = &tos[toindex];
340 if (top->selfpc == selfpc)
343 * arc at front of chain; usual case.
345 top->count++;
346 goto done;
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 */ ;)
356 if (top->link == 0)
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)
367 goto overflow;
369 top = &tos[toindex];
370 top->selfpc = selfpc;
371 top->count = 1;
372 top->link = *frompcindex;
373 *frompcindex = toindex;
374 goto done;
377 * otherwise, check the next arc on the chain.
379 prevtop = top;
380 top = &tos[top->link];
381 if (top->selfpc == selfpc)
384 * there it is.
385 * increment its count
386 * move it to the head of the chain.
388 top->count++;
389 toindex = prevtop->link;
390 prevtop->link = top->link;
391 top->link = *frompcindex;
392 *frompcindex = toindex;
393 goto done;
397 done:
398 profiling--;
399 /* and fall through */
400 out:
401 return; /* normal return restores saved registers */
403 overflow:
404 profiling++; /* halt further profiling */
405 # define TOLIMIT "mcount: tos overflow\n"
406 write (2, TOLIMIT, sizeof (TOLIMIT));
407 goto out;