massive overhaul for new profiling structure from mccanne at LBL
[unix-history] / usr / src / lib / libc / gmon / gmon.c
CommitLineData
d78617f3
KB
1/*-
2 * Copyright (c) 1983 The Regents of the University of California.
3 * All rights reserved.
4 *
d58fa3ae 5 * %sccs.include.redist.c%
586c39b1
DF
6 */
7
d58fa3ae 8#ifndef lint
1ad65fe0 9static char sccsid[] = "@(#)gmon.c 5.10 (Berkeley) %G%";
d58fa3ae 10#endif /* not lint */
50084e08 11
2aa4eb50 12#include <unistd.h>
0754472c
KM
13#include <sys/types.h>
14#include <sys/time.h>
15#include <sys/kinfo.h>
2aa4eb50 16
bb9c5045 17#ifdef DEBUG
50084e08 18#include <stdio.h>
d78617f3 19#endif
50084e08 20
1ad65fe0 21#include <sys/gmon.h>
387d0540 22
2aa4eb50
DS
23extern char *minbrk asm ("minbrk");
24
1ad65fe0 25struct gmonparam _gmonparam = { GMON_PROF_OFF };
50084e08 26
387d0540 27static int ssiz;
37a37eeb 28static char *sbuf;
13c3ba68 29static int s_scale;
1ad65fe0 30/* see profil(2) where this is describe (incorrectly) */
37a37eeb 31#define SCALE_1_TO_1 0x10000L
50084e08 32
1ad65fe0
KM
33#define ERR(s) write(2, s, sizeof(s))
34
35static struct gmonhdr gmonhdr;
50084e08 36
ee56ba6f 37monstartup(lowpc, highpc)
1ad65fe0
KM
38 u_long lowpc;
39 u_long highpc;
50084e08 40{
1ad65fe0
KM
41 register int o;
42 struct clockinfo clockinfo;
43 int tsize, fsize, size;
44 char *cp;
45 struct gmonhdr *hdr;
46 struct gmonparam *p = &_gmonparam;
50084e08 47
019e8582 48 /*
1ad65fe0
KM
49 * round lowpc and highpc to multiples of the density we're using
50 * so the rest of the scaling (here and in gprof) stays in ints.
019e8582 51 */
1ad65fe0
KM
52 lowpc = ROUNDDOWN(lowpc, HISTFRACTION * sizeof(HISTCOUNTER));
53 p->lowpc = lowpc;
54 highpc = ROUNDUP(highpc, HISTFRACTION * sizeof(HISTCOUNTER));
55 p->highpc = highpc;
56 p->textsize = highpc - lowpc;
57 ssiz = p->textsize / HISTFRACTION;
58 fsize = p->textsize / HASHFRACTION;
59 tsize = p->textsize * ARCDENSITY / 100;
60 if (tsize < MINARCS)
61 tsize = MINARCS;
62 else if (tsize > MAXARCS)
63 tsize = MAXARCS;
64 p->tolimit = tsize;
65 tsize *= sizeof(struct tostruct);
66
67 cp = sbrk(ssiz + fsize + tsize);
68 if (cp == (char *)-1) {
69 ERR("monstartup: out of memory\n");
70 return;
71 }
72#ifdef notdef
73 bzero(cp, ssiz + fsize + tsize);
74#endif
75 p->tos = (struct tostruct *)cp;
76 cp += tsize;
77 sbuf = cp;
78 cp += ssiz;
79 p->froms = (u_short *)cp;
80
81 minbrk = sbrk(0);
82 p->tos[0].link = 0;
83
84 o = highpc - lowpc;
85 if (ssiz < o) {
0754472c 86#ifndef hp300
1ad65fe0 87 s_scale = ((float)ssiz / o ) * SCALE_1_TO_1;
0754472c 88#else /* avoid floating point */
1ad65fe0
KM
89 int quot = o / ssiz;
90
91 if (quot >= 0x10000)
92 s_scale = 1;
93 else if (quot >= 0x100)
94 s_scale = 0x10000 / quot;
95 else if (o >= 0x800000)
96 s_scale = 0x1000000 / (o / (ssiz >> 8));
97 else
98 s_scale = 0x1000000 / ((o << 8) / ssiz);
0754472c 99#endif
1ad65fe0
KM
100 } else
101 s_scale = SCALE_1_TO_1;
102
103 moncontrol(1);
104 size = sizeof(clockinfo);
105 if (getkerninfo(KINFO_CLOCKRATE, &clockinfo, &size, 0) < 0)
106 /*
107 * Best guess
108 */
109 clockinfo.profhz = hertz();
110 else if (clockinfo.profhz == 0) {
111 if (clockinfo.hz != 0)
112 clockinfo.profhz = clockinfo.hz;
113 else
114 clockinfo.profhz = hertz();
115 }
116 hdr = (struct gmonhdr *)&gmonhdr;
117 hdr->lpc = lowpc;
118 hdr->hpc = highpc;
119 hdr->ncnt = ssiz + sizeof(gmonhdr);
120 hdr->version = GMONVERSION;
121 hdr->profrate = clockinfo.profhz;
50084e08
PK
122}
123
124_mcleanup()
125{
1ad65fe0
KM
126 int fd;
127 int fromindex;
128 int endfrom;
129 u_long frompc;
130 int toindex;
131 struct rawarc rawarc;
132 struct gmonparam *p = &_gmonparam;
133
134 if (p->state == GMON_PROF_ERROR)
135 ERR("_mcleanup: tos overflow\n");
136
137 moncontrol(0);
138 fd = creat("gmon.out", 0666);
139 if (fd < 0) {
140 perror("mcount: gmon.out");
141 return;
50084e08 142 }
1ad65fe0
KM
143#ifdef DEBUG
144 fprintf(stderr, "[mcleanup] sbuf 0x%x ssiz %d\n", sbuf, ssiz);
145#endif
146 write(fd, (char *)&gmonhdr, sizeof(gmonhdr));
147 write(fd, sbuf, ssiz);
148 endfrom = p->textsize / (HASHFRACTION * sizeof(*p->froms));
149 for (fromindex = 0; fromindex < endfrom; fromindex++) {
150 if (p->froms[fromindex] == 0)
151 continue;
152
153 frompc = p->lowpc;
154 frompc += fromindex * HASHFRACTION * sizeof(*p->froms);
155 for (toindex = p->froms[fromindex]; toindex != 0;
156 toindex = p->tos[toindex].link) {
157#ifdef DEBUG
158 fprintf(stderr,
22f3ec41 159 "[mcleanup] frompc 0x%x selfpc 0x%x count %d\n" ,
1ad65fe0
KM
160 frompc, p->tos[toindex].selfpc,
161 p->tos[toindex].count);
162#endif
163 rawarc.raw_frompc = frompc;
164 rawarc.raw_selfpc = p->tos[toindex].selfpc;
165 rawarc.raw_count = p->tos[toindex].count;
166 write(fd, &rawarc, sizeof rawarc);
167 }
50084e08 168 }
1ad65fe0 169 close(fd);
50084e08
PK
170}
171
13c3ba68
PK
172/*
173 * Control profiling
174 * profiling is what mcount checks to see if
175 * all the data structures are ready.
176 */
177moncontrol(mode)
1ad65fe0 178 int mode;
13c3ba68 179{
1ad65fe0
KM
180 struct gmonparam *p = &_gmonparam;
181
182 if (mode) {
183 /* start */
184 profil(sbuf, ssiz, (int)p->lowpc, s_scale);
185 p->state = GMON_PROF_ON;
186 } else {
187 /* stop */
188 profil((char *)0, 0, 0, 0);
189 p->state = GMON_PROF_OFF;
190 }
50084e08 191}
0754472c 192
1ad65fe0
KM
193/*
194 * discover the tick frequency of the machine
195 * if something goes wrong, we return 0, an impossible hertz.
196 */
0754472c
KM
197hertz()
198{
199 struct itimerval tim;
1ad65fe0 200
0754472c
KM
201 tim.it_interval.tv_sec = 0;
202 tim.it_interval.tv_usec = 1;
203 tim.it_value.tv_sec = 0;
204 tim.it_value.tv_usec = 0;
205 setitimer(ITIMER_REAL, &tim, 0);
206 setitimer(ITIMER_REAL, 0, &tim);
207 if (tim.it_interval.tv_usec < 2)
208 return(0);
209 return (1000000 / tim.it_interval.tv_usec);
210}
1ad65fe0
KM
211
212