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