1 /*- 2 * Copyright (c) 1983, 1992 The Regents of the University of California. 3 * All rights reserved. 4 * 5 * %sccs.include.redist.c% 6 */ 7 8 #if !defined(lint) && defined(LIBC_SCCS) 9 static char sccsid[] = "@(#)gmon.c 5.11 (Berkeley) 07/10/92"; 10 #endif 11 12 #include <unistd.h> 13 #include <sys/types.h> 14 #include <sys/time.h> 15 #include <sys/kinfo.h> 16 17 #ifdef DEBUG 18 #include <stdio.h> 19 #endif 20 21 #include <sys/gmon.h> 22 23 extern char *minbrk asm ("minbrk"); 24 25 struct gmonparam _gmonparam = { GMON_PROF_OFF }; 26 27 static int ssiz; 28 static char *sbuf; 29 static int s_scale; 30 /* see profil(2) where this is describe (incorrectly) */ 31 #define SCALE_1_TO_1 0x10000L 32 33 #define ERR(s) write(2, s, sizeof(s)) 34 35 static struct gmonhdr gmonhdr; 36 37 monstartup(lowpc, highpc) 38 u_long lowpc; 39 u_long highpc; 40 { 41 register int o; 42 struct clockinfo clockinfo; 43 int tsize, fsize, size; 44 char *cp; 45 struct gmonhdr *hdr; 46 struct gmonparam *p = &_gmonparam; 47 48 /* 49 * round lowpc and highpc to multiples of the density we're using 50 * so the rest of the scaling (here and in gprof) stays in ints. 51 */ 52 lowpc = ROUNDDOWN(lowpc, HISTFRACTION * sizeof(HISTCOUNTER)); 53 p->lowpc = lowpc; 54 highpc = ROUNDUP(highpc, HISTFRACTION * sizeof(HISTCOUNTER)); 55 p->highpc = highpc; 56 p->textsize = highpc - lowpc; 57 ssiz = p->textsize / HISTFRACTION; 58 fsize = p->textsize / HASHFRACTION; 59 tsize = p->textsize * ARCDENSITY / 100; 60 if (tsize < MINARCS) 61 tsize = MINARCS; 62 else if (tsize > MAXARCS) 63 tsize = MAXARCS; 64 p->tolimit = tsize; 65 tsize *= sizeof(struct tostruct); 66 67 cp = sbrk(ssiz + fsize + tsize); 68 if (cp == (char *)-1) { 69 ERR("monstartup: out of memory\n"); 70 return; 71 } 72 #ifdef notdef 73 bzero(cp, ssiz + fsize + tsize); 74 #endif 75 p->tos = (struct tostruct *)cp; 76 cp += tsize; 77 sbuf = cp; 78 cp += ssiz; 79 p->froms = (u_short *)cp; 80 81 minbrk = sbrk(0); 82 p->tos[0].link = 0; 83 84 o = highpc - lowpc; 85 if (ssiz < o) { 86 #ifndef hp300 87 s_scale = ((float)ssiz / o ) * SCALE_1_TO_1; 88 #else /* avoid floating point */ 89 int quot = o / ssiz; 90 91 if (quot >= 0x10000) 92 s_scale = 1; 93 else if (quot >= 0x100) 94 s_scale = 0x10000 / quot; 95 else if (o >= 0x800000) 96 s_scale = 0x1000000 / (o / (ssiz >> 8)); 97 else 98 s_scale = 0x1000000 / ((o << 8) / ssiz); 99 #endif 100 } else 101 s_scale = SCALE_1_TO_1; 102 103 moncontrol(1); 104 size = sizeof(clockinfo); 105 if (getkerninfo(KINFO_CLOCKRATE, &clockinfo, &size, 0) < 0) 106 /* 107 * Best guess 108 */ 109 clockinfo.profhz = hertz(); 110 else if (clockinfo.profhz == 0) { 111 if (clockinfo.hz != 0) 112 clockinfo.profhz = clockinfo.hz; 113 else 114 clockinfo.profhz = hertz(); 115 } 116 hdr = (struct gmonhdr *)&gmonhdr; 117 hdr->lpc = lowpc; 118 hdr->hpc = highpc; 119 hdr->ncnt = ssiz + sizeof(gmonhdr); 120 hdr->version = GMONVERSION; 121 hdr->profrate = clockinfo.profhz; 122 } 123 124 _mcleanup() 125 { 126 int fd; 127 int fromindex; 128 int endfrom; 129 u_long frompc; 130 int toindex; 131 struct rawarc rawarc; 132 struct gmonparam *p = &_gmonparam; 133 134 if (p->state == GMON_PROF_ERROR) 135 ERR("_mcleanup: tos overflow\n"); 136 137 moncontrol(0); 138 fd = creat("gmon.out", 0666); 139 if (fd < 0) { 140 perror("mcount: gmon.out"); 141 return; 142 } 143 #ifdef DEBUG 144 fprintf(stderr, "[mcleanup] sbuf 0x%x ssiz %d\n", sbuf, ssiz); 145 #endif 146 write(fd, (char *)&gmonhdr, sizeof(gmonhdr)); 147 write(fd, sbuf, ssiz); 148 endfrom = p->textsize / (HASHFRACTION * sizeof(*p->froms)); 149 for (fromindex = 0; fromindex < endfrom; fromindex++) { 150 if (p->froms[fromindex] == 0) 151 continue; 152 153 frompc = p->lowpc; 154 frompc += fromindex * HASHFRACTION * sizeof(*p->froms); 155 for (toindex = p->froms[fromindex]; toindex != 0; 156 toindex = p->tos[toindex].link) { 157 #ifdef DEBUG 158 fprintf(stderr, 159 "[mcleanup] frompc 0x%x selfpc 0x%x count %d\n" , 160 frompc, p->tos[toindex].selfpc, 161 p->tos[toindex].count); 162 #endif 163 rawarc.raw_frompc = frompc; 164 rawarc.raw_selfpc = p->tos[toindex].selfpc; 165 rawarc.raw_count = p->tos[toindex].count; 166 write(fd, &rawarc, sizeof rawarc); 167 } 168 } 169 close(fd); 170 } 171 172 /* 173 * Control profiling 174 * profiling is what mcount checks to see if 175 * all the data structures are ready. 176 */ 177 moncontrol(mode) 178 int mode; 179 { 180 struct gmonparam *p = &_gmonparam; 181 182 if (mode) { 183 /* start */ 184 profil(sbuf, ssiz, (int)p->lowpc, s_scale); 185 p->state = GMON_PROF_ON; 186 } else { 187 /* stop */ 188 profil((char *)0, 0, 0, 0); 189 p->state = GMON_PROF_OFF; 190 } 191 } 192 193 /* 194 * discover the tick frequency of the machine 195 * if something goes wrong, we return 0, an impossible hertz. 196 */ 197 hertz() 198 { 199 struct itimerval tim; 200 201 tim.it_interval.tv_sec = 0; 202 tim.it_interval.tv_usec = 1; 203 tim.it_value.tv_sec = 0; 204 tim.it_value.tv_usec = 0; 205 setitimer(ITIMER_REAL, &tim, 0); 206 setitimer(ITIMER_REAL, 0, &tim); 207 if (tim.it_interval.tv_usec < 2) 208 return(0); 209 return (1000000 / tim.it_interval.tv_usec); 210 } 211 212 213