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