147884Sbostic /*- 2*54904Smckusick * Copyright (c) 1983, 1992 The Regents of the University of California. 347884Sbostic * All rights reserved. 447884Sbostic * 549278Sbostic * %sccs.include.redist.c% 621415Sdist */ 74514Speter 8*54904Smckusick #if !defined(lint) && defined(LIBC_SCCS) 9*54904Smckusick static char sccsid[] = "@(#)gmon.c 5.11 (Berkeley) 07/10/92"; 10*54904Smckusick #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> 1947884Sbostic #endif 204514Speter 2154903Smckusick #include <sys/gmon.h> 224514Speter 2348972Sdonn extern char *minbrk asm ("minbrk"); 2448972Sdonn 2554903Smckusick struct gmonparam _gmonparam = { GMON_PROF_OFF }; 264514Speter 274564Speter static int ssiz; 2811998Speter static char *sbuf; 2911796Speter static int s_scale; 3054903Smckusick /* see profil(2) where this is describe (incorrectly) */ 3111998Speter #define SCALE_1_TO_1 0x10000L 324514Speter 3354903Smckusick #define ERR(s) write(2, s, sizeof(s)) 344514Speter 3554903Smckusick static struct gmonhdr gmonhdr; 3654903Smckusick 379433Smckusick monstartup(lowpc, highpc) 3854903Smckusick u_long lowpc; 3954903Smckusick u_long highpc; 404514Speter { 4154903Smckusick register int o; 4254903Smckusick struct clockinfo clockinfo; 4354903Smckusick int tsize, fsize, size; 4454903Smckusick char *cp; 4554903Smckusick struct gmonhdr *hdr; 4654903Smckusick struct gmonparam *p = &_gmonparam; 474514Speter 489608Speter /* 4954903Smckusick * round lowpc and highpc to multiples of the density we're using 5054903Smckusick * so the rest of the scaling (here and in gprof) stays in ints. 519608Speter */ 5254903Smckusick lowpc = ROUNDDOWN(lowpc, HISTFRACTION * sizeof(HISTCOUNTER)); 5354903Smckusick p->lowpc = lowpc; 5454903Smckusick highpc = ROUNDUP(highpc, HISTFRACTION * sizeof(HISTCOUNTER)); 5554903Smckusick p->highpc = highpc; 5654903Smckusick p->textsize = highpc - lowpc; 5754903Smckusick ssiz = p->textsize / HISTFRACTION; 5854903Smckusick fsize = p->textsize / HASHFRACTION; 5954903Smckusick tsize = p->textsize * ARCDENSITY / 100; 6054903Smckusick if (tsize < MINARCS) 6154903Smckusick tsize = MINARCS; 6254903Smckusick else if (tsize > MAXARCS) 6354903Smckusick tsize = MAXARCS; 6454903Smckusick p->tolimit = tsize; 6554903Smckusick tsize *= sizeof(struct tostruct); 6654903Smckusick 6754903Smckusick cp = sbrk(ssiz + fsize + tsize); 6854903Smckusick if (cp == (char *)-1) { 6954903Smckusick ERR("monstartup: out of memory\n"); 7054903Smckusick return; 7154903Smckusick } 7254903Smckusick #ifdef notdef 7354903Smckusick bzero(cp, ssiz + fsize + tsize); 7454903Smckusick #endif 7554903Smckusick p->tos = (struct tostruct *)cp; 7654903Smckusick cp += tsize; 7754903Smckusick sbuf = cp; 7854903Smckusick cp += ssiz; 7954903Smckusick p->froms = (u_short *)cp; 8054903Smckusick 8154903Smckusick minbrk = sbrk(0); 8254903Smckusick p->tos[0].link = 0; 8354903Smckusick 8454903Smckusick o = highpc - lowpc; 8554903Smckusick if (ssiz < o) { 8652814Smckusick #ifndef hp300 8754903Smckusick s_scale = ((float)ssiz / o ) * SCALE_1_TO_1; 8852814Smckusick #else /* avoid floating point */ 8954903Smckusick int quot = o / ssiz; 9054903Smckusick 9154903Smckusick if (quot >= 0x10000) 9254903Smckusick s_scale = 1; 9354903Smckusick else if (quot >= 0x100) 9454903Smckusick s_scale = 0x10000 / quot; 9554903Smckusick else if (o >= 0x800000) 9654903Smckusick s_scale = 0x1000000 / (o / (ssiz >> 8)); 9754903Smckusick else 9854903Smckusick s_scale = 0x1000000 / ((o << 8) / ssiz); 9954903Smckusick #endif 10054903Smckusick } else 10154903Smckusick s_scale = SCALE_1_TO_1; 10252814Smckusick 10354903Smckusick moncontrol(1); 10454903Smckusick size = sizeof(clockinfo); 10554903Smckusick if (getkerninfo(KINFO_CLOCKRATE, &clockinfo, &size, 0) < 0) 10654903Smckusick /* 10754903Smckusick * Best guess 10854903Smckusick */ 10954903Smckusick clockinfo.profhz = hertz(); 11054903Smckusick else if (clockinfo.profhz == 0) { 11154903Smckusick if (clockinfo.hz != 0) 11254903Smckusick clockinfo.profhz = clockinfo.hz; 11354903Smckusick else 11454903Smckusick clockinfo.profhz = hertz(); 11554903Smckusick } 11654903Smckusick hdr = (struct gmonhdr *)&gmonhdr; 11754903Smckusick hdr->lpc = lowpc; 11854903Smckusick hdr->hpc = highpc; 11954903Smckusick hdr->ncnt = ssiz + sizeof(gmonhdr); 12054903Smckusick hdr->version = GMONVERSION; 12154903Smckusick hdr->profrate = clockinfo.profhz; 1224514Speter } 1234514Speter 1244514Speter _mcleanup() 1254514Speter { 12654903Smckusick int fd; 12754903Smckusick int fromindex; 12854903Smckusick int endfrom; 12954903Smckusick u_long frompc; 13054903Smckusick int toindex; 13154903Smckusick struct rawarc rawarc; 13254903Smckusick struct gmonparam *p = &_gmonparam; 1334514Speter 13454903Smckusick if (p->state == GMON_PROF_ERROR) 13554903Smckusick ERR("_mcleanup: tos overflow\n"); 13654903Smckusick 13754903Smckusick moncontrol(0); 13854903Smckusick fd = creat("gmon.out", 0666); 13954903Smckusick if (fd < 0) { 14054903Smckusick perror("mcount: gmon.out"); 14154903Smckusick return; 1424514Speter } 14354903Smckusick #ifdef DEBUG 14454903Smckusick fprintf(stderr, "[mcleanup] sbuf 0x%x ssiz %d\n", sbuf, ssiz); 14554903Smckusick #endif 14654903Smckusick write(fd, (char *)&gmonhdr, sizeof(gmonhdr)); 14754903Smckusick write(fd, sbuf, ssiz); 14854903Smckusick endfrom = p->textsize / (HASHFRACTION * sizeof(*p->froms)); 14954903Smckusick for (fromindex = 0; fromindex < endfrom; fromindex++) { 15054903Smckusick if (p->froms[fromindex] == 0) 15154903Smckusick continue; 15254903Smckusick 15354903Smckusick frompc = p->lowpc; 15454903Smckusick frompc += fromindex * HASHFRACTION * sizeof(*p->froms); 15554903Smckusick for (toindex = p->froms[fromindex]; toindex != 0; 15654903Smckusick toindex = p->tos[toindex].link) { 15754903Smckusick #ifdef DEBUG 15854903Smckusick fprintf(stderr, 1594748Speter "[mcleanup] frompc 0x%x selfpc 0x%x count %d\n" , 16054903Smckusick frompc, p->tos[toindex].selfpc, 16154903Smckusick p->tos[toindex].count); 16254903Smckusick #endif 16354903Smckusick rawarc.raw_frompc = frompc; 16454903Smckusick rawarc.raw_selfpc = p->tos[toindex].selfpc; 16554903Smckusick rawarc.raw_count = p->tos[toindex].count; 16654903Smckusick write(fd, &rawarc, sizeof rawarc); 16754903Smckusick } 1684514Speter } 16954903Smckusick 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) 17854903Smckusick int mode; 17911796Speter { 18054903Smckusick struct gmonparam *p = &_gmonparam; 18154903Smckusick 18254903Smckusick if (mode) { 18354903Smckusick /* start */ 18454903Smckusick profil(sbuf, ssiz, (int)p->lowpc, s_scale); 18554903Smckusick p->state = GMON_PROF_ON; 18654903Smckusick } else { 18754903Smckusick /* stop */ 18854903Smckusick profil((char *)0, 0, 0, 0); 18954903Smckusick p->state = GMON_PROF_OFF; 19054903Smckusick } 19111796Speter } 19252814Smckusick 19354903Smckusick /* 19454903Smckusick * discover the tick frequency of the machine 19554903Smckusick * if something goes wrong, we return 0, an impossible hertz. 19654903Smckusick */ 19752814Smckusick hertz() 19852814Smckusick { 19952814Smckusick struct itimerval tim; 20054903Smckusick 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 } 21154903Smckusick 21254903Smckusick 213