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 34 #if !defined(lint) && !defined(_KERNEL) && defined(LIBC_SCCS) 35 #if 0 36 static char sccsid[] = "@(#)mcount.c 8.1 (Berkeley) 6/4/93"; 37 #endif 38 static const char rcsid[] = 39 "$FreeBSD$"; 40 #endif 41 42 #include <sys/param.h> 43 #include <sys/gmon.h> 44 #ifdef _KERNEL 45 #include <sys/systm.h> 46 #include <vm/vm.h> 47 #include <vm/vm_param.h> 48 #include <vm/pmap.h> 49 void bintr __P((void)); 50 void btrap __P((void)); 51 void eintr __P((void)); 52 void user __P((void)); 53 #endif 54 55 /* 56 * mcount is called on entry to each function compiled with the profiling 57 * switch set. _mcount(), which is declared in a machine-dependent way 58 * with _MCOUNT_DECL, does the actual work and is either inlined into a 59 * C routine or called by an assembly stub. In any case, this magic is 60 * taken care of by the MCOUNT definition in <machine/profile.h>. 61 * 62 * _mcount updates data structures that represent traversals of the 63 * program's call graph edges. frompc and selfpc are the return 64 * address and function address that represents the given call graph edge. 65 * 66 * Note: the original BSD code used the same variable (frompcindex) for 67 * both frompcindex and frompc. Any reasonable, modern compiler will 68 * perform this optimization. 69 */ 70 _MCOUNT_DECL(frompc, selfpc) /* _mcount; may be static, inline, etc */ 71 register uintfptr_t frompc, selfpc; 72 { 73 #ifdef GUPROF 74 u_int delta; 75 #endif 76 register fptrdiff_t frompci; 77 register u_short *frompcindex; 78 register struct tostruct *top, *prevtop; 79 register struct gmonparam *p; 80 register long toindex; 81 #ifdef _KERNEL 82 MCOUNT_DECL(s) 83 #endif 84 85 p = &_gmonparam; 86 #ifndef GUPROF /* XXX */ 87 /* 88 * check that we are profiling 89 * and that we aren't recursively invoked. 90 */ 91 if (p->state != GMON_PROF_ON) 92 return; 93 #endif 94 #ifdef _KERNEL 95 MCOUNT_ENTER(s); 96 #else 97 p->state = GMON_PROF_BUSY; 98 #endif 99 frompci = frompc - p->lowpc; 100 101 #ifdef _KERNEL 102 /* 103 * When we are called from an exception handler, frompci may be 104 * for a user address. Convert such frompci's to the index of 105 * user() to merge all user counts. 106 */ 107 if (frompci >= p->textsize) { 108 if (frompci + p->lowpc 109 >= (uintfptr_t)(VM_MAXUSER_ADDRESS + UPAGES * PAGE_SIZE)) 110 goto done; 111 frompci = (uintfptr_t)user - p->lowpc; 112 if (frompci >= p->textsize) 113 goto done; 114 } 115 #endif 116 117 #ifdef GUPROF 118 if (p->state != GMON_PROF_HIRES) 119 goto skip_guprof_stuff; 120 /* 121 * Look at the clock and add the count of clock cycles since the 122 * clock was last looked at to a counter for frompc. This 123 * solidifies the count for the function containing frompc and 124 * effectively starts another clock for the current function. 125 * The count for the new clock will be solidified when another 126 * function call is made or the function returns. 127 * 128 * We use the usual sampling counters since they can be located 129 * efficiently. 4-byte counters are usually necessary. 130 * 131 * There are many complications for subtracting the profiling 132 * overheads from the counts for normal functions and adding 133 * them to the counts for mcount(), mexitcount() and cputime(). 134 * We attempt to handle fractional cycles, but the overheads 135 * are usually underestimated because they are calibrated for 136 * a simpler than usual setup. 137 */ 138 delta = cputime() - p->mcount_overhead; 139 p->cputime_overhead_resid += p->cputime_overhead_frac; 140 p->mcount_overhead_resid += p->mcount_overhead_frac; 141 if ((int)delta < 0) 142 *p->mcount_count += delta + p->mcount_overhead 143 - p->cputime_overhead; 144 else if (delta != 0) { 145 if (p->cputime_overhead_resid >= CALIB_SCALE) { 146 p->cputime_overhead_resid -= CALIB_SCALE; 147 ++*p->cputime_count; 148 --delta; 149 } 150 if (delta != 0) { 151 if (p->mcount_overhead_resid >= CALIB_SCALE) { 152 p->mcount_overhead_resid -= CALIB_SCALE; 153 ++*p->mcount_count; 154 --delta; 155 } 156 KCOUNT(p, frompci) += delta; 157 } 158 *p->mcount_count += p->mcount_overhead_sub; 159 } 160 *p->cputime_count += p->cputime_overhead; 161 skip_guprof_stuff: 162 #endif /* GUPROF */ 163 164 #ifdef _KERNEL 165 /* 166 * When we are called from an exception handler, frompc is faked 167 * to be for where the exception occurred. We've just solidified 168 * the count for there. Now convert frompci to the index of btrap() 169 * for trap handlers and bintr() for interrupt handlers to make 170 * exceptions appear in the call graph as calls from btrap() and 171 * bintr() instead of calls from all over. 172 */ 173 if ((uintfptr_t)selfpc >= (uintfptr_t)btrap 174 && (uintfptr_t)selfpc < (uintfptr_t)eintr) { 175 if ((uintfptr_t)selfpc >= (uintfptr_t)bintr) 176 frompci = (uintfptr_t)bintr - p->lowpc; 177 else 178 frompci = (uintfptr_t)btrap - p->lowpc; 179 } 180 #endif 181 182 /* 183 * check that frompc is a reasonable pc value. 184 * for example: signal catchers get called from the stack, 185 * not from text space. too bad. 186 */ 187 if (frompci >= p->textsize) 188 goto done; 189 190 frompcindex = &p->froms[frompci / (p->hashfraction * sizeof(*p->froms))]; 191 toindex = *frompcindex; 192 if (toindex == 0) { 193 /* 194 * first time traversing this arc 195 */ 196 toindex = ++p->tos[0].link; 197 if (toindex >= p->tolimit) 198 /* halt further profiling */ 199 goto overflow; 200 201 *frompcindex = toindex; 202 top = &p->tos[toindex]; 203 top->selfpc = selfpc; 204 top->count = 1; 205 top->link = 0; 206 goto done; 207 } 208 top = &p->tos[toindex]; 209 if (top->selfpc == selfpc) { 210 /* 211 * arc at front of chain; usual case. 212 */ 213 top->count++; 214 goto done; 215 } 216 /* 217 * have to go looking down chain for it. 218 * top points to what we are looking at, 219 * prevtop points to previous top. 220 * we know it is not at the head of the chain. 221 */ 222 for (; /* goto done */; ) { 223 if (top->link == 0) { 224 /* 225 * top is end of the chain and none of the chain 226 * had top->selfpc == selfpc. 227 * so we allocate a new tostruct 228 * and link it to the head of the chain. 229 */ 230 toindex = ++p->tos[0].link; 231 if (toindex >= p->tolimit) 232 goto overflow; 233 234 top = &p->tos[toindex]; 235 top->selfpc = selfpc; 236 top->count = 1; 237 top->link = *frompcindex; 238 *frompcindex = toindex; 239 goto done; 240 } 241 /* 242 * otherwise, check the next arc on the chain. 243 */ 244 prevtop = top; 245 top = &p->tos[top->link]; 246 if (top->selfpc == selfpc) { 247 /* 248 * there it is. 249 * increment its count 250 * move it to the head of the chain. 251 */ 252 top->count++; 253 toindex = prevtop->link; 254 prevtop->link = top->link; 255 top->link = *frompcindex; 256 *frompcindex = toindex; 257 goto done; 258 } 259 260 } 261 done: 262 #ifdef _KERNEL 263 MCOUNT_EXIT(s); 264 #else 265 p->state = GMON_PROF_ON; 266 #endif 267 return; 268 overflow: 269 p->state = GMON_PROF_ERROR; 270 #ifdef _KERNEL 271 MCOUNT_EXIT(s); 272 #endif 273 return; 274 } 275 276 /* 277 * Actual definition of mcount function. Defined in <machine/profile.h>, 278 * which is included by <sys/gmon.h>. 279 */ 280 MCOUNT 281 282 #ifdef GUPROF 283 void 284 mexitcount(selfpc) 285 uintfptr_t selfpc; 286 { 287 struct gmonparam *p; 288 uintfptr_t selfpcdiff; 289 290 p = &_gmonparam; 291 selfpcdiff = selfpc - (uintfptr_t)p->lowpc; 292 if (selfpcdiff < p->textsize) { 293 u_int delta; 294 295 /* 296 * Solidify the count for the current function. 297 */ 298 delta = cputime() - p->mexitcount_overhead; 299 p->cputime_overhead_resid += p->cputime_overhead_frac; 300 p->mexitcount_overhead_resid += p->mexitcount_overhead_frac; 301 if ((int)delta < 0) 302 *p->mexitcount_count += delta + p->mexitcount_overhead 303 - p->cputime_overhead; 304 else if (delta != 0) { 305 if (p->cputime_overhead_resid >= CALIB_SCALE) { 306 p->cputime_overhead_resid -= CALIB_SCALE; 307 ++*p->cputime_count; 308 --delta; 309 } 310 if (delta != 0) { 311 if (p->mexitcount_overhead_resid 312 >= CALIB_SCALE) { 313 p->mexitcount_overhead_resid 314 -= CALIB_SCALE; 315 ++*p->mexitcount_count; 316 --delta; 317 } 318 KCOUNT(p, selfpcdiff) += delta; 319 } 320 *p->mexitcount_count += p->mexitcount_overhead_sub; 321 } 322 *p->cputime_count += p->cputime_overhead; 323 } 324 } 325 #endif /* GUPROF */ 326