1
0
mirror of https://git.FreeBSD.org/src.git synced 2024-12-23 11:18:54 +00:00
freebsd/sys/i386/isa/prof_machdep.c
Bruce Evans 912e603778 Implemented non-statistical kernel profiling. This is based on
looking at a high resolution clock for each of the following events:
function call, function return, interrupt entry, interrupt exit,
and interesting branches.  The differences between the times of
these events are added at appropriate places in a ordinary histogram
(as if very fast statistical profiling sampled the pc at those
places) so that ordinary gprof can be used to analyze the times.

gmon.h:
Histogram counters need to be 4 bytes for microsecond resolutions.
They will need to be larger for the 586 clock.
The comments were vax-centric and wrong even on vaxes.  Does anyone
disagree?

gprof4.c:
The standard gprof should support counters of all integral sizes
and the size of the counter should be in the gmon header.  This
hack will do until then.  (Use gprof4 -u to examine the results
of non-statistical profiling.)

config/*:
Non-statistical profiling is configured with `config -pp'.
`config -p' still gives ordinary profiling.

kgmon/*:
Non-statistical profiling is enabled with `kgmon -B'.  `kgmon -b'
still enables ordinary profiling (and distables non-statistical
profiling) if non-statistical profiling is configured.
1995-12-29 15:30:05 +00:00

154 lines
3.0 KiB
C

#include <sys/param.h>
#include <sys/systm.h>
#include <machine/clock.h>
#include <i386/isa/isa.h>
#include <i386/isa/timerreg.h>
#ifdef GUPROF
extern u_int cputime __P((void));
#endif
#ifdef __GNUC__
asm("
GM_STATE = 0
GMON_PROF_OFF = 3
.text
.align 4,0x90
.globl __mcount
__mcount:
#
# Check that we are profiling. Do it early for speed.
#
cmpl $GMON_PROF_OFF,__gmonparam+GM_STATE
je Lmcount_exit
#
# __mcount is the same as mcount except the caller hasn't changed
# the stack except to call here, so the caller's raddr is above
# our raddr.
#
movl 4(%esp),%edx
jmp Lgot_frompc
.align 4,0x90
.globl mcount
mcount:
cmpl $GMON_PROF_OFF,__gmonparam+GM_STATE
je Lmcount_exit
#
# The caller's stack frame has already been built, so %ebp is
# the caller's frame pointer. The caller's raddr is in the
# caller's frame following the caller's caller's frame pointer.
#
movl 4(%ebp),%edx
Lgot_frompc:
#
# Our raddr is the caller's pc.
#
movl (%esp),%eax
pushf
pushl %eax
pushl %edx
cli
call _mcount
addl $8,%esp
popf
Lmcount_exit:
ret
");
#else /* !__GNUC__ */
#error
#endif /* __GNUC__ */
#ifdef GUPROF
/*
* mexitcount saves the return register(s), loads selfpc and calls
* mexitcount(selfpc) to do the work. Someday it should be in a machine
* dependent file together with cputime(), __mcount and mcount. cputime()
* can't just be put in machdep.c because it has to be compiled without -pg.
*/
#ifdef __GNUC__
asm("
.text
#
# Dummy label to be seen when gprof -u hides mexitcount.
#
.align 4,0x90
.globl __mexitcount
__mexitcount:
nop
GMON_PROF_HIRES = 4
.align 4,0x90
.globl mexitcount
mexitcount:
cmpl $GMON_PROF_HIRES,__gmonparam+GM_STATE
jne Lmexitcount_exit
pushl %edx
pushl %eax
movl 8(%esp),%eax
pushf
pushl %eax
cli
call _mexitcount
addl $4,%esp
popf
popl %eax
popl %edx
Lmexitcount_exit:
ret
");
#else /* !__GNUC__ */
#error
#endif /* __GNUC__ */
/*
* Return the time elapsed since the last call. The units are machine-
* dependent.
*/
u_int
cputime()
{
u_int count;
u_int delta;
u_char low;
static u_int prev_count;
/*
* Read the current value of the 8254 timer counter 0.
*/
outb(TIMER_MODE, TIMER_SEL0 | TIMER_LATCH);
low = inb(TIMER_CNTR0);
count = low | (inb(TIMER_CNTR0) << 8);
/*
* The timer counts down from TIMER_CNTR0_MAX to 0 and then resets.
* While profiling is enabled, this routine is called at least twice
* per timer reset (for mcounting and mexitcounting hardclock()),
* so at most one reset has occurred since the last call, and one
* has occurred iff the current count is larger than the previous
* count. This allows counter underflow to be detected faster
* than in microtime().
*/
delta = prev_count - count;
prev_count = count;
if ((int) delta <= 0)
return (delta + timer0_max_count);
return (delta);
}
#else /* not GUPROF */
#ifdef __GNUC__
asm("
.text
.align 4,0x90
.globl mexitcount
mexitcount:
ret
");
#else /* !__GNUC__ */
#error
#endif /* __GNUC__ */
#endif /* GUPROF */