summaryrefslogtreecommitdiffstats
path: root/sys/kern
diff options
context:
space:
mode:
authorfsmp <fsmp@FreeBSD.org>1997-12-08 23:00:24 +0000
committerfsmp <fsmp@FreeBSD.org>1997-12-08 23:00:24 +0000
commit6dd7dcc53b675eb0167c348bd2a4b6f527ec387c (patch)
tree8ceb88629b524e26e069a9a105e202d2131596e3 /sys/kern
parentc29fe145047eadea9dcee01d907b3a990906a6af (diff)
downloadFreeBSD-src-6dd7dcc53b675eb0167c348bd2a4b6f527ec387c.zip
FreeBSD-src-6dd7dcc53b675eb0167c348bd2a4b6f527ec387c.tar.gz
The improvements to clock statistics by Tor Egge
Wrappered and enabled by the define BETTER_CLOCK (on by default in smpyests.h) Reviewed by: smp@csn.net Submitted by: Tor Egge <Tor.Egge@idi.ntnu.no>
Diffstat (limited to 'sys/kern')
-rw-r--r--sys/kern/kern_clock.c21
-rw-r--r--sys/kern/kern_tc.c21
-rw-r--r--sys/kern/kern_timeout.c21
-rw-r--r--sys/kern/subr_smp.c316
4 files changed, 375 insertions, 4 deletions
diff --git a/sys/kern/kern_clock.c b/sys/kern/kern_clock.c
index 5f138615..220e4b5 100644
--- a/sys/kern/kern_clock.c
+++ b/sys/kern/kern_clock.c
@@ -36,7 +36,7 @@
* SUCH DAMAGE.
*
* @(#)kern_clock.c 8.5 (Berkeley) 1/21/94
- * $Id: kern_clock.c,v 1.44 1997/11/18 12:24:22 bde Exp $
+ * $Id: kern_clock.c,v 1.45 1997/11/24 15:15:27 bde Exp $
*/
/* Portions of this software are covered by the following: */
@@ -80,6 +80,10 @@
#include <sys/gmon.h>
#endif
+#if defined(SMP) && defined(BETTER_CLOCK)
+#include <machine/smp.h>
+#endif
+
static void initclocks __P((void *dummy));
SYSINIT(clocks, SI_SUB_CLOCKS, SI_ORDER_FIRST, initclocks, NULL)
@@ -91,7 +95,11 @@ struct callout_tailq *callwheel;
/* Some of these don't belong here, but it's easiest to concentrate them. */
+#if defined(SMP) && defined(BETTER_CLOCK)
+long cp_time[CPUSTATES];
+#else
static long cp_time[CPUSTATES];
+#endif
long dk_seek[DK_NDRIVE];
static long dk_time[DK_NDRIVE]; /* time busy (in statclock ticks) */
long dk_wds[DK_NDRIVE];
@@ -471,6 +479,9 @@ hardclock(frame)
psignal(p, SIGPROF);
}
+#if defined(SMP) && defined(BETTER_CLOCK)
+ forward_hardclock(pscnt);
+#endif
/*
* If no separate statistics clock is available, run it from here.
*/
@@ -971,6 +982,10 @@ statclock(frame)
p = curproc;
if (p->p_flag & P_PROFIL)
addupc_intr(p, CLKF_PC(frame), 1);
+#if defined(SMP) && defined(BETTER_CLOCK)
+ if (stathz != 0)
+ forward_statclock(pscnt);
+#endif
if (--pscnt > 0)
return;
/*
@@ -996,6 +1011,10 @@ statclock(frame)
}
}
#endif
+#if defined(SMP) && defined(BETTER_CLOCK)
+ if (stathz != 0)
+ forward_statclock(pscnt);
+#endif
if (--pscnt > 0)
return;
/*
diff --git a/sys/kern/kern_tc.c b/sys/kern/kern_tc.c
index 5f138615..220e4b5 100644
--- a/sys/kern/kern_tc.c
+++ b/sys/kern/kern_tc.c
@@ -36,7 +36,7 @@
* SUCH DAMAGE.
*
* @(#)kern_clock.c 8.5 (Berkeley) 1/21/94
- * $Id: kern_clock.c,v 1.44 1997/11/18 12:24:22 bde Exp $
+ * $Id: kern_clock.c,v 1.45 1997/11/24 15:15:27 bde Exp $
*/
/* Portions of this software are covered by the following: */
@@ -80,6 +80,10 @@
#include <sys/gmon.h>
#endif
+#if defined(SMP) && defined(BETTER_CLOCK)
+#include <machine/smp.h>
+#endif
+
static void initclocks __P((void *dummy));
SYSINIT(clocks, SI_SUB_CLOCKS, SI_ORDER_FIRST, initclocks, NULL)
@@ -91,7 +95,11 @@ struct callout_tailq *callwheel;
/* Some of these don't belong here, but it's easiest to concentrate them. */
+#if defined(SMP) && defined(BETTER_CLOCK)
+long cp_time[CPUSTATES];
+#else
static long cp_time[CPUSTATES];
+#endif
long dk_seek[DK_NDRIVE];
static long dk_time[DK_NDRIVE]; /* time busy (in statclock ticks) */
long dk_wds[DK_NDRIVE];
@@ -471,6 +479,9 @@ hardclock(frame)
psignal(p, SIGPROF);
}
+#if defined(SMP) && defined(BETTER_CLOCK)
+ forward_hardclock(pscnt);
+#endif
/*
* If no separate statistics clock is available, run it from here.
*/
@@ -971,6 +982,10 @@ statclock(frame)
p = curproc;
if (p->p_flag & P_PROFIL)
addupc_intr(p, CLKF_PC(frame), 1);
+#if defined(SMP) && defined(BETTER_CLOCK)
+ if (stathz != 0)
+ forward_statclock(pscnt);
+#endif
if (--pscnt > 0)
return;
/*
@@ -996,6 +1011,10 @@ statclock(frame)
}
}
#endif
+#if defined(SMP) && defined(BETTER_CLOCK)
+ if (stathz != 0)
+ forward_statclock(pscnt);
+#endif
if (--pscnt > 0)
return;
/*
diff --git a/sys/kern/kern_timeout.c b/sys/kern/kern_timeout.c
index 5f138615..220e4b5 100644
--- a/sys/kern/kern_timeout.c
+++ b/sys/kern/kern_timeout.c
@@ -36,7 +36,7 @@
* SUCH DAMAGE.
*
* @(#)kern_clock.c 8.5 (Berkeley) 1/21/94
- * $Id: kern_clock.c,v 1.44 1997/11/18 12:24:22 bde Exp $
+ * $Id: kern_clock.c,v 1.45 1997/11/24 15:15:27 bde Exp $
*/
/* Portions of this software are covered by the following: */
@@ -80,6 +80,10 @@
#include <sys/gmon.h>
#endif
+#if defined(SMP) && defined(BETTER_CLOCK)
+#include <machine/smp.h>
+#endif
+
static void initclocks __P((void *dummy));
SYSINIT(clocks, SI_SUB_CLOCKS, SI_ORDER_FIRST, initclocks, NULL)
@@ -91,7 +95,11 @@ struct callout_tailq *callwheel;
/* Some of these don't belong here, but it's easiest to concentrate them. */
+#if defined(SMP) && defined(BETTER_CLOCK)
+long cp_time[CPUSTATES];
+#else
static long cp_time[CPUSTATES];
+#endif
long dk_seek[DK_NDRIVE];
static long dk_time[DK_NDRIVE]; /* time busy (in statclock ticks) */
long dk_wds[DK_NDRIVE];
@@ -471,6 +479,9 @@ hardclock(frame)
psignal(p, SIGPROF);
}
+#if defined(SMP) && defined(BETTER_CLOCK)
+ forward_hardclock(pscnt);
+#endif
/*
* If no separate statistics clock is available, run it from here.
*/
@@ -971,6 +982,10 @@ statclock(frame)
p = curproc;
if (p->p_flag & P_PROFIL)
addupc_intr(p, CLKF_PC(frame), 1);
+#if defined(SMP) && defined(BETTER_CLOCK)
+ if (stathz != 0)
+ forward_statclock(pscnt);
+#endif
if (--pscnt > 0)
return;
/*
@@ -996,6 +1011,10 @@ statclock(frame)
}
}
#endif
+#if defined(SMP) && defined(BETTER_CLOCK)
+ if (stathz != 0)
+ forward_statclock(pscnt);
+#endif
if (--pscnt > 0)
return;
/*
diff --git a/sys/kern/subr_smp.c b/sys/kern/subr_smp.c
index f1e720f..632d5dd 100644
--- a/sys/kern/subr_smp.c
+++ b/sys/kern/subr_smp.c
@@ -22,23 +22,37 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * $Id: mp_machdep.c,v 1.59 1997/10/28 15:58:10 bde Exp $
+ * $Id: mp_machdep.c,v 1.40 1997/12/04 19:30:03 smp Exp smp $
*/
#include "opt_smp.h"
#include "opt_vm86.h"
+#ifdef SMP
+#include <machine/smptests.h>
+#else
+#error
+#endif
+
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/proc.h>
#include <sys/sysctl.h>
+#ifdef BETTER_CLOCK
+#include <sys/dkstat.h>
+#endif
#include <vm/vm.h>
#include <vm/vm_param.h>
#include <vm/pmap.h>
#include <vm/vm_kern.h>
#include <vm/vm_extern.h>
+#ifdef BETTER_CLOCK
+#include <sys/lock.h>
+#include <vm/vm_map.h>
+#include <sys/user.h>
+#endif
#include <machine/smp.h>
#include <machine/apic.h>
@@ -548,6 +562,16 @@ mp_enable(u_int boot_addr)
setidt(XINVLTLB_OFFSET, Xinvltlb,
SDT_SYS386IGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL));
+#ifdef BETTER_CLOCK
+ /* install an inter-CPU IPI for reading processor state */
+ setidt(XCPUCHECKSTATE_OFFSET, Xcpucheckstate,
+ SDT_SYS386IGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL));
+
+ /* install an inter-CPU IPI for forcing an additional software trap */
+ setidt(XCPUAST_OFFSET, Xcpuast,
+ SDT_SYS386IGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL));
+#endif
+
/* install an inter-CPU IPI for CPU stop/restart */
setidt(XCPUSTOP_OFFSET, Xcpustop,
SDT_SYS386IGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL));
@@ -2051,3 +2075,293 @@ putfmtrr()
wrmsr(0x259, 0x0101010101010101LL);
}
}
+
+
+#ifdef BETTER_CLOCK
+
+#define CHECKSTATE_USER 0
+#define CHECKSTATE_SYS 1
+#define CHECKSTATE_INTR 2
+
+struct proc* checkstate_curproc[NCPU];
+int checkstate_cpustate[NCPU];
+u_long checkstate_pc[NCPU];
+
+extern long cp_time[CPUSTATES];
+
+#define PC_TO_INDEX(pc, prof) \
+ ((int)(((u_quad_t)((pc) - (prof)->pr_off) * \
+ (u_quad_t)((prof)->pr_scale)) >> 16) & ~1)
+
+static void
+addupc_intr_forwarded(struct proc *p, int id, int *astmap)
+{
+ int i;
+ struct uprof *prof;
+ u_long pc;
+
+ pc = checkstate_pc[id];
+ prof = &p->p_stats->p_prof;
+ if (pc >= prof->pr_off &&
+ (i = PC_TO_INDEX(pc, prof)) < prof->pr_size) {
+ if ((p->p_flag & P_OWEUPC) == 0) {
+ prof->pr_addr = pc;
+ prof->pr_ticks = 1;
+ p->p_flag |= P_OWEUPC;
+ }
+ *astmap |= (1 << id);
+ }
+}
+
+static void
+forwarded_statclock(int id, int pscnt, int *astmap)
+{
+ struct pstats *pstats;
+ long rss;
+ struct rusage *ru;
+ struct vmspace *vm;
+ int cpustate;
+ struct proc *p;
+#ifdef GPROF
+ register struct gmonparam *g;
+ int i;
+#endif
+
+ p = checkstate_curproc[id];
+ cpustate = checkstate_cpustate[id];
+
+ switch (cpustate) {
+ case CHECKSTATE_USER:
+ if (p->p_flag & P_PROFIL)
+ addupc_intr_forwarded(p, id, astmap);
+ if (pscnt > 1)
+ return;
+ p->p_uticks++;
+ if (p->p_nice > NZERO)
+ cp_time[CP_NICE]++;
+ else
+ cp_time[CP_USER]++;
+ break;
+ case CHECKSTATE_SYS:
+#ifdef GPROF
+ /*
+ * Kernel statistics are just like addupc_intr, only easier.
+ */
+ g = &_gmonparam;
+ if (g->state == GMON_PROF_ON) {
+ i = checkstate_pc[id] - g->lowpc;
+ if (i < g->textsize) {
+ i /= HISTFRACTION * sizeof(*g->kcount);
+ g->kcount[i]++;
+ }
+ }
+#endif
+ if (pscnt > 1)
+ return;
+
+ if (!p)
+ cp_time[CP_IDLE]++;
+ else {
+ p->p_sticks++;
+ cp_time[CP_SYS]++;
+ }
+ break;
+ case CHECKSTATE_INTR:
+ default:
+#ifdef GPROF
+ /*
+ * Kernel statistics are just like addupc_intr, only easier.
+ */
+ g = &_gmonparam;
+ if (g->state == GMON_PROF_ON) {
+ i = checkstate_pc[id] - g->lowpc;
+ if (i < g->textsize) {
+ i /= HISTFRACTION * sizeof(*g->kcount);
+ g->kcount[i]++;
+ }
+ }
+#endif
+ if (pscnt > 1)
+ return;
+ if (p)
+ p->p_iticks++;
+ cp_time[CP_INTR]++;
+ }
+ if (p != NULL) {
+ p->p_cpticks++;
+ if (++p->p_estcpu == 0)
+ p->p_estcpu--;
+ if ((p->p_estcpu & 3) == 0) {
+ resetpriority(p);
+ if (p->p_priority >= PUSER)
+ p->p_priority = p->p_usrpri;
+ }
+
+ /* Update resource usage integrals and maximums. */
+ if ((pstats = p->p_stats) != NULL &&
+ (ru = &pstats->p_ru) != NULL &&
+ (vm = p->p_vmspace) != NULL) {
+ ru->ru_ixrss += vm->vm_tsize * PAGE_SIZE / 1024;
+ ru->ru_idrss += vm->vm_dsize * PAGE_SIZE / 1024;
+ ru->ru_isrss += vm->vm_ssize * PAGE_SIZE / 1024;
+ rss = vm->vm_pmap.pm_stats.resident_count *
+ PAGE_SIZE / 1024;
+ if (ru->ru_maxrss < rss)
+ ru->ru_maxrss = rss;
+ }
+ }
+}
+
+void
+forward_statclock(int pscnt)
+{
+ int map;
+ int id;
+ int i;
+
+ /* Kludge. We don't yet have separate locks for the interrupts
+ * and the kernel. This means that we cannot let the other processors
+ * handle complex interrupts while inhibiting them from entering
+ * the kernel in a non-interrupt context.
+ *
+ * What we can do, without changing the locking mechanisms yet,
+ * is letting the other processors handle a very simple interrupt
+ * (wich determines the processor states), and do the main
+ * work ourself.
+ */
+
+ if (!smp_started || !invltlb_ok)
+ return;
+
+ /* Step 1: Probe state (user, cpu, interrupt, spinlock, idle ) */
+
+ map = other_cpus;
+ checkstate_probed_cpus = 0;
+ selected_apic_ipi(map, XCPUCHECKSTATE_OFFSET, APIC_DELMODE_FIXED);
+
+ i = 0;
+ while (checkstate_probed_cpus != map) {
+ /* spin */
+ i++;
+ if (i == 1000000) {
+ printf("forward_statclock: checkstate %x\n",
+ checkstate_probed_cpus);
+ }
+ }
+
+ /*
+ * Step 2: walk through other processors processes, update ticks and
+ * profiling info.
+ */
+
+ map = 0;
+ for (id = 0; id < mp_ncpus; id++) {
+ if (id == cpuid)
+ continue;
+ if (((1 << id) & checkstate_probed_cpus) == 0)
+ panic("state for cpu %d not available", cpuid);
+ forwarded_statclock(id, pscnt, &map);
+ }
+ if (map != 0) {
+ checkstate_need_ast |= map;
+ selected_apic_ipi(map, XCPUAST_OFFSET, APIC_DELMODE_FIXED);
+ i = 0;
+ while (checkstate_need_ast != 0) {
+ /* spin */
+ i++;
+ if (i > 1000000) {
+ printf("forward_statclock: dropped ast 0x%x\n",
+ checkstate_need_ast);
+ break;
+ }
+ }
+ }
+}
+
+void
+forward_hardclock(int pscnt)
+{
+ int map;
+ int id;
+ struct proc *p;
+ struct pstats *pstats;
+ int i;
+
+ /* Kludge. We don't yet have separate locks for the interrupts
+ * and the kernel. This means that we cannot let the other processors
+ * handle complex interrupts while inhibiting them from entering
+ * the kernel in a non-interrupt context.
+ *
+ * What we can do, without changing the locking mechanisms yet,
+ * is letting the other processors handle a very simple interrupt
+ * (wich determines the processor states), and do the main
+ * work ourself.
+ */
+
+ if (!smp_started || !invltlb_ok)
+ return;
+
+ /* Step 1: Probe state (user, cpu, interrupt, spinlock, idle) */
+
+ map = other_cpus;
+ checkstate_probed_cpus = 0;
+ selected_apic_ipi(map, XCPUCHECKSTATE_OFFSET, APIC_DELMODE_FIXED);
+
+ i = 0;
+ while (checkstate_probed_cpus != map) {
+ /* spin */
+ i++;
+ if (i == 1000000) {
+ printf("forward_hardclock: checkstate %x\n",
+ checkstate_probed_cpus);
+ }
+ }
+
+ /*
+ * Step 2: walk through other processors processes, update virtual
+ * timer and profiling timer. If stathz == 0, also update ticks and
+ * profiling info.
+ */
+
+ map = 0;
+ for (id = 0; id < mp_ncpus; id++) {
+ if (id == cpuid)
+ continue;
+ if (((1 << id) & checkstate_probed_cpus) == 0)
+ panic("state for cpu %d not available", cpuid);
+ p = checkstate_curproc[id];
+ if (p) {
+ pstats = p->p_stats;
+ if (checkstate_cpustate[id] == CHECKSTATE_USER &&
+ timerisset(&pstats->p_timer[ITIMER_VIRTUAL].it_value) &&
+ itimerdecr(&pstats->p_timer[ITIMER_VIRTUAL], tick) == 0) {
+ psignal(p, SIGVTALRM);
+ map |= (1 << id);
+ }
+ if (timerisset(&pstats->p_timer[ITIMER_PROF].it_value) &&
+ itimerdecr(&pstats->p_timer[ITIMER_PROF], tick) == 0) {
+ psignal(p, SIGPROF);
+ map |= (1 << id);
+ }
+ }
+ if (stathz == 0) {
+ forwarded_statclock( id, pscnt, &map);
+ }
+ }
+ if (map != 0) {
+ checkstate_need_ast |= map;
+ selected_apic_ipi(map, XCPUAST_OFFSET, APIC_DELMODE_FIXED);
+ i = 0;
+ while (checkstate_need_ast != 0) {
+ /* spin */
+ i++;
+ if (i > 1000000) {
+ printf("forward_hardclock: dropped ast 0x%x\n",
+ checkstate_need_ast);
+ break;
+ }
+ }
+ }
+}
+
+#endif /* BETTER_CLOCK */
OpenPOWER on IntegriCloud