xref: /csrg-svn/sys/kern/subr_prof.c (revision 29946)
1 /*
2  * Copyright (c) 1982, 1986 Regents of the University of California.
3  * All rights reserved.  The Berkeley software License Agreement
4  * specifies the terms and conditions for redistribution.
5  *
6  *	@(#)subr_prof.c	7.2 (Berkeley) 11/03/86
7  */
8 
9 #ifdef GPROF
10 #include "gprof.h"
11 #include "param.h"
12 #include "systm.h"
13 
14 /*
15  * Froms is actually a bunch of unsigned shorts indexing tos
16  */
17 int	profiling = 3;
18 u_short	*froms;
19 struct	tostruct *tos = 0;
20 long	tolimit = 0;
21 #if defined(vax)
22 char	*s_lowpc = (char *)0x80000000;
23 #endif
24 #if defined(tahoe)
25 char	*s_lowpc = (char *)0xc0000000;
26 #endif
27 extern	char etext;
28 char	*s_highpc = &etext;
29 u_long	s_textsize = 0;
30 int	ssiz;
31 u_short	*sbuf;
32 u_short	*kcount;
33 
34 kmstartup()
35 {
36 	u_long fromssize, tossize;
37 
38 	/*
39 	 * Round lowpc and highpc to multiples of the density we're using
40 	 * so the rest of the scaling (here and in gprof) stays in ints.
41 	 */
42 	s_lowpc = (char *)
43 	    ROUNDDOWN((unsigned)s_lowpc, HISTFRACTION*sizeof (HISTCOUNTER));
44 	s_highpc = (char *)
45 	    ROUNDUP((unsigned)s_highpc, HISTFRACTION*sizeof (HISTCOUNTER));
46 	s_textsize = s_highpc - s_lowpc;
47 	printf("Profiling kernel, s_textsize=%d [%x..%x]\n",
48 		s_textsize, s_lowpc, s_highpc);
49 	ssiz = (s_textsize / HISTFRACTION) + sizeof (struct phdr);
50 	sbuf = (u_short *)calloc(ssiz);
51 	if (sbuf == 0) {
52 		printf("No space for monitor buffer(s)\n");
53 		return;
54 	}
55 	fromssize = s_textsize / HASHFRACTION;
56 	froms = (u_short *)calloc(fromssize);
57 	if (froms == 0) {
58 		printf("No space for monitor buffer(s)\n");
59 		cfreemem(sbuf, ssiz);
60 		sbuf = 0;
61 		return;
62 	}
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 *)calloc(tossize);
70 	if (tos == 0) {
71 		printf("No space for monitor buffer(s)\n");
72 		cfreemem(sbuf, ssiz), sbuf = 0;
73 		cfreemem(froms, fromssize), froms = 0;
74 		return;
75 	}
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 #ifdef notdef
82 	/*
83 	 * Profiling is what mcount checks to see if
84 	 * all the data structures are ready!!!
85 	 */
86 	profiling = 0;		/* patch by hand when you're ready */
87 #endif
88 }
89 
90 /*
91  * This routine is massaged so that it may be jsb'ed to on vax.
92  */
93 asm(".text");
94 asm("#the beginning of mcount()");
95 asm(".data");
96 mcount()
97 {
98 	register char *selfpc;			/* r11 => r5 */
99 	register u_short *frompcindex;		/* r10 => r4 */
100 	register struct tostruct *top;		/* r9  => r3 */
101 	register struct tostruct *prevtop;	/* r8  => r2 */
102 	register long toindex;			/* r7  => r1 */
103 	static int s;
104 
105 	asm("	.text");		/* make sure we're in text space */
106 	/*
107 	 * Check that we are profiling.
108 	 */
109 	if (profiling)
110 		goto out;
111 	/*
112 	 * Find the return address for mcount,
113 	 * and the return address for mcount's caller.
114 	 */
115 #ifdef lint
116 	selfpc = (char *)0;
117 	frompcindex = 0;
118 #else
119 #if defined(vax)
120 	asm("	movl (sp), r11");	/* selfpc = ... (jsb frame) */
121 	asm("	movl 16(fp), r10");	/* frompcindex =     (calls frame) */
122 #endif
123 #if defined(tahoe)
124 	;				/* avoid label botch */
125 	asm("	movl -8(fp),r12");	/* selfpc = callf frame */
126 	asm("	movl (fp),r11");
127 	asm("	movl -8(r11),r11");	/* frompcindex = 1 callf frame back */
128 #endif
129 #endif
130 	/*
131 	 * Insure that we cannot be recursively invoked.
132 	 * this requires that splhigh() and splx() below
133 	 * do NOT call mcount!
134 	 */
135 	s = splhigh();
136 	/*
137 	 * Check that frompcindex is a reasonable pc value.
138 	 * For example:	signal catchers get called from the stack,
139 	 *	not from text space.  too bad.
140 	 */
141 	frompcindex = (u_short *)((long)frompcindex - (long)s_lowpc);
142 	if ((u_long)frompcindex > s_textsize)
143 		goto done;
144 	frompcindex =
145 	    &froms[((long)frompcindex) / (HASHFRACTION * sizeof (*froms))];
146 	toindex = *frompcindex;
147 	if (toindex == 0) {
148 		/*
149 		 * First time traversing this arc
150 		 */
151 		toindex = ++tos[0].link;
152 		if (toindex >= tolimit)
153 			goto overflow;
154 		*frompcindex = toindex;
155 		top = &tos[toindex];
156 		top->selfpc = selfpc;
157 		top->count = 1;
158 		top->link = 0;
159 		goto done;
160 	}
161 	top = &tos[toindex];
162 	if (top->selfpc == selfpc) {
163 		/*
164 		 * Arc at front of chain; usual case.
165 		 */
166 		top->count++;
167 		goto done;
168 	}
169 	/*
170 	 * Have to go looking down chain for it.
171 	 * Top points to what we are looking at,
172 	 * prevtop points to previous top.
173 	 * We know it is not at the head of the chain.
174 	 */
175 	for (; /* goto done */; ) {
176 		if (top->link == 0) {
177 			/*
178 			 * Top is end of the chain and none of the chain
179 			 * had top->selfpc == selfpc.
180 			 * So we allocate a new tostruct
181 			 * and link it to the head of the chain.
182 			 */
183 			toindex = ++tos[0].link;
184 			if (toindex >= tolimit)
185 				goto overflow;
186 			top = &tos[toindex];
187 			top->selfpc = selfpc;
188 			top->count = 1;
189 			top->link = *frompcindex;
190 			*frompcindex = toindex;
191 			goto done;
192 		}
193 		/*
194 		 * Otherwise, check the next arc on the chain.
195 		 */
196 		prevtop = top;
197 		top = &tos[top->link];
198 		if (top->selfpc == selfpc) {
199 			/*
200 			 * There it is, increment its count and
201 			 * move it to the head of the chain.
202 			 */
203 			top->count++;
204 			toindex = prevtop->link;
205 			prevtop->link = top->link;
206 			top->link = *frompcindex;
207 			*frompcindex = toindex;
208 			goto done;
209 		}
210 
211 	}
212 done:
213 	splx(s);
214 	/* and fall through */
215 out:
216 #if defined(vax)
217 	asm("	rsb");
218 #endif
219 	return;
220 overflow:
221 	profiling = 3;
222 	printf("mcount: tos overflow\n");
223 	goto out;
224 }
225 asm(".text");
226 asm("#the end of mcount()");
227 asm(".data");
228 #endif
229