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