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*60351Storek static char sccsid[] = "@(#)gmon.c 5.16 (Berkeley) 05/25/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 31*60351Storek void moncontrol __P((int)); 32*60351Storek static int hertz __P((void)); 33*60351Storek 34*60351Storek void 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 99*60351Storek void 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; 111*60351Storek int mib[2]; 112*60351Storek size_t size; 113*60351Storek #ifdef DEBUG 11455187Smckusick int log, len; 11555187Smckusick char buf[200]; 116*60351Storek #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); 137*60351Storek 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 */ 190*60351Storek void 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 */ 212*60351Storek static int 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