xref: /original-bsd/sys/kern/subr_prof.c (revision caa496f3)
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.8 (Berkeley) 05/25/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 #if defined(vax)
24 char	*s_lowpc = (char *)0x80000000;
25 #endif
26 #if defined(tahoe)
27 char	*s_lowpc = (char *)0xc0000000;
28 #endif
29 #if defined(hp300)
30 char	*s_lowpc = (char *)0x00000000;
31 #endif
32 extern	char etext;
33 char	*s_highpc = &etext;
34 u_long	s_textsize = 0;
35 int	ssiz;
36 u_short	*sbuf;
37 u_short	*kcount;
38 
39 kmstartup()
40 {
41 	u_long fromssize, tossize;
42 
43 	/*
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.
46 	 */
47 	s_lowpc = (char *)
48 	    ROUNDDOWN((unsigned)s_lowpc, HISTFRACTION*sizeof (HISTCOUNTER));
49 	s_highpc = (char *)
50 	    ROUNDUP((unsigned)s_highpc, HISTFRACTION*sizeof (HISTCOUNTER));
51 	s_textsize = s_highpc - s_lowpc;
52 	printf("Profiling kernel, s_textsize=%d [%x..%x]\n",
53 		s_textsize, s_lowpc, s_highpc);
54 	ssiz = (s_textsize / HISTFRACTION) + sizeof (struct phdr);
55 	sbuf = (u_short *)malloc(ssiz, M_GPROF, M_WAITOK);
56 	if (sbuf == 0) {
57 		printf("No space for monitor buffer(s)\n");
58 		return;
59 	}
60 	bzero(sbuf, ssiz);
61 	fromssize = s_textsize / HASHFRACTION;
62 	froms = (u_short *)malloc(fromssize, M_GPROF, M_WAITOK);
63 	if (froms == 0) {
64 		printf("No space for monitor buffer(s)\n");
65 		free(sbuf, M_GPROF);
66 		sbuf = 0;
67 		return;
68 	}
69 	bzero(froms, fromssize);
70 	tolimit = s_textsize * ARCDENSITY / 100;
71 	if (tolimit < MINARCS)
72 		tolimit = MINARCS;
73 	else if (tolimit > (0xffff - 1))
74 		tolimit = 0xffff - 1;
75 	tossize = tolimit * sizeof (struct tostruct);
76 	tos = (struct tostruct *)malloc(tossize, M_GPROF, M_WAITOK);
77 	if (tos == 0) {
78 		printf("No space for monitor buffer(s)\n");
79 		free(sbuf, M_GPROF), sbuf = 0;
80 		free(froms, M_GPROF), froms = 0;
81 		return;
82 	}
83 	bzero(tos, tossize);
84 	tos[0].link = 0;
85 	((struct phdr *)sbuf)->lpc = s_lowpc;
86 	((struct phdr *)sbuf)->hpc = s_highpc;
87 	((struct phdr *)sbuf)->ncnt = ssiz;
88 	kcount = (u_short *)(((int)sbuf) + sizeof (struct phdr));
89 }
90 
91 /*
92  * Special, non-profiled versions
93  */
94 #if defined(hp300) && !defined(__GNUC__)
95 #define splhigh	_splhigh
96 #define splx	_splx
97 #endif
98 
99 /*
100  * This routine is massaged so that it may be jsb'ed to on vax.
101  */
102 asm(".text");
103 asm("#the beginning of mcount()");
104 asm(".data");
105 mcount()
106 {
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 */
112 	static int s;
113 
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 	 */
124 #ifdef lint
125 	selfpc = (char *)0;
126 	frompcindex = 0;
127 #else
128 	;				/* avoid label botch */
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
149 #if defined(vax)
150 	asm("	movl (sp), r11");	/* selfpc = ... (jsb frame) */
151 	asm("	movl 16(fp), r10");	/* frompcindex =     (calls frame) */
152 #endif
153 #if defined(tahoe)
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
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 */
163 #endif
164 #endif /* not __GNUC__ */
165 #endif /* not lint */
166 	/*
167 	 * Insure that we cannot be recursively invoked.
168 	 * this requires that splhigh() and splx() below
169 	 * do NOT call mcount!
170 	 */
171 #if defined(hp300) && defined(__GNUC__)
172 	asm("movw	sr,%0" : "=g" (s));
173 	asm("movw	#0x2700,sr");
174 #else
175 	s = splhigh();
176 #endif
177 	/*
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.
181 	 */
182 	frompcindex = (u_short *)((long)frompcindex - (long)s_lowpc);
183 	if ((u_long)frompcindex > s_textsize)
184 		goto done;
185 	frompcindex =
186 	    &froms[((long)frompcindex) / (HASHFRACTION * sizeof (*froms))];
187 	toindex = *frompcindex;
188 	if (toindex == 0) {
189 		/*
190 		 * First time traversing this arc
191 		 */
192 		toindex = ++tos[0].link;
193 		if (toindex >= tolimit)
194 			goto overflow;
195 		*frompcindex = toindex;
196 		top = &tos[toindex];
197 		top->selfpc = selfpc;
198 		top->count = 1;
199 		top->link = 0;
200 		goto done;
201 	}
202 	top = &tos[toindex];
203 	if (top->selfpc == selfpc) {
204 		/*
205 		 * Arc at front of chain; usual case.
206 		 */
207 		top->count++;
208 		goto done;
209 	}
210 	/*
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.
215 	 */
216 	for (; /* goto done */; ) {
217 		if (top->link == 0) {
218 			/*
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.
223 			 */
224 			toindex = ++tos[0].link;
225 			if (toindex >= tolimit)
226 				goto overflow;
227 			top = &tos[toindex];
228 			top->selfpc = selfpc;
229 			top->count = 1;
230 			top->link = *frompcindex;
231 			*frompcindex = toindex;
232 			goto done;
233 		}
234 		/*
235 		 * Otherwise, check the next arc on the chain.
236 		 */
237 		prevtop = top;
238 		top = &tos[top->link];
239 		if (top->selfpc == selfpc) {
240 			/*
241 			 * There it is, increment its count and
242 			 * move it to the head of the chain.
243 			 */
244 			top->count++;
245 			toindex = prevtop->link;
246 			prevtop->link = top->link;
247 			top->link = *frompcindex;
248 			*frompcindex = toindex;
249 			goto done;
250 		}
251 
252 	}
253 done:
254 #if defined(hp300) && defined(__GNUC__)
255 	asm("movw	%0,sr" : : "g" (s));
256 #else
257 	splx(s);
258 #endif
259 	/* and fall through */
260 out:
261 #if defined(vax)
262 	asm("	rsb");
263 #endif
264 	return;
265 overflow:
266 	profiling = 3;
267 	printf("mcount: tos overflow\n");
268 	goto out;
269 }
270 asm(".text");
271 asm("#the end of mcount()");
272 asm(".data");
273 #endif
274