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