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