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*55187Smckusick static char sccsid[] = "@(#)gmon.c 5.12 (Berkeley) 07/14/92"; 1054904Smckusick #endif 1121415Sdist 1248972Sdonn #include <unistd.h> 1352814Smckusick #include <sys/types.h> 1452814Smckusick #include <sys/time.h> 1552814Smckusick #include <sys/kinfo.h> 1648972Sdonn 174869Smckusic #ifdef DEBUG 184514Speter #include <stdio.h> 19*55187Smckusick #include <fcntl.h> 2047884Sbostic #endif 214514Speter 2254903Smckusick #include <sys/gmon.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; 4454903Smckusick int 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); 10654903Smckusick if (getkerninfo(KINFO_CLOCKRATE, &clockinfo, &size, 0) < 0) 10754903Smckusick /* 10854903Smckusick * Best guess 10954903Smckusick */ 11054903Smckusick clockinfo.profhz = hertz(); 11154903Smckusick else if (clockinfo.profhz == 0) { 11254903Smckusick if (clockinfo.hz != 0) 11354903Smckusick clockinfo.profhz = clockinfo.hz; 11454903Smckusick else 11554903Smckusick clockinfo.profhz = hertz(); 11654903Smckusick } 11754903Smckusick hdr = (struct gmonhdr *)&gmonhdr; 11854903Smckusick hdr->lpc = lowpc; 11954903Smckusick hdr->hpc = highpc; 12054903Smckusick hdr->ncnt = ssiz + sizeof(gmonhdr); 12154903Smckusick hdr->version = GMONVERSION; 12254903Smckusick hdr->profrate = clockinfo.profhz; 1234514Speter } 1244514Speter 1254514Speter _mcleanup() 1264514Speter { 12754903Smckusick int fd; 12854903Smckusick int fromindex; 12954903Smckusick int endfrom; 13054903Smckusick u_long frompc; 13154903Smckusick int toindex; 13254903Smckusick struct rawarc rawarc; 13354903Smckusick struct gmonparam *p = &_gmonparam; 134*55187Smckusick int log, len; 135*55187Smckusick char buf[200]; 1364514Speter 13754903Smckusick if (p->state == GMON_PROF_ERROR) 13854903Smckusick ERR("_mcleanup: tos overflow\n"); 13954903Smckusick 14054903Smckusick moncontrol(0); 14154903Smckusick fd = creat("gmon.out", 0666); 14254903Smckusick if (fd < 0) { 14354903Smckusick perror("mcount: gmon.out"); 14454903Smckusick return; 1454514Speter } 14654903Smckusick #ifdef DEBUG 147*55187Smckusick log = open("gmon.log", O_CREAT|O_TRUNC|O_WRONLY, 0664); 148*55187Smckusick if (log < 0) { 149*55187Smckusick perror("mcount: gmon.log"); 150*55187Smckusick return; 151*55187Smckusick } 152*55187Smckusick len = sprintf(buf, "[mcleanup1] sbuf 0x%x ssiz %d\n", sbuf, ssiz); 153*55187Smckusick write(log, buf, len); 15454903Smckusick #endif 15554903Smckusick write(fd, (char *)&gmonhdr, sizeof(gmonhdr)); 15654903Smckusick write(fd, sbuf, ssiz); 15754903Smckusick endfrom = p->textsize / (HASHFRACTION * sizeof(*p->froms)); 15854903Smckusick for (fromindex = 0; fromindex < endfrom; fromindex++) { 15954903Smckusick if (p->froms[fromindex] == 0) 16054903Smckusick continue; 16154903Smckusick 16254903Smckusick frompc = p->lowpc; 16354903Smckusick frompc += fromindex * HASHFRACTION * sizeof(*p->froms); 16454903Smckusick for (toindex = p->froms[fromindex]; toindex != 0; 16554903Smckusick toindex = p->tos[toindex].link) { 16654903Smckusick #ifdef DEBUG 167*55187Smckusick len = sprintf(buf, 168*55187Smckusick "[mcleanup2] frompc 0x%x selfpc 0x%x count %d\n" , 16954903Smckusick frompc, p->tos[toindex].selfpc, 17054903Smckusick p->tos[toindex].count); 171*55187Smckusick write(log, buf, len); 17254903Smckusick #endif 17354903Smckusick rawarc.raw_frompc = frompc; 17454903Smckusick rawarc.raw_selfpc = p->tos[toindex].selfpc; 17554903Smckusick rawarc.raw_count = p->tos[toindex].count; 17654903Smckusick write(fd, &rawarc, sizeof rawarc); 17754903Smckusick } 1784514Speter } 17954903Smckusick close(fd); 1804514Speter } 1814514Speter 1826177Smckusick /* 18311796Speter * Control profiling 18411796Speter * profiling is what mcount checks to see if 18511796Speter * all the data structures are ready. 18611796Speter */ 18711796Speter moncontrol(mode) 18854903Smckusick int mode; 18911796Speter { 19054903Smckusick struct gmonparam *p = &_gmonparam; 19154903Smckusick 19254903Smckusick if (mode) { 19354903Smckusick /* start */ 19454903Smckusick profil(sbuf, ssiz, (int)p->lowpc, s_scale); 19554903Smckusick p->state = GMON_PROF_ON; 19654903Smckusick } else { 19754903Smckusick /* stop */ 19854903Smckusick profil((char *)0, 0, 0, 0); 19954903Smckusick p->state = GMON_PROF_OFF; 20054903Smckusick } 20111796Speter } 20252814Smckusick 20354903Smckusick /* 20454903Smckusick * discover the tick frequency of the machine 20554903Smckusick * if something goes wrong, we return 0, an impossible hertz. 20654903Smckusick */ 20752814Smckusick hertz() 20852814Smckusick { 20952814Smckusick struct itimerval tim; 21054903Smckusick 21152814Smckusick tim.it_interval.tv_sec = 0; 21252814Smckusick tim.it_interval.tv_usec = 1; 21352814Smckusick tim.it_value.tv_sec = 0; 21452814Smckusick tim.it_value.tv_usec = 0; 21552814Smckusick setitimer(ITIMER_REAL, &tim, 0); 21652814Smckusick setitimer(ITIMER_REAL, 0, &tim); 21752814Smckusick if (tim.it_interval.tv_usec < 2) 21852814Smckusick return(0); 21952814Smckusick return (1000000 / tim.it_interval.tv_usec); 22052814Smckusick } 22154903Smckusick 22254903Smckusick 223