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(_KERNEL) && defined(LIBC_SCCS) && !defined(lint) 35 static char sccsid[] = "@(#)mcount.c 8.1 (Berkeley) 6/4/93"; 36 #endif 37 #include <sys/cdefs.h> 38 __FBSDID("$FreeBSD$"); 39 40 #include <sys/param.h> 41 #include <sys/gmon.h> 42 #ifdef _KERNEL 43 #include <sys/systm.h> 44 #include <vm/vm.h> 45 #include <vm/vm_param.h> 46 #include <vm/pmap.h> 47 void bintr(void); 48 void btrap(void); 49 void eintr(void); 50 void user(void); 51 #endif 52 #include <machine/atomic.h> 53 54 /* 55 * mcount is called on entry to each function compiled with the profiling 56 * switch set. _mcount(), which is declared in a machine-dependent way 57 * with _MCOUNT_DECL, does the actual work and is either inlined into a 58 * C routine or called by an assembly stub. In any case, this magic is 59 * taken care of by the MCOUNT definition in <machine/profile.h>. 60 * 61 * _mcount updates data structures that represent traversals of the 62 * program's call graph edges. frompc and selfpc are the return 63 * address and function address that represents the given call graph edge. 64 * 65 * Note: the original BSD code used the same variable (frompcindex) for 66 * both frompcindex and frompc. Any reasonable, modern compiler will 67 * perform this optimization. 68 */ 69 /* _mcount; may be static, inline, etc */ 70 _MCOUNT_DECL(uintfptr_t frompc, uintfptr_t selfpc) 71 { 72 #ifdef GUPROF 73 u_int delta; 74 #endif 75 fptrdiff_t frompci; 76 u_short *frompcindex; 77 struct tostruct *top, *prevtop; 78 struct gmonparam *p; 79 long toindex; 80 #ifdef _KERNEL 81 MCOUNT_DECL(s) 82 #endif 83 84 p = &_gmonparam; 85 #ifndef GUPROF /* XXX */ 86 /* 87 * check that we are profiling 88 * and that we aren't recursively invoked. 89 */ 90 if (p->state != GMON_PROF_ON) 91 return; 92 #endif 93 #ifdef _KERNEL 94 MCOUNT_ENTER(s); 95 #else 96 if (!atomic_cmpset_acq_int(&p->state, GMON_PROF_ON, GMON_PROF_BUSY)) 97 return; 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 atomic_store_rel_int(&p->state, GMON_PROF_ON); 266 #endif 267 return; 268 overflow: 269 atomic_store_rel_int(&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