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