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