Fix high resolution kernel profiling just enough to not crash at boot

time, especially for SMP.  If configured, it turns itself on at boot
time for calibration, so is fragile even if never otherwise used.

Both types of kernel profiling were supposed to use a global spinlock
in the SMP case.  If hi-res profiling is configured (but not necessarily
used), this was supposed to be optimized by only using it when
necessary, and slightly more efficiently, in asm.  But it was not done
at all for mcount entry where it is necessary.  This caused crashes
in the SMP case when either type of profiling was enabled.  For mcount
exit, it only caused wrong times.  The times were wrongest with an
i8254 timer since using that requires exclusive access to the hardware.
The i8254 timer was too slow to use here 20 years ago and is much less
usable now, but it is the default for the SMP case since TSCs weren't
invariant when SMP was new.  Do the locking in all hi-res SMP cases for
simplicity.

Calibration uses special asms, and the clobber lists in these were sort
of inverted.  They contained the arg and return registers which are not
clobbered, but on amd64 they didn't contain the residue of the call-used
registers which may be clobbered (%r10 and %r11).  This usually caused
hangs at boot time.  This usually affected even the UP case.
This commit is contained in:
bde 2018-06-02 05:48:44 +00:00
parent c60e3080a1
commit 0409ad53fa
4 changed files with 48 additions and 12 deletions

View File

@ -56,6 +56,20 @@ static int cputime_prof_active;
#endif /* GUPROF */
#ifdef __GNUCLIKE_ASM
#if defined(SMP) && defined(GUPROF)
#define MPLOCK " \n\
movl $1,%edx \n\
9: \n\
xorl %eax,%eax \n\
lock \n\
cmpxchgl %edx,mcount_lock \n\
jne 9b \n"
#define MPUNLOCK "movl $0,mcount_lock \n"
#else /* !(SMP && GUPROF) */
#define MPLOCK
#define MPUNLOCK
#endif /* SMP && GUPROF */
__asm(" \n\
GM_STATE = 0 \n\
GMON_PROF_OFF = 3 \n\
@ -111,8 +125,10 @@ __mcount: \n\
movq 7*8(%rsp),%rsi \n\
\n\
pushfq \n\
cli \n\
call mcount \n\
cli \n"
MPLOCK " \n\
call mcount \n"
MPUNLOCK " \n\
popfq \n\
popq %r9 \n\
popq %r8 \n\
@ -163,8 +179,10 @@ GMON_PROF_HIRES = 4 \n\
pushq %r9 \n\
movq 7*8(%rsp),%rdi \n\
pushfq \n\
cli \n\
call mexitcount \n\
cli \n"
MPLOCK " \n\
call mexitcount \n"
MPUNLOCK " \n\
popfq \n\
popq %r9 \n\
popq %r8 \n\

View File

@ -64,11 +64,11 @@
__asm __volatile("pushq %0; call __mcount; popq %%rcx" \
: \
: "i" (label) \
: "ax", "dx", "cx", "di", "si", "r8", "r9", "memory")
: "cx", "r10", "r11", "memory")
#define MEXITCOUNT_OVERHEAD() \
__asm __volatile("call .mexitcount; 1:" \
: : \
: "ax", "dx", "cx", "di", "si", "r8", "r9", "memory")
: "r10", "r11", "memory")
#define MEXITCOUNT_OVERHEAD_GETLABEL(labelp) \
__asm __volatile("movq $1b,%0" : "=rm" (labelp))
#else

View File

@ -67,6 +67,20 @@ static int cputime_prof_active;
#endif /* GUPROF */
#ifdef __GNUCLIKE_ASM
#if defined(SMP) && defined(GUPROF)
#define MPLOCK " \n\
movl $1,%edx \n\
9: \n\
xorl %eax,%eax \n\
lock \n\
cmpxchgl %edx,mcount_lock \n\
jne 9b \n"
#define MPUNLOCK "movl $0,mcount_lock \n"
#else /* !(SMP && GUPROF) */
#define MPLOCK
#define MPUNLOCK
#endif /* SMP && GUPROF */
__asm(" \n\
GM_STATE = 0 \n\
GMON_PROF_OFF = 3 \n\
@ -110,8 +124,10 @@ __mcount: \n\
pushfl \n\
pushl %eax \n\
pushl %edx \n\
cli \n\
call mcount \n\
cli \n"
MPLOCK " \n\
call mcount \n"
MPUNLOCK " \n\
addl $8,%esp \n\
popfl \n\
.mcount_exit: \n\
@ -155,8 +171,10 @@ GMON_PROF_HIRES = 4 \n\
movl 8(%esp),%eax \n\
pushfl \n\
pushl %eax \n\
cli \n\
call mexitcount \n\
cli \n"
MPLOCK " \n\
call mexitcount \n"
MPUNLOCK " \n\
addl $4,%esp \n\
popfl \n\
popl %eax \n\

View File

@ -64,11 +64,11 @@
__asm __volatile("pushl %0; call __mcount; popl %%ecx" \
: \
: "i" (label) \
: "ax", "dx", "cx", "memory")
: "cx", "memory")
#define MEXITCOUNT_OVERHEAD() \
__asm __volatile("call .mexitcount; 1:" \
: : \
: "ax", "dx", "cx", "memory")
: "cx", "memory")
#define MEXITCOUNT_OVERHEAD_GETLABEL(labelp) \
__asm __volatile("movl $1b,%0" : "=rm" (labelp))
#else