147884Sbostic /*- 254904Smckusick * Copyright (c) 1983, 1992 The Regents of the University of California. 347884Sbostic * All rights reserved. 447884Sbostic * 549278Sbostic * %sccs.include.redist.c% 621415Sdist */ 74514Speter 854904Smckusick #if !defined(lint) && defined(LIBC_SCCS) 9*59560Smckusick static char sccsid[] = "@(#)gmon.c 5.15 (Berkeley) 04/30/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 174869Smckusic #ifdef DEBUG 184514Speter #include <stdio.h> 1955187Smckusick #include <fcntl.h> 2047884Sbostic #endif 214514Speter 2259391Sbostic #include <unistd.h> 234514Speter 2448972Sdonn extern char *minbrk asm ("minbrk"); 2548972Sdonn 2654903Smckusick struct gmonparam _gmonparam = { GMON_PROF_OFF }; 274514Speter 2811796Speter static int s_scale; 2954903Smckusick /* see profil(2) where this is describe (incorrectly) */ 3011998Speter #define SCALE_1_TO_1 0x10000L 314514Speter 3254903Smckusick #define ERR(s) write(2, s, sizeof(s)) 334514Speter 349433Smckusick monstartup(lowpc, highpc) 3554903Smckusick u_long lowpc; 3654903Smckusick u_long highpc; 374514Speter { 3854903Smckusick register int o; 3954903Smckusick char *cp; 4054903Smckusick struct gmonparam *p = &_gmonparam; 414514Speter 429608Speter /* 4354903Smckusick * round lowpc and highpc to multiples of the density we're using 4454903Smckusick * so the rest of the scaling (here and in gprof) stays in ints. 459608Speter */ 46*59560Smckusick p->lowpc = ROUNDDOWN(lowpc, HISTFRACTION * sizeof(HISTCOUNTER)); 47*59560Smckusick p->highpc = ROUNDUP(highpc, HISTFRACTION * sizeof(HISTCOUNTER)); 48*59560Smckusick p->textsize = p->highpc - p->lowpc; 49*59560Smckusick p->kcountsize = p->textsize / HISTFRACTION; 50*59560Smckusick p->hashfraction = HASHFRACTION; 51*59560Smckusick p->fromssize = p->textsize / HASHFRACTION; 52*59560Smckusick p->tolimit = p->textsize * ARCDENSITY / 100; 53*59560Smckusick if (p->tolimit < MINARCS) 54*59560Smckusick p->tolimit = MINARCS; 55*59560Smckusick else if (p->tolimit > MAXARCS) 56*59560Smckusick p->tolimit = MAXARCS; 57*59560Smckusick p->tossize = p->tolimit * sizeof(struct tostruct); 5854903Smckusick 59*59560Smckusick cp = sbrk(p->kcountsize + p->fromssize + p->tossize); 6054903Smckusick if (cp == (char *)-1) { 6154903Smckusick ERR("monstartup: out of memory\n"); 6254903Smckusick return; 6354903Smckusick } 6454903Smckusick #ifdef notdef 65*59560Smckusick bzero(cp, p->kcountsize + p->fromssize + p->tossize); 6654903Smckusick #endif 6754903Smckusick p->tos = (struct tostruct *)cp; 68*59560Smckusick cp += p->tossize; 69*59560Smckusick p->kcount = (u_short *)cp; 70*59560Smckusick cp += p->kcountsize; 7154903Smckusick p->froms = (u_short *)cp; 7254903Smckusick 7354903Smckusick minbrk = sbrk(0); 7454903Smckusick p->tos[0].link = 0; 7554903Smckusick 76*59560Smckusick o = p->highpc - p->lowpc; 77*59560Smckusick if (p->kcountsize < o) { 7852814Smckusick #ifndef hp300 79*59560Smckusick s_scale = ((float)p->kcountsize / o ) * SCALE_1_TO_1; 8052814Smckusick #else /* avoid floating point */ 81*59560Smckusick int quot = o / p->kcountsize; 8254903Smckusick 8354903Smckusick if (quot >= 0x10000) 8454903Smckusick s_scale = 1; 8554903Smckusick else if (quot >= 0x100) 8654903Smckusick s_scale = 0x10000 / quot; 8754903Smckusick else if (o >= 0x800000) 88*59560Smckusick s_scale = 0x1000000 / (o / (p->kcountsize >> 8)); 8954903Smckusick else 90*59560Smckusick s_scale = 0x1000000 / ((o << 8) / p->kcountsize); 9154903Smckusick #endif 9254903Smckusick } else 9354903Smckusick s_scale = SCALE_1_TO_1; 9452814Smckusick 9554903Smckusick moncontrol(1); 964514Speter } 974514Speter 984514Speter _mcleanup() 994514Speter { 10054903Smckusick int fd; 10154903Smckusick int fromindex; 10254903Smckusick int endfrom; 10354903Smckusick u_long frompc; 10454903Smckusick int toindex; 10554903Smckusick struct rawarc rawarc; 10654903Smckusick struct gmonparam *p = &_gmonparam; 107*59560Smckusick struct gmonhdr gmonhdr, *hdr; 108*59560Smckusick struct clockinfo clockinfo; 109*59560Smckusick int mib[2], size; 11055187Smckusick int log, len; 11155187Smckusick char buf[200]; 1124514Speter 11354903Smckusick if (p->state == GMON_PROF_ERROR) 11454903Smckusick ERR("_mcleanup: tos overflow\n"); 11554903Smckusick 116*59560Smckusick size = sizeof(clockinfo); 117*59560Smckusick mib[0] = CTL_KERN; 118*59560Smckusick mib[1] = KERN_CLOCKRATE; 119*59560Smckusick if (sysctl(mib, 2, &clockinfo, &size, NULL, 0) < 0) { 120*59560Smckusick /* 121*59560Smckusick * Best guess 122*59560Smckusick */ 123*59560Smckusick clockinfo.profhz = hertz(); 124*59560Smckusick } else if (clockinfo.profhz == 0) { 125*59560Smckusick if (clockinfo.hz != 0) 126*59560Smckusick clockinfo.profhz = clockinfo.hz; 127*59560Smckusick else 128*59560Smckusick clockinfo.profhz = hertz(); 129*59560Smckusick } 130*59560Smckusick 13154903Smckusick moncontrol(0); 13254903Smckusick fd = creat("gmon.out", 0666); 13354903Smckusick if (fd < 0) { 13454903Smckusick perror("mcount: gmon.out"); 13554903Smckusick return; 1364514Speter } 13754903Smckusick #ifdef DEBUG 13855187Smckusick log = open("gmon.log", O_CREAT|O_TRUNC|O_WRONLY, 0664); 13955187Smckusick if (log < 0) { 14055187Smckusick perror("mcount: gmon.log"); 14155187Smckusick return; 14255187Smckusick } 143*59560Smckusick len = sprintf(buf, "[mcleanup1] kcount 0x%x ssiz %d\n", 144*59560Smckusick p->kcount, p->kcountsize); 14555187Smckusick write(log, buf, len); 14654903Smckusick #endif 147*59560Smckusick hdr = (struct gmonhdr *)&gmonhdr; 148*59560Smckusick hdr->lpc = p->lowpc; 149*59560Smckusick hdr->hpc = p->highpc; 150*59560Smckusick hdr->ncnt = p->kcountsize + sizeof(gmonhdr); 151*59560Smckusick hdr->version = GMONVERSION; 152*59560Smckusick hdr->profrate = clockinfo.profhz; 153*59560Smckusick write(fd, (char *)hdr, sizeof *hdr); 154*59560Smckusick write(fd, p->kcount, p->kcountsize); 155*59560Smckusick endfrom = p->fromssize / sizeof(*p->froms); 15654903Smckusick for (fromindex = 0; fromindex < endfrom; fromindex++) { 15754903Smckusick if (p->froms[fromindex] == 0) 15854903Smckusick continue; 15954903Smckusick 16054903Smckusick frompc = p->lowpc; 161*59560Smckusick frompc += fromindex * p->hashfraction * sizeof(*p->froms); 16254903Smckusick for (toindex = p->froms[fromindex]; toindex != 0; 16354903Smckusick toindex = p->tos[toindex].link) { 16454903Smckusick #ifdef DEBUG 16555187Smckusick len = sprintf(buf, 16655187Smckusick "[mcleanup2] frompc 0x%x selfpc 0x%x count %d\n" , 16754903Smckusick frompc, p->tos[toindex].selfpc, 16854903Smckusick p->tos[toindex].count); 16955187Smckusick write(log, buf, len); 17054903Smckusick #endif 17154903Smckusick rawarc.raw_frompc = frompc; 17254903Smckusick rawarc.raw_selfpc = p->tos[toindex].selfpc; 17354903Smckusick rawarc.raw_count = p->tos[toindex].count; 17454903Smckusick write(fd, &rawarc, sizeof rawarc); 17554903Smckusick } 1764514Speter } 17754903Smckusick close(fd); 1784514Speter } 1794514Speter 1806177Smckusick /* 18111796Speter * Control profiling 18211796Speter * profiling is what mcount checks to see if 18311796Speter * all the data structures are ready. 18411796Speter */ 18511796Speter moncontrol(mode) 18654903Smckusick int mode; 18711796Speter { 18854903Smckusick struct gmonparam *p = &_gmonparam; 18954903Smckusick 19054903Smckusick if (mode) { 19154903Smckusick /* start */ 192*59560Smckusick profil((char *)p->kcount, p->kcountsize, (int)p->lowpc, 193*59560Smckusick s_scale); 19454903Smckusick p->state = GMON_PROF_ON; 19554903Smckusick } else { 19654903Smckusick /* stop */ 19754903Smckusick profil((char *)0, 0, 0, 0); 19854903Smckusick p->state = GMON_PROF_OFF; 19954903Smckusick } 20011796Speter } 20152814Smckusick 20254903Smckusick /* 20354903Smckusick * discover the tick frequency of the machine 20454903Smckusick * if something goes wrong, we return 0, an impossible hertz. 20554903Smckusick */ 20652814Smckusick hertz() 20752814Smckusick { 20852814Smckusick struct itimerval tim; 20954903Smckusick 21052814Smckusick tim.it_interval.tv_sec = 0; 21152814Smckusick tim.it_interval.tv_usec = 1; 21252814Smckusick tim.it_value.tv_sec = 0; 21352814Smckusick tim.it_value.tv_usec = 0; 21452814Smckusick setitimer(ITIMER_REAL, &tim, 0); 21552814Smckusick setitimer(ITIMER_REAL, 0, &tim); 21652814Smckusick if (tim.it_interval.tv_usec < 2) 21752814Smckusick return(0); 21852814Smckusick return (1000000 / tim.it_interval.tv_usec); 21952814Smckusick } 22054903Smckusick 22154903Smckusick 222