xref: /csrg-svn/lib/libc/gmon/gmon.c (revision 21415)
1 /*
2  * Copyright (c) 1980 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 
7 #ifndef lint
8 static char sccsid[] = "@(#)gmon.c	5.1 (Berkeley) 05/30/85";
9 #endif not lint
10 
11 #ifdef DEBUG
12 #include <stdio.h>
13 #endif DEBUG
14 
15 #include "gmon.h"
16 
17     /*
18      *	froms is actually a bunch of unsigned shorts indexing tos
19      */
20 static int		profiling = 3;
21 static unsigned short	*froms;
22 static struct tostruct	*tos = 0;
23 static long		tolimit = 0;
24 static char		*s_lowpc = 0;
25 static char		*s_highpc = 0;
26 static unsigned long	s_textsize = 0;
27 
28 static int	ssiz;
29 static char	*sbuf;
30 static int	s_scale;
31     /* see profil(2) where this is describe (incorrectly) */
32 #define		SCALE_1_TO_1	0x10000L
33 
34 #define	MSG "No space for monitor buffer(s)\n"
35 
36 monstartup(lowpc, highpc)
37     char	*lowpc;
38     char	*highpc;
39 {
40     int			monsize;
41     char		*buffer;
42     char		*sbrk();
43     extern char		*minbrk;
44 
45 	/*
46 	 *	round lowpc and highpc to multiples of the density we're using
47 	 *	so the rest of the scaling (here and in gprof) stays in ints.
48 	 */
49     lowpc = (char *)
50 	    ROUNDDOWN((unsigned)lowpc, HISTFRACTION*sizeof(HISTCOUNTER));
51     s_lowpc = lowpc;
52     highpc = (char *)
53 	    ROUNDUP((unsigned)highpc, HISTFRACTION*sizeof(HISTCOUNTER));
54     s_highpc = highpc;
55     s_textsize = highpc - lowpc;
56     monsize = (s_textsize / HISTFRACTION) + sizeof(struct phdr);
57     buffer = sbrk( monsize );
58     if ( buffer == (char *) -1 ) {
59 	write( 2 , MSG , sizeof(MSG) );
60 	return;
61     }
62     froms = (unsigned short *) sbrk( s_textsize / HASHFRACTION );
63     if ( froms == (unsigned short *) -1 ) {
64 	write( 2 , MSG , sizeof(MSG) );
65 	froms = 0;
66 	return;
67     }
68     tolimit = s_textsize * ARCDENSITY / 100;
69     if ( tolimit < MINARCS ) {
70 	tolimit = MINARCS;
71     } else if ( tolimit > 65534 ) {
72 	tolimit = 65534;
73     }
74     tos = (struct tostruct *) sbrk( tolimit * sizeof( struct tostruct ) );
75     if ( tos == (struct tostruct *) -1 ) {
76 	write( 2 , MSG , sizeof(MSG) );
77 	froms = 0;
78 	tos = 0;
79 	return;
80     }
81     minbrk = sbrk(0);
82     tos[0].link = 0;
83     monitor( lowpc , highpc , buffer , monsize , tolimit );
84 }
85 
86 _mcleanup()
87 {
88     int			fd;
89     int			fromindex;
90     int			endfrom;
91     char		*frompc;
92     int			toindex;
93     struct rawarc	rawarc;
94 
95     fd = creat( "gmon.out" , 0666 );
96     if ( fd < 0 ) {
97 	perror( "mcount: gmon.out" );
98 	return;
99     }
100 #   ifdef DEBUG
101 	fprintf( stderr , "[mcleanup] sbuf 0x%x ssiz %d\n" , sbuf , ssiz );
102 #   endif DEBUG
103     write( fd , sbuf , ssiz );
104     endfrom = s_textsize / (HASHFRACTION * sizeof(*froms));
105     for ( fromindex = 0 ; fromindex < endfrom ; fromindex++ ) {
106 	if ( froms[fromindex] == 0 ) {
107 	    continue;
108 	}
109 	frompc = s_lowpc + (fromindex * HASHFRACTION * sizeof(*froms));
110 	for (toindex=froms[fromindex]; toindex!=0; toindex=tos[toindex].link) {
111 #	    ifdef DEBUG
112 		fprintf( stderr ,
113 			"[mcleanup] frompc 0x%x selfpc 0x%x count %d\n" ,
114 			frompc , tos[toindex].selfpc , tos[toindex].count );
115 #	    endif DEBUG
116 	    rawarc.raw_frompc = (unsigned long) frompc;
117 	    rawarc.raw_selfpc = (unsigned long) tos[toindex].selfpc;
118 	    rawarc.raw_count = tos[toindex].count;
119 	    write( fd , &rawarc , sizeof rawarc );
120 	}
121     }
122     close( fd );
123 }
124 
125 asm(".text");
126 asm(".align 2");
127 asm("#the beginning of mcount()");
128 asm(".data");
129 mcount()
130 {
131 	register char			*selfpc;	/* r11 => r5 */
132 	register unsigned short		*frompcindex;	/* r10 => r4 */
133 	register struct tostruct	*top;		/* r9  => r3 */
134 	register struct tostruct	*prevtop;	/* r8  => r2 */
135 	register long			toindex;	/* r7  => r1 */
136 
137 #ifdef lint
138 	selfpc = (char *)0;
139 	frompcindex = 0;
140 #else not lint
141 	/*
142 	 *	find the return address for mcount,
143 	 *	and the return address for mcount's caller.
144 	 */
145 	asm("	.text");		/* make sure we're in text space */
146 	asm("	movl (sp), r11");	/* selfpc = ... (jsb frame) */
147 	asm("	movl 16(fp), r10");	/* frompcindex =     (calls frame) */
148 #endif not lint
149 	/*
150 	 *	check that we are profiling
151 	 *	and that we aren't recursively invoked.
152 	 */
153 	if (profiling) {
154 		goto out;
155 	}
156 	profiling++;
157 	/*
158 	 *	check that frompcindex is a reasonable pc value.
159 	 *	for example:	signal catchers get called from the stack,
160 	 *			not from text space.  too bad.
161 	 */
162 	frompcindex = (unsigned short *)((long)frompcindex - (long)s_lowpc);
163 	if ((unsigned long)frompcindex > s_textsize) {
164 		goto done;
165 	}
166 	frompcindex =
167 	    &froms[((long)frompcindex) / (HASHFRACTION * sizeof(*froms))];
168 	toindex = *frompcindex;
169 	if (toindex == 0) {
170 		/*
171 		 *	first time traversing this arc
172 		 */
173 		toindex = ++tos[0].link;
174 		if (toindex >= tolimit) {
175 			goto overflow;
176 		}
177 		*frompcindex = toindex;
178 		top = &tos[toindex];
179 		top->selfpc = selfpc;
180 		top->count = 1;
181 		top->link = 0;
182 		goto done;
183 	}
184 	top = &tos[toindex];
185 	if (top->selfpc == selfpc) {
186 		/*
187 		 *	arc at front of chain; usual case.
188 		 */
189 		top->count++;
190 		goto done;
191 	}
192 	/*
193 	 *	have to go looking down chain for it.
194 	 *	top points to what we are looking at,
195 	 *	prevtop points to previous top.
196 	 *	we know it is not at the head of the chain.
197 	 */
198 	for (; /* goto done */; ) {
199 		if (top->link == 0) {
200 			/*
201 			 *	top is end of the chain and none of the chain
202 			 *	had top->selfpc == selfpc.
203 			 *	so we allocate a new tostruct
204 			 *	and link it to the head of the chain.
205 			 */
206 			toindex = ++tos[0].link;
207 			if (toindex >= tolimit) {
208 				goto overflow;
209 			}
210 			top = &tos[toindex];
211 			top->selfpc = selfpc;
212 			top->count = 1;
213 			top->link = *frompcindex;
214 			*frompcindex = toindex;
215 			goto done;
216 		}
217 		/*
218 		 *	otherwise, check the next arc on the chain.
219 		 */
220 		prevtop = top;
221 		top = &tos[top->link];
222 		if (top->selfpc == selfpc) {
223 			/*
224 			 *	there it is.
225 			 *	increment its count
226 			 *	move it to the head of the chain.
227 			 */
228 			top->count++;
229 			toindex = prevtop->link;
230 			prevtop->link = top->link;
231 			top->link = *frompcindex;
232 			*frompcindex = toindex;
233 			goto done;
234 		}
235 
236 	}
237 done:
238 	profiling--;
239 	/* and fall through */
240 out:
241 	asm("	rsb");
242 
243 overflow:
244 	profiling++; /* halt further profiling */
245 #   define	TOLIMIT	"mcount: tos overflow\n"
246 	write(2, TOLIMIT, sizeof(TOLIMIT));
247 	goto out;
248 }
249 asm(".text");
250 asm("#the end of mcount()");
251 asm(".data");
252 
253 /*VARARGS1*/
254 monitor( lowpc , highpc , buf , bufsiz , nfunc )
255     char	*lowpc;
256     char	*highpc;
257     char	*buf;	/* declared ``short buffer[]'' in monitor(3) */
258     int		bufsiz;
259     int		nfunc;	/* not used, available for compatability only */
260 {
261     register o;
262 
263     if ( lowpc == 0 ) {
264 	moncontrol(0);
265 	_mcleanup();
266 	return;
267     }
268     sbuf = buf;
269     ssiz = bufsiz;
270     ( (struct phdr *) buf ) -> lpc = lowpc;
271     ( (struct phdr *) buf ) -> hpc = highpc;
272     ( (struct phdr *) buf ) -> ncnt = ssiz;
273     bufsiz -= sizeof(struct phdr);
274     if ( bufsiz <= 0 )
275 	return;
276     o = highpc - lowpc;
277     if( bufsiz < o )
278 	s_scale = ( (float) bufsiz / o ) * SCALE_1_TO_1;
279     else
280 	s_scale = SCALE_1_TO_1;
281     moncontrol(1);
282 }
283 
284 /*
285  * Control profiling
286  *	profiling is what mcount checks to see if
287  *	all the data structures are ready.
288  */
289 moncontrol(mode)
290     int mode;
291 {
292     if (mode) {
293 	/* start */
294 	profil(sbuf + sizeof(struct phdr), ssiz - sizeof(struct phdr),
295 		s_lowpc, s_scale);
296 	profiling = 0;
297     } else {
298 	/* stop */
299 	profil((char *)0, 0, 0, 0);
300 	profiling = 3;
301     }
302 }
303