mcount.c revision 136582
11573Srgrimes/*- 21573Srgrimes * Copyright (c) 1983, 1992, 1993 31573Srgrimes * The Regents of the University of California. All rights reserved. 41573Srgrimes * 51573Srgrimes * Redistribution and use in source and binary forms, with or without 61573Srgrimes * modification, are permitted provided that the following conditions 71573Srgrimes * are met: 81573Srgrimes * 1. Redistributions of source code must retain the above copyright 91573Srgrimes * notice, this list of conditions and the following disclaimer. 101573Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 111573Srgrimes * notice, this list of conditions and the following disclaimer in the 121573Srgrimes * documentation and/or other materials provided with the distribution. 131573Srgrimes * 3. All advertising materials mentioning features or use of this software 141573Srgrimes * must display the following acknowledgement: 151573Srgrimes * This product includes software developed by the University of 161573Srgrimes * California, Berkeley and its contributors. 171573Srgrimes * 4. Neither the name of the University nor the names of its contributors 181573Srgrimes * may be used to endorse or promote products derived from this software 191573Srgrimes * without specific prior written permission. 201573Srgrimes * 211573Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 221573Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 231573Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 241573Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 251573Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 261573Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 271573Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 281573Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 291573Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 301573Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 311573Srgrimes * SUCH DAMAGE. 321573Srgrimes */ 331573Srgrimes 34136582Sobrien#if !defined(_KERNEL) && defined(LIBC_SCCS) && !defined(lint) 351573Srgrimesstatic char sccsid[] = "@(#)mcount.c 8.1 (Berkeley) 6/4/93"; 361573Srgrimes#endif 3790046Sobrien#include <sys/cdefs.h> 3890046Sobrien__FBSDID("$FreeBSD: head/lib/libc/gmon/mcount.c 136582 2004-10-16 06:32:43Z obrien $"); 391573Srgrimes 401573Srgrimes#include <sys/param.h> 411573Srgrimes#include <sys/gmon.h> 4255206Speter#ifdef _KERNEL 4313107Sbde#include <sys/systm.h> 4413107Sbde#include <vm/vm.h> 4513107Sbde#include <vm/vm_param.h> 4613107Sbde#include <vm/pmap.h> 4790046Sobrienvoid bintr(void); 4890046Sobrienvoid btrap(void); 4990046Sobrienvoid eintr(void); 5090046Sobrienvoid user(void); 512800Spaul#endif 521573Srgrimes 531573Srgrimes/* 541573Srgrimes * mcount is called on entry to each function compiled with the profiling 551573Srgrimes * switch set. _mcount(), which is declared in a machine-dependent way 561573Srgrimes * with _MCOUNT_DECL, does the actual work and is either inlined into a 571573Srgrimes * C routine or called by an assembly stub. In any case, this magic is 581573Srgrimes * taken care of by the MCOUNT definition in <machine/profile.h>. 591573Srgrimes * 601573Srgrimes * _mcount updates data structures that represent traversals of the 611573Srgrimes * program's call graph edges. frompc and selfpc are the return 621573Srgrimes * address and function address that represents the given call graph edge. 638870Srgrimes * 641573Srgrimes * Note: the original BSD code used the same variable (frompcindex) for 651573Srgrimes * both frompcindex and frompc. Any reasonable, modern compiler will 661573Srgrimes * perform this optimization. 671573Srgrimes */ 68124180Snectar/* _mcount; may be static, inline, etc */ 69124180Snectar_MCOUNT_DECL(uintfptr_t frompc, uintfptr_t selfpc) 701573Srgrimes{ 7113107Sbde#ifdef GUPROF 7213107Sbde u_int delta; 7313107Sbde#endif 7490046Sobrien fptrdiff_t frompci; 7590046Sobrien u_short *frompcindex; 7690046Sobrien struct tostruct *top, *prevtop; 7790046Sobrien struct gmonparam *p; 7890046Sobrien long toindex; 7955206Speter#ifdef _KERNEL 8017879Sbde MCOUNT_DECL(s) 811573Srgrimes#endif 821573Srgrimes 831573Srgrimes p = &_gmonparam; 8413107Sbde#ifndef GUPROF /* XXX */ 851573Srgrimes /* 861573Srgrimes * check that we are profiling 871573Srgrimes * and that we aren't recursively invoked. 881573Srgrimes */ 891573Srgrimes if (p->state != GMON_PROF_ON) 901573Srgrimes return; 9113107Sbde#endif 9255206Speter#ifdef _KERNEL 9317879Sbde MCOUNT_ENTER(s); 941573Srgrimes#else 951573Srgrimes p->state = GMON_PROF_BUSY; 961573Srgrimes#endif 9713107Sbde frompci = frompc - p->lowpc; 9813107Sbde 9955206Speter#ifdef _KERNEL 1001573Srgrimes /* 10113107Sbde * When we are called from an exception handler, frompci may be 10213107Sbde * for a user address. Convert such frompci's to the index of 10313107Sbde * user() to merge all user counts. 10413107Sbde */ 10513107Sbde if (frompci >= p->textsize) { 10613107Sbde if (frompci + p->lowpc 10737629Sbde >= (uintfptr_t)(VM_MAXUSER_ADDRESS + UPAGES * PAGE_SIZE)) 10813107Sbde goto done; 10937629Sbde frompci = (uintfptr_t)user - p->lowpc; 11013107Sbde if (frompci >= p->textsize) 11113107Sbde goto done; 11213107Sbde } 11355206Speter#endif 11413107Sbde 11513107Sbde#ifdef GUPROF 11613107Sbde if (p->state != GMON_PROF_HIRES) 11713107Sbde goto skip_guprof_stuff; 11813107Sbde /* 11913107Sbde * Look at the clock and add the count of clock cycles since the 12013107Sbde * clock was last looked at to a counter for frompc. This 12113107Sbde * solidifies the count for the function containing frompc and 12213107Sbde * effectively starts another clock for the current function. 12313107Sbde * The count for the new clock will be solidified when another 12413107Sbde * function call is made or the function returns. 12513107Sbde * 12613107Sbde * We use the usual sampling counters since they can be located 12713107Sbde * efficiently. 4-byte counters are usually necessary. 12813107Sbde * 12913107Sbde * There are many complications for subtracting the profiling 13013107Sbde * overheads from the counts for normal functions and adding 13113107Sbde * them to the counts for mcount(), mexitcount() and cputime(). 13213107Sbde * We attempt to handle fractional cycles, but the overheads 13313107Sbde * are usually underestimated because they are calibrated for 13413107Sbde * a simpler than usual setup. 13513107Sbde */ 13613107Sbde delta = cputime() - p->mcount_overhead; 13713107Sbde p->cputime_overhead_resid += p->cputime_overhead_frac; 13813107Sbde p->mcount_overhead_resid += p->mcount_overhead_frac; 13913107Sbde if ((int)delta < 0) 14013107Sbde *p->mcount_count += delta + p->mcount_overhead 14113107Sbde - p->cputime_overhead; 14213107Sbde else if (delta != 0) { 14313107Sbde if (p->cputime_overhead_resid >= CALIB_SCALE) { 14413107Sbde p->cputime_overhead_resid -= CALIB_SCALE; 14513107Sbde ++*p->cputime_count; 14613107Sbde --delta; 14713107Sbde } 14813107Sbde if (delta != 0) { 14913107Sbde if (p->mcount_overhead_resid >= CALIB_SCALE) { 15013107Sbde p->mcount_overhead_resid -= CALIB_SCALE; 15113107Sbde ++*p->mcount_count; 15213107Sbde --delta; 15313107Sbde } 15413107Sbde KCOUNT(p, frompci) += delta; 15513107Sbde } 15613107Sbde *p->mcount_count += p->mcount_overhead_sub; 15713107Sbde } 15813107Sbde *p->cputime_count += p->cputime_overhead; 15913107Sbdeskip_guprof_stuff: 16013107Sbde#endif /* GUPROF */ 16113107Sbde 16255206Speter#ifdef _KERNEL 16313107Sbde /* 16413107Sbde * When we are called from an exception handler, frompc is faked 16513107Sbde * to be for where the exception occurred. We've just solidified 16613107Sbde * the count for there. Now convert frompci to the index of btrap() 16713107Sbde * for trap handlers and bintr() for interrupt handlers to make 16813107Sbde * exceptions appear in the call graph as calls from btrap() and 16913107Sbde * bintr() instead of calls from all over. 17013107Sbde */ 17137629Sbde if ((uintfptr_t)selfpc >= (uintfptr_t)btrap 17237629Sbde && (uintfptr_t)selfpc < (uintfptr_t)eintr) { 17337629Sbde if ((uintfptr_t)selfpc >= (uintfptr_t)bintr) 17437629Sbde frompci = (uintfptr_t)bintr - p->lowpc; 17513107Sbde else 17637629Sbde frompci = (uintfptr_t)btrap - p->lowpc; 17713107Sbde } 17855206Speter#endif 17913107Sbde 18013107Sbde /* 18113107Sbde * check that frompc is a reasonable pc value. 1821573Srgrimes * for example: signal catchers get called from the stack, 1831573Srgrimes * not from text space. too bad. 1841573Srgrimes */ 18513107Sbde if (frompci >= p->textsize) 1861573Srgrimes goto done; 1871573Srgrimes 18813107Sbde frompcindex = &p->froms[frompci / (p->hashfraction * sizeof(*p->froms))]; 1891573Srgrimes toindex = *frompcindex; 1901573Srgrimes if (toindex == 0) { 1911573Srgrimes /* 1921573Srgrimes * first time traversing this arc 1931573Srgrimes */ 1941573Srgrimes toindex = ++p->tos[0].link; 1951573Srgrimes if (toindex >= p->tolimit) 1961573Srgrimes /* halt further profiling */ 1971573Srgrimes goto overflow; 1981573Srgrimes 1991573Srgrimes *frompcindex = toindex; 2001573Srgrimes top = &p->tos[toindex]; 2011573Srgrimes top->selfpc = selfpc; 2021573Srgrimes top->count = 1; 2031573Srgrimes top->link = 0; 2041573Srgrimes goto done; 2051573Srgrimes } 2061573Srgrimes top = &p->tos[toindex]; 2071573Srgrimes if (top->selfpc == selfpc) { 2081573Srgrimes /* 2091573Srgrimes * arc at front of chain; usual case. 2101573Srgrimes */ 2111573Srgrimes top->count++; 2121573Srgrimes goto done; 2131573Srgrimes } 2141573Srgrimes /* 2151573Srgrimes * have to go looking down chain for it. 2161573Srgrimes * top points to what we are looking at, 2171573Srgrimes * prevtop points to previous top. 2181573Srgrimes * we know it is not at the head of the chain. 2191573Srgrimes */ 2201573Srgrimes for (; /* goto done */; ) { 2211573Srgrimes if (top->link == 0) { 2221573Srgrimes /* 2231573Srgrimes * top is end of the chain and none of the chain 2241573Srgrimes * had top->selfpc == selfpc. 2251573Srgrimes * so we allocate a new tostruct 2261573Srgrimes * and link it to the head of the chain. 2271573Srgrimes */ 2281573Srgrimes toindex = ++p->tos[0].link; 2291573Srgrimes if (toindex >= p->tolimit) 2301573Srgrimes goto overflow; 2311573Srgrimes 2321573Srgrimes top = &p->tos[toindex]; 2331573Srgrimes top->selfpc = selfpc; 2341573Srgrimes top->count = 1; 2351573Srgrimes top->link = *frompcindex; 2361573Srgrimes *frompcindex = toindex; 2371573Srgrimes goto done; 2381573Srgrimes } 2391573Srgrimes /* 2401573Srgrimes * otherwise, check the next arc on the chain. 2411573Srgrimes */ 2421573Srgrimes prevtop = top; 2431573Srgrimes top = &p->tos[top->link]; 2441573Srgrimes if (top->selfpc == selfpc) { 2451573Srgrimes /* 2461573Srgrimes * there it is. 2471573Srgrimes * increment its count 2481573Srgrimes * move it to the head of the chain. 2491573Srgrimes */ 2501573Srgrimes top->count++; 2511573Srgrimes toindex = prevtop->link; 2521573Srgrimes prevtop->link = top->link; 2531573Srgrimes top->link = *frompcindex; 2541573Srgrimes *frompcindex = toindex; 2551573Srgrimes goto done; 2561573Srgrimes } 2578870Srgrimes 2581573Srgrimes } 2591573Srgrimesdone: 26055206Speter#ifdef _KERNEL 26117879Sbde MCOUNT_EXIT(s); 2621573Srgrimes#else 2631573Srgrimes p->state = GMON_PROF_ON; 2641573Srgrimes#endif 2651573Srgrimes return; 2661573Srgrimesoverflow: 2671573Srgrimes p->state = GMON_PROF_ERROR; 26855206Speter#ifdef _KERNEL 26917879Sbde MCOUNT_EXIT(s); 2701573Srgrimes#endif 2711573Srgrimes return; 2721573Srgrimes} 2731573Srgrimes 2741573Srgrimes/* 2751573Srgrimes * Actual definition of mcount function. Defined in <machine/profile.h>, 2761573Srgrimes * which is included by <sys/gmon.h>. 2771573Srgrimes */ 2781573SrgrimesMCOUNT 27913107Sbde 28013107Sbde#ifdef GUPROF 28113107Sbdevoid 28213107Sbdemexitcount(selfpc) 28337629Sbde uintfptr_t selfpc; 28413107Sbde{ 28513107Sbde struct gmonparam *p; 28637629Sbde uintfptr_t selfpcdiff; 28713107Sbde 28813107Sbde p = &_gmonparam; 28937629Sbde selfpcdiff = selfpc - (uintfptr_t)p->lowpc; 29013107Sbde if (selfpcdiff < p->textsize) { 29113107Sbde u_int delta; 29213107Sbde 29313107Sbde /* 29413107Sbde * Solidify the count for the current function. 29513107Sbde */ 29613107Sbde delta = cputime() - p->mexitcount_overhead; 29713107Sbde p->cputime_overhead_resid += p->cputime_overhead_frac; 29813107Sbde p->mexitcount_overhead_resid += p->mexitcount_overhead_frac; 29913107Sbde if ((int)delta < 0) 30013107Sbde *p->mexitcount_count += delta + p->mexitcount_overhead 30113107Sbde - p->cputime_overhead; 30213107Sbde else if (delta != 0) { 30313107Sbde if (p->cputime_overhead_resid >= CALIB_SCALE) { 30413107Sbde p->cputime_overhead_resid -= CALIB_SCALE; 30513107Sbde ++*p->cputime_count; 30613107Sbde --delta; 30713107Sbde } 30813107Sbde if (delta != 0) { 30913107Sbde if (p->mexitcount_overhead_resid 31013107Sbde >= CALIB_SCALE) { 31113107Sbde p->mexitcount_overhead_resid 31213107Sbde -= CALIB_SCALE; 31313107Sbde ++*p->mexitcount_count; 31413107Sbde --delta; 31513107Sbde } 31613107Sbde KCOUNT(p, selfpcdiff) += delta; 31713107Sbde } 31813107Sbde *p->mexitcount_count += p->mexitcount_overhead_sub; 31913107Sbde } 32013107Sbde *p->cputime_count += p->cputime_overhead; 32113107Sbde } 32213107Sbde} 32313107Sbde#endif /* GUPROF */ 324