LibXenon
Bare-metal Xbox 360 homebrew library
Loading...
Searching...
No Matches
gmon.c
Go to the documentation of this file.
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 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by the University of
16 * California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33
34#if !defined(lint) && defined(LIBC_SCCS)
35static char sccsid[] = "@(#)gmon.c 8.1 (Berkeley) 6/4/93";
36#endif
37
38#include <sys/param.h>
39#include <sys/time.h>
40#include <arch/lib.h>
41#include "gmon.h"
42//#include <sys/sysctl.h>
43
44#include <ppc/timebase.h>
45
46#include <stdio.h>
47#include <fcntl.h>
48#include <unistd.h>
49#include <debug.h>
50
51char *minbrk;
52
54
55static int s_scale;
56/* see profil(2) where this is describe (incorrectly) */
57#define SCALE_1_TO_1 0x10000L
58
59#define ERR(s) write(2, s, sizeof(s))
60
61//#define HISTFRACTION 2
62//#define HISTCOUNTER unsigned short
63//#define HASHFRACTION 1
64
65// #define GUPROF 1
66
67static int cputime_bias = 0;
68static u_long prev_count= 0;
69
70/*
71 * Return the time elapsed since the last call. The units are machine-
72 * dependent.
73 * XXX: this is not SMP-safe. It should use per-CPU variables; %tick can be
74 * used though.
75 */
76int
78{
79 u_long count;
80 int delta;
81
82 count = mftb();
83 delta = (int)(count - prev_count);
84 prev_count = count;
85 return (delta);
86}
87
88void moncontrol (int);
89
90void
92 u_long lowpc;
93 u_long highpc;
94{
95 register int o;
96 char *cp;
97 struct gmonparam *p = &_gmonparam;
98
99 prev_count = mftb();
100
101 /*
102 * round lowpc and highpc to multiples of the density we're using
103 * so the rest of the scaling (here and in gprof) stays in ints.
104 */
107 p->textsize = p->highpc - p->lowpc;
111 p->tolimit = p->textsize * ARCDENSITY / 100;
112 if (p->tolimit < MINARCS)
113 p->tolimit = MINARCS;
114 else if (p->tolimit > MAXARCS)
115 p->tolimit = MAXARCS;
116 p->tossize = p->tolimit * sizeof(struct tostruct);
117
118 cp = sbrk(p->kcountsize + p->fromssize + p->tossize);
119 if (cp == (char *)-1) {
120 ERR("monstartup: out of memory\n");
121 return;
122 }
123//#ifdef notdef
124 bzero(cp, p->kcountsize + p->fromssize + p->tossize);
125//#endif
126 p->tos = (struct tostruct *)cp;
127 cp += p->tossize;
128 p->kcount = (u_short *)cp;
129 cp += p->kcountsize;
130 p->froms = (u_short *)cp;
131
132 minbrk = sbrk(0);
133 p->tos[0].link = 0;
134
135 o = p->highpc - p->lowpc;
136 if (p->kcountsize < o) {
137#ifndef hp300
138 s_scale = ((float)p->kcountsize / o ) * SCALE_1_TO_1;
139#else /* avoid floating point */
140 int quot = o / p->kcountsize;
141
142 if (quot >= 0x10000)
143 s_scale = 1;
144 else if (quot >= 0x100)
145 s_scale = 0x10000 / quot;
146 else if (o >= 0x800000)
147 s_scale = 0x1000000 / (o / (p->kcountsize >> 8));
148 else
149 s_scale = 0x1000000 / ((o << 8) / p->kcountsize);
150#endif
151 } else
152 s_scale = SCALE_1_TO_1;
153
154 moncontrol(1);
155}
156
157void
159{
160 int fd;
161 int fromindex;
162 int endfrom;
163 u_long frompc;
164 int toindex;
165 struct rawarc rawarc;
166 struct gmonparam *p = &_gmonparam;
167 struct gmonhdr gmonhdr, *hdr;
168 struct clockinfo clockinfo;
169#ifdef DEBUG
170 int log, len;
171 char buf[200];
172#endif
173
174 if (p->state == GMON_PROF_ERROR)
175 ERR("_mcleanup: tos overflow\n");
176
177 size_t size = sizeof(clockinfo);
178
179#if 0
180 mib[0] = CTL_KERN;
181 mib[1] = KERN_CLOCKRATE;
182 if (sysctl(mib, 2, &clockinfo, &size, NULL, 0) < 0) {
183 /*
184 * Best guess
185 */
186 clockinfo.profhz = hertz();
187 } else if (clockinfo.profhz == 0) {
188 if (clockinfo.hz != 0)
190 else
191 clockinfo.profhz = hertz();
192 }
193#else
194 //clockinfo.profhz = (PPC_TIMEBASE_FREQ);
195 //clockinfo.profhz = (1000);
196 clockinfo.profhz = 100;
197#endif
198
199 moncontrol(0);
200 fd = open("uda:/gmon.out", O_CREAT|O_TRUNC|O_WRONLY, 0666);
201 if (fd < 0) {
202 perror("mcount: uda:/gmon.out");
203 return;
204 }
205#ifdef DEBUG
206 log = open("uda:/gmon.log", O_CREAT|O_TRUNC|O_WRONLY, 0664);
207 if (log < 0) {
208 perror("mcount: uda:/gmon.log");
209 return;
210 }
211 len = sprintf(buf, "[mcleanup1] kcount 0x%x ssiz %d\n",
212 p->kcount, p->kcountsize);
213 write(log, buf, len);
214#endif
215 hdr = (struct gmonhdr *)&gmonhdr;
216 hdr->lpc = p->lowpc;
217 hdr->hpc = p->highpc;
218 hdr->ncnt = p->kcountsize + sizeof(gmonhdr);
219 hdr->version = GMONVERSION;
221 write(fd, (char *)hdr, sizeof *hdr);
222 write(fd, p->kcount, p->kcountsize);
223 endfrom = p->fromssize / sizeof(*p->froms);
224 for (fromindex = 0; fromindex < endfrom; fromindex++) {
225 if (p->froms[fromindex] == 0)
226 continue;
227
228 frompc = p->lowpc;
229 frompc += fromindex * p->hashfraction * sizeof(*p->froms);
230 for (toindex = p->froms[fromindex]; toindex != 0;
231 toindex = p->tos[toindex].link) {
232#ifdef DEBUG
233 len = sprintf(buf,
234 "[mcleanup2] frompc 0x%x selfpc 0x%x count %d\n" ,
235 frompc, p->tos[toindex].selfpc,
236 p->tos[toindex].count);
237 write(log, buf, len);
238#endif
239 rawarc.raw_frompc = frompc;
240 rawarc.raw_selfpc = p->tos[toindex].selfpc;
241 rawarc.raw_count = p->tos[toindex].count;
242 write(fd, &rawarc, sizeof rawarc);
243 }
244 }
245 close(fd);
246}
247
248/*
249 * Control profiling
250 * profiling is what mcount checks to see if
251 * all the data structures are ready.
252 */
253void
255 int mode;
256{
257 TR;
258 struct gmonparam *p = &_gmonparam;
259
260 if (mode) {
261 /* start */
262/* profil((char *)p->kcount, p->kcountsize, (int)p->lowpc,
263 s_scale); */
264 p->state = GMON_PROF_ON;
265 } else {
266 /* stop */
267/* profil((char *)0, 0, 0, 0); */
268 p->state = GMON_PROF_OFF;
269 }
270}
271
272
274 ".global _mcount \n"
275 "_mcount: \n"
276 "stwu %sp, -0x70(%sp) \n"
277 "mflr %r0 \n"
278 "stw %r0, 0x60(%sp) \n"
279 "std %r3, 0x10(%sp) \n"
280 "std %r4, 0x18(%sp) \n"
281 "std %r5, 0x20(%sp) \n"
282 "std %r6, 0x28(%sp) \n"
283 "std %r7, 0x30(%sp) \n"
284 "std %r8, 0x38(%sp) \n"
285 "std %r9, 0x40(%sp) \n"
286 "std %r10, 0x48(%sp) \n"
287 "mflr %r3 \n"
288 "lwz %r4,0x74(%sp) \n"
289 "bl internal_mcount \n"
290 "ld %r3, 0x10(%sp) \n"
291 "ld %r4, 0x18(%sp) \n"
292 "ld %r5, 0x20(%sp) \n"
293 "ld %r6, 0x28(%sp) \n"
294 "ld %r7, 0x30(%sp) \n"
295 "ld %r8, 0x38(%sp) \n"
296 "ld %r9, 0x40(%sp) \n"
297 "ld %r10, 0x48(%sp) \n"
298 "lwz %r11, 0x60(%sp) \n"
299 "addi %sp, %sp, 0x70 \n"
300 "mtlr %r0 \n"
301 "lwz %r0,4(%sp) \n"
302 "mtctr %r11 \n"
303 "mtlr %r0 \n"
304 "bctr \n"
305);
306
307/*
308 * mcount is called on entry to each function compiled with the profiling
309 * switch set. _mcount(), which is declared in a machine-dependent way
310 * with _MCOUNT_DECL, does the actual work and is either inlined into a
311 * C routine or called by an assembly stub. In any case, this magic is
312 * taken care of by the MCOUNT definition in <machine/profile.h>.
313 *
314 * _mcount updates data structures that represent traversals of the
315 * program's call graph edges. frompc and selfpc are the return
316 * address and function address that represents the given call graph edge.
317 *
318 * Note: the original BSD code used the same variable (frompcindex) for
319 * both frompcindex and frompc. Any reasonable, modern compiler will
320 * perform this optimization.
321 */
322 #if 0
323_MCOUNT_DECL(frompc, selfpc) /* _mcount; may be static, inline, etc */
324 register fptrint_t frompc, selfpc;
325#else
326void internal_mcount(selfpc, frompc)
327 register fptrint_t selfpc, frompc;
328#endif
329{
330//#ifdef GUPROF
331 u_int delta;
332//#endif
333 register fptrdiff_t frompci;
334 register u_short *frompcindex;
335 register struct tostruct *top, *prevtop;
336 register struct gmonparam *p;
337 register long toindex;
338#ifdef KERNEL
339 MCOUNT_DECL(s)
340#endif
341
342// printf("%p %p\r\n",selfpc,frompc);
343// printf("%x %x\r\n",selfpc,frompc);
344// printf("\r\n");
345
346 static char already_setup;
347 if(!already_setup) {
348 extern char bss_start[];
349 already_setup = 1;
350 monstartup(0x80000000, bss_start);
351#ifdef USE_ONEXIT
352 on_exit(_mcleanup, 0);
353#else
354 atexit(_mcleanup);
355#endif
356 }
357
358 p = &_gmonparam;
359#ifndef GUPROF /* XXX */
360 /*
361 * check that we are profiling
362 * and that we aren't recursively invoked.
363 */
364 if (p->state != GMON_PROF_ON)
365 return;
366#endif
367#ifdef KERNEL
368 MCOUNT_ENTER(s);
369#else
371#endif
372 frompci = frompc - p->lowpc;
373
374#ifdef KERNEL
375 /*
376 * When we are called from an exception handler, frompci may be
377 * for a user address. Convert such frompci's to the index of
378 * user() to merge all user counts.
379 */
380 if (frompci >= p->textsize) {
381 if (frompci + p->lowpc
382 >= (fptrint_t)(VM_MAXUSER_ADDRESS + UPAGES * PAGE_SIZE))
383 goto done;
384 frompci = (fptrint_t)user - p->lowpc;
385 if (frompci >= p->textsize)
386 goto done;
387 }
388#endif /* KERNEL */
389
390//#ifdef GUPROF
391#if 1
392// if (p->state != GMON_PROF_HIRES){
393 /*
394 * Count the time since cputime() was previously called
395 * against `frompc'. Compensate for overheads.
396 *
397 * cputime() sets its prev_count variable to the count when
398 * it is called. This in effect starts a counter for
399 * the next period of execution (normally from now until
400 * the next call to mcount() or mexitcount()). We set
401 * cputime_bias to compensate for our own overhead.
402 *
403 * We use the usual sampling counters since they can be
404 * located efficiently. 4-byte counters are usually
405 * necessary. gprof will add up the scattered counts
406 * just like it does for statistical profiling. All
407 * counts are signed so that underflow in the subtractions
408 * doesn't matter much (negative counts are normally
409 * compensated for by larger counts elsewhere). Underflow
410 * shouldn't occur, but may be caused by slightly wrong
411 * calibrations or from not clearing cputime_bias.
412 */
413 delta = cputime() - cputime_bias - p->mcount_pre_overhead;
414 cputime_bias = p->mcount_post_overhead;
415 //TR;
416 //printf("(index) / (HISTFRACTION * sizeof(HISTCOUNTER))\r\n");
417 //printf("%x / (%x * %x)\r\n",frompci,HISTFRACTION,sizeof(HISTCOUNTER));
418
419 KCOUNT(p, frompci) += delta;
420
421 //TR;
422 //*p->cputime_count += p->cputime_overhead;
423 //*p->mcount_count += p->mcount_overhead;
424 //TR;
425 //}
426#endif
427//#endif /* GUPROF */
428
429#ifdef KERNEL
430 /*
431 * When we are called from an exception handler, frompc is faked
432 * to be for where the exception occurred. We've just solidified
433 * the count for there. Now convert frompci to the index of btrap()
434 * for trap handlers and bintr() for interrupt handlers to make
435 * exceptions appear in the call graph as calls from btrap() and
436 * bintr() instead of calls from all over.
437 */
438 if ((fptrint_t)selfpc >= (fptrint_t)btrap
439 && (fptrint_t)selfpc < (fptrint_t)eintr) {
440 if ((fptrint_t)selfpc >= (fptrint_t)bintr)
441 frompci = (fptrint_t)bintr - p->lowpc;
442 else
443 frompci = (fptrint_t)btrap - p->lowpc;
444 }
445#endif /* KERNEL */
446
447 /*
448 * check that frompc is a reasonable pc value.
449 * for example: signal catchers get called from the stack,
450 * not from text space. too bad.
451 */
452 if (frompci >= p->textsize)
453 goto done;
454
455// TR;
456// printf("%p %p\n",toindex,frompci);
457
458// printf("p->hashfraction = %x\r\n",p->hashfraction);
459// printf("sizeof(*p->froms) = %x\r\n",sizeof(*p->froms));
460
461 frompcindex = &p->froms[frompci / (p->hashfraction * sizeof(*p->froms))];
462 toindex = *frompcindex;
463
464// TR;
465// printf("%p %p\n",toindex,frompcindex);
466
467 if (toindex == 0) {
468 /*
469 * first time traversing this arc
470 */
471 toindex = ++p->tos[0].link;
472 if (toindex >= p->tolimit)
473 /* halt further profiling */
474 goto overflow;
475
476 *frompcindex = toindex;
477 top = &p->tos[toindex];
478 top->selfpc = selfpc;
479 top->count = 1;
480 top->link = 0;
481 goto done;
482 }
483 top = &p->tos[toindex];
484 if (top->selfpc == selfpc) {
485 /*
486 * arc at front of chain; usual case.
487 */
488 top->count++;
489 goto done;
490 }
491 /*
492 * have to go looking down chain for it.
493 * top points to what we are looking at,
494 * prevtop points to previous top.
495 * we know it is not at the head of the chain.
496 */
497 for (; /* goto done */; ) {
498 if (top->link == 0) {
499// printf("toindex : %08x %p\n",toindex,toindex);
500 /*
501 * top is end of the chain and none of the chain
502 * had top->selfpc == selfpc.
503 * so we allocate a new tostruct
504 * and link it to the head of the chain.
505 */
506 toindex = ++p->tos[0].link;
507 if (toindex >= p->tolimit)
508 goto overflow;
509
510 top = &p->tos[toindex];
511 top->selfpc = selfpc;
512 top->count = 1;
513 top->link = *frompcindex;
514 *frompcindex = toindex;
515 goto done;
516 }
517 /*
518 * otherwise, check the next arc on the chain.
519 */
520 prevtop = top;
521 top = &p->tos[top->link];
522 if (top->selfpc == selfpc) {
523// printf("selfpc : %08x %p\n",top->selfpc,top->selfpc);
524// printf("toindex : %08x %p\n",toindex,toindex);
525 /*
526 * there it is.
527 * increment its count
528 * move it to the head of the chain.
529 */
530 top->count++;
531 toindex = prevtop->link;
532 prevtop->link = top->link;
533 top->link = *frompcindex;
534 *frompcindex = toindex;
535 goto done;
536 }
537
538 }
539done:
540#ifdef KERNEL
541 MCOUNT_EXIT(s);
542#else
543 p->state = GMON_PROF_ON;
544#endif
545 return;
546overflow:
548#ifdef KERNEL
549 MCOUNT_EXIT(s);
550#endif
551 return;
552}
#define NULL
Definition: def.h:47
void monstartup(u_long lowpc, u_long highpc)
Definition: gmon.c:91
#define SCALE_1_TO_1
Definition: gmon.c:57
int cputime(void)
Definition: gmon.c:77
struct gmonparam _gmonparam
Definition: gmon.c:53
__asm__(".global _mcount \n" "_mcount: \n" "stwu %sp, -0x70(%sp) \n" "mflr %r0 \n" "stw %r0, 0x60(%sp) \n" "std %r3, 0x10(%sp) \n" "std %r4, 0x18(%sp) \n" "std %r5, 0x20(%sp) \n" "std %r6, 0x28(%sp) \n" "std %r7, 0x30(%sp) \n" "std %r8, 0x38(%sp) \n" "std %r9, 0x40(%sp) \n" "std %r10, 0x48(%sp) \n" "mflr %r3 \n" "lwz %r4,0x74(%sp) \n" "bl internal_mcount \n" "ld %r3, 0x10(%sp) \n" "ld %r4, 0x18(%sp) \n" "ld %r5, 0x20(%sp) \n" "ld %r6, 0x28(%sp) \n" "ld %r7, 0x30(%sp) \n" "ld %r8, 0x38(%sp) \n" "ld %r9, 0x40(%sp) \n" "ld %r10, 0x48(%sp) \n" "lwz %r11, 0x60(%sp) \n" "addi %sp, %sp, 0x70 \n" "mtlr %r0 \n" "lwz %r0,4(%sp) \n" "mtctr %r11 \n" "mtlr %r0 \n" "bctr \n")
void moncontrol(int)
Definition: gmon.c:254
void _mcleanup()
Definition: gmon.c:158
#define ERR(s)
Definition: gmon.c:59
char * minbrk
Definition: gmon.c:51
void internal_mcount(fptrint_t selfpc, fptrint_t frompc)
Definition: gmon.c:326
#define KCOUNT(p, index)
Definition: gmon.h:225
#define ROUNDUP(x, y)
Definition: gmon.h:174
int fptrdiff_t
Definition: gmon.h:42
#define GMON_PROF_ON
Definition: gmon.h:209
#define ARCDENSITY
Definition: gmon.h:144
#define GMON_PROF_OFF
Definition: gmon.h:212
#define ROUNDDOWN(x, y)
Definition: gmon.h:173
#define GMONVERSION
Definition: gmon.h:74
#define HISTCOUNTER
Definition: gmon.h:82
#define MAXARCS
Definition: gmon.h:151
#define HISTFRACTION
Definition: gmon.h:92
#define MINARCS
Definition: gmon.h:145
u_int fptrint_t
Definition: gmon.h:41
#define HASHFRACTION
Definition: gmon.h:138
#define GMON_PROF_ERROR
Definition: gmon.h:211
#define GMON_PROF_BUSY
Definition: gmon.h:210
#define TR
Definition: debug.h:15
u32 size
Definition: iso9660.c:537
#define bzero(d, l)
Definition: lib.h:41
int close(int fileDesc)
Definition: newlib.c:829
int write(int fileDesc, const void *ptr, size_t len)
Definition: newlib.c:584
int open(const char *file, int flags, int mode)
Definition: newlib.c:522
void * sbrk(ptrdiff_t incr)
Definition: newlib.c:124
Definition: gmon.h:48
int profhz
Definition: gmon.h:53
int hz
Definition: gmon.h:49
Definition: gmon.h:65
int version
Definition: gmon.h:69
u_long lpc
Definition: gmon.h:66
int ncnt
Definition: gmon.h:68
u_long hpc
Definition: gmon.h:67
int profrate
Definition: gmon.h:70
u_long hashfraction
Definition: gmon.h:191
long tolimit
Definition: gmon.h:187
u_short * froms
Definition: gmon.h:183
struct tostruct * tos
Definition: gmon.h:185
u_long textsize
Definition: gmon.h:190
uintfptr_t highpc
Definition: gmon.h:189
u_long kcountsize
Definition: gmon.h:182
int mcount_pre_overhead
Definition: gmon.h:198
u_long tossize
Definition: gmon.h:186
int mcount_post_overhead
Definition: gmon.h:197
uintfptr_t lowpc
Definition: gmon.h:188
int state
Definition: gmon.h:180
HISTCOUNTER * kcount
Definition: gmon.h:181
u_long fromssize
Definition: gmon.h:184
Definition: gmon.h:164
u_long raw_selfpc
Definition: gmon.h:166
u_long raw_frompc
Definition: gmon.h:165
long raw_count
Definition: gmon.h:167
Definition: gmon.h:153
long count
Definition: gmon.h:155
u_long selfpc
Definition: gmon.h:154
u_short link
Definition: gmon.h:156