From a282253a29c07ac570798529ce98e2cc6e9bf7de Mon Sep 17 00:00:00 2001 From: Julian Elischer Date: Sat, 8 Feb 2003 02:58:16 +0000 Subject: [PATCH] A little infrastructure, preceding some upcoming changes to the profiling and statistics code. Submitted by: DavidXu@ Reviewed by: peter@ --- sys/kern/kern_clock.c | 22 ++++++++++++-- sys/kern/kern_exit.c | 2 +- sys/kern/subr_prof.c | 67 +++++++++++++++++++++++++++++-------------- sys/sys/proc.h | 4 ++- 4 files changed, 69 insertions(+), 26 deletions(-) diff --git a/sys/kern/kern_clock.c b/sys/kern/kern_clock.c index 5c6756babe10..25e558a0a928 100644 --- a/sys/kern/kern_clock.c +++ b/sys/kern/kern_clock.c @@ -313,6 +313,10 @@ startprofclock(p) * cover psdiv, etc. as well. */ mtx_lock_spin(&sched_lock); + if (p->p_sflag & PS_STOPPROF) { + mtx_unlock_spin(&sched_lock); + return; + } if ((p->p_sflag & PS_PROFIL) == 0) { p->p_sflag |= PS_PROFIL; if (++profprocs == 1) @@ -329,9 +333,18 @@ stopprofclock(p) register struct proc *p; { + PROC_LOCK_ASSERT(p, MA_OWNED); +retry: mtx_lock_spin(&sched_lock); if (p->p_sflag & PS_PROFIL) { - p->p_sflag &= ~PS_PROFIL; + if (p->p_profthreads) { + p->p_sflag |= PS_STOPPROF; + mtx_unlock_spin(&sched_lock); + msleep(&p->p_profthreads, &p->p_mtx, PPAUSE, + "stopprof", NULL); + goto retry; + } + p->p_sflag &= ~(PS_PROFIL|PS_STOPPROF); if (--profprocs == 0) cpu_stopprofclock(); } @@ -400,7 +413,7 @@ statclock(frame) } } - sched_clock(ke->ke_thread); + sched_clock(td); /* Update resource usage integrals and maximums. */ if ((pstats = p->p_stats) != NULL && @@ -430,9 +443,12 @@ profclock(frame) /* * Came from user mode; CPU was in user state. * If this process is being profiled, record the tick. + * if there is no related user location yet, don't + * bother trying to count it. */ td = curthread; - if (td->td_proc->p_sflag & PS_PROFIL) + if ((td->td_proc->p_sflag & PS_PROFIL) && + !(td->td_flags & TDF_UPCALLING)) addupc_intr(td->td_kse, CLKF_PC(frame), 1); } #ifdef GPROF diff --git a/sys/kern/kern_exit.c b/sys/kern/kern_exit.c index 0b2c2e80f060..572144499078 100644 --- a/sys/kern/kern_exit.c +++ b/sys/kern/kern_exit.c @@ -238,7 +238,6 @@ exit1(td, rv) TAILQ_FOREACH(ep, &exit_list, next) (*ep->function)(p); - stopprofclock(p); MALLOC(p->p_ru, struct rusage *, sizeof(struct rusage), M_ZOMBIE, 0); @@ -247,6 +246,7 @@ exit1(td, rv) * P_PPWAIT is set; we will wakeup the parent below. */ PROC_LOCK(p); + stopprofclock(p); p->p_flag &= ~(P_TRACED | P_PPWAIT); SIGEMPTYSET(p->p_siglist); PROC_UNLOCK(p); diff --git a/sys/kern/subr_prof.c b/sys/kern/subr_prof.c index 2c22a92fbe7e..b8cd61e27630 100644 --- a/sys/kern/subr_prof.c +++ b/sys/kern/subr_prof.c @@ -358,7 +358,9 @@ sysctl_kern_prof(SYSCTL_HANDLER_ARGS) return (0); if (state == GMON_PROF_OFF) { gp->state = state; + PROC_LOCK(&proc0); stopprofclock(&proc0); + PROC_UNLOCK(&proc0); stopguprof(gp); } else if (state == GMON_PROF_ON) { gp->state = GMON_PROF_OFF; @@ -369,7 +371,9 @@ sysctl_kern_prof(SYSCTL_HANDLER_ARGS) #ifdef GUPROF } else if (state == GMON_PROF_HIRES) { gp->state = GMON_PROF_OFF; + PROC_LOCK(&proc0); stopprofclock(&proc0); + PROC_UNLOCK(&proc0); startguprof(gp); gp->state = state; #endif @@ -419,7 +423,7 @@ profil(td, uap) struct thread *td; register struct profil_args *uap; { - register struct uprof *upp; + struct uprof *upp; int s; int error = 0; @@ -430,7 +434,9 @@ profil(td, uap) goto done2; } if (uap->scale == 0) { + PROC_LOCK(td->td_proc); stopprofclock(td->td_proc); + PROC_UNLOCK(td->td_proc); goto done2; } upp = &td->td_proc->p_stats->p_prof; @@ -472,15 +478,12 @@ profil(td, uap) * inaccurate. */ void -addupc_intr(ke, pc, ticks) - register struct kse *ke; - register uintptr_t pc; - u_int ticks; +addupc_intr(struct kse *ke, uintptr_t pc, u_int ticks) { - register struct uprof *prof; - register caddr_t addr; - register u_int i; - register int v; + struct uprof *prof; + caddr_t addr; + u_int i; + int v; if (ticks == 0) return; @@ -502,34 +505,56 @@ addupc_intr(ke, pc, ticks) /* * Much like before, but we can afford to take faults here. If the * update fails, we simply turn off profiling. + * XXXKSE, don't use kse unless we got sched lock. */ void -addupc_task(ke, pc, ticks) - register struct kse *ke; - register uintptr_t pc; - u_int ticks; +addupc_task(struct kse *ke, uintptr_t pc, u_int ticks) { - struct proc *p = ke->ke_proc; - register struct uprof *prof; - register caddr_t addr; - register u_int i; + struct proc *p = ke->ke_proc; + struct uprof *prof; + caddr_t addr; + u_int i; u_short v; + int stop = 0; if (ticks == 0) return; + PROC_LOCK(p); + mtx_lock_spin(&sched_lock); + if (!(p->p_sflag & PS_PROFIL)) { + mtx_unlock_spin(&sched_lock); + PROC_UNLOCK(p); + return; + } + p->p_profthreads++; + mtx_unlock_spin(&sched_lock); + PROC_UNLOCK(p); prof = &p->p_stats->p_prof; if (pc < prof->pr_off || - (i = PC_TO_INDEX(pc, prof)) >= prof->pr_size) - return; + (i = PC_TO_INDEX(pc, prof)) >= prof->pr_size) { + goto out; + } addr = prof->pr_base + i; if (copyin(addr, &v, sizeof(v)) == 0) { v += ticks; if (copyout(&v, addr, sizeof(v)) == 0) - return; + goto out; } - stopprofclock(p); + stop = 1; + +out: + PROC_LOCK(p); + if (--p->p_profthreads == 0) { + if (p->p_sflag & PS_STOPPROF) { + wakeup(&p->p_profthreads); + stop = 0; + } + } + if (stop) + stopprofclock(p); + PROC_UNLOCK(p); } #if defined(__i386__) && __GNUC__ >= 2 diff --git a/sys/sys/proc.h b/sys/sys/proc.h index b6e11ee932fc..4e9af13642a8 100644 --- a/sys/sys/proc.h +++ b/sys/sys/proc.h @@ -569,12 +569,13 @@ struct proc { u_int p_swtime; /* (j) Time swapped in or out. */ struct itimerval p_realtimer; /* (h?/k?) Alarm timer. */ struct bintime p_runtime; /* (j) Real time. */ + int p_profthreads; /* (c) Num threads in addupc_task */ int p_traceflag; /* (o) Kernel trace points. */ struct vnode *p_tracep; /* (c + o) Trace to vnode. */ sigset_t p_siglist; /* (c) Sigs arrived, not delivered. */ struct vnode *p_textvp; /* (b) Vnode of executable. */ char p_lock; /* (c) Proclock (prevent swap) count. */ - struct klist p_klist; /* (c) Knotes attached to this proc. */ + struct klist p_klist; /* (c) Knotes attached to this proc. */ struct sigiolst p_sigiolst; /* (c) List of sigio sources. */ int p_sigparent; /* (c) Signal to parent on exit. */ sigset_t p_oldsigmask; /* (c) Saved mask from pre sigpause. */ @@ -669,6 +670,7 @@ struct proc { #define PS_INMEM 0x00001 /* Loaded into memory. */ #define PS_XCPU 0x00002 /* Exceeded CPU limit. */ #define PS_PROFIL 0x00004 /* Has started profiling. */ +#define PS_STOPPROF 0x00008 /* Has thread in requesting to stop prof */ #define PS_ALRMPEND 0x00020 /* Pending SIGVTALRM needs to be posted. */ #define PS_PROFPEND 0x00040 /* Pending SIGPROF needs to be posted. */ #define PS_SWAPINREQ 0x00100 /* Swapin request due to wakeup. */