diff options
| author | Thomas Gleixner <tglx@linutronix.de> | 2007-02-16 04:28:03 -0500 |
|---|---|---|
| committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-02-16 11:13:59 -0500 |
| commit | 79bf2bb335b85db25d27421c798595a2fa2a0e82 (patch) | |
| tree | 550ec2654ae1dd65b871de7fe9c890108c6e86d8 /kernel | |
| parent | f8381cba04ba8173fd5a2b8e5cd8b3290ee13a98 (diff) | |
[PATCH] tick-management: dyntick / highres functionality
With Ingo Molnar <mingo@elte.hu>
Add functions to provide dynamic ticks and high resolution timers. The code
which keeps track of jiffies and handles the long idle periods is shared
between tick based and high resolution timer based dynticks. The dyntick
functionality can be disabled on the kernel commandline. Provide also the
infrastructure to support high resolution timers.
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Cc: john stultz <johnstul@us.ibm.com>
Cc: Roman Zippel <zippel@linux-m68k.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'kernel')
| -rw-r--r-- | kernel/hrtimer.c | 20 | ||||
| -rw-r--r-- | kernel/softirq.c | 15 | ||||
| -rw-r--r-- | kernel/time/Kconfig | 15 | ||||
| -rw-r--r-- | kernel/time/Makefile | 2 | ||||
| -rw-r--r-- | kernel/time/clocksource.c | 8 | ||||
| -rw-r--r-- | kernel/time/tick-broadcast.c | 191 | ||||
| -rw-r--r-- | kernel/time/tick-common.c | 26 | ||||
| -rw-r--r-- | kernel/time/tick-internal.h | 49 | ||||
| -rw-r--r-- | kernel/time/tick-oneshot.c | 84 | ||||
| -rw-r--r-- | kernel/time/tick-sched.c | 558 | ||||
| -rw-r--r-- | kernel/timer.c | 5 |
11 files changed, 959 insertions, 14 deletions
diff --git a/kernel/hrtimer.c b/kernel/hrtimer.c index a2310d1bebe1..e04ef38ea3be 100644 --- a/kernel/hrtimer.c +++ b/kernel/hrtimer.c | |||
| @@ -2,8 +2,8 @@ | |||
| 2 | * linux/kernel/hrtimer.c | 2 | * linux/kernel/hrtimer.c |
| 3 | * | 3 | * |
| 4 | * Copyright(C) 2005-2006, Thomas Gleixner <tglx@linutronix.de> | 4 | * Copyright(C) 2005-2006, Thomas Gleixner <tglx@linutronix.de> |
| 5 | * Copyright(C) 2005-2006, Red Hat, Inc., Ingo Molnar | 5 | * Copyright(C) 2005-2007, Red Hat, Inc., Ingo Molnar |
| 6 | * Copyright(C) 2006 Timesys Corp., Thomas Gleixner <tglx@timesys.com> | 6 | * Copyright(C) 2006-2007 Timesys Corp., Thomas Gleixner <tglx@timesys.com> |
| 7 | * | 7 | * |
| 8 | * High-resolution kernel timers | 8 | * High-resolution kernel timers |
| 9 | * | 9 | * |
| @@ -38,6 +38,7 @@ | |||
| 38 | #include <linux/notifier.h> | 38 | #include <linux/notifier.h> |
| 39 | #include <linux/syscalls.h> | 39 | #include <linux/syscalls.h> |
| 40 | #include <linux/interrupt.h> | 40 | #include <linux/interrupt.h> |
| 41 | #include <linux/tick.h> | ||
| 41 | 42 | ||
| 42 | #include <asm/uaccess.h> | 43 | #include <asm/uaccess.h> |
| 43 | 44 | ||
| @@ -288,7 +289,7 @@ ktime_t ktime_add_ns(const ktime_t kt, u64 nsec) | |||
| 288 | /* | 289 | /* |
| 289 | * Divide a ktime value by a nanosecond value | 290 | * Divide a ktime value by a nanosecond value |
| 290 | */ | 291 | */ |
| 291 | static unsigned long ktime_divns(const ktime_t kt, s64 div) | 292 | unsigned long ktime_divns(const ktime_t kt, s64 div) |
| 292 | { | 293 | { |
| 293 | u64 dclc, inc, dns; | 294 | u64 dclc, inc, dns; |
| 294 | int sft = 0; | 295 | int sft = 0; |
| @@ -305,9 +306,6 @@ static unsigned long ktime_divns(const ktime_t kt, s64 div) | |||
| 305 | 306 | ||
| 306 | return (unsigned long) dclc; | 307 | return (unsigned long) dclc; |
| 307 | } | 308 | } |
| 308 | |||
| 309 | #else /* BITS_PER_LONG < 64 */ | ||
| 310 | # define ktime_divns(kt, div) (unsigned long)((kt).tv64 / (div)) | ||
| 311 | #endif /* BITS_PER_LONG >= 64 */ | 309 | #endif /* BITS_PER_LONG >= 64 */ |
| 312 | 310 | ||
| 313 | /* | 311 | /* |
| @@ -682,6 +680,16 @@ void hrtimer_run_queues(void) | |||
| 682 | struct hrtimer_cpu_base *cpu_base = &__get_cpu_var(hrtimer_bases); | 680 | struct hrtimer_cpu_base *cpu_base = &__get_cpu_var(hrtimer_bases); |
| 683 | int i; | 681 | int i; |
| 684 | 682 | ||
| 683 | /* | ||
| 684 | * This _is_ ugly: We have to check in the softirq context, | ||
| 685 | * whether we can switch to highres and / or nohz mode. The | ||
| 686 | * clocksource switch happens in the timer interrupt with | ||
| 687 | * xtime_lock held. Notification from there only sets the | ||
| 688 | * check bit in the tick_oneshot code, otherwise we might | ||
| 689 | * deadlock vs. xtime_lock. | ||
| 690 | */ | ||
| 691 | tick_check_oneshot_change(1); | ||
| 692 | |||
| 685 | hrtimer_get_softirq_time(cpu_base); | 693 | hrtimer_get_softirq_time(cpu_base); |
| 686 | 694 | ||
| 687 | for (i = 0; i < HRTIMER_MAX_CLOCK_BASES; i++) | 695 | for (i = 0; i < HRTIMER_MAX_CLOCK_BASES; i++) |
diff --git a/kernel/softirq.c b/kernel/softirq.c index 14e1a14f94d2..8b75008e2bd8 100644 --- a/kernel/softirq.c +++ b/kernel/softirq.c | |||
| @@ -17,6 +17,7 @@ | |||
| 17 | #include <linux/kthread.h> | 17 | #include <linux/kthread.h> |
| 18 | #include <linux/rcupdate.h> | 18 | #include <linux/rcupdate.h> |
| 19 | #include <linux/smp.h> | 19 | #include <linux/smp.h> |
| 20 | #include <linux/tick.h> | ||
| 20 | 21 | ||
| 21 | #include <asm/irq.h> | 22 | #include <asm/irq.h> |
| 22 | /* | 23 | /* |
| @@ -278,9 +279,11 @@ EXPORT_SYMBOL(do_softirq); | |||
| 278 | */ | 279 | */ |
| 279 | void irq_enter(void) | 280 | void irq_enter(void) |
| 280 | { | 281 | { |
| 281 | account_system_vtime(current); | 282 | __irq_enter(); |
| 282 | add_preempt_count(HARDIRQ_OFFSET); | 283 | #ifdef CONFIG_NO_HZ |
| 283 | trace_hardirq_enter(); | 284 | if (idle_cpu(smp_processor_id())) |
| 285 | tick_nohz_update_jiffies(); | ||
| 286 | #endif | ||
| 284 | } | 287 | } |
| 285 | 288 | ||
| 286 | #ifdef __ARCH_IRQ_EXIT_IRQS_DISABLED | 289 | #ifdef __ARCH_IRQ_EXIT_IRQS_DISABLED |
| @@ -299,6 +302,12 @@ void irq_exit(void) | |||
| 299 | sub_preempt_count(IRQ_EXIT_OFFSET); | 302 | sub_preempt_count(IRQ_EXIT_OFFSET); |
| 300 | if (!in_interrupt() && local_softirq_pending()) | 303 | if (!in_interrupt() && local_softirq_pending()) |
| 301 | invoke_softirq(); | 304 | invoke_softirq(); |
| 305 | |||
| 306 | #ifdef CONFIG_NO_HZ | ||
| 307 | /* Make sure that timer wheel updates are propagated */ | ||
| 308 | if (!in_interrupt() && idle_cpu(smp_processor_id()) && !need_resched()) | ||
| 309 | tick_nohz_stop_sched_tick(); | ||
| 310 | #endif | ||
| 302 | preempt_enable_no_resched(); | 311 | preempt_enable_no_resched(); |
| 303 | } | 312 | } |
| 304 | 313 | ||
diff --git a/kernel/time/Kconfig b/kernel/time/Kconfig new file mode 100644 index 000000000000..9ec54eb3667f --- /dev/null +++ b/kernel/time/Kconfig | |||
| @@ -0,0 +1,15 @@ | |||
| 1 | # | ||
| 2 | # Timer subsystem related configuration options | ||
| 3 | # | ||
| 4 | config TICK_ONESHOT | ||
| 5 | bool | ||
| 6 | default n | ||
| 7 | |||
| 8 | config NO_HZ | ||
| 9 | bool "Tickless System (Dynamic Ticks)" | ||
| 10 | depends on GENERIC_TIME && GENERIC_CLOCKEVENTS | ||
| 11 | select TICK_ONESHOT | ||
| 12 | help | ||
| 13 | This option enables a tickless system: timer interrupts will | ||
| 14 | only trigger on an as-needed basis both when the system is | ||
| 15 | busy and when the system is idle. | ||
diff --git a/kernel/time/Makefile b/kernel/time/Makefile index a941743c3ff8..f246bc836b9a 100644 --- a/kernel/time/Makefile +++ b/kernel/time/Makefile | |||
| @@ -3,3 +3,5 @@ obj-y += ntp.o clocksource.o jiffies.o | |||
| 3 | obj-$(CONFIG_GENERIC_CLOCKEVENTS) += clockevents.o | 3 | obj-$(CONFIG_GENERIC_CLOCKEVENTS) += clockevents.o |
| 4 | obj-$(CONFIG_GENERIC_CLOCKEVENTS) += tick-common.o | 4 | obj-$(CONFIG_GENERIC_CLOCKEVENTS) += tick-common.o |
| 5 | obj-$(CONFIG_GENERIC_CLOCKEVENTS_BROADCAST) += tick-broadcast.o | 5 | obj-$(CONFIG_GENERIC_CLOCKEVENTS_BROADCAST) += tick-broadcast.o |
| 6 | obj-$(CONFIG_TICK_ONESHOT) += tick-oneshot.o | ||
| 7 | obj-$(CONFIG_TICK_ONESHOT) += tick-sched.o | ||
diff --git a/kernel/time/clocksource.c b/kernel/time/clocksource.c index 3cb8ac978270..193a0793af95 100644 --- a/kernel/time/clocksource.c +++ b/kernel/time/clocksource.c | |||
| @@ -29,6 +29,7 @@ | |||
| 29 | #include <linux/init.h> | 29 | #include <linux/init.h> |
| 30 | #include <linux/module.h> | 30 | #include <linux/module.h> |
| 31 | #include <linux/sched.h> /* for spin_unlock_irq() using preempt_count() m68k */ | 31 | #include <linux/sched.h> /* for spin_unlock_irq() using preempt_count() m68k */ |
| 32 | #include <linux/tick.h> | ||
| 32 | 33 | ||
| 33 | /* XXX - Would like a better way for initializing curr_clocksource */ | 34 | /* XXX - Would like a better way for initializing curr_clocksource */ |
| 34 | extern struct clocksource clocksource_jiffies; | 35 | extern struct clocksource clocksource_jiffies; |
| @@ -109,6 +110,13 @@ static void clocksource_watchdog(unsigned long data) | |||
| 109 | if ((cs->flags & CLOCK_SOURCE_IS_CONTINUOUS) && | 110 | if ((cs->flags & CLOCK_SOURCE_IS_CONTINUOUS) && |
| 110 | (watchdog->flags & CLOCK_SOURCE_IS_CONTINUOUS)) { | 111 | (watchdog->flags & CLOCK_SOURCE_IS_CONTINUOUS)) { |
| 111 | cs->flags |= CLOCK_SOURCE_VALID_FOR_HRES; | 112 | cs->flags |= CLOCK_SOURCE_VALID_FOR_HRES; |
| 113 | /* | ||
| 114 | * We just marked the clocksource as | ||
| 115 | * highres-capable, notify the rest of the | ||
| 116 | * system as well so that we transition | ||
| 117 | * into high-res mode: | ||
| 118 | */ | ||
| 119 | tick_clock_notify(); | ||
| 112 | } | 120 | } |
| 113 | cs->flags |= CLOCK_SOURCE_WATCHDOG; | 121 | cs->flags |= CLOCK_SOURCE_WATCHDOG; |
| 114 | cs->wd_last = csnow; | 122 | cs->wd_last = csnow; |
diff --git a/kernel/time/tick-broadcast.c b/kernel/time/tick-broadcast.c index 0ee4968ff791..8314ecb32d33 100644 --- a/kernel/time/tick-broadcast.c +++ b/kernel/time/tick-broadcast.c | |||
| @@ -29,7 +29,7 @@ | |||
| 29 | 29 | ||
| 30 | struct tick_device tick_broadcast_device; | 30 | struct tick_device tick_broadcast_device; |
| 31 | static cpumask_t tick_broadcast_mask; | 31 | static cpumask_t tick_broadcast_mask; |
| 32 | DEFINE_SPINLOCK(tick_broadcast_lock); | 32 | static DEFINE_SPINLOCK(tick_broadcast_lock); |
| 33 | 33 | ||
| 34 | /* | 34 | /* |
| 35 | * Start the device in periodic mode | 35 | * Start the device in periodic mode |
| @@ -215,6 +215,8 @@ static void tick_do_broadcast_on_off(void *why) | |||
| 215 | else { | 215 | else { |
