147884Sbostic /*- 247884Sbostic * Copyright (c) 1983 The Regents of the University of California. 347884Sbostic * All rights reserved. 447884Sbostic * 549278Sbostic * %sccs.include.redist.c% 621415Sdist */ 74514Speter 849278Sbostic #ifndef lint 9*54903Smckusick static char sccsid[] = "@(#)gmon.c 5.10 (Berkeley) 07/10/92"; 1049278Sbostic #endif /* not lint */ 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> 1947884Sbostic #endif 204514Speter 21*54903Smckusick #include <sys/gmon.h> 224514Speter 2348972Sdonn extern char *minbrk asm ("minbrk"); 2448972Sdonn 25*54903Smckusick struct gmonparam _gmonparam = { GMON_PROF_OFF }; 264514Speter 274564Speter static int ssiz; 2811998Speter static char *sbuf; 2911796Speter static int s_scale; 30*54903Smckusick /* see profil(2) where this is describe (incorrectly) */ 3111998Speter #define SCALE_1_TO_1 0x10000L 324514Speter 33*54903Smckusick #define ERR(s) write(2, s, sizeof(s)) 344514Speter 35*54903Smckusick static struct gmonhdr gmonhdr; 36*54903Smckusick 379433Smckusick monstartup(lowpc, highpc) 38*54903Smckusick u_long lowpc; 39*54903Smckusick u_long highpc; 404514Speter { 41*54903Smckusick register int o; 42*54903Smckusick struct clockinfo clockinfo; 43*54903Smckusick int tsize, fsize, size; 44*54903Smckusick char *cp; 45*54903Smckusick struct gmonhdr *hdr; 46*54903Smckusick struct gmonparam *p = &_gmonparam; 474514Speter 489608Speter /* 49*54903Smckusick * round lowpc and highpc to multiples of the density we're using 50*54903Smckusick * so the rest of the scaling (here and in gprof) stays in ints. 519608Speter */ 52*54903Smckusick lowpc = ROUNDDOWN(lowpc, HISTFRACTION * sizeof(HISTCOUNTER)); 53*54903Smckusick p->lowpc = lowpc; 54*54903Smckusick highpc = ROUNDUP(highpc, HISTFRACTION * sizeof(HISTCOUNTER)); 55*54903Smckusick p->highpc = highpc; 56*54903Smckusick p->textsize = highpc - lowpc; 57*54903Smckusick ssiz = p->textsize / HISTFRACTION; 58*54903Smckusick fsize = p->textsize / HASHFRACTION; 59*54903Smckusick tsize = p->textsize * ARCDENSITY / 100; 60*54903Smckusick if (tsize < MINARCS) 61*54903Smckusick tsize = MINARCS; 62*54903Smckusick else if (tsize > MAXARCS) 63*54903Smckusick tsize = MAXARCS; 64*54903Smckusick p->tolimit = tsize; 65*54903Smckusick tsize *= sizeof(struct tostruct); 66*54903Smckusick 67*54903Smckusick cp = sbrk(ssiz + fsize + tsize); 68*54903Smckusick if (cp == (char *)-1) { 69*54903Smckusick ERR("monstartup: out of memory\n"); 70*54903Smckusick return; 71*54903Smckusick } 72*54903Smckusick #ifdef notdef 73*54903Smckusick bzero(cp, ssiz + fsize + tsize); 74*54903Smckusick #endif 75*54903Smckusick p->tos = (struct tostruct *)cp; 76*54903Smckusick cp += tsize; 77*54903Smckusick sbuf = cp; 78*54903Smckusick cp += ssiz; 79*54903Smckusick p->froms = (u_short *)cp; 80*54903Smckusick 81*54903Smckusick minbrk = sbrk(0); 82*54903Smckusick p->tos[0].link = 0; 83*54903Smckusick 84*54903Smckusick o = highpc - lowpc; 85*54903Smckusick if (ssiz < o) { 8652814Smckusick #ifndef hp300 87*54903Smckusick s_scale = ((float)ssiz / o ) * SCALE_1_TO_1; 8852814Smckusick #else /* avoid floating point */ 89*54903Smckusick int quot = o / ssiz; 90*54903Smckusick 91*54903Smckusick if (quot >= 0x10000) 92*54903Smckusick s_scale = 1; 93*54903Smckusick else if (quot >= 0x100) 94*54903Smckusick s_scale = 0x10000 / quot; 95*54903Smckusick else if (o >= 0x800000) 96*54903Smckusick s_scale = 0x1000000 / (o / (ssiz >> 8)); 97*54903Smckusick else 98*54903Smckusick s_scale = 0x1000000 / ((o << 8) / ssiz); 99*54903Smckusick #endif 100*54903Smckusick } else 101*54903Smckusick s_scale = SCALE_1_TO_1; 10252814Smckusick 103*54903Smckusick moncontrol(1); 104*54903Smckusick size = sizeof(clockinfo); 105*54903Smckusick if (getkerninfo(KINFO_CLOCKRATE, &clockinfo, &size, 0) < 0) 106*54903Smckusick /* 107*54903Smckusick * Best guess 108*54903Smckusick */ 109*54903Smckusick clockinfo.profhz = hertz(); 110*54903Smckusick else if (clockinfo.profhz == 0) { 111*54903Smckusick if (clockinfo.hz != 0) 112*54903Smckusick clockinfo.profhz = clockinfo.hz; 113*54903Smckusick else 114*54903Smckusick clockinfo.profhz = hertz(); 115*54903Smckusick } 116*54903Smckusick hdr = (struct gmonhdr *)&gmonhdr; 117*54903Smckusick hdr->lpc = lowpc; 118*54903Smckusick hdr->hpc = highpc; 119*54903Smckusick hdr->ncnt = ssiz + sizeof(gmonhdr); 120*54903Smckusick hdr->version = GMONVERSION; 121*54903Smckusick hdr->profrate = clockinfo.profhz; 1224514Speter } 1234514Speter 1244514Speter _mcleanup() 1254514Speter { 126*54903Smckusick int fd; 127*54903Smckusick int fromindex; 128*54903Smckusick int endfrom; 129*54903Smckusick u_long frompc; 130*54903Smckusick int toindex; 131*54903Smckusick struct rawarc rawarc; 132*54903Smckusick struct gmonparam *p = &_gmonparam; 1334514Speter 134*54903Smckusick if (p->state == GMON_PROF_ERROR) 135*54903Smckusick ERR("_mcleanup: tos overflow\n"); 136*54903Smckusick 137*54903Smckusick moncontrol(0); 138*54903Smckusick fd = creat("gmon.out", 0666); 139*54903Smckusick if (fd < 0) { 140*54903Smckusick perror("mcount: gmon.out"); 141*54903Smckusick return; 1424514Speter } 143*54903Smckusick #ifdef DEBUG 144*54903Smckusick fprintf(stderr, "[mcleanup] sbuf 0x%x ssiz %d\n", sbuf, ssiz); 145*54903Smckusick #endif 146*54903Smckusick write(fd, (char *)&gmonhdr, sizeof(gmonhdr)); 147*54903Smckusick write(fd, sbuf, ssiz); 148*54903Smckusick endfrom = p->textsize / (HASHFRACTION * sizeof(*p->froms)); 149*54903Smckusick for (fromindex = 0; fromindex < endfrom; fromindex++) { 150*54903Smckusick if (p->froms[fromindex] == 0) 151*54903Smckusick continue; 152*54903Smckusick 153*54903Smckusick frompc = p->lowpc; 154*54903Smckusick frompc += fromindex * HASHFRACTION * sizeof(*p->froms); 155*54903Smckusick for (toindex = p->froms[fromindex]; toindex != 0; 156*54903Smckusick toindex = p->tos[toindex].link) { 157*54903Smckusick #ifdef DEBUG 158*54903Smckusick fprintf(stderr, 1594748Speter "[mcleanup] frompc 0x%x selfpc 0x%x count %d\n" , 160*54903Smckusick frompc, p->tos[toindex].selfpc, 161*54903Smckusick p->tos[toindex].count); 162*54903Smckusick #endif 163*54903Smckusick rawarc.raw_frompc = frompc; 164*54903Smckusick rawarc.raw_selfpc = p->tos[toindex].selfpc; 165*54903Smckusick rawarc.raw_count = p->tos[toindex].count; 166*54903Smckusick write(fd, &rawarc, sizeof rawarc); 167*54903Smckusick } 1684514Speter } 169*54903Smckusick close(fd); 1704514Speter } 1714514Speter 1726177Smckusick /* 17311796Speter * Control profiling 17411796Speter * profiling is what mcount checks to see if 17511796Speter * all the data structures are ready. 17611796Speter */ 17711796Speter moncontrol(mode) 178*54903Smckusick int mode; 17911796Speter { 180*54903Smckusick struct gmonparam *p = &_gmonparam; 181*54903Smckusick 182*54903Smckusick if (mode) { 183*54903Smckusick /* start */ 184*54903Smckusick profil(sbuf, ssiz, (int)p->lowpc, s_scale); 185*54903Smckusick p->state = GMON_PROF_ON; 186*54903Smckusick } else { 187*54903Smckusick /* stop */ 188*54903Smckusick profil((char *)0, 0, 0, 0); 189*54903Smckusick p->state = GMON_PROF_OFF; 190*54903Smckusick } 19111796Speter } 19252814Smckusick 193*54903Smckusick /* 194*54903Smckusick * discover the tick frequency of the machine 195*54903Smckusick * if something goes wrong, we return 0, an impossible hertz. 196*54903Smckusick */ 19752814Smckusick hertz() 19852814Smckusick { 19952814Smckusick struct itimerval tim; 200*54903Smckusick 20152814Smckusick tim.it_interval.tv_sec = 0; 20252814Smckusick tim.it_interval.tv_usec = 1; 20352814Smckusick tim.it_value.tv_sec = 0; 20452814Smckusick tim.it_value.tv_usec = 0; 20552814Smckusick setitimer(ITIMER_REAL, &tim, 0); 20652814Smckusick setitimer(ITIMER_REAL, 0, &tim); 20752814Smckusick if (tim.it_interval.tv_usec < 2) 20852814Smckusick return(0); 20952814Smckusick return (1000000 / tim.it_interval.tv_usec); 21052814Smckusick } 211*54903Smckusick 212*54903Smckusick 213