add pmax
[unix-history] / usr / src / sys / kern / subr_prof.c
CommitLineData
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
19int profiling = 3;
20u_short *froms;
21struct tostruct *tos = 0;
22long tolimit = 0;
d293217c 23char *s_lowpc = (char *)KERNBASE;
fb1db32c
MK
24extern char etext;
25char *s_highpc = &etext;
3a3e0b91 26u_long s_textsize = 0;
fb1db32c 27int ssiz;
3a3e0b91
SL
28u_short *sbuf;
29u_short *kcount;
30
31kmstartup()
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
86asm(".text");
87asm("#the beginning of mcount()");
88asm(".data");
3a3e0b91
SL
89mcount()
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 }
234done:
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 */
241out:
fb1db32c 242#if defined(vax)
3a3e0b91 243 asm(" rsb");
fb1db32c
MK
244#endif
245 return;
3a3e0b91 246overflow:
08621963 247 profiling = 3;
3a3e0b91
SL
248 printf("mcount: tos overflow\n");
249 goto out;
250}
08621963
KM
251asm(".text");
252asm("#the end of mcount()");
253asm(".data");
fb1db32c 254#endif