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