147884Sbostic /*-
2*61112Sbostic * Copyright (c) 1983, 1992, 1993
3*61112Sbostic * The Regents of the University of California. All rights reserved.
447884Sbostic *
549278Sbostic * %sccs.include.redist.c%
621415Sdist */
74514Speter
854904Smckusick #if !defined(lint) && defined(LIBC_SCCS)
9*61112Sbostic static char sccsid[] = "@(#)gmon.c 8.1 (Berkeley) 06/04/93";
1054904Smckusick #endif
1121415Sdist
1259391Sbostic #include <sys/param.h>
1352814Smckusick #include <sys/time.h>
1459391Sbostic #include <sys/gmon.h>
1558901Smckusick #include <sys/sysctl.h>
1648972Sdonn
174514Speter #include <stdio.h>
1855187Smckusick #include <fcntl.h>
1959391Sbostic #include <unistd.h>
204514Speter
2148972Sdonn extern char *minbrk asm ("minbrk");
2248972Sdonn
2354903Smckusick struct gmonparam _gmonparam = { GMON_PROF_OFF };
244514Speter
2511796Speter static int s_scale;
2654903Smckusick /* see profil(2) where this is describe (incorrectly) */
2711998Speter #define SCALE_1_TO_1 0x10000L
284514Speter
2954903Smckusick #define ERR(s) write(2, s, sizeof(s))
304514Speter
3160351Storek void moncontrol __P((int));
3260351Storek static int hertz __P((void));
3360351Storek
3460351Storek void
monstartup(lowpc,highpc)359433Smckusick monstartup(lowpc, highpc)
3654903Smckusick u_long lowpc;
3754903Smckusick u_long highpc;
384514Speter {
3954903Smckusick register int o;
4054903Smckusick char *cp;
4154903Smckusick struct gmonparam *p = &_gmonparam;
424514Speter
439608Speter /*
4454903Smckusick * round lowpc and highpc to multiples of the density we're using
4554903Smckusick * so the rest of the scaling (here and in gprof) stays in ints.
469608Speter */
4759560Smckusick p->lowpc = ROUNDDOWN(lowpc, HISTFRACTION * sizeof(HISTCOUNTER));
4859560Smckusick p->highpc = ROUNDUP(highpc, HISTFRACTION * sizeof(HISTCOUNTER));
4959560Smckusick p->textsize = p->highpc - p->lowpc;
5059560Smckusick p->kcountsize = p->textsize / HISTFRACTION;
5159560Smckusick p->hashfraction = HASHFRACTION;
5259560Smckusick p->fromssize = p->textsize / HASHFRACTION;
5359560Smckusick p->tolimit = p->textsize * ARCDENSITY / 100;
5459560Smckusick if (p->tolimit < MINARCS)
5559560Smckusick p->tolimit = MINARCS;
5659560Smckusick else if (p->tolimit > MAXARCS)
5759560Smckusick p->tolimit = MAXARCS;
5859560Smckusick p->tossize = p->tolimit * sizeof(struct tostruct);
5954903Smckusick
6059560Smckusick cp = sbrk(p->kcountsize + p->fromssize + p->tossize);
6154903Smckusick if (cp == (char *)-1) {
6254903Smckusick ERR("monstartup: out of memory\n");
6354903Smckusick return;
6454903Smckusick }
6554903Smckusick #ifdef notdef
6659560Smckusick bzero(cp, p->kcountsize + p->fromssize + p->tossize);
6754903Smckusick #endif
6854903Smckusick p->tos = (struct tostruct *)cp;
6959560Smckusick cp += p->tossize;
7059560Smckusick p->kcount = (u_short *)cp;
7159560Smckusick cp += p->kcountsize;
7254903Smckusick p->froms = (u_short *)cp;
7354903Smckusick
7454903Smckusick minbrk = sbrk(0);
7554903Smckusick p->tos[0].link = 0;
7654903Smckusick
7759560Smckusick o = p->highpc - p->lowpc;
7859560Smckusick if (p->kcountsize < o) {
7952814Smckusick #ifndef hp300
8059560Smckusick s_scale = ((float)p->kcountsize / o ) * SCALE_1_TO_1;
8152814Smckusick #else /* avoid floating point */
8259560Smckusick int quot = o / p->kcountsize;
8354903Smckusick
8454903Smckusick if (quot >= 0x10000)
8554903Smckusick s_scale = 1;
8654903Smckusick else if (quot >= 0x100)
8754903Smckusick s_scale = 0x10000 / quot;
8854903Smckusick else if (o >= 0x800000)
8959560Smckusick s_scale = 0x1000000 / (o / (p->kcountsize >> 8));
9054903Smckusick else
9159560Smckusick s_scale = 0x1000000 / ((o << 8) / p->kcountsize);
9254903Smckusick #endif
9354903Smckusick } else
9454903Smckusick s_scale = SCALE_1_TO_1;
9552814Smckusick
9654903Smckusick moncontrol(1);
974514Speter }
984514Speter
9960351Storek void
_mcleanup()1004514Speter _mcleanup()
1014514Speter {
10254903Smckusick int fd;
10354903Smckusick int fromindex;
10454903Smckusick int endfrom;
10554903Smckusick u_long frompc;
10654903Smckusick int toindex;
10754903Smckusick struct rawarc rawarc;
10854903Smckusick struct gmonparam *p = &_gmonparam;
10959560Smckusick struct gmonhdr gmonhdr, *hdr;
11059560Smckusick struct clockinfo clockinfo;
11160351Storek int mib[2];
11260351Storek size_t size;
11360351Storek #ifdef DEBUG
11455187Smckusick int log, len;
11555187Smckusick char buf[200];
11660351Storek #endif
1174514Speter
11854903Smckusick if (p->state == GMON_PROF_ERROR)
11954903Smckusick ERR("_mcleanup: tos overflow\n");
12054903Smckusick
12159560Smckusick size = sizeof(clockinfo);
12259560Smckusick mib[0] = CTL_KERN;
12359560Smckusick mib[1] = KERN_CLOCKRATE;
12459560Smckusick if (sysctl(mib, 2, &clockinfo, &size, NULL, 0) < 0) {
12559560Smckusick /*
12659560Smckusick * Best guess
12759560Smckusick */
12859560Smckusick clockinfo.profhz = hertz();
12959560Smckusick } else if (clockinfo.profhz == 0) {
13059560Smckusick if (clockinfo.hz != 0)
13159560Smckusick clockinfo.profhz = clockinfo.hz;
13259560Smckusick else
13359560Smckusick clockinfo.profhz = hertz();
13459560Smckusick }
13559560Smckusick
13654903Smckusick moncontrol(0);
13760351Storek fd = open("gmon.out", O_CREAT|O_TRUNC|O_WRONLY, 0666);
13854903Smckusick if (fd < 0) {
13954903Smckusick perror("mcount: gmon.out");
14054903Smckusick return;
1414514Speter }
14254903Smckusick #ifdef DEBUG
14355187Smckusick log = open("gmon.log", O_CREAT|O_TRUNC|O_WRONLY, 0664);
14455187Smckusick if (log < 0) {
14555187Smckusick perror("mcount: gmon.log");
14655187Smckusick return;
14755187Smckusick }
14859560Smckusick len = sprintf(buf, "[mcleanup1] kcount 0x%x ssiz %d\n",
14959560Smckusick p->kcount, p->kcountsize);
15055187Smckusick write(log, buf, len);
15154903Smckusick #endif
15259560Smckusick hdr = (struct gmonhdr *)&gmonhdr;
15359560Smckusick hdr->lpc = p->lowpc;
15459560Smckusick hdr->hpc = p->highpc;
15559560Smckusick hdr->ncnt = p->kcountsize + sizeof(gmonhdr);
15659560Smckusick hdr->version = GMONVERSION;
15759560Smckusick hdr->profrate = clockinfo.profhz;
15859560Smckusick write(fd, (char *)hdr, sizeof *hdr);
15959560Smckusick write(fd, p->kcount, p->kcountsize);
16059560Smckusick endfrom = p->fromssize / sizeof(*p->froms);
16154903Smckusick for (fromindex = 0; fromindex < endfrom; fromindex++) {
16254903Smckusick if (p->froms[fromindex] == 0)
16354903Smckusick continue;
16454903Smckusick
16554903Smckusick frompc = p->lowpc;
16659560Smckusick frompc += fromindex * p->hashfraction * sizeof(*p->froms);
16754903Smckusick for (toindex = p->froms[fromindex]; toindex != 0;
16854903Smckusick toindex = p->tos[toindex].link) {
16954903Smckusick #ifdef DEBUG
17055187Smckusick len = sprintf(buf,
17155187Smckusick "[mcleanup2] frompc 0x%x selfpc 0x%x count %d\n" ,
17254903Smckusick frompc, p->tos[toindex].selfpc,
17354903Smckusick p->tos[toindex].count);
17455187Smckusick write(log, buf, len);
17554903Smckusick #endif
17654903Smckusick rawarc.raw_frompc = frompc;
17754903Smckusick rawarc.raw_selfpc = p->tos[toindex].selfpc;
17854903Smckusick rawarc.raw_count = p->tos[toindex].count;
17954903Smckusick write(fd, &rawarc, sizeof rawarc);
18054903Smckusick }
1814514Speter }
18254903Smckusick close(fd);
1834514Speter }
1844514Speter
1856177Smckusick /*
18611796Speter * Control profiling
18711796Speter * profiling is what mcount checks to see if
18811796Speter * all the data structures are ready.
18911796Speter */
19060351Storek void
moncontrol(mode)19111796Speter moncontrol(mode)
19254903Smckusick int mode;
19311796Speter {
19454903Smckusick struct gmonparam *p = &_gmonparam;
19554903Smckusick
19654903Smckusick if (mode) {
19754903Smckusick /* start */
19859560Smckusick profil((char *)p->kcount, p->kcountsize, (int)p->lowpc,
19959560Smckusick s_scale);
20054903Smckusick p->state = GMON_PROF_ON;
20154903Smckusick } else {
20254903Smckusick /* stop */
20354903Smckusick profil((char *)0, 0, 0, 0);
20454903Smckusick p->state = GMON_PROF_OFF;
20554903Smckusick }
20611796Speter }
20752814Smckusick
20854903Smckusick /*
20954903Smckusick * discover the tick frequency of the machine
21054903Smckusick * if something goes wrong, we return 0, an impossible hertz.
21154903Smckusick */
21260351Storek static int
hertz()21352814Smckusick hertz()
21452814Smckusick {
21552814Smckusick struct itimerval tim;
21654903Smckusick
21752814Smckusick tim.it_interval.tv_sec = 0;
21852814Smckusick tim.it_interval.tv_usec = 1;
21952814Smckusick tim.it_value.tv_sec = 0;
22052814Smckusick tim.it_value.tv_usec = 0;
22152814Smckusick setitimer(ITIMER_REAL, &tim, 0);
22252814Smckusick setitimer(ITIMER_REAL, 0, &tim);
22352814Smckusick if (tim.it_interval.tv_usec < 2)
22452814Smckusick return(0);
22552814Smckusick return (1000000 / tim.it_interval.tv_usec);
22652814Smckusick }
22754903Smckusick
22854903Smckusick
229