Created
March 31, 2010 11:58
-
-
Save oza/350230 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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