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