1765c014eSbostic /*-
2*c7ac4bd9Sbostic * Copyright (c) 1983, 1992, 1993
3*c7ac4bd9Sbostic * The Regents of the University of California. All rights reserved.
4765c014eSbostic *
592e1012bSbostic * %sccs.include.redist.c%
61bbdfc7eSdist */
71bbdfc7eSdist
879cb2974Smckusick #if !defined(lint) && defined(LIBC_SCCS)
9*c7ac4bd9Sbostic static char sccsid[] = "@(#)gmon.c 8.1 (Berkeley) 06/04/93";
1079cb2974Smckusick #endif
11c06660d0Speter
12b218084aSbostic #include <sys/param.h>
1351e5c269Smckusick #include <sys/time.h>
14b218084aSbostic #include <sys/gmon.h>
15c16e8556Smckusick #include <sys/sysctl.h>
16368a6872Sdonn
17c06660d0Speter #include <stdio.h>
186e9962b0Smckusick #include <fcntl.h>
19b218084aSbostic #include <unistd.h>
209699256bSpeter
21368a6872Sdonn extern char *minbrk asm ("minbrk");
22368a6872Sdonn
23d06aaf11Smckusick struct gmonparam _gmonparam = { GMON_PROF_OFF };
24c06660d0Speter
259b3bc73fSpeter static int s_scale;
265e9f68a9Speter /* see profil(2) where this is describe (incorrectly) */
275e9f68a9Speter #define SCALE_1_TO_1 0x10000L
28c06660d0Speter
29d06aaf11Smckusick #define ERR(s) write(2, s, sizeof(s))
30d06aaf11Smckusick
31b63fca47Storek void moncontrol __P((int));
32b63fca47Storek static int hertz __P((void));
33b63fca47Storek
34b63fca47Storek void
monstartup(lowpc,highpc)353252918bSmckusick monstartup(lowpc, highpc)
36d06aaf11Smckusick u_long lowpc;
37d06aaf11Smckusick u_long highpc;
38c06660d0Speter {
39645f7f03Smckusick register int o;
40d06aaf11Smckusick char *cp;
41d06aaf11Smckusick struct gmonparam *p = &_gmonparam;
42c06660d0Speter
43f025804bSpeter /*
44f025804bSpeter * round lowpc and highpc to multiples of the density we're using
45f025804bSpeter * so the rest of the scaling (here and in gprof) stays in ints.
46f025804bSpeter */
47b9a56342Smckusick p->lowpc = ROUNDDOWN(lowpc, HISTFRACTION * sizeof(HISTCOUNTER));
48b9a56342Smckusick p->highpc = ROUNDUP(highpc, HISTFRACTION * sizeof(HISTCOUNTER));
49b9a56342Smckusick p->textsize = p->highpc - p->lowpc;
50b9a56342Smckusick p->kcountsize = p->textsize / HISTFRACTION;
51b9a56342Smckusick p->hashfraction = HASHFRACTION;
52b9a56342Smckusick p->fromssize = p->textsize / HASHFRACTION;
53b9a56342Smckusick p->tolimit = p->textsize * ARCDENSITY / 100;
54b9a56342Smckusick if (p->tolimit < MINARCS)
55b9a56342Smckusick p->tolimit = MINARCS;
56b9a56342Smckusick else if (p->tolimit > MAXARCS)
57b9a56342Smckusick p->tolimit = MAXARCS;
58b9a56342Smckusick p->tossize = p->tolimit * sizeof(struct tostruct);
59d06aaf11Smckusick
60b9a56342Smckusick cp = sbrk(p->kcountsize + p->fromssize + p->tossize);
61d06aaf11Smckusick if (cp == (char *)-1) {
62d06aaf11Smckusick ERR("monstartup: out of memory\n");
63c06660d0Speter return;
64c06660d0Speter }
65d06aaf11Smckusick #ifdef notdef
66b9a56342Smckusick bzero(cp, p->kcountsize + p->fromssize + p->tossize);
67d06aaf11Smckusick #endif
68d06aaf11Smckusick p->tos = (struct tostruct *)cp;
69b9a56342Smckusick cp += p->tossize;
70b9a56342Smckusick p->kcount = (u_short *)cp;
71b9a56342Smckusick cp += p->kcountsize;
72d06aaf11Smckusick p->froms = (u_short *)cp;
73d06aaf11Smckusick
741f3b6987Smckusick minbrk = sbrk(0);
75d06aaf11Smckusick p->tos[0].link = 0;
76d06aaf11Smckusick
77b9a56342Smckusick o = p->highpc - p->lowpc;
78b9a56342Smckusick if (p->kcountsize < o) {
7951e5c269Smckusick #ifndef hp300
80b9a56342Smckusick s_scale = ((float)p->kcountsize / o ) * SCALE_1_TO_1;
8151e5c269Smckusick #else /* avoid floating point */
82b9a56342Smckusick int quot = o / p->kcountsize;
8351e5c269Smckusick
8451e5c269Smckusick if (quot >= 0x10000)
8551e5c269Smckusick s_scale = 1;
8651e5c269Smckusick else if (quot >= 0x100)
8751e5c269Smckusick s_scale = 0x10000 / quot;
8851e5c269Smckusick else if (o >= 0x800000)
89b9a56342Smckusick s_scale = 0x1000000 / (o / (p->kcountsize >> 8));
9051e5c269Smckusick else
91b9a56342Smckusick s_scale = 0x1000000 / ((o << 8) / p->kcountsize);
9251e5c269Smckusick #endif
93d06aaf11Smckusick } else
94645f7f03Smckusick s_scale = SCALE_1_TO_1;
95d06aaf11Smckusick
96645f7f03Smckusick moncontrol(1);
97c06660d0Speter }
98c06660d0Speter
99b63fca47Storek void
_mcleanup()100c06660d0Speter _mcleanup()
101c06660d0Speter {
102536340e2Smckusic int fd;
103c06660d0Speter int fromindex;
104eb6779cfSmckusick int endfrom;
105d06aaf11Smckusick u_long frompc;
106c06660d0Speter int toindex;
107536340e2Smckusic struct rawarc rawarc;
108d06aaf11Smckusick struct gmonparam *p = &_gmonparam;
109b9a56342Smckusick struct gmonhdr gmonhdr, *hdr;
110b9a56342Smckusick struct clockinfo clockinfo;
111b63fca47Storek int mib[2];
112b63fca47Storek size_t size;
113b63fca47Storek #ifdef DEBUG
1146e9962b0Smckusick int log, len;
1156e9962b0Smckusick char buf[200];
116b63fca47Storek #endif
117d06aaf11Smckusick
118d06aaf11Smckusick if (p->state == GMON_PROF_ERROR)
119d06aaf11Smckusick ERR("_mcleanup: tos overflow\n");
120c06660d0Speter
121b9a56342Smckusick size = sizeof(clockinfo);
122b9a56342Smckusick mib[0] = CTL_KERN;
123b9a56342Smckusick mib[1] = KERN_CLOCKRATE;
124b9a56342Smckusick if (sysctl(mib, 2, &clockinfo, &size, NULL, 0) < 0) {
125b9a56342Smckusick /*
126b9a56342Smckusick * Best guess
127b9a56342Smckusick */
128b9a56342Smckusick clockinfo.profhz = hertz();
129b9a56342Smckusick } else if (clockinfo.profhz == 0) {
130b9a56342Smckusick if (clockinfo.hz != 0)
131b9a56342Smckusick clockinfo.profhz = clockinfo.hz;
132b9a56342Smckusick else
133b9a56342Smckusick clockinfo.profhz = hertz();
134b9a56342Smckusick }
135b9a56342Smckusick
136645f7f03Smckusick moncontrol(0);
137b63fca47Storek fd = open("gmon.out", O_CREAT|O_TRUNC|O_WRONLY, 0666);
138536340e2Smckusic if (fd < 0) {
1399699256bSpeter perror("mcount: gmon.out");
140c06660d0Speter return;
141c06660d0Speter }
1429699256bSpeter #ifdef DEBUG
1436e9962b0Smckusick log = open("gmon.log", O_CREAT|O_TRUNC|O_WRONLY, 0664);
1446e9962b0Smckusick if (log < 0) {
1456e9962b0Smckusick perror("mcount: gmon.log");
1466e9962b0Smckusick return;
1476e9962b0Smckusick }
148b9a56342Smckusick len = sprintf(buf, "[mcleanup1] kcount 0x%x ssiz %d\n",
149b9a56342Smckusick p->kcount, p->kcountsize);
1506e9962b0Smckusick write(log, buf, len);
151d06aaf11Smckusick #endif
152b9a56342Smckusick hdr = (struct gmonhdr *)&gmonhdr;
153b9a56342Smckusick hdr->lpc = p->lowpc;
154b9a56342Smckusick hdr->hpc = p->highpc;
155b9a56342Smckusick hdr->ncnt = p->kcountsize + sizeof(gmonhdr);
156b9a56342Smckusick hdr->version = GMONVERSION;
157b9a56342Smckusick hdr->profrate = clockinfo.profhz;
158b9a56342Smckusick write(fd, (char *)hdr, sizeof *hdr);
159b9a56342Smckusick write(fd, p->kcount, p->kcountsize);
160b9a56342Smckusick endfrom = p->fromssize / sizeof(*p->froms);
161eb6779cfSmckusick for (fromindex = 0; fromindex < endfrom; fromindex++) {
162d06aaf11Smckusick if (p->froms[fromindex] == 0)
163c06660d0Speter continue;
164d06aaf11Smckusick
165d06aaf11Smckusick frompc = p->lowpc;
166b9a56342Smckusick frompc += fromindex * p->hashfraction * sizeof(*p->froms);
167d06aaf11Smckusick for (toindex = p->froms[fromindex]; toindex != 0;
168d06aaf11Smckusick toindex = p->tos[toindex].link) {
169c06660d0Speter #ifdef DEBUG
1706e9962b0Smckusick len = sprintf(buf,
1716e9962b0Smckusick "[mcleanup2] frompc 0x%x selfpc 0x%x count %d\n" ,
172d06aaf11Smckusick frompc, p->tos[toindex].selfpc,
173d06aaf11Smckusick p->tos[toindex].count);
1746e9962b0Smckusick write(log, buf, len);
175d06aaf11Smckusick #endif
176d06aaf11Smckusick rawarc.raw_frompc = frompc;
177d06aaf11Smckusick rawarc.raw_selfpc = p->tos[toindex].selfpc;
178d06aaf11Smckusick rawarc.raw_count = p->tos[toindex].count;
179536340e2Smckusic write(fd, &rawarc, sizeof rawarc);
180c06660d0Speter }
181c06660d0Speter }
182536340e2Smckusic close(fd);
183c06660d0Speter }
184c06660d0Speter
1859b3bc73fSpeter /*
1869b3bc73fSpeter * Control profiling
1879b3bc73fSpeter * profiling is what mcount checks to see if
1889b3bc73fSpeter * all the data structures are ready.
1899b3bc73fSpeter */
190b63fca47Storek void
moncontrol(mode)1919b3bc73fSpeter moncontrol(mode)
1929b3bc73fSpeter int mode;
1939b3bc73fSpeter {
194d06aaf11Smckusick struct gmonparam *p = &_gmonparam;
195d06aaf11Smckusick
1969b3bc73fSpeter if (mode) {
1979b3bc73fSpeter /* start */
198b9a56342Smckusick profil((char *)p->kcount, p->kcountsize, (int)p->lowpc,
199b9a56342Smckusick s_scale);
200d06aaf11Smckusick p->state = GMON_PROF_ON;
2019b3bc73fSpeter } else {
2029b3bc73fSpeter /* stop */
2039b3bc73fSpeter profil((char *)0, 0, 0, 0);
204d06aaf11Smckusick p->state = GMON_PROF_OFF;
2059b3bc73fSpeter }
206c06660d0Speter }
20751e5c269Smckusick
20851e5c269Smckusick /*
20951e5c269Smckusick * discover the tick frequency of the machine
21051e5c269Smckusick * if something goes wrong, we return 0, an impossible hertz.
21151e5c269Smckusick */
212b63fca47Storek static int
hertz()21351e5c269Smckusick hertz()
21451e5c269Smckusick {
21551e5c269Smckusick struct itimerval tim;
21651e5c269Smckusick
21751e5c269Smckusick tim.it_interval.tv_sec = 0;
21851e5c269Smckusick tim.it_interval.tv_usec = 1;
21951e5c269Smckusick tim.it_value.tv_sec = 0;
22051e5c269Smckusick tim.it_value.tv_usec = 0;
22151e5c269Smckusick setitimer(ITIMER_REAL, &tim, 0);
22251e5c269Smckusick setitimer(ITIMER_REAL, 0, &tim);
22351e5c269Smckusick if (tim.it_interval.tv_usec < 2)
22451e5c269Smckusick return(0);
22551e5c269Smckusick return (1000000 / tim.it_interval.tv_usec);
22651e5c269Smckusick }
227d06aaf11Smckusick
228d06aaf11Smckusick
229