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