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