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