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*59391Sbostic static char sccsid[] = "@(#)gmon.c 5.14 (Berkeley) 04/27/93"; 1054904Smckusick #endif 1121415Sdist 12*59391Sbostic #include <sys/param.h> 1352814Smckusick #include <sys/time.h> 14*59391Sbostic #include <sys/gmon.h> 1558901Smckusick #include <sys/sysctl.h> 1648972Sdonn 174869Smckusic #ifdef DEBUG 184514Speter #include <stdio.h> 1955187Smckusick #include <fcntl.h> 2047884Sbostic #endif 214514Speter 22*59391Sbostic #include <unistd.h> 234514Speter 2448972Sdonn extern char *minbrk asm ("minbrk"); 2548972Sdonn 2654903Smckusick struct gmonparam _gmonparam = { GMON_PROF_OFF }; 274514Speter 284564Speter static int ssiz; 2911998Speter static char *sbuf; 3011796Speter static int s_scale; 3154903Smckusick /* see profil(2) where this is describe (incorrectly) */ 3211998Speter #define SCALE_1_TO_1 0x10000L 334514Speter 3454903Smckusick #define ERR(s) write(2, s, sizeof(s)) 354514Speter 3654903Smckusick static struct gmonhdr gmonhdr; 3754903Smckusick 389433Smckusick monstartup(lowpc, highpc) 3954903Smckusick u_long lowpc; 4054903Smckusick u_long highpc; 414514Speter { 4254903Smckusick register int o; 4354903Smckusick struct clockinfo clockinfo; 4458901Smckusick int mib[2], tsize, fsize, size; 4554903Smckusick char *cp; 4654903Smckusick struct gmonhdr *hdr; 4754903Smckusick struct gmonparam *p = &_gmonparam; 484514Speter 499608Speter /* 5054903Smckusick * round lowpc and highpc to multiples of the density we're using 5154903Smckusick * so the rest of the scaling (here and in gprof) stays in ints. 529608Speter */ 5354903Smckusick lowpc = ROUNDDOWN(lowpc, HISTFRACTION * sizeof(HISTCOUNTER)); 5454903Smckusick p->lowpc = lowpc; 5554903Smckusick highpc = ROUNDUP(highpc, HISTFRACTION * sizeof(HISTCOUNTER)); 5654903Smckusick p->highpc = highpc; 5754903Smckusick p->textsize = highpc - lowpc; 5854903Smckusick ssiz = p->textsize / HISTFRACTION; 5954903Smckusick fsize = p->textsize / HASHFRACTION; 6054903Smckusick tsize = p->textsize * ARCDENSITY / 100; 6154903Smckusick if (tsize < MINARCS) 6254903Smckusick tsize = MINARCS; 6354903Smckusick else if (tsize > MAXARCS) 6454903Smckusick tsize = MAXARCS; 6554903Smckusick p->tolimit = tsize; 6654903Smckusick tsize *= sizeof(struct tostruct); 6754903Smckusick 6854903Smckusick cp = sbrk(ssiz + fsize + tsize); 6954903Smckusick if (cp == (char *)-1) { 7054903Smckusick ERR("monstartup: out of memory\n"); 7154903Smckusick return; 7254903Smckusick } 7354903Smckusick #ifdef notdef 7454903Smckusick bzero(cp, ssiz + fsize + tsize); 7554903Smckusick #endif 7654903Smckusick p->tos = (struct tostruct *)cp; 7754903Smckusick cp += tsize; 7854903Smckusick sbuf = cp; 7954903Smckusick cp += ssiz; 8054903Smckusick p->froms = (u_short *)cp; 8154903Smckusick 8254903Smckusick minbrk = sbrk(0); 8354903Smckusick p->tos[0].link = 0; 8454903Smckusick 8554903Smckusick o = highpc - lowpc; 8654903Smckusick if (ssiz < o) { 8752814Smckusick #ifndef hp300 8854903Smckusick s_scale = ((float)ssiz / o ) * SCALE_1_TO_1; 8952814Smckusick #else /* avoid floating point */ 9054903Smckusick int quot = o / ssiz; 9154903Smckusick 9254903Smckusick if (quot >= 0x10000) 9354903Smckusick s_scale = 1; 9454903Smckusick else if (quot >= 0x100) 9554903Smckusick s_scale = 0x10000 / quot; 9654903Smckusick else if (o >= 0x800000) 9754903Smckusick s_scale = 0x1000000 / (o / (ssiz >> 8)); 9854903Smckusick else 9954903Smckusick s_scale = 0x1000000 / ((o << 8) / ssiz); 10054903Smckusick #endif 10154903Smckusick } else 10254903Smckusick s_scale = SCALE_1_TO_1; 10352814Smckusick 10454903Smckusick moncontrol(1); 10554903Smckusick size = sizeof(clockinfo); 10658901Smckusick mib[0] = CTL_KERN; 10758901Smckusick mib[1] = KERN_CLOCKRATE; 10858901Smckusick if (sysctl(mib, 2, &clockinfo, &size, NULL, 0) < 0) 10954903Smckusick /* 11054903Smckusick * Best guess 11154903Smckusick */ 11254903Smckusick clockinfo.profhz = hertz(); 11354903Smckusick else if (clockinfo.profhz == 0) { 11454903Smckusick if (clockinfo.hz != 0) 11554903Smckusick clockinfo.profhz = clockinfo.hz; 11654903Smckusick else 11754903Smckusick clockinfo.profhz = hertz(); 11854903Smckusick } 11954903Smckusick hdr = (struct gmonhdr *)&gmonhdr; 12054903Smckusick hdr->lpc = lowpc; 12154903Smckusick hdr->hpc = highpc; 12254903Smckusick hdr->ncnt = ssiz + sizeof(gmonhdr); 12354903Smckusick hdr->version = GMONVERSION; 12454903Smckusick hdr->profrate = clockinfo.profhz; 1254514Speter } 1264514Speter 1274514Speter _mcleanup() 1284514Speter { 12954903Smckusick int fd; 13054903Smckusick int fromindex; 13154903Smckusick int endfrom; 13254903Smckusick u_long frompc; 13354903Smckusick int toindex; 13454903Smckusick struct rawarc rawarc; 13554903Smckusick struct gmonparam *p = &_gmonparam; 13655187Smckusick int log, len; 13755187Smckusick char buf[200]; 1384514Speter 13954903Smckusick if (p->state == GMON_PROF_ERROR) 14054903Smckusick ERR("_mcleanup: tos overflow\n"); 14154903Smckusick 14254903Smckusick moncontrol(0); 14354903Smckusick fd = creat("gmon.out", 0666); 14454903Smckusick if (fd < 0) { 14554903Smckusick perror("mcount: gmon.out"); 14654903Smckusick return; 1474514Speter } 14854903Smckusick #ifdef DEBUG 14955187Smckusick log = open("gmon.log", O_CREAT|O_TRUNC|O_WRONLY, 0664); 15055187Smckusick if (log < 0) { 15155187Smckusick perror("mcount: gmon.log"); 15255187Smckusick return; 15355187Smckusick } 15455187Smckusick len = sprintf(buf, "[mcleanup1] sbuf 0x%x ssiz %d\n", sbuf, ssiz); 15555187Smckusick write(log, buf, len); 15654903Smckusick #endif 15754903Smckusick write(fd, (char *)&gmonhdr, sizeof(gmonhdr)); 15854903Smckusick write(fd, sbuf, ssiz); 15954903Smckusick endfrom = p->textsize / (HASHFRACTION * sizeof(*p->froms)); 16054903Smckusick for (fromindex = 0; fromindex < endfrom; fromindex++) { 16154903Smckusick if (p->froms[fromindex] == 0) 16254903Smckusick continue; 16354903Smckusick 16454903Smckusick frompc = p->lowpc; 16554903Smckusick frompc += fromindex * HASHFRACTION * sizeof(*p->froms); 16654903Smckusick for (toindex = p->froms[fromindex]; toindex != 0; 16754903Smckusick toindex = p->tos[toindex].link) { 16854903Smckusick #ifdef DEBUG 16955187Smckusick len = sprintf(buf, 17055187Smckusick "[mcleanup2] frompc 0x%x selfpc 0x%x count %d\n" , 17154903Smckusick frompc, p->tos[toindex].selfpc, 17254903Smckusick p->tos[toindex].count); 17355187Smckusick write(log, buf, len); 17454903Smckusick #endif 17554903Smckusick rawarc.raw_frompc = frompc; 17654903Smckusick rawarc.raw_selfpc = p->tos[toindex].selfpc; 17754903Smckusick rawarc.raw_count = p->tos[toindex].count; 17854903Smckusick write(fd, &rawarc, sizeof rawarc); 17954903Smckusick } 1804514Speter } 18154903Smckusick close(fd); 1824514Speter } 1834514Speter 1846177Smckusick /* 18511796Speter * Control profiling 18611796Speter * profiling is what mcount checks to see if 18711796Speter * all the data structures are ready. 18811796Speter */ 18911796Speter moncontrol(mode) 19054903Smckusick int mode; 19111796Speter { 19254903Smckusick struct gmonparam *p = &_gmonparam; 19354903Smckusick 19454903Smckusick if (mode) { 19554903Smckusick /* start */ 19654903Smckusick profil(sbuf, ssiz, (int)p->lowpc, s_scale); 19754903Smckusick p->state = GMON_PROF_ON; 19854903Smckusick } else { 19954903Smckusick /* stop */ 20054903Smckusick profil((char *)0, 0, 0, 0); 20154903Smckusick p->state = GMON_PROF_OFF; 20254903Smckusick } 20311796Speter } 20452814Smckusick 20554903Smckusick /* 20654903Smckusick * discover the tick frequency of the machine 20754903Smckusick * if something goes wrong, we return 0, an impossible hertz. 20854903Smckusick */ 20952814Smckusick hertz() 21052814Smckusick { 21152814Smckusick struct itimerval tim; 21254903Smckusick 21352814Smckusick tim.it_interval.tv_sec = 0; 21452814Smckusick tim.it_interval.tv_usec = 1; 21552814Smckusick tim.it_value.tv_sec = 0; 21652814Smckusick tim.it_value.tv_usec = 0; 21752814Smckusick setitimer(ITIMER_REAL, &tim, 0); 21852814Smckusick setitimer(ITIMER_REAL, 0, &tim); 21952814Smckusick if (tim.it_interval.tv_usec < 2) 22052814Smckusick return(0); 22152814Smckusick return (1000000 / tim.it_interval.tv_usec); 22252814Smckusick } 22354903Smckusick 22454903Smckusick 225