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