Commit | Line | Data |
---|---|---|
da7c5cc6 | 1 | /* |
0880b18e | 2 | * Copyright (c) 1982, 1986 Regents of the University of California. |
2b75fa20 | 3 | * All rights reserved. |
da7c5cc6 | 4 | * |
2b75fa20 KM |
5 | * %sccs.include.redist.c% |
6 | * | |
dd9ec193 | 7 | * @(#)subr_prof.c 7.8 (Berkeley) %G% |
da7c5cc6 | 8 | */ |
08621963 | 9 | |
3a3e0b91 | 10 | #ifdef GPROF |
94368568 JB |
11 | #include "gprof.h" |
12 | #include "param.h" | |
13 | #include "systm.h" | |
093d2b12 | 14 | #include "malloc.h" |
3a3e0b91 SL |
15 | |
16 | /* | |
17 | * Froms is actually a bunch of unsigned shorts indexing tos | |
18 | */ | |
fb1db32c MK |
19 | int profiling = 3; |
20 | u_short *froms; | |
21 | struct tostruct *tos = 0; | |
22 | long tolimit = 0; | |
23 | #if defined(vax) | |
3a3e0b91 | 24 | char *s_lowpc = (char *)0x80000000; |
961945a8 | 25 | #endif |
fb1db32c MK |
26 | #if defined(tahoe) |
27 | char *s_lowpc = (char *)0xc0000000; | |
28 | #endif | |
2b75fa20 KM |
29 | #if defined(hp300) |
30 | char *s_lowpc = (char *)0x00000000; | |
31 | #endif | |
fb1db32c MK |
32 | extern char etext; |
33 | char *s_highpc = &etext; | |
3a3e0b91 | 34 | u_long s_textsize = 0; |
fb1db32c | 35 | int ssiz; |
3a3e0b91 SL |
36 | u_short *sbuf; |
37 | u_short *kcount; | |
38 | ||
39 | kmstartup() | |
40 | { | |
fb1db32c | 41 | u_long fromssize, tossize; |
3a3e0b91 | 42 | |
08621963 | 43 | /* |
fb1db32c MK |
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. | |
08621963 KM |
46 | */ |
47 | s_lowpc = (char *) | |
fb1db32c | 48 | ROUNDDOWN((unsigned)s_lowpc, HISTFRACTION*sizeof (HISTCOUNTER)); |
08621963 | 49 | s_highpc = (char *) |
fb1db32c | 50 | ROUNDUP((unsigned)s_highpc, HISTFRACTION*sizeof (HISTCOUNTER)); |
3a3e0b91 | 51 | s_textsize = s_highpc - s_lowpc; |
3a3e0b91 SL |
52 | printf("Profiling kernel, s_textsize=%d [%x..%x]\n", |
53 | s_textsize, s_lowpc, s_highpc); | |
fb1db32c | 54 | ssiz = (s_textsize / HISTFRACTION) + sizeof (struct phdr); |
093d2b12 | 55 | sbuf = (u_short *)malloc(ssiz, M_GPROF, M_WAITOK); |
3a3e0b91 SL |
56 | if (sbuf == 0) { |
57 | printf("No space for monitor buffer(s)\n"); | |
58 | return; | |
59 | } | |
878656ca | 60 | bzero(sbuf, ssiz); |
08621963 | 61 | fromssize = s_textsize / HASHFRACTION; |
093d2b12 | 62 | froms = (u_short *)malloc(fromssize, M_GPROF, M_WAITOK); |
3a3e0b91 SL |
63 | if (froms == 0) { |
64 | printf("No space for monitor buffer(s)\n"); | |
093d2b12 | 65 | free(sbuf, M_GPROF); |
3a3e0b91 SL |
66 | sbuf = 0; |
67 | return; | |
68 | } | |
2e6f9d78 | 69 | bzero(froms, fromssize); |
08621963 | 70 | tolimit = s_textsize * ARCDENSITY / 100; |
fb1db32c | 71 | if (tolimit < MINARCS) |
08621963 | 72 | tolimit = MINARCS; |
fb1db32c MK |
73 | else if (tolimit > (0xffff - 1)) |
74 | tolimit = 0xffff - 1; | |
75 | tossize = tolimit * sizeof (struct tostruct); | |
093d2b12 | 76 | tos = (struct tostruct *)malloc(tossize, M_GPROF, M_WAITOK); |
3a3e0b91 SL |
77 | if (tos == 0) { |
78 | printf("No space for monitor buffer(s)\n"); | |
093d2b12 KM |
79 | free(sbuf, M_GPROF), sbuf = 0; |
80 | free(froms, M_GPROF), froms = 0; | |
3a3e0b91 SL |
81 | return; |
82 | } | |
878656ca | 83 | bzero(tos, tossize); |
3a3e0b91 | 84 | tos[0].link = 0; |
3a3e0b91 SL |
85 | ((struct phdr *)sbuf)->lpc = s_lowpc; |
86 | ((struct phdr *)sbuf)->hpc = s_highpc; | |
87 | ((struct phdr *)sbuf)->ncnt = ssiz; | |
fb1db32c | 88 | kcount = (u_short *)(((int)sbuf) + sizeof (struct phdr)); |
3a3e0b91 SL |
89 | } |
90 | ||
2b75fa20 KM |
91 | /* |
92 | * Special, non-profiled versions | |
93 | */ | |
dd9ec193 | 94 | #if defined(hp300) && !defined(__GNUC__) |
2b75fa20 KM |
95 | #define splhigh _splhigh |
96 | #define splx _splx | |
97 | #endif | |
98 | ||
3a3e0b91 | 99 | /* |
fb1db32c | 100 | * This routine is massaged so that it may be jsb'ed to on vax. |
3a3e0b91 | 101 | */ |
08621963 KM |
102 | asm(".text"); |
103 | asm("#the beginning of mcount()"); | |
104 | asm(".data"); | |
3a3e0b91 SL |
105 | mcount() |
106 | { | |
fb1db32c MK |
107 | register char *selfpc; /* r11 => r5 */ |
108 | register u_short *frompcindex; /* r10 => r4 */ | |
109 | register struct tostruct *top; /* r9 => r3 */ | |
110 | register struct tostruct *prevtop; /* r8 => r2 */ | |
111 | register long toindex; /* r7 => r1 */ | |
31e126ae | 112 | static int s; |
3a3e0b91 | 113 | |
fb1db32c MK |
114 | asm(" .text"); /* make sure we're in text space */ |
115 | /* | |
116 | * Check that we are profiling. | |
117 | */ | |
118 | if (profiling) | |
119 | goto out; | |
120 | /* | |
121 | * Find the return address for mcount, | |
122 | * and the return address for mcount's caller. | |
123 | */ | |
3a3e0b91 | 124 | #ifdef lint |
08621963 | 125 | selfpc = (char *)0; |
3a3e0b91 | 126 | frompcindex = 0; |
fb1db32c | 127 | #else |
139d8e78 | 128 | ; /* avoid label botch */ |
2b75fa20 KM |
129 | #ifdef __GNUC__ |
130 | #if defined(vax) | |
131 | Fix Me!! | |
132 | #endif | |
133 | #if defined(tahoe) | |
134 | Fix Me!! | |
135 | #endif | |
136 | #if defined(hp300) | |
137 | /* | |
138 | * selfpc = pc pushed by mcount jsr, | |
139 | * frompcindex = pc pushed by jsr into self. | |
140 | * In GCC the caller's stack frame has already been built so we | |
141 | * have to chase a6 to find caller's raddr. This assumes that all | |
142 | * routines we are profiling were built with GCC and that all | |
143 | * profiled routines use link/unlk. | |
144 | */ | |
145 | asm("movl a6@(4),%0" : "=r" (selfpc)); | |
146 | asm("movl a6@(0)@(4),%0" : "=r" (frompcindex)); | |
147 | #endif | |
148 | #else | |
fb1db32c | 149 | #if defined(vax) |
3a3e0b91 SL |
150 | asm(" movl (sp), r11"); /* selfpc = ... (jsb frame) */ |
151 | asm(" movl 16(fp), r10"); /* frompcindex = (calls frame) */ | |
fb1db32c MK |
152 | #endif |
153 | #if defined(tahoe) | |
fb1db32c MK |
154 | asm(" movl -8(fp),r12"); /* selfpc = callf frame */ |
155 | asm(" movl (fp),r11"); | |
156 | asm(" movl -8(r11),r11"); /* frompcindex = 1 callf frame back */ | |
157 | #endif | |
2b75fa20 KM |
158 | #if defined(hp300) |
159 | asm(" .text"); /* make sure we're in text space */ | |
160 | asm(" movl a6@(4),a5"); /* selfpc = pc pushed by mcount jsr */ | |
161 | asm(" movl a6@(8),a4"); /* frompcindex = pc pushed by jsr into | |
162 | self, stack frame not yet built */ | |
fb1db32c | 163 | #endif |
2b75fa20 KM |
164 | #endif /* not __GNUC__ */ |
165 | #endif /* not lint */ | |
31e126ae | 166 | /* |
fb1db32c MK |
167 | * Insure that we cannot be recursively invoked. |
168 | * this requires that splhigh() and splx() below | |
169 | * do NOT call mcount! | |
31e126ae | 170 | */ |
dd9ec193 KM |
171 | #if defined(hp300) && defined(__GNUC__) |
172 | asm("movw sr,%0" : "=g" (s)); | |
173 | asm("movw #0x2700,sr"); | |
174 | #else | |
31e126ae | 175 | s = splhigh(); |
dd9ec193 | 176 | #endif |
3a3e0b91 | 177 | /* |
fb1db32c MK |
178 | * Check that frompcindex is a reasonable pc value. |
179 | * For example: signal catchers get called from the stack, | |
180 | * not from text space. too bad. | |
3a3e0b91 | 181 | */ |
fb1db32c MK |
182 | frompcindex = (u_short *)((long)frompcindex - (long)s_lowpc); |
183 | if ((u_long)frompcindex > s_textsize) | |
3a3e0b91 | 184 | goto done; |
08621963 | 185 | frompcindex = |
fb1db32c | 186 | &froms[((long)frompcindex) / (HASHFRACTION * sizeof (*froms))]; |
08621963 KM |
187 | toindex = *frompcindex; |
188 | if (toindex == 0) { | |
189 | /* | |
fb1db32c | 190 | * First time traversing this arc |
08621963 KM |
191 | */ |
192 | toindex = ++tos[0].link; | |
fb1db32c | 193 | if (toindex >= tolimit) |
3a3e0b91 | 194 | goto overflow; |
08621963 KM |
195 | *frompcindex = toindex; |
196 | top = &tos[toindex]; | |
3a3e0b91 | 197 | top->selfpc = selfpc; |
08621963 | 198 | top->count = 1; |
3a3e0b91 | 199 | top->link = 0; |
08621963 | 200 | goto done; |
3a3e0b91 | 201 | } |
08621963 KM |
202 | top = &tos[toindex]; |
203 | if (top->selfpc == selfpc) { | |
204 | /* | |
fb1db32c | 205 | * Arc at front of chain; usual case. |
08621963 KM |
206 | */ |
207 | top->count++; | |
208 | goto done; | |
209 | } | |
210 | /* | |
fb1db32c MK |
211 | * Have to go looking down chain for it. |
212 | * Top points to what we are looking at, | |
213 | * prevtop points to previous top. | |
214 | * We know it is not at the head of the chain. | |
08621963 KM |
215 | */ |
216 | for (; /* goto done */; ) { | |
217 | if (top->link == 0) { | |
218 | /* | |
fb1db32c MK |
219 | * Top is end of the chain and none of the chain |
220 | * had top->selfpc == selfpc. | |
221 | * So we allocate a new tostruct | |
222 | * and link it to the head of the chain. | |
08621963 KM |
223 | */ |
224 | toindex = ++tos[0].link; | |
fb1db32c | 225 | if (toindex >= tolimit) |
08621963 | 226 | goto overflow; |
08621963 KM |
227 | top = &tos[toindex]; |
228 | top->selfpc = selfpc; | |
229 | top->count = 1; | |
230 | top->link = *frompcindex; | |
231 | *frompcindex = toindex; | |
232 | goto done; | |
233 | } | |
234 | /* | |
fb1db32c | 235 | * Otherwise, check the next arc on the chain. |
08621963 KM |
236 | */ |
237 | prevtop = top; | |
238 | top = &tos[top->link]; | |
3a3e0b91 | 239 | if (top->selfpc == selfpc) { |
08621963 | 240 | /* |
fb1db32c MK |
241 | * There it is, increment its count and |
242 | * move it to the head of the chain. | |
08621963 | 243 | */ |
3a3e0b91 | 244 | top->count++; |
08621963 KM |
245 | toindex = prevtop->link; |
246 | prevtop->link = top->link; | |
247 | top->link = *frompcindex; | |
248 | *frompcindex = toindex; | |
249 | goto done; | |
3a3e0b91 | 250 | } |
08621963 | 251 | |
3a3e0b91 SL |
252 | } |
253 | done: | |
dd9ec193 KM |
254 | #if defined(hp300) && defined(__GNUC__) |
255 | asm("movw %0,sr" : : "g" (s)); | |
256 | #else | |
31e126ae | 257 | splx(s); |
dd9ec193 | 258 | #endif |
3a3e0b91 SL |
259 | /* and fall through */ |
260 | out: | |
fb1db32c | 261 | #if defined(vax) |
3a3e0b91 | 262 | asm(" rsb"); |
fb1db32c MK |
263 | #endif |
264 | return; | |
3a3e0b91 | 265 | overflow: |
08621963 | 266 | profiling = 3; |
3a3e0b91 SL |
267 | printf("mcount: tos overflow\n"); |
268 | goto out; | |
269 | } | |
08621963 KM |
270 | asm(".text"); |
271 | asm("#the end of mcount()"); | |
272 | asm(".data"); | |
fb1db32c | 273 | #endif |