Skip to content

Instantly share code, notes, and snippets.

@oza
Created March 31, 2010 11:58
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
Star You must be signed in to star a gist
Save oza/350230 to your computer and use it in GitHub Desktop.
diff --git a/sys/i386/i386/local_apic.c b/sys/i386/i386/local_apic.c
index 10a5854..b82a822 100644
--- a/sys/i386/i386/local_apic.c
+++ b/sys/i386/i386/local_apic.c
@@ -68,6 +68,8 @@ __FBSDID("$FreeBSD: src/sys/i386/i386/local_apic.c,v 1.61.2.4.2.1 2009/10/25 01:
#include <ddb/ddb.h>
#endif
+#include <sys/dynticks.h>
+
#ifdef KDTRACE_HOOKS
#include <sys/dtrace_bsd.h>
cyclic_clock_func_t lapic_cyclic_clock_func[MAXCPU];
@@ -111,6 +113,7 @@ struct lapic {
u_long la_hard_ticks;
u_long la_stat_ticks;
u_long la_prof_ticks;
+ u_long la_last_tick;
/* Include IDT_SYSCALL to make indexing easier. */
int la_ioint_irqs[APIC_NUM_IOINTS + 1];
} static lapics[MAX_APIC_ID + 1];
@@ -144,6 +147,9 @@ static u_int32_t lapic_timer_divisors[] = {
APIC_TDCR_32, APIC_TDCR_64, APIC_TDCR_128
};
+
+static void (*timer_handler)(struct trapframe *frame);
+
extern inthand_t IDTVEC(rsvd);
volatile lapic_t *lapic;
@@ -158,6 +164,9 @@ static void lapic_timer_periodic(u_int count);
static void lapic_timer_set_divisor(u_int divisor);
static uint32_t lvt_mode(struct lapic *la, u_int pin, uint32_t value);
+static void lapic_handle_timer_dynamically(struct trapframe *frame);
+static void __lapic_handle_timer(struct trapframe *frame);
+
struct pic lapic_pic = { .pic_resume = lapic_resume };
static uint32_t
@@ -216,6 +225,8 @@ lapic_init(vm_paddr_t addr)
setidt(APIC_SPURIOUS_INT, IDTVEC(spuriousint), SDT_SYS386IGT, SEL_KPL,
GSEL(GCODE_SEL, SEL_KPL));
+ timer_handler = __lapic_handle_timer;
+
/* Perform basic initialization of the BSP's local APIC. */
lapic_enable();
@@ -740,6 +751,12 @@ lapic_handle_intr(int vector, struct trapframe *frame)
void
lapic_handle_timer(struct trapframe *frame)
{
+ timer_handler(frame);
+}
+
+static void
+__lapic_handle_timer(struct trapframe *frame)
+{
struct lapic *la;
/* Send EOI first thing. */
@@ -1398,3 +1415,99 @@ lapic_ipi_vectored(u_int vector, int dest)
#endif /* DETECT_DEADLOCK */
}
#endif /* SMP */
+
+
+static void
+lapic_handle_timer_dynamically(struct trapframe *frame)
+{
+ struct lapic *la;
+ u_long cnt_to_skip;
+ int curticks;
+ int skip;
+ int last_skip;
+ int i;
+
+ /* Send EOI first thing. */
+ lapic_eoi();
+
+#if defined(SMP) && !defined(SCHED_ULE)
+ /*
+ * Don't do any accounting for the disabled HTT cores, since it
+ * will provide misleading numbers for the userland.
+ *
+ * No locking is necessary here, since even if we loose the race
+ * when hlt_cpus_mask changes it is not a big deal, really.
+ *
+ * Don't do that for ULE, since ULE doesn't consider hlt_cpus_mask
+ * and unlike other schedulers it actually schedules threads to
+ * those CPUs.
+ */
+ if ((hlt_cpus_mask & (1 << PCPU_GET(cpuid))) != 0)
+ return;
+#endif
+
+ /* Look up our local APIC structure for the tick counters. */
+ la = &lapics[PCPU_GET(apic_id)];
+ (*la->la_timer_count)++;
+ critical_enter();
+
+#ifdef KDTRACE_HOOKS
+ /*
+ * If the DTrace hooks are configured and a callback function
+ * has been registered, then call it to process the high speed
+ * timers.
+ */
+ int cpu = PCPU_GET(cpuid);
+ if (lapic_cyclic_clock_func[cpu] != NULL)
+ (*lapic_cyclic_clock_func[cpu])(frame);
+#endif
+ /* Fire hardclock at hz. */
+ curticks = ticks;
+ last_skip = curticks - la->la_last_tick;
+ la->la_hard_ticks += hz * last_skip;
+ if (la->la_hard_ticks >= lapic_timer_hz * last_skip) {
+ la->la_hard_ticks -= lapic_timer_hz * last_skip;
+ if (PCPU_GET(cpuid) == 0)
+ hardclock_dynticks(TRAPF_USERMODE(frame), TRAPF_PC(frame), last_skip);
+ else
+ hardclock_cpu(TRAPF_USERMODE(frame));
+ }
+
+ /* Fire statclock at stathz. */
+ la->la_stat_ticks += stathz * last_skip;
+ if (la->la_stat_ticks >= lapic_timer_hz * last_skip ) {
+ la->la_stat_ticks -= lapic_timer_hz * last_skip;
+ for( i = 0 ; i < last_skip ; i++ )
+ statclock(TRAPF_USERMODE(frame));
+ }
+
+ /* Fire profclock at profhz, but only when needed. */
+ la->la_prof_ticks += profhz * last_skip;
+ if (la->la_prof_ticks >= lapic_timer_hz * last_skip) {
+ la->la_prof_ticks -= lapic_timer_hz * last_skip;
+ if (profprocs != 0){
+ for( i = 0 ; i < last_skip ; i++ )
+ profclock(TRAPF_USERMODE(frame), TRAPF_PC(frame));
+ }
+ }
+
+ /* get next interrupt time */
+ skip = callout_get_next_event();
+ cnt_to_skip = lapic_timer_period * skip ;
+ lapic_timer_oneshot( cnt_to_skip );
+
+ /* refresh time */
+ la->la_last_tick = curticks;
+
+ critical_exit();
+}
+
+void switch_to_dynticks(void)
+{
+ timer_handler = lapic_handle_timer_dynamically;
+}
+
+void switch_to_perticks(void)
+{
+ timer_handler = __lapic_handle_timer;
+}
diff --git a/sys/kern/kern_clock.c b/sys/kern/kern_clock.c
index 391df1a..7110117 100644
--- a/sys/kern/kern_clock.c
+++ b/sys/kern/kern_clock.c
@@ -323,6 +323,33 @@ hardclock(int usermode, uintfptr_t pc)
#endif /* SW_WATCHDOG */
}
+void
+hardclock_dynticks(int usermode, uintfptr_t pc,int skip)
+{
+ //int i;
+
+ //atomic_add_int((volatile int *)&ticks, skip); // FIXME
+ atomic_add_int((volatile int *)&ticks, 1);
+ hardclock_cpu(usermode);
+ tc_ticktock();
+ /*
+ * If no separate statistics clock is available, run it from here.
+ *
+ * XXX: this only works for UP
+ */
+ if (stathz == 0) {
+ profclock(usermode, pc);
+ statclock(usermode);
+ }
+#ifdef DEVICE_POLLING
+ hardclock_device_poll(); /* this is very short and quick */
+#endif /* DEVICE_POLLING */
+#ifdef SW_WATCHDOG
+ if (watchdog_enabled > 0 && (watchdog_ticks -= skip ) <= 0)
+ watchdog_fire();
+#endif /* SW_WATCHDOG */
+}
+
/*
* Compute number of ticks in the specified amount of time.
*/
diff --git a/sys/kern/kern_timeout.c b/sys/kern/kern_timeout.c
index e853ae9..51919ea 100644
--- a/sys/kern/kern_timeout.c
+++ b/sys/kern/kern_timeout.c
@@ -55,6 +55,7 @@ __FBSDID("$FreeBSD: src/sys/kern/kern_timeout.c,v 1.118.2.1.2.1 2009/10/25 01:10
#include <sys/sleepqueue.h>
#include <sys/sysctl.h>
#include <sys/smp.h>
+#include <sys/dynticks.h>
SDT_PROVIDER_DEFINE(callout_execute);
SDT_PROBE_DEFINE(callout_execute, kernel, , callout_start);
@@ -883,3 +884,32 @@ adjust_timeout_calltodo(time_change)
return;
}
#endif /* APM_FIXUP_CALLTODO */
+
+int
+callout_get_next_event(void)
+{
+ struct callout_cpu *cc;
+ struct callout *c;
+ struct callout_tailq *sc;
+ int curticks;
+ int skip = 1;
+
+ cc = CC_SELF();
+ curticks = cc->cc_softticks;
+
+ while( skip < ncallout ) {
+ sc = &cc->cc_callwheel[ (curticks+skip) & callwheelmask ];
+ /* search scanning ticks */
+ TAILQ_FOREACH( c, sc, c_links.tqe ){
+ if( c && c->c_time <= curticks + ncallout ){
+ if( c->c_time > 0 ){
+ goto out;
+ }
+ }
+ }
+ skip++;
+ }
+
+out:
+ return skip;
+}
diff --git a/sys/sys/dynticks.h b/sys/sys/dynticks.h
new file mode 100644
index 0000000..13220b3
--- /dev/null
+++ b/sys/sys/dynticks.h
@@ -0,0 +1,34 @@
+#ifndef _SYS_DYNTICKS_H_
+#define _SYS_DYNTICKS_H_
+/*-
+ * Copyright (c) 2010 Tsuyoshi OZAWA
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+/* FIXME : */
+int callout_get_next_event(void);
+void switch_to_dynticks(void);
+void switch_to_perticks(void);
+
+#endif /* _SYS_DYNTICKS_H_ */
diff --git a/sys/sys/systm.h b/sys/sys/systm.h
index 543fe60..3d74cae 100644
--- a/sys/sys/systm.h
+++ b/sys/sys/systm.h
@@ -227,6 +227,7 @@ void realitexpire(void *);
int sysbeep(int hertz, int period);
void hardclock(int usermode, uintfptr_t pc);
+void hardclock_dynticks(int usermode, uintfptr_t pc,int skip);
void hardclock_cpu(int usermode);
void softclock(void *);
void statclock(int usermode);
--
1.7.0.3
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment