prof_machdep.c revision 15146
1/*
2 * NEED A COPYRIGHT NOPTICE HERE
3 *
4 *	$Id$
5 */
6#include <sys/param.h>
7#include <sys/systm.h>
8#include <machine/clock.h>
9#include <i386/isa/isa.h>
10#include <i386/isa/timerreg.h>
11
12#ifdef GUPROF
13extern u_int	cputime __P((void));
14#endif
15
16#ifdef __GNUC__
17asm("
18GM_STATE	=	0
19GMON_PROF_OFF	=	3
20
21	.text
22	.align	4,0x90
23	.globl	__mcount
24__mcount:
25	#
26	# Check that we are profiling.  Do it early for speed.
27	#
28	cmpl	$GMON_PROF_OFF,__gmonparam+GM_STATE
29 	je	Lmcount_exit
30 	#
31 	# __mcount is the same as mcount except the caller hasn't changed
32 	# the stack except to call here, so the caller's raddr is above
33 	# our raddr.
34 	#
35 	movl	4(%esp),%edx
36 	jmp	Lgot_frompc
37
38 	.align	4,0x90
39 	.globl	mcount
40mcount:
41	cmpl	$GMON_PROF_OFF,__gmonparam+GM_STATE
42	je	Lmcount_exit
43	#
44	# The caller's stack frame has already been built, so %ebp is
45	# the caller's frame pointer.  The caller's raddr is in the
46	# caller's frame following the caller's caller's frame pointer.
47	#
48	movl	4(%ebp),%edx
49Lgot_frompc:
50	#
51	# Our raddr is the caller's pc.
52	#
53	movl	(%esp),%eax
54
55	pushf
56	pushl	%eax
57	pushl	%edx
58	cli
59	call	_mcount
60	addl	$8,%esp
61	popf
62Lmcount_exit:
63	ret
64");
65#else /* !__GNUC__ */
66#error
67#endif /* __GNUC__ */
68
69#ifdef GUPROF
70/*
71 * mexitcount saves the return register(s), loads selfpc and calls
72 * mexitcount(selfpc) to do the work.  Someday it should be in a machine
73 * dependent file together with cputime(), __mcount and mcount.  cputime()
74 * can't just be put in machdep.c because it has to be compiled without -pg.
75 */
76#ifdef __GNUC__
77asm("
78	.text
79#
80# Dummy label to be seen when gprof -u hides mexitcount.
81#
82	.align	4,0x90
83	.globl	__mexitcount
84__mexitcount:
85	nop
86
87GMON_PROF_HIRES	=	4
88
89	.align	4,0x90
90	.globl	mexitcount
91mexitcount:
92	cmpl	$GMON_PROF_HIRES,__gmonparam+GM_STATE
93	jne	Lmexitcount_exit
94	pushl	%edx
95	pushl	%eax
96	movl	8(%esp),%eax
97	pushf
98	pushl	%eax
99	cli
100	call	_mexitcount
101	addl	$4,%esp
102	popf
103	popl	%eax
104	popl	%edx
105Lmexitcount_exit:
106	ret
107");
108#else /* !__GNUC__ */
109#error
110#endif /* __GNUC__ */
111
112/*
113 * Return the time elapsed since the last call.  The units are machine-
114 * dependent.
115 */
116u_int
117cputime()
118{
119	u_int count;
120	u_int delta;
121	u_char low;
122	static u_int prev_count;
123
124	/*
125	 * Read the current value of the 8254 timer counter 0.
126	 */
127	outb(TIMER_MODE, TIMER_SEL0 | TIMER_LATCH);
128	low = inb(TIMER_CNTR0);
129	count = low | (inb(TIMER_CNTR0) << 8);
130
131	/*
132	 * The timer counts down from TIMER_CNTR0_MAX to 0 and then resets.
133	 * While profiling is enabled, this routine is called at least twice
134	 * per timer reset (for mcounting and mexitcounting hardclock()),
135	 * so at most one reset has occurred since the last call, and one
136	 * has occurred iff the current count is larger than the previous
137	 * count.  This allows counter underflow to be detected faster
138	 * than in microtime().
139	 */
140	delta = prev_count - count;
141	prev_count = count;
142	if ((int) delta <= 0)
143		return (delta + timer0_max_count);
144	return (delta);
145}
146#else /* not GUPROF */
147#ifdef __GNUC__
148asm("
149	.text
150	.align	4,0x90
151	.globl	mexitcount
152mexitcount:
153	ret
154");
155#else /* !__GNUC__ */
156#error
157#endif /* __GNUC__ */
158#endif /* GUPROF */
159