From: Martin Schwidefsky update_wall_time calls change_clocksource HZ times per second to check if a new clock source is available. In close to 100% of all calls there is no new clock. Replace the tick based check by an update done with stop_machine. Cc: Ingo Molnar Cc: Thomas Gleixner Cc: john stultz Signed-off-by: Martin Schwidefsky --- include/linux/clocksource.h | 2 - kernel/time/clocksource.c | 82 ++++++++++++++++---------------------------- kernel/time/timekeeping.c | 2 - 3 files changed, 31 insertions(+), 55 deletions(-) Index: linux-2.6/include/linux/clocksource.h =================================================================== --- linux-2.6.orig/include/linux/clocksource.h +++ linux-2.6/include/linux/clocksource.h @@ -340,10 +340,8 @@ extern void clocksource_resume(void); #ifdef CONFIG_GENERIC_TIME extern void clocksource_forward_now(void); -extern void change_clocksource(void); #else static inline void clocksource_forward_now(void) { } -static inline void change_clocksource(void) { } #endif #ifdef CONFIG_GENERIC_TIME_VSYSCALL Index: linux-2.6/kernel/time/clocksource.c =================================================================== --- linux-2.6.orig/kernel/time/clocksource.c +++ linux-2.6/kernel/time/clocksource.c @@ -30,6 +30,7 @@ #include #include /* for spin_unlock_irq() using preempt_count() m68k */ #include +#include void timecounter_init(struct timecounter *tc, const struct cyclecounter *cc, @@ -107,46 +108,26 @@ u64 timecounter_cyc2time(struct timecoun } EXPORT_SYMBOL(timecounter_cyc2time); -/* XXX - Would like a better way for initializing curr_clocksource */ +/* XXX - Would like a better way for initializing clock */ extern struct clocksource clocksource_jiffies; /* Currently selected clock source. */ struct clocksource *clock; /*[Clocksource internal variables]--------- - * curr_clocksource: - * currently selected clocksource. Initialized to clocksource_jiffies. - * next_clocksource: - * pending next selected clocksource. * clocksource_list: * linked list with the registered clocksources * clocksource_lock: - * protects manipulations to curr_clocksource and next_clocksource - * and the clocksource_list + * protects manipulations to the clocksource_list * override_name: * Name of the user-specified clocksource. */ -static struct clocksource *curr_clocksource = &clocksource_jiffies; -static struct clocksource *next_clocksource; static struct clocksource *clocksource_override; static LIST_HEAD(clocksource_list); static DEFINE_SPINLOCK(clocksource_lock); static char override_name[32]; static int finished_booting; -/* clocksource_done_booting - Called near the end of core bootup - * - * Hack to avoid lots of clocksource churn at boot time. - * We use fs_initcall because we want this to start before - * device_initcall but after subsys_initcall. - */ -static int __init clocksource_done_booting(void) -{ - finished_booting = 1; - return 0; -} -fs_initcall(clocksource_done_booting); - #ifdef CONFIG_CLOCKSOURCE_WATCHDOG static LIST_HEAD(watchdog_list); static struct clocksource *watchdog; @@ -323,24 +304,6 @@ void clocksource_touch_watchdog(void) clocksource_resume_watchdog(); } -/** - * clocksource_get_next - Returns the selected clocksource - * - */ -struct clocksource *clocksource_get_next(void) -{ - unsigned long flags; - - spin_lock_irqsave(&clocksource_lock, flags); - if (next_clocksource && finished_booting) { - curr_clocksource = next_clocksource; - next_clocksource = NULL; - } - spin_unlock_irqrestore(&clocksource_lock, flags); - - return curr_clocksource; -} - /* * Enqueue the clocksource sorted by rating */ @@ -552,23 +515,22 @@ static struct clocksource *select_clocks } /** - * change_clocksource - Swaps clocksources if a new one is available + * clocksource_swap - Swaps clocksources if a new one is available * * Accumulates current time interval and initializes new clocksource */ -void change_clocksource(void) +static int clocksource_swap(void *dummy) { struct clocksource *new, *old; - new = clocksource_get_next(); - - if (clock == new) - return; + new = select_clocksource(); + if (!new || clock == new) + return 0; clocksource_forward_now(); if (new->enable && !new->enable(new)) - return; + return 0; /* save mult_orig after successful enable */ new->mult_orig = new->mult; @@ -592,6 +554,7 @@ void change_clocksource(void) printk(KERN_INFO "Time: %s clocksource has been installed.\n", clock->name); */ + return 0; } /** @@ -602,11 +565,13 @@ static void clocksource_update(void) struct clocksource *new; unsigned long flags; + if (!finished_booting) + return; spin_lock_irqsave(&clocksource_lock, flags); new = select_clocksource(); - if (new) - next_clocksource = new; spin_unlock_irqrestore(&clocksource_lock, flags); + if (new && new != clock) + stop_machine(clocksource_swap, NULL, NULL); } #else /* CONFIG_GENERIC_TIME */ static inline void clocksource_update(void) { } @@ -657,7 +622,7 @@ void clocksource_unregister(struct clock */ void __init clocksource_init(void) { - clock = clocksource_get_next(); + clock = &clocksource_jiffies; if (clock->enable) clock->enable(clock); /* save mult_orig on enable */ @@ -666,6 +631,21 @@ void __init clocksource_init(void) clock->cycle_last = clock->read(clock); } +/** + * clocksource_done_booting - Called near the end of core bootup + * + * Hack to avoid lots of clocksource churn at boot time. + * We use fs_initcall because we want this to start before + * device_initcall but after subsys_initcall. + */ +static int __init clocksource_done_booting(void) +{ + finished_booting = 1; + clocksource_update(); + return 0; +} +fs_initcall(clocksource_done_booting); + #ifdef CONFIG_SYSFS /** * sysfs_show_current_clocksources - sysfs interface for current clocksource @@ -681,7 +661,7 @@ sysfs_show_current_clocksources(struct s ssize_t count = 0; spin_lock_irq(&clocksource_lock); - count = snprintf(buf, PAGE_SIZE, "%s\n", curr_clocksource->name); + count = snprintf(buf, PAGE_SIZE, "%s\n", clock->name); spin_unlock_irq(&clocksource_lock); return count; Index: linux-2.6/kernel/time/timekeeping.c =================================================================== --- linux-2.6.orig/kernel/time/timekeeping.c +++ linux-2.6/kernel/time/timekeeping.c @@ -491,8 +491,6 @@ void update_wall_time(void) update_xtime_cache(cyc2ns(clock, offset)); - /* check to see if there is a new clocksource to use */ - change_clocksource(); update_vsyscall(&xtime, clock); } -- blue skies, Martin. "Reality continues to ruin my life." - Calvin. -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/