profile.h revision 129408
11543Srgrimes/*
21543Srgrimes * Copyright (c) 1992, 1993
31543Srgrimes *	The Regents of the University of California.  All rights reserved.
41543Srgrimes *
51543Srgrimes * Redistribution and use in source and binary forms, with or without
61543Srgrimes * modification, are permitted provided that the following conditions
71543Srgrimes * are met:
81543Srgrimes * 1. Redistributions of source code must retain the above copyright
91543Srgrimes *    notice, this list of conditions and the following disclaimer.
101543Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
111543Srgrimes *    notice, this list of conditions and the following disclaimer in the
121543Srgrimes *    documentation and/or other materials provided with the distribution.
131543Srgrimes * 4. Neither the name of the University nor the names of its contributors
141543Srgrimes *    may be used to endorse or promote products derived from this software
151543Srgrimes *    without specific prior written permission.
161543Srgrimes *
171543Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
181543Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
191543Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
201543Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
211543Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
221543Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
231543Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
241543Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
251543Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
261543Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
271543Srgrimes * SUCH DAMAGE.
281543Srgrimes *
291543Srgrimes *	@(#)profile.h	8.1 (Berkeley) 6/11/93
3050477Speter * $FreeBSD: head/sys/amd64/include/profile.h 129408 2004-05-18 22:52:32Z peter $
311543Srgrimes */
321543Srgrimes
3313107Sbde#ifndef _MACHINE_PROFILE_H_
3413107Sbde#define	_MACHINE_PROFILE_H_
352166Spaul
3655205Speter#ifdef _KERNEL
3737542Sbde
3813157Sbde/*
3922639Sbde * Config generates something to tell the compiler to align functions on 16
4022639Sbde * byte boundaries.  A strict alignment is good for keeping the tables small.
4122639Sbde */
4222639Sbde#define	FUNCTION_ALIGNMENT	16
4322639Sbde
4422639Sbde/*
4513157Sbde * The kernel uses assembler stubs instead of unportable inlines.
4613157Sbde * This is mainly to save a little time when profiling is not enabled,
4713157Sbde * which is the usual case for the kernel.
4813157Sbde */
4913157Sbde#define	_MCOUNT_DECL void mcount
5013157Sbde#define	MCOUNT
511543Srgrimes
5217879Sbde#ifdef GUPROF
5317879Sbde#define	CALIB_SCALE	1000
5417879Sbde#define	KCOUNT(p,index)	((p)->kcount[(index) \
5522639Sbde			 / (HISTFRACTION * sizeof(HISTCOUNTER))])
5617879Sbde#define	MCOUNT_DECL(s)
5717879Sbde#define	MCOUNT_ENTER(s)
5817879Sbde#define	MCOUNT_EXIT(s)
5937629Sbde#define	PC_TO_I(p, pc)	((uintfptr_t)(pc) - (uintfptr_t)(p)->lowpc)
6017879Sbde#else
6117879Sbde#define	MCOUNT_DECL(s)	u_long s;
6228921Sfsmp#ifdef SMP
6390024Sbdeextern int	mcount_lock;
64114349Speter#define	MCOUNT_ENTER(s)	{ s = read_rflags(); disable_intr(); \
6579734Sjhb 			  while (!atomic_cmpset_acq_int(&mcount_lock, 0, 1)) \
6678908Sjhb			  	/* nothing */ ; }
6778908Sjhb#define	MCOUNT_EXIT(s)	{ atomic_store_rel_int(&mcount_lock, 0); \
68114349Speter			  write_rflags(s); }
6928921Sfsmp#else
70114349Speter#define	MCOUNT_ENTER(s)	{ s = read_rflags(); disable_intr(); }
71114349Speter#define	MCOUNT_EXIT(s)	(write_rflags(s))
7228921Sfsmp#endif
7317879Sbde#endif /* GUPROF */
7417879Sbde
7555205Speter#else /* !_KERNEL */
7613157Sbde
7722639Sbde#define	FUNCTION_ALIGNMENT	4
7822639Sbde
79129408Speter#define	_MCOUNT_DECL \
80129408Speterstatic void _mcount(uintfptr_t frompc, uintfptr_t selfpc) __unused; \
81129408Speterstatic void _mcount
8213157Sbde
8395195Smarkm#ifdef	__GNUC__
84129408Speter#define	MCOUNT __asm ("			\n\
85129408Speter	.globl	.mcount			\n\
86129408Speter	.type	.mcount @function	\n\
87129408Speter.mcount:				\n\
88129408Speter	pushq	%rbp			\n\
89129408Speter	movq	%rsp, %rbp		\n\
90129408Speter	pushq	%rdi			\n\
91129408Speter	pushq	%rsi			\n\
92129408Speter	pushq	%rdx			\n\
93129408Speter	pushq	%rcx			\n\
94129408Speter	pushq	%r8			\n\
95129408Speter	pushq	%r9			\n\
96129408Speter	movq	8(%rbp),%rsi		\n\
97129408Speter	movq	(%rbp),%rdi		\n\
98129408Speter	movq	8(%rdi),%rdi		\n\
99129408Speter	call	_mcount			\n\
100129408Speter	popq	%r9			\n\
101129408Speter	popq	%r8			\n\
102129408Speter	popq	%rcx			\n\
103129408Speter	popq	%rdx			\n\
104129408Speter	popq	%rsi			\n\
105129408Speter	popq	%rdi			\n\
106129408Speter	leave				\n\
107129408Speter	ret				\n\
108129408Speter	.size	.mcount, . - .mcount");
109129408Speter#if 0
110129408Speter/*
111129408Speter * We could use this, except it doesn't preserve the registers that were
112129408Speter * being passed with arguments to the function that we were inserted
113129408Speter * into.  I've left it here as documentation of what the code above is
114129408Speter * supposed to do.
115129408Speter */
11695195Smarkm#define	MCOUNT								\
11795195Smarkmvoid									\
11895195Smarkmmcount()								\
11995195Smarkm{									\
12095195Smarkm	uintfptr_t selfpc, frompc;					\
12195195Smarkm	/*								\
12295195Smarkm	 * Find the return address for mcount,				\
12395195Smarkm	 * and the return address for mcount's caller.			\
12495195Smarkm	 *								\
12595195Smarkm	 * selfpc = pc pushed by call to mcount				\
12695195Smarkm	 */								\
127115659Sobrien	__asm("movq 8(%%rbp),%0" : "=r" (selfpc));			\
12895195Smarkm	/*								\
12995195Smarkm	 * frompc = pc pushed by call to mcount's caller.		\
13095195Smarkm	 * The caller's stack frame has already been built, so %ebp is	\
13195195Smarkm	 * the caller's frame pointer.  The caller's raddr is in the	\
13295195Smarkm	 * caller's frame following the caller's caller's frame pointer.\
13395195Smarkm	 */								\
134129408Speter	__asm("movq (%%rbp),%0" : "=r" (frompc));			\
13595195Smarkm	frompc = ((uintfptr_t *)frompc)[1];				\
13695195Smarkm	_mcount(frompc, selfpc);					\
1371543Srgrimes}
138129408Speter#endif
13995195Smarkm#else	/* __GNUC__ */
140103965Smarkm#define	MCOUNT		\
14195195Smarkmvoid			\
14295195Smarkmmcount()		\
14395195Smarkm{			\
14495195Smarkm}
14595195Smarkm#endif	/* __GNUC__ */
14637542Sbde
147114349Spetertypedef	unsigned long	uintfptr_t;
14837542Sbde
14955205Speter#endif /* _KERNEL */
1502166Spaul
15113107Sbde/*
15213107Sbde * An unsigned integral type that can hold non-negative difference between
15313107Sbde * function pointers.
15413107Sbde */
15531723Steggetypedef	u_int	fptrdiff_t;
15613107Sbde
15755205Speter#ifdef _KERNEL
15819000Sbde
15992761Salfredvoid	mcount(uintfptr_t frompc, uintfptr_t selfpc);
16092761Salfredvoid	kmupetext(uintfptr_t nhighpc);
16119000Sbde
16219000Sbde#ifdef GUPROF
16319000Sbdestruct gmonparam;
16419000Sbde
16592761Salfredvoid	nullfunc_loop_profiled(void);
16692761Salfredvoid	nullfunc_profiled(void);
16792761Salfredvoid	startguprof(struct gmonparam *p);
16892761Salfredvoid	stopguprof(struct gmonparam *p);
16913157Sbde#else
17019000Sbde#define	startguprof(p)
17119000Sbde#define	stopguprof(p)
17219000Sbde#endif /* GUPROF */
17319000Sbde
17455205Speter#else /* !_KERNEL */
17519000Sbde
17619000Sbde#include <sys/cdefs.h>
17719000Sbde
17819000Sbde__BEGIN_DECLS
17933047Sbde#ifdef __GNUC__
18092761Salfredvoid	mcount(void) __asm(".mcount");
18133047Sbde#endif
18219000Sbde__END_DECLS
18313157Sbde
18455205Speter#endif /* _KERNEL */
18519000Sbde
18613157Sbde#ifdef GUPROF
18719000Sbde/* XXX doesn't quite work outside kernel yet. */
18819000Sbdeextern int	cputime_bias;
18919000Sbde
19019000Sbde__BEGIN_DECLS
19192761Salfredint	cputime(void);
19292761Salfredvoid	empty_loop(void);
19392761Salfredvoid	mexitcount(uintfptr_t selfpc);
19492761Salfredvoid	nullfunc(void);
19592761Salfredvoid	nullfunc_loop(void);
19619000Sbde__END_DECLS
19713157Sbde#endif
19813107Sbde
19913157Sbde#endif /* !_MACHINE_PROFILE_H_ */
200