1 /*- 2 * Copyright (c) 1983, 1992, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. All advertising materials mentioning features or use of this software 14 * must display the following acknowledgement: 15 * This product includes software developed by the University of 16 * California, Berkeley and its contributors. 17 * 4. Neither the name of the University nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 * 33 * $FreeBSD: src/lib/libc/gmon/gmon.c,v 1.8 2000/01/27 23:06:25 jasone Exp $ 34 * $DragonFly: src/lib/libc/gmon/gmon.c,v 1.6 2005/01/31 22:29:17 dillon Exp $ 35 * 36 * @(#)gmon.c 8.1 (Berkeley) 6/4/93 37 */ 38 39 #include "namespace.h" 40 #include <sys/param.h> 41 #include <sys/time.h> 42 #include <sys/gmon.h> 43 #include <sys/sysctl.h> 44 45 #include <err.h> 46 #include <errno.h> 47 #include <stdio.h> 48 #include <fcntl.h> 49 #include <string.h> 50 #include <unistd.h> 51 #include "un-namespace.h" 52 53 #if defined(__i386__) || defined(__amd64__) 54 extern char *minbrk asm (".minbrk"); 55 #else 56 extern char *minbrk asm ("minbrk"); 57 #endif 58 59 extern char *__progname; 60 61 struct gmonparam _gmonparam = { GMON_PROF_OFF }; 62 63 static int s_scale; 64 /* see profil(2) where this is describe (incorrectly) */ 65 #define SCALE_1_TO_1 0x10000L 66 67 #define ERR(s) _write(2, s, sizeof(s)) 68 69 void moncontrol (int); 70 static int hertz (void); 71 72 void 73 monstartup(lowpc, highpc) 74 u_long lowpc; 75 u_long highpc; 76 { 77 int o; 78 char *cp; 79 struct gmonparam *p = &_gmonparam; 80 81 /* 82 * round lowpc and highpc to multiples of the density we're using 83 * so the rest of the scaling (here and in gprof) stays in ints. 84 */ 85 p->lowpc = ROUNDDOWN(lowpc, HISTFRACTION * sizeof(HISTCOUNTER)); 86 p->highpc = ROUNDUP(highpc, HISTFRACTION * sizeof(HISTCOUNTER)); 87 p->textsize = p->highpc - p->lowpc; 88 p->kcountsize = p->textsize / HISTFRACTION; 89 p->hashfraction = HASHFRACTION; 90 p->fromssize = p->textsize / HASHFRACTION; 91 p->tolimit = p->textsize * ARCDENSITY / 100; 92 if (p->tolimit < MINARCS) 93 p->tolimit = MINARCS; 94 else if (p->tolimit > MAXARCS) 95 p->tolimit = MAXARCS; 96 p->tossize = p->tolimit * sizeof(struct tostruct); 97 98 cp = sbrk(p->kcountsize + p->fromssize + p->tossize); 99 if (cp == (char *)-1) { 100 ERR("monstartup: out of memory\n"); 101 return; 102 } 103 #ifdef notdef 104 bzero(cp, p->kcountsize + p->fromssize + p->tossize); 105 #endif 106 p->tos = (struct tostruct *)cp; 107 cp += p->tossize; 108 p->kcount = (u_short *)cp; 109 cp += p->kcountsize; 110 p->froms = (u_short *)cp; 111 112 minbrk = sbrk(0); 113 p->tos[0].link = 0; 114 115 o = p->highpc - p->lowpc; 116 if (p->kcountsize < o) { 117 #ifndef hp300 118 s_scale = ((float)p->kcountsize / o ) * SCALE_1_TO_1; 119 #else /* avoid floating point */ 120 int quot = o / p->kcountsize; 121 122 if (quot >= 0x10000) 123 s_scale = 1; 124 else if (quot >= 0x100) 125 s_scale = 0x10000 / quot; 126 else if (o >= 0x800000) 127 s_scale = 0x1000000 / (o / (p->kcountsize >> 8)); 128 else 129 s_scale = 0x1000000 / ((o << 8) / p->kcountsize); 130 #endif 131 } else 132 s_scale = SCALE_1_TO_1; 133 134 moncontrol(1); 135 } 136 137 void 138 _mcleanup() 139 { 140 int fd; 141 int fromindex; 142 int endfrom; 143 u_long frompc; 144 int toindex; 145 struct rawarc rawarc; 146 struct gmonparam *p = &_gmonparam; 147 struct gmonhdr gmonhdr, *hdr; 148 struct clockinfo clockinfo; 149 char outname[128]; 150 int mib[2]; 151 size_t size; 152 #ifdef DEBUG 153 int log, len; 154 char buf[200]; 155 #endif 156 157 if (p->state == GMON_PROF_ERROR) 158 ERR("_mcleanup: tos overflow\n"); 159 160 size = sizeof(clockinfo); 161 mib[0] = CTL_KERN; 162 mib[1] = KERN_CLOCKRATE; 163 if (sysctl(mib, 2, &clockinfo, &size, NULL, 0) < 0) { 164 /* 165 * Best guess 166 */ 167 clockinfo.profhz = hertz(); 168 } else if (clockinfo.profhz == 0) { 169 if (clockinfo.hz != 0) 170 clockinfo.profhz = clockinfo.hz; 171 else 172 clockinfo.profhz = hertz(); 173 } 174 175 moncontrol(0); 176 snprintf(outname,sizeof(outname),"%s.gmon",__progname); 177 fd = _open(outname, O_CREAT|O_TRUNC|O_WRONLY, 0666); 178 if (fd < 0) { 179 warnx("_mcleanup: %s - %s",outname,strerror(errno)); 180 return; 181 } 182 #ifdef DEBUG 183 log = _open("gmon.log", O_CREAT|O_TRUNC|O_WRONLY, 0664); 184 if (log < 0) { 185 perror("_mcleanup: gmon.log"); 186 return; 187 } 188 len = sprintf(buf, "[mcleanup1] kcount 0x%x ssiz %d\n", 189 p->kcount, p->kcountsize); 190 _write(log, buf, len); 191 #endif 192 hdr = (struct gmonhdr *)&gmonhdr; 193 hdr->lpc = p->lowpc; 194 hdr->hpc = p->highpc; 195 hdr->ncnt = p->kcountsize + sizeof(gmonhdr); 196 hdr->version = GMONVERSION; 197 hdr->profrate = clockinfo.profhz; 198 _write(fd, (char *)hdr, sizeof *hdr); 199 _write(fd, p->kcount, p->kcountsize); 200 endfrom = p->fromssize / sizeof(*p->froms); 201 for (fromindex = 0; fromindex < endfrom; fromindex++) { 202 if (p->froms[fromindex] == 0) 203 continue; 204 205 frompc = p->lowpc; 206 frompc += fromindex * p->hashfraction * sizeof(*p->froms); 207 for (toindex = p->froms[fromindex]; toindex != 0; 208 toindex = p->tos[toindex].link) { 209 #ifdef DEBUG 210 len = sprintf(buf, 211 "[mcleanup2] frompc 0x%x selfpc 0x%x count %d\n" , 212 frompc, p->tos[toindex].selfpc, 213 p->tos[toindex].count); 214 _write(log, buf, len); 215 #endif 216 rawarc.raw_frompc = frompc; 217 rawarc.raw_selfpc = p->tos[toindex].selfpc; 218 rawarc.raw_count = p->tos[toindex].count; 219 _write(fd, &rawarc, sizeof rawarc); 220 } 221 } 222 _close(fd); 223 } 224 225 /* 226 * Control profiling 227 * profiling is what mcount checks to see if 228 * all the data structures are ready. 229 */ 230 void 231 moncontrol(mode) 232 int mode; 233 { 234 struct gmonparam *p = &_gmonparam; 235 236 if (mode) { 237 /* start */ 238 profil((char *)p->kcount, p->kcountsize, p->lowpc, s_scale); 239 p->state = GMON_PROF_ON; 240 } else { 241 /* stop */ 242 profil((char *)0, 0, 0, 0); 243 p->state = GMON_PROF_OFF; 244 } 245 } 246 247 /* 248 * discover the tick frequency of the machine 249 * if something goes wrong, we return 0, an impossible hertz. 250 */ 251 static int 252 hertz() 253 { 254 struct itimerval tim; 255 256 tim.it_interval.tv_sec = 0; 257 tim.it_interval.tv_usec = 1; 258 tim.it_value.tv_sec = 0; 259 tim.it_value.tv_usec = 0; 260 setitimer(ITIMER_REAL, &tim, 0); 261 setitimer(ITIMER_REAL, 0, &tim); 262 if (tim.it_interval.tv_usec < 2) 263 return(0); 264 return (1000000 / tim.it_interval.tv_usec); 265 } 266