Subject: Re: mips kernel profiling?
To: Simon Burge <simonb@netbsd.org>
From: Ethan Solomita <ethan@geocast.com>
List: port-mips
Date: 03/31/2000 19:26:39
Simon Burge wrote:
>
> ...
> le0 at ioasic0 offset 0xc0000ioasic0: can't allocate DMA area for LANCE
> le0: DMA area not set up
> ...
> Profiling kernel, textsize=1810624 [80030000..801ea0c0]
> trap: address error (load or I-fetch) in kernel mode
> status=0xff03, cause=0x10, epc=0x8005d91c, vaddr=0xf
> pid=0 cmd=swapper usp=0x0 ksp=0x80294e40
> Stopped in swapper at fork1+0x5c: lw v1,16(s1)
> db> trace
> fork1+5c (1,414,14,0) ra 800565c4 sz 64
> main+4a0 (1,414,14,0) ra 80030084 sz 88
> User-level: pid 0
>
I've tracked this down, since I am trying to get profiling working too.
I've tracked it down to the _mcount function, but it has been the way it
is for a real long time now, so I'm confused as to how it ever worked.
In _mcount, defined as an assembler routine in arch/mips/profile.h, it
saves various registers to 0(sp) through 20(sp). Unfortunately, looking
at the call into _mcount from various functions, it decrements sp by 8,
and _mcount doesn't decrement it further. ie. _mcount appears to be
writing all over the caller's stack!
But clearly this worked for someone at some point, so what am I
missing? The failure in fork1() above happens because main() called
siginit(), siginit() calls _mcount(), and that trashes main's proc
pointer in the stack. So fork1 is passed a bogus proc pointer.
> When was the last time anyone had kernel profiling working? Is
> what I have below ok - if so I'll commit it.
>
I did something much simpler -- no new code, just changed MCOUNT_ENTER
to s = _splset(0); and MCOUNT_EXIT to _splset(s); This seems to work
with my platform -- is it a problem for pmax or others?
-- Ethan
> Simon.
> --
> Index: mips/include/profile.h
> ===================================================================
> RCS file: /cvsroot/syssrc/sys/arch/mips/include/profile.h,v
> retrieving revision 1.13
> diff -p -u -r1.13 profile.h
> --- profile.h 2000/03/28 02:58:46 1.13
> +++ profile.h 2000/03/28 12:01:34
> @@ -46,9 +46,9 @@
> * Declare non-profiled _splhigh() /_splx() entrypoints for _mcount.
> * see MCOUNT_ENTER and MCOUNT_EXIT.
> */
> -#define _KERNEL_MCOUNT_DECL \
> - int _splhigh __P((void)); \
> - int _splx __P((int));
> +#define _KERNEL_MCOUNT_DECL \
> + int _splraise_noprof __P((int)); \
> + int _splset_noprof __P((int));
> #else /* !_KERNEL */
> /* Make __mcount static. */
> #define _KERNEL_MCOUNT_DECL static
> @@ -96,13 +96,13 @@
> #ifdef _KERNEL
> /*
> * The following two macros do splhigh and splx respectively.
> - * They have to be defined this way because these are real
> - * functions on the MIPS, and we do not want to invoke mcount
> - * recursively.
> + * We use versions of _splraise() and _splset that don't
> + * including profiling support.
> */
> -#define MCOUNT_ENTER s = _splhigh()
>
> -#define MCOUNT_EXIT _splx(s)
> +#define MCOUNT_ENTER s = _splraise_noprof(MIPS_INT_MASK)
> +
> +#define MCOUNT_EXIT (void)_splset_noprof(s)
> #endif /* _KERNEL */
>
> #endif /* _MIPS_PROFILE_H_ */
> Index: mips/mips/locore.S
> ===================================================================
> RCS file: /cvsroot/syssrc/sys/arch/mips/mips/locore.S,v
> retrieving revision 1.92
> diff -p -u -r1.92 locore.S
> --- locore.S 2000/03/28 02:58:48 1.92
> +++ locore.S 2000/03/28 12:01:34
> @@ -493,6 +493,18 @@ LEAF(_splraise)
> and v0, v0, (MIPS_INT_MASK | MIPS_SR_INT_IE)
> END(_splraise)
>
> +/* as above, with no profiling support */
> +LEAF_NOPROFILE(_splraise_noprof)
> + mfc0 v0, MIPS_COP_0_STATUS # fetch status register
> + and a0, a0, MIPS_INT_MASK # extract INT bits
> + nor a0, zero, a0 # bitwise inverse of A0
> + and a0, a0, v0 # disable retaining other bits
> + mtc0 a0, MIPS_COP_0_STATUS # store back
> + nop
> + j ra
> + and v0, v0, (MIPS_INT_MASK | MIPS_SR_INT_IE)
> +END(_splraise_noprof)
> +
> LEAF(_spllower)
> mfc0 v0, MIPS_COP_0_STATUS # fetch status register
> li v1, ~MIPS_INT_MASK
> @@ -529,6 +541,19 @@ LEAF(_splset)
> j ra
> and v0, v0, (MIPS_INT_MASK | MIPS_SR_INT_IE)
> END(_splset)
> +
> +/* as above, with no profiling support */
> +LEAF_NOPROFILE(_splset_noprof)
> + mfc0 v0, MIPS_COP_0_STATUS # fetch status register
> + and a0, a0, (MIPS_INT_MASK | MIPS_SR_INT_IE)
> + li v1, ~(MIPS_INT_MASK | MIPS_SR_INT_IE)
> + and v1, v1, v0 # turn off every INT bit
> + or v1, v1, a0 # set old INT bits
> + mtc0 v1, MIPS_COP_0_STATUS # store back
> + nop
> + j ra
> + and v0, v0, (MIPS_INT_MASK | MIPS_SR_INT_IE)
> +END(_splset_noprof)
>
> LEAF(_splget)
> mfc0 v0, MIPS_COP_0_STATUS # fetch status register