Commit | Line | Data |
---|---|---|
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 | 9 | static 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 |
23 | extern char *minbrk asm ("minbrk"); |
24 | ||
1ad65fe0 | 25 | struct gmonparam _gmonparam = { GMON_PROF_OFF }; |
50084e08 | 26 | |
387d0540 | 27 | static int ssiz; |
37a37eeb | 28 | static char *sbuf; |
13c3ba68 | 29 | static 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 | ||
35 | static struct gmonhdr gmonhdr; | |
50084e08 | 36 | |
ee56ba6f | 37 | monstartup(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 | */ | |
177 | moncontrol(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 |
197 | hertz() |
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 |