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