xref: /original-bsd/lib/libc/gmon/gmon.c (revision b5ed8b48)
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.9 (Berkeley) 03/03/92";
10 #endif /* not lint */
11 
12 #include <unistd.h>
13 #include <sys/types.h>
14 #include <sys/time.h>
15 #include <sys/kinfo.h>
16 
17 #ifdef DEBUG
18 #include <stdio.h>
19 #endif
20 
21 #include "gmon.h"
22 
23 extern char *minbrk asm ("minbrk");
24 
25     /*
26      *	froms is actually a bunch of unsigned shorts indexing tos
27      */
28 static int		profiling = 3;
29 static unsigned short	*froms;
30 static struct tostruct	*tos = 0;
31 static long		tolimit = 0;
32 static char		*s_lowpc = 0;
33 static char		*s_highpc = 0;
34 static unsigned long	s_textsize = 0;
35 
36 static int	ssiz;
37 static char	*sbuf;
38 static int	s_scale;
39     /* see profil(2) where this is describe (incorrectly) */
40 #define		SCALE_1_TO_1	0x10000L
41 
42 #define	MSG "No space for profiling buffer(s)\n"
43 
44 monstartup(lowpc, highpc)
45     char	*lowpc;
46     char	*highpc;
47 {
48     int			monsize;
49     char		*buffer;
50     register int	o;
51     struct clockinfo	clockinfo;
52     int			size;
53 
54 	/*
55 	 *	round lowpc and highpc to multiples of the density we're using
56 	 *	so the rest of the scaling (here and in gprof) stays in ints.
57 	 */
58     lowpc = (char *)
59 	    ROUNDDOWN((unsigned)lowpc, HISTFRACTION*sizeof(HISTCOUNTER));
60     s_lowpc = lowpc;
61     highpc = (char *)
62 	    ROUNDUP((unsigned)highpc, HISTFRACTION*sizeof(HISTCOUNTER));
63     s_highpc = highpc;
64     s_textsize = highpc - lowpc;
65     monsize = (s_textsize / HISTFRACTION) + sizeof(struct phdr);
66     buffer = sbrk( monsize );
67     if ( buffer == (char *) -1 ) {
68 	write( 2 , MSG , sizeof(MSG) );
69 	return;
70     }
71     froms = (unsigned short *) sbrk( s_textsize / HASHFRACTION );
72     if ( froms == (unsigned short *) -1 ) {
73 	write( 2 , MSG , sizeof(MSG) );
74 	froms = 0;
75 	return;
76     }
77     tolimit = s_textsize * ARCDENSITY / 100;
78     if ( tolimit < MINARCS ) {
79 	tolimit = MINARCS;
80     } else if ( tolimit > 65534 ) {
81 	tolimit = 65534;
82     }
83     tos = (struct tostruct *) sbrk( tolimit * sizeof( struct tostruct ) );
84     if ( tos == (struct tostruct *) -1 ) {
85 	write( 2 , MSG , sizeof(MSG) );
86 	froms = 0;
87 	tos = 0;
88 	return;
89     }
90     minbrk = sbrk(0);
91     tos[0].link = 0;
92     sbuf = buffer;
93     ssiz = monsize;
94     ( (struct phdr *) buffer ) -> lpc = lowpc;
95     ( (struct phdr *) buffer ) -> hpc = highpc;
96     ( (struct phdr *) buffer ) -> ncnt = ssiz;
97     ( (struct phdr *) buffer ) -> version = GMONVERSION;
98     monsize -= sizeof(struct phdr);
99     if ( monsize <= 0 )
100 	return;
101     o = highpc - lowpc;
102     if( monsize < o )
103 #ifndef hp300
104 	s_scale = ( (float) monsize / o ) * SCALE_1_TO_1;
105 #else /* avoid floating point */
106     {
107 	int quot = o / monsize;
108 
109 	if (quot >= 0x10000)
110 		s_scale = 1;
111 	else if (quot >= 0x100)
112 		s_scale = 0x10000 / quot;
113 	else if (o >= 0x800000)
114 		s_scale = 0x1000000 / (o / (monsize >> 8));
115 	else
116 		s_scale = 0x1000000 / ((o << 8) / monsize);
117     }
118 #endif
119     else
120 	s_scale = SCALE_1_TO_1;
121     moncontrol(1);
122     size = sizeof( clockinfo );
123     if ( getkerninfo( KINFO_CLOCKRATE , &clockinfo , &size , 0 ) < 0 ) {
124 	/*
125 	 * Best guess
126 	 */
127 	clockinfo.profhz = hertz();
128     } else if ( clockinfo.profhz == 0 ) {
129 	if ( clockinfo.hz != 0 )
130 	    clockinfo.profhz = clockinfo.hz;
131 	else
132 	    clockinfo.profhz = hertz();
133     }
134     ( (struct phdr *) buffer ) -> profrate = clockinfo.profhz;
135 }
136 
137 _mcleanup()
138 {
139     int			fd;
140     int			fromindex;
141     int			endfrom;
142     char		*frompc;
143     int			toindex;
144     struct rawarc	rawarc;
145 
146     moncontrol(0);
147     fd = creat( "gmon.out" , 0666 );
148     if ( fd < 0 ) {
149 	perror( "mcount: gmon.out" );
150 	return;
151     }
152 #   ifdef DEBUG
153 	fprintf( stderr , "[mcleanup] sbuf 0x%x ssiz %d\n" , sbuf , ssiz );
154 #   endif DEBUG
155     write( fd , sbuf , ssiz );
156     endfrom = s_textsize / (HASHFRACTION * sizeof(*froms));
157     for ( fromindex = 0 ; fromindex < endfrom ; fromindex++ ) {
158 	if ( froms[fromindex] == 0 ) {
159 	    continue;
160 	}
161 	frompc = s_lowpc + (fromindex * HASHFRACTION * sizeof(*froms));
162 	for (toindex=froms[fromindex]; toindex!=0; toindex=tos[toindex].link) {
163 #	    ifdef DEBUG
164 		fprintf( stderr ,
165 			"[mcleanup] frompc 0x%x selfpc 0x%x count %d\n" ,
166 			frompc , tos[toindex].selfpc , tos[toindex].count );
167 #	    endif DEBUG
168 	    rawarc.raw_frompc = (unsigned long) frompc;
169 	    rawarc.raw_selfpc = (unsigned long) tos[toindex].selfpc;
170 	    rawarc.raw_count = tos[toindex].count;
171 	    write( fd , &rawarc , sizeof rawarc );
172 	}
173     }
174     close( fd );
175 }
176 
177 /*
178  * Control profiling
179  *	profiling is what mcount checks to see if
180  *	all the data structures are ready.
181  */
182 moncontrol(mode)
183     int mode;
184 {
185     if (mode) {
186 	/* start */
187 	profil(sbuf + sizeof(struct phdr), ssiz - sizeof(struct phdr),
188 		(int)s_lowpc, s_scale);
189 	profiling = 0;
190     } else {
191 	/* stop */
192 	profil((char *)0, 0, 0, 0);
193 	profiling = 3;
194     }
195 }
196 
197     /*
198      *	discover the tick frequency of the machine
199      *	if something goes wrong, we return 0, an impossible hertz.
200      */
201 
202 hertz()
203 {
204 	struct itimerval tim;
205 
206 	tim.it_interval.tv_sec = 0;
207 	tim.it_interval.tv_usec = 1;
208 	tim.it_value.tv_sec = 0;
209 	tim.it_value.tv_usec = 0;
210 	setitimer(ITIMER_REAL, &tim, 0);
211 	setitimer(ITIMER_REAL, 0, &tim);
212 	if (tim.it_interval.tv_usec < 2)
213 		return(0);
214 	return (1000000 / tim.it_interval.tv_usec);
215 }
216