* [PATCH 1/2] Dynamic Tick: Prevent clocksource wrapping during idle
@ 2009-05-27 14:49 Jon Hunter
2009-05-27 16:01 ` Thomas Gleixner
` (2 more replies)
0 siblings, 3 replies; 20+ messages in thread
From: Jon Hunter @ 2009-05-27 14:49 UTC (permalink / raw)
To: linux-kernel@vger.kernel.org; +Cc: john stultz, Thomas Gleixner, Ingo Molnar
The dynamic tick allows the kernel to sleep for periods longer than a
single tick. This patch prevents that the kernel from sleeping for a
period longer than the maximum time that the current clocksource can
count. This ensures that the kernel will not lose track of time. This
patch adds a new function called "timekeeping_max_deferment()" that
calculates the maximum time the kernel can sleep for a given clocksource.
Signed-off-by: Jon Hunter <jon-hunter@ti.com>
---
include/linux/time.h | 1 +
kernel/time/tick-sched.c | 36 +++++++++++++++++++++++----------
kernel/time/timekeeping.c | 47
+++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 73 insertions(+), 11 deletions(-)
diff --git a/include/linux/time.h b/include/linux/time.h
index 242f624..090be07 100644
--- a/include/linux/time.h
+++ b/include/linux/time.h
@@ -130,6 +130,7 @@ extern void monotonic_to_bootbased(struct timespec *ts);
extern struct timespec timespec_trunc(struct timespec t, unsigned gran);
extern int timekeeping_valid_for_hres(void);
+extern s64 timekeeping_max_deferment(void);
extern void update_wall_time(void);
extern void update_xtime_cache(u64 nsec);
diff --git a/kernel/time/tick-sched.c b/kernel/time/tick-sched.c
index d3f1ef4..f0155ae 100644
--- a/kernel/time/tick-sched.c
+++ b/kernel/time/tick-sched.c
@@ -217,6 +217,7 @@ void tick_nohz_stop_sched_tick(int inidle)
ktime_t last_update, expires, now;
struct clock_event_device *dev = __get_cpu_var(tick_cpu_device).evtdev;
int cpu;
+ s64 time_delta, max_time_delta;
local_irq_save(flags);
@@ -264,6 +265,7 @@ void tick_nohz_stop_sched_tick(int inidle)
seq = read_seqbegin(&xtime_lock);
last_update = last_jiffies_update;
last_jiffies = jiffies;
+ max_time_delta = timekeeping_max_deferment();
} while (read_seqretry(&xtime_lock, seq));
/* Get the next timer wheel timer */
@@ -283,11 +285,22 @@ void tick_nohz_stop_sched_tick(int inidle)
if ((long)delta_jiffies >= 1) {
/*
- * calculate the expiry time for the next timer wheel
- * timer
- */
- expires = ktime_add_ns(last_update, tick_period.tv64 *
- delta_jiffies);
+ * Calculate the time delta for the next timer event.
+ * If the time delta exceeds the maximum time delta
+ * permitted by the current clocksource then adjust
+ * the time delta accordingly to ensure the
+ * clocksource does not wrap.
+ */
+ time_delta = tick_period.tv64 * delta_jiffies;
+
+ if (time_delta > max_time_delta)
+ time_delta = max_time_delta;
+
+ /*
+ * calculate the expiry time for the next timer wheel
+ * timer
+ */
+ expires = ktime_add_ns(last_update, time_delta);
/*
* If this cpu is the one which updates jiffies, then
@@ -300,7 +313,7 @@ void tick_nohz_stop_sched_tick(int inidle)
if (cpu == tick_do_timer_cpu)
tick_do_timer_cpu = TICK_DO_TIMER_NONE;
- if (delta_jiffies > 1)
+ if (time_delta > tick_period.tv64)
cpumask_set_cpu(cpu, nohz_cpu_mask);
/* Skip reprogram of event if its not changed */
@@ -332,12 +345,13 @@ void tick_nohz_stop_sched_tick(int inidle)
ts->idle_sleeps++;
/*
- * delta_jiffies >= NEXT_TIMER_MAX_DELTA signals that
- * there is no timer pending or at least extremly far
- * into the future (12 days for HZ=1000). In this case
- * we simply stop the tick timer:
+ * time_delta >= (tick_period.tv64 * NEXT_TIMER_MAX_DELTA)
+ * signals that there is no timer pending or at least
+ * extremely far into the future (12 days for HZ=1000).
+ * In this case we simply stop the tick timer:
*/
- if (unlikely(delta_jiffies >= NEXT_TIMER_MAX_DELTA)) {
+ if (unlikely(time_delta >=
+ (tick_period.tv64 * NEXT_TIMER_MAX_DELTA))) {
ts->idle_expires.tv64 = KTIME_MAX;
if (ts->nohz_mode == NOHZ_MODE_HIGHRES)
hrtimer_cancel(&ts->sched_timer);
diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c
index 687dff4..608fc6f 100644
--- a/kernel/time/timekeeping.c
+++ b/kernel/time/timekeeping.c
@@ -271,6 +271,53 @@ int timekeeping_valid_for_hres(void)
}
/**
+ * timekeeping_max_deferment - Returns max time the clocksource can be
deferred
+ *
+ * IMPORTANT: Must be called with xtime_lock held!
+ */
+s64 timekeeping_max_deferment(void)
+{
+ s64 max_nsecs;
+ u64 max_cycles;
+
+ /*
+ * Calculate the maximum number of cycles that we can pass to the
+ * cyc2ns function without overflowing a 64-bit signed result. The
+ * maximum number of cycles is equal to ULLONG_MAX/clock->mult which
+ * is equivalent to the below.
+ * max_cycles < (2^63)/clock->mult
+ * max_cycles < 2^(log2((2^63)/clock->mult))
+ * max_cycles < 2^(log2(2^63) - log2(clock->mult))
+ * max_cycles < 2^(63 - log2(clock->mult))
+ * max_cycles < 1 << (63 - log2(clock->mult))
+ * Please note that we add 1 to the result of the log2 to account for
+ * any rounding errors, ensure the above inequality is satisfied and
+ * no overflow will occur.
+ */
+ max_cycles = 1ULL << (63 - (ilog2(clock->mult) + 1));
+
+ /*
+ * The actual maximum number of cycles we can defer the clocksource is
+ * determined by the minimum of max_cycles and clock->mask.
+ */
+ max_cycles = min(max_cycles, clock->mask);
+ max_nsecs = cyc2ns(clock, max_cycles);
+
+ /*
+ * To ensure that the clocksource does not wrap whilst we are idle,
+ * limit the time the clocksource can be deferred by 6.25%. Please
+ * note a margin of 6.25% is used because this can be computed with
+ * a shift, versus say 5% which would require division.
+ */
+ max_nsecs = max_nsecs - (max_nsecs >> 4);
+
+ if (max_nsecs < 0)
+ max_nsecs = 0;
+
+ return max_nsecs;
+}
+
+/**
* read_persistent_clock - Return time in seconds from the persistent
clock.
*
* Weak dummy function for arches that do not yet support it.
--
1.6.1
^ permalink raw reply related [flat|nested] 20+ messages in thread
* Re: [PATCH 1/2] Dynamic Tick: Prevent clocksource wrapping during idle
2009-05-27 14:49 [PATCH 1/2] Dynamic Tick: Prevent clocksource wrapping during idle Jon Hunter
@ 2009-05-27 16:01 ` Thomas Gleixner
2009-05-27 20:20 ` john stultz
2009-05-27 18:15 ` john stultz
2009-05-27 20:54 ` Alok Kataria
2 siblings, 1 reply; 20+ messages in thread
From: Thomas Gleixner @ 2009-05-27 16:01 UTC (permalink / raw)
To: Jon Hunter; +Cc: linux-kernel@vger.kernel.org, john stultz, Ingo Molnar
On Wed, 27 May 2009, Jon Hunter wrote:
> /**
> + * timekeeping_max_deferment - Returns max time the clocksource can be
> deferred
> + *
> + * IMPORTANT: Must be called with xtime_lock held!
No, that would mean that xtime_lock needs to be write locked. And we
definitely do not want that.
The caller needs to observe xtime_lock via read_seqbegin /
read_seqretry because clock might change.
> + */
> +s64 timekeeping_max_deferment(void)
> +{
> + s64 max_nsecs;
> + u64 max_cycles;
> +
> + /*
> + * Calculate the maximum number of cycles that we can pass to the
> + * cyc2ns function without overflowing a 64-bit signed result. The
> + * maximum number of cycles is equal to ULLONG_MAX/clock->mult which
> + * is equivalent to the below.
> + * max_cycles < (2^63)/clock->mult
> + * max_cycles < 2^(log2((2^63)/clock->mult))
> + * max_cycles < 2^(log2(2^63) - log2(clock->mult))
> + * max_cycles < 2^(63 - log2(clock->mult))
> + * max_cycles < 1 << (63 - log2(clock->mult))
> + * Please note that we add 1 to the result of the log2 to account for
> + * any rounding errors, ensure the above inequality is satisfied and
> + * no overflow will occur.
> + */
> + max_cycles = 1ULL << (63 - (ilog2(clock->mult) + 1));
> +
> + /*
> + * The actual maximum number of cycles we can defer the clocksource is
> + * determined by the minimum of max_cycles and clock->mask.
> + */
> + max_cycles = min(max_cycles, clock->mask);
> + max_nsecs = cyc2ns(clock, max_cycles);
Why do you want to recalculate the whole stuff over and over ?
That computation can be done when the clock source is initialized or
any fundamental change of the clock parameters happens.
Stick that value into the clocksource struct and just read it out.
> + /*
> + * To ensure that the clocksource does not wrap whilst we are idle,
> + * limit the time the clocksource can be deferred by 6.25%. Please
> + * note a margin of 6.25% is used because this can be computed with
> + * a shift, versus say 5% which would require division.
> + */
> + max_nsecs = max_nsecs - (max_nsecs >> 4);
> +
> + if (max_nsecs < 0)
> + max_nsecs = 0;
How does "max_nsecs = max_nsecs - (max_nsecs >> 4)" ever become
negative ?
Thanks,
tglx
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH 1/2] Dynamic Tick: Prevent clocksource wrapping during idle
2009-05-27 14:49 [PATCH 1/2] Dynamic Tick: Prevent clocksource wrapping during idle Jon Hunter
2009-05-27 16:01 ` Thomas Gleixner
@ 2009-05-27 18:15 ` john stultz
2009-05-27 20:54 ` Alok Kataria
2 siblings, 0 replies; 20+ messages in thread
From: john stultz @ 2009-05-27 18:15 UTC (permalink / raw)
To: Jon Hunter; +Cc: linux-kernel@vger.kernel.org, Thomas Gleixner, Ingo Molnar
On Wed, 2009-05-27 at 09:49 -0500, Jon Hunter wrote:
> The dynamic tick allows the kernel to sleep for periods longer than a
> single tick. This patch prevents that the kernel from sleeping for a
> period longer than the maximum time that the current clocksource can
> count. This ensures that the kernel will not lose track of time. This
> patch adds a new function called "timekeeping_max_deferment()" that
> calculates the maximum time the kernel can sleep for a given clocksource.
>
> Signed-off-by: Jon Hunter <jon-hunter@ti.com>
Acked-by: John Stultz <johnstul@us.ibm.com>
> ---
> include/linux/time.h | 1 +
> kernel/time/tick-sched.c | 36 +++++++++++++++++++++++----------
> kernel/time/timekeeping.c | 47
> +++++++++++++++++++++++++++++++++++++++++++++
> 3 files changed, 73 insertions(+), 11 deletions(-)
>
> diff --git a/include/linux/time.h b/include/linux/time.h
> index 242f624..090be07 100644
> --- a/include/linux/time.h
> +++ b/include/linux/time.h
> @@ -130,6 +130,7 @@ extern void monotonic_to_bootbased(struct timespec *ts);
>
> extern struct timespec timespec_trunc(struct timespec t, unsigned gran);
> extern int timekeeping_valid_for_hres(void);
> +extern s64 timekeeping_max_deferment(void);
> extern void update_wall_time(void);
> extern void update_xtime_cache(u64 nsec);
>
> diff --git a/kernel/time/tick-sched.c b/kernel/time/tick-sched.c
> index d3f1ef4..f0155ae 100644
> --- a/kernel/time/tick-sched.c
> +++ b/kernel/time/tick-sched.c
> @@ -217,6 +217,7 @@ void tick_nohz_stop_sched_tick(int inidle)
> ktime_t last_update, expires, now;
> struct clock_event_device *dev = __get_cpu_var(tick_cpu_device).evtdev;
> int cpu;
> + s64 time_delta, max_time_delta;
>
> local_irq_save(flags);
>
> @@ -264,6 +265,7 @@ void tick_nohz_stop_sched_tick(int inidle)
> seq = read_seqbegin(&xtime_lock);
> last_update = last_jiffies_update;
> last_jiffies = jiffies;
> + max_time_delta = timekeeping_max_deferment();
> } while (read_seqretry(&xtime_lock, seq));
>
> /* Get the next timer wheel timer */
> @@ -283,11 +285,22 @@ void tick_nohz_stop_sched_tick(int inidle)
> if ((long)delta_jiffies >= 1) {
>
> /*
> - * calculate the expiry time for the next timer wheel
> - * timer
> - */
> - expires = ktime_add_ns(last_update, tick_period.tv64 *
> - delta_jiffies);
> + * Calculate the time delta for the next timer event.
> + * If the time delta exceeds the maximum time delta
> + * permitted by the current clocksource then adjust
> + * the time delta accordingly to ensure the
> + * clocksource does not wrap.
> + */
> + time_delta = tick_period.tv64 * delta_jiffies;
> +
> + if (time_delta > max_time_delta)
> + time_delta = max_time_delta;
> +
> + /*
> + * calculate the expiry time for the next timer wheel
> + * timer
> + */
> + expires = ktime_add_ns(last_update, time_delta);
>
> /*
> * If this cpu is the one which updates jiffies, then
> @@ -300,7 +313,7 @@ void tick_nohz_stop_sched_tick(int inidle)
> if (cpu == tick_do_timer_cpu)
> tick_do_timer_cpu = TICK_DO_TIMER_NONE;
>
> - if (delta_jiffies > 1)
> + if (time_delta > tick_period.tv64)
> cpumask_set_cpu(cpu, nohz_cpu_mask);
>
> /* Skip reprogram of event if its not changed */
> @@ -332,12 +345,13 @@ void tick_nohz_stop_sched_tick(int inidle)
> ts->idle_sleeps++;
>
> /*
> - * delta_jiffies >= NEXT_TIMER_MAX_DELTA signals that
> - * there is no timer pending or at least extremly far
> - * into the future (12 days for HZ=1000). In this case
> - * we simply stop the tick timer:
> + * time_delta >= (tick_period.tv64 * NEXT_TIMER_MAX_DELTA)
> + * signals that there is no timer pending or at least
> + * extremely far into the future (12 days for HZ=1000).
> + * In this case we simply stop the tick timer:
> */
> - if (unlikely(delta_jiffies >= NEXT_TIMER_MAX_DELTA)) {
> + if (unlikely(time_delta >=
> + (tick_period.tv64 * NEXT_TIMER_MAX_DELTA))) {
> ts->idle_expires.tv64 = KTIME_MAX;
> if (ts->nohz_mode == NOHZ_MODE_HIGHRES)
> hrtimer_cancel(&ts->sched_timer);
> diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c
> index 687dff4..608fc6f 100644
> --- a/kernel/time/timekeeping.c
> +++ b/kernel/time/timekeeping.c
> @@ -271,6 +271,53 @@ int timekeeping_valid_for_hres(void)
> }
>
> /**
> + * timekeeping_max_deferment - Returns max time the clocksource can be
> deferred
> + *
> + * IMPORTANT: Must be called with xtime_lock held!
> + */
> +s64 timekeeping_max_deferment(void)
> +{
> + s64 max_nsecs;
> + u64 max_cycles;
> +
> + /*
> + * Calculate the maximum number of cycles that we can pass to the
> + * cyc2ns function without overflowing a 64-bit signed result. The
> + * maximum number of cycles is equal to ULLONG_MAX/clock->mult which
> + * is equivalent to the below.
> + * max_cycles < (2^63)/clock->mult
> + * max_cycles < 2^(log2((2^63)/clock->mult))
> + * max_cycles < 2^(log2(2^63) - log2(clock->mult))
> + * max_cycles < 2^(63 - log2(clock->mult))
> + * max_cycles < 1 << (63 - log2(clock->mult))
> + * Please note that we add 1 to the result of the log2 to account for
> + * any rounding errors, ensure the above inequality is satisfied and
> + * no overflow will occur.
> + */
> + max_cycles = 1ULL << (63 - (ilog2(clock->mult) + 1));
> +
> + /*
> + * The actual maximum number of cycles we can defer the clocksource is
> + * determined by the minimum of max_cycles and clock->mask.
> + */
> + max_cycles = min(max_cycles, clock->mask);
> + max_nsecs = cyc2ns(clock, max_cycles);
> +
> + /*
> + * To ensure that the clocksource does not wrap whilst we are idle,
> + * limit the time the clocksource can be deferred by 6.25%. Please
> + * note a margin of 6.25% is used because this can be computed with
> + * a shift, versus say 5% which would require division.
> + */
> + max_nsecs = max_nsecs - (max_nsecs >> 4);
> +
> + if (max_nsecs < 0)
> + max_nsecs = 0;
> +
> + return max_nsecs;
> +}
> +
> +/**
> * read_persistent_clock - Return time in seconds from the persistent
> clock.
> *
> * Weak dummy function for arches that do not yet support it.
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH 1/2] Dynamic Tick: Prevent clocksource wrapping during idle
2009-05-27 16:01 ` Thomas Gleixner
@ 2009-05-27 20:20 ` john stultz
2009-05-27 20:32 ` Thomas Gleixner
0 siblings, 1 reply; 20+ messages in thread
From: john stultz @ 2009-05-27 20:20 UTC (permalink / raw)
To: Thomas Gleixner; +Cc: Jon Hunter, linux-kernel@vger.kernel.org, Ingo Molnar
On Wed, 2009-05-27 at 18:01 +0200, Thomas Gleixner wrote:
> On Wed, 27 May 2009, Jon Hunter wrote:
> > + */
> > +s64 timekeeping_max_deferment(void)
> > +{
> > + s64 max_nsecs;
> > + u64 max_cycles;
> > +
> > + /*
> > + * Calculate the maximum number of cycles that we can pass to the
> > + * cyc2ns function without overflowing a 64-bit signed result. The
> > + * maximum number of cycles is equal to ULLONG_MAX/clock->mult which
> > + * is equivalent to the below.
> > + * max_cycles < (2^63)/clock->mult
> > + * max_cycles < 2^(log2((2^63)/clock->mult))
> > + * max_cycles < 2^(log2(2^63) - log2(clock->mult))
> > + * max_cycles < 2^(63 - log2(clock->mult))
> > + * max_cycles < 1 << (63 - log2(clock->mult))
> > + * Please note that we add 1 to the result of the log2 to account for
> > + * any rounding errors, ensure the above inequality is satisfied and
> > + * no overflow will occur.
> > + */
> > + max_cycles = 1ULL << (63 - (ilog2(clock->mult) + 1));
> > +
> > + /*
> > + * The actual maximum number of cycles we can defer the clocksource is
> > + * determined by the minimum of max_cycles and clock->mask.
> > + */
> > + max_cycles = min(max_cycles, clock->mask);
> > + max_nsecs = cyc2ns(clock, max_cycles);
>
> Why do you want to recalculate the whole stuff over and over ?
>
> That computation can be done when the clock source is initialized or
> any fundamental change of the clock parameters happens.
>
> Stick that value into the clocksource struct and just read it out.
Sigh.
I was hoping to avoid hanging another bit of junk off of the clocksource
struct.
But I guess we could compute that value on registration and keep it
around. Changes to mult could effect things, but should be well within
the 6% safety net we give ourselves.
> > + /*
> > + * To ensure that the clocksource does not wrap whilst we are idle,
> > + * limit the time the clocksource can be deferred by 6.25%. Please
> > + * note a margin of 6.25% is used because this can be computed with
> > + * a shift, versus say 5% which would require division.
> > + */
> > + max_nsecs = max_nsecs - (max_nsecs >> 4);
> > +
> > + if (max_nsecs < 0)
> > + max_nsecs = 0;
>
> How does "max_nsecs = max_nsecs - (max_nsecs >> 4)" ever become
> negative ?
Fair point. Now we've limited the overflow case, we shouldn't trip
negative values.
thanks
-john
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH 1/2] Dynamic Tick: Prevent clocksource wrapping during idle
2009-05-27 20:20 ` john stultz
@ 2009-05-27 20:32 ` Thomas Gleixner
2009-05-28 20:21 ` Jon Hunter
0 siblings, 1 reply; 20+ messages in thread
From: Thomas Gleixner @ 2009-05-27 20:32 UTC (permalink / raw)
To: john stultz; +Cc: Jon Hunter, linux-kernel@vger.kernel.org, Ingo Molnar
On Wed, 27 May 2009, john stultz wrote:
> > Why do you want to recalculate the whole stuff over and over ?
> >
> > That computation can be done when the clock source is initialized or
> > any fundamental change of the clock parameters happens.
> >
> > Stick that value into the clocksource struct and just read it out.
>
> Sigh.
>
> I was hoping to avoid hanging another bit of junk off of the clocksource
> struct.
Sure, but buying that 8 bytes with Einsteinian insanity is nuts.
> But I guess we could compute that value on registration and keep it
> around. Changes to mult could effect things, but should be well within
> the 6% safety net we give ourselves.
That was my thought as well, but even if we have to go to 12% it's way
better than doing repeated nonsense on the way to idle.
Thanks,
tglx
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH 1/2] Dynamic Tick: Prevent clocksource wrapping during idle
2009-05-27 14:49 [PATCH 1/2] Dynamic Tick: Prevent clocksource wrapping during idle Jon Hunter
2009-05-27 16:01 ` Thomas Gleixner
2009-05-27 18:15 ` john stultz
@ 2009-05-27 20:54 ` Alok Kataria
2009-05-27 21:12 ` Thomas Gleixner
2 siblings, 1 reply; 20+ messages in thread
From: Alok Kataria @ 2009-05-27 20:54 UTC (permalink / raw)
To: Jon Hunter
Cc: linux-kernel@vger.kernel.org, john stultz, Thomas Gleixner,
Ingo Molnar, akataria
On Wed, May 27, 2009 at 7:49 AM, Jon Hunter <jon-hunter@ti.com> wrote:
>
> The dynamic tick allows the kernel to sleep for periods longer than a single
> tick. This patch prevents that the kernel from sleeping for a period longer
> than the maximum time that the current clocksource can count. This ensures
> that the kernel will not lose track of time. This patch adds a new function
> called "timekeeping_max_deferment()" that calculates the maximum time the
> kernel can sleep for a given clocksource.
>
>From the patch description I understand that this will avoid wrapping
around for only the *current* clocksource. What happens if, say, TSC
is the clocksource and ACPI_PM is being used as the
watchdog_clocksource, in that case the timekeeping_max_deferement will
give TSC' max allowed sleep value (which is greater than ACPI_PMs).
i.e. We could still sleep beyond ACPI_PM's wrap around threshold which
may result in us marking TSC as unsuable as a clocksource.
That could still result in incorrect timekeeping right ?
Thanks,
Alok
> Signed-off-by: Jon Hunter <jon-hunter@ti.com>
> ---
> include/linux/time.h | 1 +
> kernel/time/tick-sched.c | 36 +++++++++++++++++++++++----------
> kernel/time/timekeeping.c | 47
> +++++++++++++++++++++++++++++++++++++++++++++
> 3 files changed, 73 insertions(+), 11 deletions(-)
>
> diff --git a/include/linux/time.h b/include/linux/time.h
> index 242f624..090be07 100644
> --- a/include/linux/time.h
> +++ b/include/linux/time.h
> @@ -130,6 +130,7 @@ extern void monotonic_to_bootbased(struct timespec *ts);
>
> extern struct timespec timespec_trunc(struct timespec t, unsigned gran);
> extern int timekeeping_valid_for_hres(void);
> +extern s64 timekeeping_max_deferment(void);
> extern void update_wall_time(void);
> extern void update_xtime_cache(u64 nsec);
>
> diff --git a/kernel/time/tick-sched.c b/kernel/time/tick-sched.c
> index d3f1ef4..f0155ae 100644
> --- a/kernel/time/tick-sched.c
> +++ b/kernel/time/tick-sched.c
> @@ -217,6 +217,7 @@ void tick_nohz_stop_sched_tick(int inidle)
> ktime_t last_update, expires, now;
> struct clock_event_device *dev =
> __get_cpu_var(tick_cpu_device).evtdev;
> int cpu;
> + s64 time_delta, max_time_delta;
>
> local_irq_save(flags);
>
> @@ -264,6 +265,7 @@ void tick_nohz_stop_sched_tick(int inidle)
> seq = read_seqbegin(&xtime_lock);
> last_update = last_jiffies_update;
> last_jiffies = jiffies;
> + max_time_delta = timekeeping_max_deferment();
> } while (read_seqretry(&xtime_lock, seq));
>
> /* Get the next timer wheel timer */
> @@ -283,11 +285,22 @@ void tick_nohz_stop_sched_tick(int inidle)
> if ((long)delta_jiffies >= 1) {
>
> /*
> - * calculate the expiry time for the next timer wheel
> - * timer
> - */
> - expires = ktime_add_ns(last_update, tick_period.tv64 *
> - delta_jiffies);
> + * Calculate the time delta for the next timer event.
> + * If the time delta exceeds the maximum time delta
> + * permitted by the current clocksource then adjust
> + * the time delta accordingly to ensure the
> + * clocksource does not wrap.
> + */
> + time_delta = tick_period.tv64 * delta_jiffies;
> +
> + if (time_delta > max_time_delta)
> + time_delta = max_time_delta;
> +
> + /*
> + * calculate the expiry time for the next timer wheel
> + * timer
> + */
> + expires = ktime_add_ns(last_update, time_delta);
>
> /*
> * If this cpu is the one which updates jiffies, then
> @@ -300,7 +313,7 @@ void tick_nohz_stop_sched_tick(int inidle)
> if (cpu == tick_do_timer_cpu)
> tick_do_timer_cpu = TICK_DO_TIMER_NONE;
>
> - if (delta_jiffies > 1)
> + if (time_delta > tick_period.tv64)
> cpumask_set_cpu(cpu, nohz_cpu_mask);
>
> /* Skip reprogram of event if its not changed */
> @@ -332,12 +345,13 @@ void tick_nohz_stop_sched_tick(int inidle)
> ts->idle_sleeps++;
>
> /*
> - * delta_jiffies >= NEXT_TIMER_MAX_DELTA signals that
> - * there is no timer pending or at least extremly far
> - * into the future (12 days for HZ=1000). In this case
> - * we simply stop the tick timer:
> + * time_delta >= (tick_period.tv64 * NEXT_TIMER_MAX_DELTA)
> + * signals that there is no timer pending or at least
> + * extremely far into the future (12 days for HZ=1000).
> + * In this case we simply stop the tick timer:
> */
> - if (unlikely(delta_jiffies >= NEXT_TIMER_MAX_DELTA)) {
> + if (unlikely(time_delta >=
> + (tick_period.tv64 * NEXT_TIMER_MAX_DELTA)))
> {
> ts->idle_expires.tv64 = KTIME_MAX;
> if (ts->nohz_mode == NOHZ_MODE_HIGHRES)
> hrtimer_cancel(&ts->sched_timer);
> diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c
> index 687dff4..608fc6f 100644
> --- a/kernel/time/timekeeping.c
> +++ b/kernel/time/timekeeping.c
> @@ -271,6 +271,53 @@ int timekeeping_valid_for_hres(void)
> }
>
> /**
> + * timekeeping_max_deferment - Returns max time the clocksource can be
> deferred
> + *
> + * IMPORTANT: Must be called with xtime_lock held!
> + */
> +s64 timekeeping_max_deferment(void)
> +{
> + s64 max_nsecs;
> + u64 max_cycles;
> +
> + /*
> + * Calculate the maximum number of cycles that we can pass to the
> + * cyc2ns function without overflowing a 64-bit signed result. The
> + * maximum number of cycles is equal to ULLONG_MAX/clock->mult which
> + * is equivalent to the below.
> + * max_cycles < (2^63)/clock->mult
> + * max_cycles < 2^(log2((2^63)/clock->mult))
> + * max_cycles < 2^(log2(2^63) - log2(clock->mult))
> + * max_cycles < 2^(63 - log2(clock->mult))
> + * max_cycles < 1 << (63 - log2(clock->mult))
> + * Please note that we add 1 to the result of the log2 to account
> for
> + * any rounding errors, ensure the above inequality is satisfied and
> + * no overflow will occur.
> + */
> + max_cycles = 1ULL << (63 - (ilog2(clock->mult) + 1));
> +
> + /*
> + * The actual maximum number of cycles we can defer the clocksource
> is
> + * determined by the minimum of max_cycles and clock->mask.
> + */
> + max_cycles = min(max_cycles, clock->mask);
> + max_nsecs = cyc2ns(clock, max_cycles);
> +
> + /*
> + * To ensure that the clocksource does not wrap whilst we are idle,
> + * limit the time the clocksource can be deferred by 6.25%. Please
> + * note a margin of 6.25% is used because this can be computed with
> + * a shift, versus say 5% which would require division.
> + */
> + max_nsecs = max_nsecs - (max_nsecs >> 4);
> +
> + if (max_nsecs < 0)
> + max_nsecs = 0;
> +
> + return max_nsecs;
> +}
> +
> +/**
> * read_persistent_clock - Return time in seconds from the persistent
> clock.
> *
> * Weak dummy function for arches that do not yet support it.
> --
> 1.6.1
> --
> 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/
>
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH 1/2] Dynamic Tick: Prevent clocksource wrapping during idle
2009-05-27 20:54 ` Alok Kataria
@ 2009-05-27 21:12 ` Thomas Gleixner
0 siblings, 0 replies; 20+ messages in thread
From: Thomas Gleixner @ 2009-05-27 21:12 UTC (permalink / raw)
To: Alok Kataria
Cc: Jon Hunter, linux-kernel@vger.kernel.org, john stultz,
Ingo Molnar, akataria
On Wed, 27 May 2009, Alok Kataria wrote:
> On Wed, May 27, 2009 at 7:49 AM, Jon Hunter <jon-hunter@ti.com> wrote:
> >
> > The dynamic tick allows the kernel to sleep for periods longer than a single
> > tick. This patch prevents that the kernel from sleeping for a period longer
> > than the maximum time that the current clocksource can count. This ensures
> > that the kernel will not lose track of time. This patch adds a new function
> > called "timekeeping_max_deferment()" that calculates the maximum time the
> > kernel can sleep for a given clocksource.
> >
>
> >From the patch description I understand that this will avoid wrapping
> around for only the *current* clocksource. What happens if, say, TSC
> is the clocksource and ACPI_PM is being used as the
> watchdog_clocksource, in that case the timekeeping_max_deferement will
> give TSC' max allowed sleep value (which is greater than ACPI_PMs).
> i.e. We could still sleep beyond ACPI_PM's wrap around threshold which
> may result in us marking TSC as unsuable as a clocksource.
> That could still result in incorrect timekeeping right ?
No, because the watchdog timer takes care of that. It wakes up at time.
Thanks,
tglx
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH 1/2] Dynamic Tick: Prevent clocksource wrapping during idle
2009-05-27 20:32 ` Thomas Gleixner
@ 2009-05-28 20:21 ` Jon Hunter
2009-05-28 20:36 ` Thomas Gleixner
0 siblings, 1 reply; 20+ messages in thread
From: Jon Hunter @ 2009-05-28 20:21 UTC (permalink / raw)
To: Thomas Gleixner; +Cc: john stultz, linux-kernel@vger.kernel.org, Ingo Molnar
Thomas Gleixner wrote:
> On Wed, 27 May 2009, john stultz wrote:
>>> Why do you want to recalculate the whole stuff over and over ?
>>>
>>> That computation can be done when the clock source is initialized or
>>> any fundamental change of the clock parameters happens.
>>>
>>> Stick that value into the clocksource struct and just read it out.
>> Sigh.
>>
>> I was hoping to avoid hanging another bit of junk off of the clocksource
>> struct.
>
> Sure, but buying that 8 bytes with Einsteinian insanity is nuts.
Ok, I have re-worked the patch to avoid computing the value over and
over and just use the original mult value to calculate the max
deferment. This patch calculates the value on registering the
clocksource and stores the value in the clocksource struct.
>> But I guess we could compute that value on registration and keep it
>> around. Changes to mult could effect things, but should be well within
>> the 6% safety net we give ourselves.
>
> That was my thought as well, but even if we have to go to 12% it's way
> better than doing repeated nonsense on the way to idle.
For now I have modified the patch to go to 12.5% margin to be on the
safe side.
Let me know your thoughts on the below.
Cheers
Jon
The dynamic tick allows the kernel to sleep for periods longer than a
single tick. This patch prevents that the kernel from sleeping for a
period longer than the maximum time that the current clocksource can
count. This ensures that the kernel will not lose track of time. This
patch adds a function called "clocksource_max_deferment()" that
calculates the maximum time the kernel can sleep for a given clocksource
and function called "timekeeping_max_deferment()" that returns maximum
time the kernel can sleep for the current clocksource.
Signed-off-by: Jon Hunter <jon-hunter@ti.com>
---
include/linux/clocksource.h | 46
+++++++++++++++++++++++++++++++++++++++++++
include/linux/time.h | 1 +
kernel/time/clocksource.c | 3 ++
kernel/time/tick-sched.c | 36 +++++++++++++++++++++++----------
kernel/time/timekeeping.c | 11 ++++++++++
5 files changed, 86 insertions(+), 11 deletions(-)
diff --git a/include/linux/clocksource.h b/include/linux/clocksource.h
index 5a40d14..b0d676e 100644
--- a/include/linux/clocksource.h
+++ b/include/linux/clocksource.h
@@ -151,6 +151,7 @@ extern u64 timecounter_cyc2time(struct timecounter *tc,
* @mult: cycle to nanosecond multiplier (adjusted by NTP)
* @mult_orig: cycle to nanosecond multiplier (unadjusted by NTP)
* @shift: cycle to nanosecond divisor (power of two)
+ * @max_idle_ns: max idle time permitted by the clocksource (nsecs)
* @flags: flags describing special properties
* @vread: vsyscall based read
* @resume: resume function for the clocksource, if necessary
@@ -171,6 +172,7 @@ struct clocksource {
u32 mult;
u32 mult_orig;
u32 shift;
+ s64 max_idle_ns;
unsigned long flags;
cycle_t (*vread)(void);
void (*resume)(void);
@@ -322,6 +324,50 @@ static inline s64 cyc2ns(struct clocksource *cs,
cycle_t cycles)
}
/**
+ * clocksource_max_deferment - Returns max time the clocksource can be
deferred
+ * @cs: Pointer to clocksource
+ *
+ */
+static inline s64 clocksource_max_deferment(struct clocksource *cs)
+{
+ s64 max_nsecs;
+ u64 max_cycles;
+
+ /*
+ * Calculate the maximum number of cycles that we can pass to the
+ * cyc2ns function without overflowing a 64-bit signed result. The
+ * maximum number of cycles is equal to ULLONG_MAX/cs->mult which
+ * is equivalent to the below.
+ * max_cycles < (2^63)/cs->mult
+ * max_cycles < 2^(log2((2^63)/cs->mult))
+ * max_cycles < 2^(log2(2^63) - log2(cs->mult))
+ * max_cycles < 2^(63 - log2(cs->mult))
+ * max_cycles < 1 << (63 - log2(cs->mult))
+ * Please note that we add 1 to the result of the log2 to account for
+ * any rounding errors, ensure the above inequality is satisfied and
+ * no overflow will occur.
+ */
+ max_cycles = 1ULL << (63 - (ilog2(cs->mult) + 1));
+
+ /*
+ * The actual maximum number of cycles we can defer the clocksource is
+ * determined by the minimum of max_cycles and cs->mask.
+ */
+ max_cycles = min(max_cycles, cs->mask);
+ max_nsecs = cyc2ns(cs, max_cycles);
+
+ /*
+ * To ensure that the clocksource does not wrap whilst we are idle,
+ * limit the time the clocksource can be deferred by 12.5%. Please
+ * note a margin of 12.5% is used because this can be computed with
+ * a shift, versus say 10% which would require division.
+ */
+ max_nsecs = max_nsecs - (max_nsecs >> 5);
+
+ return max_nsecs;
+}
+
+/**
* clocksource_calculate_interval - Calculates a clocksource interval
struct
*
* @c: Pointer to clocksource.
diff --git a/include/linux/time.h b/include/linux/time.h
index 242f624..090be07 100644
--- a/include/linux/time.h
+++ b/include/linux/time.h
@@ -130,6 +130,7 @@ extern void monotonic_to_bootbased(struct timespec *ts);
extern struct timespec timespec_trunc(struct timespec t, unsigned gran);
extern int timekeeping_valid_for_hres(void);
+extern s64 timekeeping_max_deferment(void);
extern void update_wall_time(void);
extern void update_xtime_cache(u64 nsec);
diff --git a/kernel/time/clocksource.c b/kernel/time/clocksource.c
index ecfd7b5..0d98dc2 100644
--- a/kernel/time/clocksource.c
+++ b/kernel/time/clocksource.c
@@ -405,6 +405,9 @@ int clocksource_register(struct clocksource *c)
/* save mult_orig on registration */
c->mult_orig = c->mult;
+ /* calculate max idle time permitted for this clocksource */
+ c->max_idle_ns = clocksource_max_deferment(c);
+
spin_lock_irqsave(&clocksource_lock, flags);
ret = clocksource_enqueue(c);
if (!ret)
diff --git a/kernel/time/tick-sched.c b/kernel/time/tick-sched.c
index d3f1ef4..f0155ae 100644
--- a/kernel/time/tick-sched.c
+++ b/kernel/time/tick-sched.c
@@ -217,6 +217,7 @@ void tick_nohz_stop_sched_tick(int inidle)
ktime_t last_update, expires, now;
struct clock_event_device *dev = __get_cpu_var(tick_cpu_device).evtdev;
int cpu;
+ s64 time_delta, max_time_delta;
local_irq_save(flags);
@@ -264,6 +265,7 @@ void tick_nohz_stop_sched_tick(int inidle)
seq = read_seqbegin(&xtime_lock);
last_update = last_jiffies_update;
last_jiffies = jiffies;
+ max_time_delta = timekeeping_max_deferment();
} while (read_seqretry(&xtime_lock, seq));
/* Get the next timer wheel timer */
@@ -283,11 +285,22 @@ void tick_nohz_stop_sched_tick(int inidle)
if ((long)delta_jiffies >= 1) {
/*
- * calculate the expiry time for the next timer wheel
- * timer
- */
- expires = ktime_add_ns(last_update, tick_period.tv64 *
- delta_jiffies);
+ * Calculate the time delta for the next timer event.
+ * If the time delta exceeds the maximum time delta
+ * permitted by the current clocksource then adjust
+ * the time delta accordingly to ensure the
+ * clocksource does not wrap.
+ */
+ time_delta = tick_period.tv64 * delta_jiffies;
+
+ if (time_delta > max_time_delta)
+ time_delta = max_time_delta;
+
+ /*
+ * calculate the expiry time for the next timer wheel
+ * timer
+ */
+ expires = ktime_add_ns(last_update, time_delta);
/*
* If this cpu is the one which updates jiffies, then
@@ -300,7 +313,7 @@ void tick_nohz_stop_sched_tick(int inidle)
if (cpu == tick_do_timer_cpu)
tick_do_timer_cpu = TICK_DO_TIMER_NONE;
- if (delta_jiffies > 1)
+ if (time_delta > tick_period.tv64)
cpumask_set_cpu(cpu, nohz_cpu_mask);
/* Skip reprogram of event if its not changed */
@@ -332,12 +345,13 @@ void tick_nohz_stop_sched_tick(int inidle)
ts->idle_sleeps++;
/*
- * delta_jiffies >= NEXT_TIMER_MAX_DELTA signals that
- * there is no timer pending or at least extremly far
- * into the future (12 days for HZ=1000). In this case
- * we simply stop the tick timer:
+ * time_delta >= (tick_period.tv64 * NEXT_TIMER_MAX_DELTA)
+ * signals that there is no timer pending or at least
+ * extremely far into the future (12 days for HZ=1000).
+ * In this case we simply stop the tick timer:
*/
- if (unlikely(delta_jiffies >= NEXT_TIMER_MAX_DELTA)) {
+ if (unlikely(time_delta >=
+ (tick_period.tv64 * NEXT_TIMER_MAX_DELTA))) {
ts->idle_expires.tv64 = KTIME_MAX;
if (ts->nohz_mode == NOHZ_MODE_HIGHRES)
hrtimer_cancel(&ts->sched_timer);
diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c
index 687dff4..659cae3 100644
--- a/kernel/time/timekeeping.c
+++ b/kernel/time/timekeeping.c
@@ -271,6 +271,17 @@ int timekeeping_valid_for_hres(void)
}
/**
+ * timekeeping_max_deferment - Returns max time the clocksource can be
deferred
+ *
+ * IMPORTANT: Caller must observe xtime_lock via
read_seqbegin/read_seqretry
+ * to ensure that the clocksource does not change!
+ */
+s64 timekeeping_max_deferment(void)
+{
+ return clock->max_idle_ns;
+}
+
+/**
* read_persistent_clock - Return time in seconds from the persistent
clock.
*
* Weak dummy function for arches that do not yet support it.
--
1.6.1
^ permalink raw reply related [flat|nested] 20+ messages in thread
* Re: [PATCH 1/2] Dynamic Tick: Prevent clocksource wrapping during idle
2009-05-28 20:21 ` Jon Hunter
@ 2009-05-28 20:36 ` Thomas Gleixner
2009-05-28 21:10 ` Jon Hunter
0 siblings, 1 reply; 20+ messages in thread
From: Thomas Gleixner @ 2009-05-28 20:36 UTC (permalink / raw)
To: Jon Hunter; +Cc: john stultz, linux-kernel@vger.kernel.org, Ingo Molnar
On Thu, 28 May 2009, Jon Hunter wrote:
> /**
> + * clocksource_max_deferment - Returns max time the clocksource can be
> deferred
> + * @cs: Pointer to clocksource
> + *
> + */
> +static inline s64 clocksource_max_deferment(struct clocksource *cs)
Please make this a real function. There is no reason to stick this
into a header file. The only user is clocksource.c anyway, so please
put it there as a static function and let the compiler decide what
to do with it.
Otherwise, I'm happy with it.
Thanks,
tglx
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH 1/2] Dynamic Tick: Prevent clocksource wrapping during idle
2009-05-28 20:36 ` Thomas Gleixner
@ 2009-05-28 21:10 ` Jon Hunter
2009-05-28 21:43 ` John Stultz
` (2 more replies)
0 siblings, 3 replies; 20+ messages in thread
From: Jon Hunter @ 2009-05-28 21:10 UTC (permalink / raw)
To: Thomas Gleixner; +Cc: john stultz, linux-kernel@vger.kernel.org, Ingo Molnar
Thomas Gleixner wrote:
> Please make this a real function. There is no reason to stick this
> into a header file. The only user is clocksource.c anyway, so please
> put it there as a static function and let the compiler decide what
> to do with it.
No problem. Please see below. Let me know if this is ok and there is
anything else.
Cheers
Jon
The dynamic tick allows the kernel to sleep for periods longer
than a single tick. This patch prevents that the kernel from
sleeping for a period longer than the maximum time that the
current clocksource can count. This ensures that the kernel will
not lose track of time. This patch adds a function called
"clocksource_max_deferment()" that calculates the maximum time the
kernel can sleep for a given clocksource and function called
"timekeeping_max_deferment()" that returns maximum time the kernel
can sleep for the current clocksource.
Signed-off-by: Jon Hunter <jon-hunter@ti.com>
---
include/linux/clocksource.h | 2 +
include/linux/time.h | 1 +
kernel/time/clocksource.c | 47
+++++++++++++++++++++++++++++++++++++++++++
kernel/time/tick-sched.c | 36 ++++++++++++++++++++++----------
kernel/time/timekeeping.c | 11 ++++++++++
5 files changed, 86 insertions(+), 11 deletions(-)
diff --git a/include/linux/clocksource.h b/include/linux/clocksource.h
index 5a40d14..465af22 100644
--- a/include/linux/clocksource.h
+++ b/include/linux/clocksource.h
@@ -151,6 +151,7 @@ extern u64 timecounter_cyc2time(struct timecounter *tc,
* @mult: cycle to nanosecond multiplier (adjusted by NTP)
* @mult_orig: cycle to nanosecond multiplier (unadjusted by NTP)
* @shift: cycle to nanosecond divisor (power of two)
+ * @max_idle_ns: max idle time permitted by the clocksource (nsecs)
* @flags: flags describing special properties
* @vread: vsyscall based read
* @resume: resume function for the clocksource, if necessary
@@ -171,6 +172,7 @@ struct clocksource {
u32 mult;
u32 mult_orig;
u32 shift;
+ s64 max_idle_ns;
unsigned long flags;
cycle_t (*vread)(void);
void (*resume)(void);
diff --git a/include/linux/time.h b/include/linux/time.h
index 242f624..090be07 100644
--- a/include/linux/time.h
+++ b/include/linux/time.h
@@ -130,6 +130,7 @@ extern void monotonic_to_bootbased(struct timespec *ts);
extern struct timespec timespec_trunc(struct timespec t, unsigned gran);
extern int timekeeping_valid_for_hres(void);
+extern s64 timekeeping_max_deferment(void);
extern void update_wall_time(void);
extern void update_xtime_cache(u64 nsec);
diff --git a/kernel/time/clocksource.c b/kernel/time/clocksource.c
index ecfd7b5..18d2b9f 100644
--- a/kernel/time/clocksource.c
+++ b/kernel/time/clocksource.c
@@ -321,6 +321,50 @@ void clocksource_touch_watchdog(void)
}
/**
+ * clocksource_max_deferment - Returns max time the clocksource can be
deferred
+ * @cs: Pointer to clocksource
+ *
+ */
+static s64 clocksource_max_deferment(struct clocksource *cs)
+{
+ s64 max_nsecs;
+ u64 max_cycles;
+
+ /*
+ * Calculate the maximum number of cycles that we can pass to the
+ * cyc2ns function without overflowing a 64-bit signed result. The
+ * maximum number of cycles is equal to ULLONG_MAX/cs->mult which
+ * is equivalent to the below.
+ * max_cycles < (2^63)/cs->mult
+ * max_cycles < 2^(log2((2^63)/cs->mult))
+ * max_cycles < 2^(log2(2^63) - log2(cs->mult))
+ * max_cycles < 2^(63 - log2(cs->mult))
+ * max_cycles < 1 << (63 - log2(cs->mult))
+ * Please note that we add 1 to the result of the log2 to account for
+ * any rounding errors, ensure the above inequality is satisfied and
+ * no overflow will occur.
+ */
+ max_cycles = 1ULL << (63 - (ilog2(cs->mult) + 1));
+
+ /*
+ * The actual maximum number of cycles we can defer the clocksource is
+ * determined by the minimum of max_cycles and cs->mask.
+ */
+ max_cycles = min(max_cycles, cs->mask);
+ max_nsecs = cyc2ns(cs, max_cycles);
+
+ /*
+ * To ensure that the clocksource does not wrap whilst we are idle,
+ * limit the time the clocksource can be deferred by 12.5%. Please
+ * note a margin of 12.5% is used because this can be computed with
+ * a shift, versus say 10% which would require division.
+ */
+ max_nsecs = max_nsecs - (max_nsecs >> 5);
+
+ return max_nsecs;
+}
+
+/**
* clocksource_get_next - Returns the selected clocksource
*
*/
@@ -405,6 +449,9 @@ int clocksource_register(struct clocksource *c)
/* save mult_orig on registration */
c->mult_orig = c->mult;
+ /* calculate max idle time permitted for this clocksource */
+ c->max_idle_ns = clocksource_max_deferment(c);
+
spin_lock_irqsave(&clocksource_lock, flags);
ret = clocksource_enqueue(c);
if (!ret)
diff --git a/kernel/time/tick-sched.c b/kernel/time/tick-sched.c
index d3f1ef4..f0155ae 100644
--- a/kernel/time/tick-sched.c
+++ b/kernel/time/tick-sched.c
@@ -217,6 +217,7 @@ void tick_nohz_stop_sched_tick(int inidle)
ktime_t last_update, expires, now;
struct clock_event_device *dev = __get_cpu_var(tick_cpu_device).evtdev;
int cpu;
+ s64 time_delta, max_time_delta;
local_irq_save(flags);
@@ -264,6 +265,7 @@ void tick_nohz_stop_sched_tick(int inidle)
seq = read_seqbegin(&xtime_lock);
last_update = last_jiffies_update;
last_jiffies = jiffies;
+ max_time_delta = timekeeping_max_deferment();
} while (read_seqretry(&xtime_lock, seq));
/* Get the next timer wheel timer */
@@ -283,11 +285,22 @@ void tick_nohz_stop_sched_tick(int inidle)
if ((long)delta_jiffies >= 1) {
/*
- * calculate the expiry time for the next timer wheel
- * timer
- */
- expires = ktime_add_ns(last_update, tick_period.tv64 *
- delta_jiffies);
+ * Calculate the time delta for the next timer event.
+ * If the time delta exceeds the maximum time delta
+ * permitted by the current clocksource then adjust
+ * the time delta accordingly to ensure the
+ * clocksource does not wrap.
+ */
+ time_delta = tick_period.tv64 * delta_jiffies;
+
+ if (time_delta > max_time_delta)
+ time_delta = max_time_delta;
+
+ /*
+ * calculate the expiry time for the next timer wheel
+ * timer
+ */
+ expires = ktime_add_ns(last_update, time_delta);
/*
* If this cpu is the one which updates jiffies, then
@@ -300,7 +313,7 @@ void tick_nohz_stop_sched_tick(int inidle)
if (cpu == tick_do_timer_cpu)
tick_do_timer_cpu = TICK_DO_TIMER_NONE;
- if (delta_jiffies > 1)
+ if (time_delta > tick_period.tv64)
cpumask_set_cpu(cpu, nohz_cpu_mask);
/* Skip reprogram of event if its not changed */
@@ -332,12 +345,13 @@ void tick_nohz_stop_sched_tick(int inidle)
ts->idle_sleeps++;
/*
- * delta_jiffies >= NEXT_TIMER_MAX_DELTA signals that
- * there is no timer pending or at least extremly far
- * into the future (12 days for HZ=1000). In this case
- * we simply stop the tick timer:
+ * time_delta >= (tick_period.tv64 * NEXT_TIMER_MAX_DELTA)
+ * signals that there is no timer pending or at least
+ * extremely far into the future (12 days for HZ=1000).
+ * In this case we simply stop the tick timer:
*/
- if (unlikely(delta_jiffies >= NEXT_TIMER_MAX_DELTA)) {
+ if (unlikely(time_delta >=
+ (tick_period.tv64 * NEXT_TIMER_MAX_DELTA))) {
ts->idle_expires.tv64 = KTIME_MAX;
if (ts->nohz_mode == NOHZ_MODE_HIGHRES)
hrtimer_cancel(&ts->sched_timer);
diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c
index 687dff4..659cae3 100644
--- a/kernel/time/timekeeping.c
+++ b/kernel/time/timekeeping.c
@@ -271,6 +271,17 @@ int timekeeping_valid_for_hres(void)
}
/**
+ * timekeeping_max_deferment - Returns max time the clocksource can be
deferred
+ *
+ * IMPORTANT: Caller must observe xtime_lock via
read_seqbegin/read_seqretry
+ * to ensure that the clocksource does not change!
+ */
+s64 timekeeping_max_deferment(void)
+{
+ return clock->max_idle_ns;
+}
+
+/**
* read_persistent_clock - Return time in seconds from the persistent
clock.
*
* Weak dummy function for arches that do not yet support it.
--
1.6.1
^ permalink raw reply related [flat|nested] 20+ messages in thread
* Re: [PATCH 1/2] Dynamic Tick: Prevent clocksource wrapping during idle
2009-05-28 21:10 ` Jon Hunter
@ 2009-05-28 21:43 ` John Stultz
2009-05-28 22:16 ` Thomas Gleixner
2009-05-30 1:00 ` Jon Hunter
2 siblings, 0 replies; 20+ messages in thread
From: John Stultz @ 2009-05-28 21:43 UTC (permalink / raw)
To: Jon Hunter; +Cc: Thomas Gleixner, linux-kernel@vger.kernel.org, Ingo Molnar
On Thu, 2009-05-28 at 16:10 -0500, Jon Hunter wrote:
> Thomas Gleixner wrote:
> > Please make this a real function. There is no reason to stick this
> > into a header file. The only user is clocksource.c anyway, so please
> > put it there as a static function and let the compiler decide what
> > to do with it.
>
> No problem. Please see below. Let me know if this is ok and there is
> anything else.
>
> Cheers
> Jon
>
> The dynamic tick allows the kernel to sleep for periods longer
> than a single tick. This patch prevents that the kernel from
> sleeping for a period longer than the maximum time that the
> current clocksource can count. This ensures that the kernel will
> not lose track of time. This patch adds a function called
> "clocksource_max_deferment()" that calculates the maximum time the
> kernel can sleep for a given clocksource and function called
> "timekeeping_max_deferment()" that returns maximum time the kernel
> can sleep for the current clocksource.
>
> Signed-off-by: Jon Hunter <jon-hunter@ti.com>
Thanks for putting up with my apparent misdirections and going around
and around on this. :)
Acked-by: John Stultz <johnstul@us.ibm.com>
> ---
> include/linux/clocksource.h | 2 +
> include/linux/time.h | 1 +
> kernel/time/clocksource.c | 47
> +++++++++++++++++++++++++++++++++++++++++++
> kernel/time/tick-sched.c | 36 ++++++++++++++++++++++----------
> kernel/time/timekeeping.c | 11 ++++++++++
> 5 files changed, 86 insertions(+), 11 deletions(-)
>
> diff --git a/include/linux/clocksource.h b/include/linux/clocksource.h
> index 5a40d14..465af22 100644
> --- a/include/linux/clocksource.h
> +++ b/include/linux/clocksource.h
> @@ -151,6 +151,7 @@ extern u64 timecounter_cyc2time(struct timecounter *tc,
> * @mult: cycle to nanosecond multiplier (adjusted by NTP)
> * @mult_orig: cycle to nanosecond multiplier (unadjusted by NTP)
> * @shift: cycle to nanosecond divisor (power of two)
> + * @max_idle_ns: max idle time permitted by the clocksource (nsecs)
> * @flags: flags describing special properties
> * @vread: vsyscall based read
> * @resume: resume function for the clocksource, if necessary
> @@ -171,6 +172,7 @@ struct clocksource {
> u32 mult;
> u32 mult_orig;
> u32 shift;
> + s64 max_idle_ns;
> unsigned long flags;
> cycle_t (*vread)(void);
> void (*resume)(void);
> diff --git a/include/linux/time.h b/include/linux/time.h
> index 242f624..090be07 100644
> --- a/include/linux/time.h
> +++ b/include/linux/time.h
> @@ -130,6 +130,7 @@ extern void monotonic_to_bootbased(struct timespec *ts);
>
> extern struct timespec timespec_trunc(struct timespec t, unsigned gran);
> extern int timekeeping_valid_for_hres(void);
> +extern s64 timekeeping_max_deferment(void);
> extern void update_wall_time(void);
> extern void update_xtime_cache(u64 nsec);
>
> diff --git a/kernel/time/clocksource.c b/kernel/time/clocksource.c
> index ecfd7b5..18d2b9f 100644
> --- a/kernel/time/clocksource.c
> +++ b/kernel/time/clocksource.c
> @@ -321,6 +321,50 @@ void clocksource_touch_watchdog(void)
> }
>
> /**
> + * clocksource_max_deferment - Returns max time the clocksource can be
> deferred
> + * @cs: Pointer to clocksource
> + *
> + */
> +static s64 clocksource_max_deferment(struct clocksource *cs)
> +{
> + s64 max_nsecs;
> + u64 max_cycles;
> +
> + /*
> + * Calculate the maximum number of cycles that we can pass to the
> + * cyc2ns function without overflowing a 64-bit signed result. The
> + * maximum number of cycles is equal to ULLONG_MAX/cs->mult which
> + * is equivalent to the below.
> + * max_cycles < (2^63)/cs->mult
> + * max_cycles < 2^(log2((2^63)/cs->mult))
> + * max_cycles < 2^(log2(2^63) - log2(cs->mult))
> + * max_cycles < 2^(63 - log2(cs->mult))
> + * max_cycles < 1 << (63 - log2(cs->mult))
> + * Please note that we add 1 to the result of the log2 to account for
> + * any rounding errors, ensure the above inequality is satisfied and
> + * no overflow will occur.
> + */
> + max_cycles = 1ULL << (63 - (ilog2(cs->mult) + 1));
> +
> + /*
> + * The actual maximum number of cycles we can defer the clocksource is
> + * determined by the minimum of max_cycles and cs->mask.
> + */
> + max_cycles = min(max_cycles, cs->mask);
> + max_nsecs = cyc2ns(cs, max_cycles);
> +
> + /*
> + * To ensure that the clocksource does not wrap whilst we are idle,
> + * limit the time the clocksource can be deferred by 12.5%. Please
> + * note a margin of 12.5% is used because this can be computed with
> + * a shift, versus say 10% which would require division.
> + */
> + max_nsecs = max_nsecs - (max_nsecs >> 5);
> +
> + return max_nsecs;
> +}
> +
> +/**
> * clocksource_get_next - Returns the selected clocksource
> *
> */
> @@ -405,6 +449,9 @@ int clocksource_register(struct clocksource *c)
> /* save mult_orig on registration */
> c->mult_orig = c->mult;
>
> + /* calculate max idle time permitted for this clocksource */
> + c->max_idle_ns = clocksource_max_deferment(c);
> +
> spin_lock_irqsave(&clocksource_lock, flags);
> ret = clocksource_enqueue(c);
> if (!ret)
> diff --git a/kernel/time/tick-sched.c b/kernel/time/tick-sched.c
> index d3f1ef4..f0155ae 100644
> --- a/kernel/time/tick-sched.c
> +++ b/kernel/time/tick-sched.c
> @@ -217,6 +217,7 @@ void tick_nohz_stop_sched_tick(int inidle)
> ktime_t last_update, expires, now;
> struct clock_event_device *dev = __get_cpu_var(tick_cpu_device).evtdev;
> int cpu;
> + s64 time_delta, max_time_delta;
>
> local_irq_save(flags);
>
> @@ -264,6 +265,7 @@ void tick_nohz_stop_sched_tick(int inidle)
> seq = read_seqbegin(&xtime_lock);
> last_update = last_jiffies_update;
> last_jiffies = jiffies;
> + max_time_delta = timekeeping_max_deferment();
> } while (read_seqretry(&xtime_lock, seq));
>
> /* Get the next timer wheel timer */
> @@ -283,11 +285,22 @@ void tick_nohz_stop_sched_tick(int inidle)
> if ((long)delta_jiffies >= 1) {
>
> /*
> - * calculate the expiry time for the next timer wheel
> - * timer
> - */
> - expires = ktime_add_ns(last_update, tick_period.tv64 *
> - delta_jiffies);
> + * Calculate the time delta for the next timer event.
> + * If the time delta exceeds the maximum time delta
> + * permitted by the current clocksource then adjust
> + * the time delta accordingly to ensure the
> + * clocksource does not wrap.
> + */
> + time_delta = tick_period.tv64 * delta_jiffies;
> +
> + if (time_delta > max_time_delta)
> + time_delta = max_time_delta;
> +
> + /*
> + * calculate the expiry time for the next timer wheel
> + * timer
> + */
> + expires = ktime_add_ns(last_update, time_delta);
>
> /*
> * If this cpu is the one which updates jiffies, then
> @@ -300,7 +313,7 @@ void tick_nohz_stop_sched_tick(int inidle)
> if (cpu == tick_do_timer_cpu)
> tick_do_timer_cpu = TICK_DO_TIMER_NONE;
>
> - if (delta_jiffies > 1)
> + if (time_delta > tick_period.tv64)
> cpumask_set_cpu(cpu, nohz_cpu_mask);
>
> /* Skip reprogram of event if its not changed */
> @@ -332,12 +345,13 @@ void tick_nohz_stop_sched_tick(int inidle)
> ts->idle_sleeps++;
>
> /*
> - * delta_jiffies >= NEXT_TIMER_MAX_DELTA signals that
> - * there is no timer pending or at least extremly far
> - * into the future (12 days for HZ=1000). In this case
> - * we simply stop the tick timer:
> + * time_delta >= (tick_period.tv64 * NEXT_TIMER_MAX_DELTA)
> + * signals that there is no timer pending or at least
> + * extremely far into the future (12 days for HZ=1000).
> + * In this case we simply stop the tick timer:
> */
> - if (unlikely(delta_jiffies >= NEXT_TIMER_MAX_DELTA)) {
> + if (unlikely(time_delta >=
> + (tick_period.tv64 * NEXT_TIMER_MAX_DELTA))) {
> ts->idle_expires.tv64 = KTIME_MAX;
> if (ts->nohz_mode == NOHZ_MODE_HIGHRES)
> hrtimer_cancel(&ts->sched_timer);
> diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c
> index 687dff4..659cae3 100644
> --- a/kernel/time/timekeeping.c
> +++ b/kernel/time/timekeeping.c
> @@ -271,6 +271,17 @@ int timekeeping_valid_for_hres(void)
> }
>
> /**
> + * timekeeping_max_deferment - Returns max time the clocksource can be
> deferred
> + *
> + * IMPORTANT: Caller must observe xtime_lock via
> read_seqbegin/read_seqretry
> + * to ensure that the clocksource does not change!
> + */
> +s64 timekeeping_max_deferment(void)
> +{
> + return clock->max_idle_ns;
> +}
> +
> +/**
> * read_persistent_clock - Return time in seconds from the persistent
> clock.
> *
> * Weak dummy function for arches that do not yet support it.
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH 1/2] Dynamic Tick: Prevent clocksource wrapping during idle
2009-05-28 21:10 ` Jon Hunter
2009-05-28 21:43 ` John Stultz
@ 2009-05-28 22:16 ` Thomas Gleixner
2009-05-29 19:43 ` Jon Hunter
2009-05-30 1:00 ` Jon Hunter
2 siblings, 1 reply; 20+ messages in thread
From: Thomas Gleixner @ 2009-05-28 22:16 UTC (permalink / raw)
To: Jon Hunter; +Cc: john stultz, linux-kernel@vger.kernel.org, Ingo Molnar
On Thu, 28 May 2009, Jon Hunter wrote:
> Thomas Gleixner wrote:
> > Please make this a real function. There is no reason to stick this
> > into a header file. The only user is clocksource.c anyway, so please
> > put it there as a static function and let the compiler decide what
> > to do with it.
>
> No problem. Please see below. Let me know if this is ok and there is anything
> else.
Looks good now.
> /**
> + * timekeeping_max_deferment - Returns max time the clocksource can be
> deferred
> + *
> + * IMPORTANT: Caller must observe xtime_lock via read_seqbegin/read_seqretry
> + * to ensure that the clocksource does not change!
> + */
Just nitpicking here. For the intended use case this is irrelevant.
On UP this is called from an irq disabled section, so nothing is
going to change the clock source.
On SMP it does not matter if CPU A goes to sleep with the old clock
source and CPU B changes the clock source while A is idle. When B
goes idle it will take the change into account.
But that leads me to an interesting observation:
On SMP we really should only care for the CPU which has the do_timer
duty assigned. All other CPUs can sleep as long as they want. When
that CPU goes idle and drops the do_timer duty it needs to look at
max_deferement, but the others can sleep as long as they want.
So the rule would be:
if (cpu == tick_do_timer_cpu || tick_do_timer_cpu == TICK_DO_TIMER_NONE)
check_max_deferment();
else
sleep_as_long_as_you_want;
Could you add that perhaps ?
> +s64 timekeeping_max_deferment(void)
> +{
> + return clock->max_idle_ns;
> +}
> +
Thanks for your patience,
tglx
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH 1/2] Dynamic Tick: Prevent clocksource wrapping during idle
2009-05-28 22:16 ` Thomas Gleixner
@ 2009-05-29 19:43 ` Jon Hunter
0 siblings, 0 replies; 20+ messages in thread
From: Jon Hunter @ 2009-05-29 19:43 UTC (permalink / raw)
To: Thomas Gleixner; +Cc: john stultz, linux-kernel@vger.kernel.org, Ingo Molnar
Thomas Gleixner wrote:
> On Thu, 28 May 2009, Jon Hunter wrote:
>> /**
>> + * timekeeping_max_deferment - Returns max time the clocksource can be
>> deferred
>> + *
>> + * IMPORTANT: Caller must observe xtime_lock via read_seqbegin/read_seqretry
>> + * to ensure that the clocksource does not change!
>> + */
>
> Just nitpicking here. For the intended use case this is irrelevant.
>
> On UP this is called from an irq disabled section, so nothing is
> going to change the clock source.
>
> On SMP it does not matter if CPU A goes to sleep with the old clock
> source and CPU B changes the clock source while A is idle. When B
> goes idle it will take the change into account.
Ok, understood. Let me know if you would like me to remove the comment
above. I wanted to make sure that if someone was to use this function
else where (can't think of why right now) that they would not over look
this.
> But that leads me to an interesting observation:
>
> On SMP we really should only care for the CPU which has the do_timer
> duty assigned. All other CPUs can sleep as long as they want. When
> that CPU goes idle and drops the do_timer duty it needs to look at
> max_deferement, but the others can sleep as long as they want.
>
> So the rule would be:
>
> if (cpu == tick_do_timer_cpu || tick_do_timer_cpu == TICK_DO_TIMER_NONE)
> check_max_deferment();
> else
> sleep_as_long_as_you_want;
>
> Could you add that perhaps ?
Absolutely. Please see below and let me know if this is ok.
> Thanks for your patience,
No problem. Thanks for the feedback.
Cheers
Jon
The dynamic tick allows the kernel to sleep for periods longer
than a single tick. This patch prevents that the kernel from
sleeping for a period longer than the maximum time that the
current clocksource can count. This ensures that the kernel will
not lose track of time. This patch adds a function called
"clocksource_max_deferment()" that calculates the maximum time the
kernel can sleep for a given clocksource and function called
"timekeeping_max_deferment()" that returns maximum time the kernel
can sleep for the current clocksource.
Signed-off-by: Jon Hunter <jon-hunter@ti.com>
---
include/linux/clocksource.h | 2 +
include/linux/time.h | 1 +
kernel/time/clocksource.c | 47
+++++++++++++++++++++++++++++++++++++++++++
kernel/time/tick-sched.c | 47
++++++++++++++++++++++++++++++++----------
kernel/time/timekeeping.c | 11 ++++++++++
5 files changed, 97 insertions(+), 11 deletions(-)
diff --git a/include/linux/clocksource.h b/include/linux/clocksource.h
index 5a40d14..465af22 100644
--- a/include/linux/clocksource.h
+++ b/include/linux/clocksource.h
@@ -151,6 +151,7 @@ extern u64 timecounter_cyc2time(struct timecounter *tc,
* @mult: cycle to nanosecond multiplier (adjusted by NTP)
* @mult_orig: cycle to nanosecond multiplier (unadjusted by NTP)
* @shift: cycle to nanosecond divisor (power of two)
+ * @max_idle_ns: max idle time permitted by the clocksource (nsecs)
* @flags: flags describing special properties
* @vread: vsyscall based read
* @resume: resume function for the clocksource, if necessary
@@ -171,6 +172,7 @@ struct clocksource {
u32 mult;
u32 mult_orig;
u32 shift;
+ s64 max_idle_ns;
unsigned long flags;
cycle_t (*vread)(void);
void (*resume)(void);
diff --git a/include/linux/time.h b/include/linux/time.h
index 242f624..090be07 100644
--- a/include/linux/time.h
+++ b/include/linux/time.h
@@ -130,6 +130,7 @@ extern void monotonic_to_bootbased(struct timespec *ts);
extern struct timespec timespec_trunc(struct timespec t, unsigned gran);
extern int timekeeping_valid_for_hres(void);
+extern s64 timekeeping_max_deferment(void);
extern void update_wall_time(void);
extern void update_xtime_cache(u64 nsec);
diff --git a/kernel/time/clocksource.c b/kernel/time/clocksource.c
index ecfd7b5..18d2b9f 100644
--- a/kernel/time/clocksource.c
+++ b/kernel/time/clocksource.c
@@ -321,6 +321,50 @@ void clocksource_touch_watchdog(void)
}
/**
+ * clocksource_max_deferment - Returns max time the clocksource can be
deferred
+ * @cs: Pointer to clocksource
+ *
+ */
+static s64 clocksource_max_deferment(struct clocksource *cs)
+{
+ s64 max_nsecs;
+ u64 max_cycles;
+
+ /*
+ * Calculate the maximum number of cycles that we can pass to the
+ * cyc2ns function without overflowing a 64-bit signed result. The
+ * maximum number of cycles is equal to ULLONG_MAX/cs->mult which
+ * is equivalent to the below.
+ * max_cycles < (2^63)/cs->mult
+ * max_cycles < 2^(log2((2^63)/cs->mult))
+ * max_cycles < 2^(log2(2^63) - log2(cs->mult))
+ * max_cycles < 2^(63 - log2(cs->mult))
+ * max_cycles < 1 << (63 - log2(cs->mult))
+ * Please note that we add 1 to the result of the log2 to account for
+ * any rounding errors, ensure the above inequality is satisfied and
+ * no overflow will occur.
+ */
+ max_cycles = 1ULL << (63 - (ilog2(cs->mult) + 1));
+
+ /*
+ * The actual maximum number of cycles we can defer the clocksource is
+ * determined by the minimum of max_cycles and cs->mask.
+ */
+ max_cycles = min(max_cycles, cs->mask);
+ max_nsecs = cyc2ns(cs, max_cycles);
+
+ /*
+ * To ensure that the clocksource does not wrap whilst we are idle,
+ * limit the time the clocksource can be deferred by 12.5%. Please
+ * note a margin of 12.5% is used because this can be computed with
+ * a shift, versus say 10% which would require division.
+ */
+ max_nsecs = max_nsecs - (max_nsecs >> 5);
+
+ return max_nsecs;
+}
+
+/**
* clocksource_get_next - Returns the selected clocksource
*
*/
@@ -405,6 +449,9 @@ int clocksource_register(struct clocksource *c)
/* save mult_orig on registration */
c->mult_orig = c->mult;
+ /* calculate max idle time permitted for this clocksource */
+ c->max_idle_ns = clocksource_max_deferment(c);
+
spin_lock_irqsave(&clocksource_lock, flags);
ret = clocksource_enqueue(c);
if (!ret)
diff --git a/kernel/time/tick-sched.c b/kernel/time/tick-sched.c
index d3f1ef4..318cf8a 100644
--- a/kernel/time/tick-sched.c
+++ b/kernel/time/tick-sched.c
@@ -217,6 +217,7 @@ void tick_nohz_stop_sched_tick(int inidle)
ktime_t last_update, expires, now;
struct clock_event_device *dev = __get_cpu_var(tick_cpu_device).evtdev;
int cpu;
+ s64 time_delta, max_time_delta;
local_irq_save(flags);
@@ -264,6 +265,18 @@ void tick_nohz_stop_sched_tick(int inidle)
seq = read_seqbegin(&xtime_lock);
last_update = last_jiffies_update;
last_jiffies = jiffies;
+
+ /*
+ * On SMP we really should only care for the CPU which
+ * has the do_timer duty assigned. All other CPUs can
+ * sleep as long as they want.
+ */
+ if (cpu == tick_do_timer_cpu ||
+ tick_do_timer_cpu == TICK_DO_TIMER_NONE)
+ max_time_delta = timekeeping_max_deferment();
+ else
+ max_time_delta = KTIME_MAX;
+
} while (read_seqretry(&xtime_lock, seq));
/* Get the next timer wheel timer */
@@ -283,11 +296,22 @@ void tick_nohz_stop_sched_tick(int inidle)
if ((long)delta_jiffies >= 1) {
/*
- * calculate the expiry time for the next timer wheel
- * timer
- */
- expires = ktime_add_ns(last_update, tick_period.tv64 *
- delta_jiffies);
+ * Calculate the time delta for the next timer event.
+ * If the time delta exceeds the maximum time delta
+ * permitted by the current clocksource then adjust
+ * the time delta accordingly to ensure the
+ * clocksource does not wrap.
+ */
+ time_delta = tick_period.tv64 * delta_jiffies;
+
+ if (time_delta > max_time_delta)
+ time_delta = max_time_delta;
+
+ /*
+ * calculate the expiry time for the next timer wheel
+ * timer
+ */
+ expires = ktime_add_ns(last_update, time_delta);
/*
* If this cpu is the one which updates jiffies, then
@@ -300,7 +324,7 @@ void tick_nohz_stop_sched_tick(int inidle)
if (cpu == tick_do_timer_cpu)
tick_do_timer_cpu = TICK_DO_TIMER_NONE;
- if (delta_jiffies > 1)
+ if (time_delta > tick_period.tv64)
cpumask_set_cpu(cpu, nohz_cpu_mask);
/* Skip reprogram of event if its not changed */
@@ -332,12 +356,13 @@ void tick_nohz_stop_sched_tick(int inidle)
ts->idle_sleeps++;
/*
- * delta_jiffies >= NEXT_TIMER_MAX_DELTA signals that
- * there is no timer pending or at least extremly far
- * into the future (12 days for HZ=1000). In this case
- * we simply stop the tick timer:
+ * time_delta >= (tick_period.tv64 * NEXT_TIMER_MAX_DELTA)
+ * signals that there is no timer pending or at least
+ * extremely far into the future (12 days for HZ=1000).
+ * In this case we simply stop the tick timer:
*/
- if (unlikely(delta_jiffies >= NEXT_TIMER_MAX_DELTA)) {
+ if (unlikely(time_delta >=
+ (tick_period.tv64 * NEXT_TIMER_MAX_DELTA))) {
ts->idle_expires.tv64 = KTIME_MAX;
if (ts->nohz_mode == NOHZ_MODE_HIGHRES)
hrtimer_cancel(&ts->sched_timer);
diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c
index 687dff4..659cae3 100644
--- a/kernel/time/timekeeping.c
+++ b/kernel/time/timekeeping.c
@@ -271,6 +271,17 @@ int timekeeping_valid_for_hres(void)
}
/**
+ * timekeeping_max_deferment - Returns max time the clocksource can be
deferred
+ *
+ * IMPORTANT: Caller must observe xtime_lock via
read_seqbegin/read_seqretry
+ * to ensure that the clocksource does not change!
+ */
+s64 timekeeping_max_deferment(void)
+{
+ return clock->max_idle_ns;
+}
+
+/**
* read_persistent_clock - Return time in seconds from the persistent
clock.
*
* Weak dummy function for arches that do not yet support it.
--
1.6.1
^ permalink raw reply related [flat|nested] 20+ messages in thread
* Re: [PATCH 1/2] Dynamic Tick: Prevent clocksource wrapping during idle
2009-05-28 21:10 ` Jon Hunter
2009-05-28 21:43 ` John Stultz
2009-05-28 22:16 ` Thomas Gleixner
@ 2009-05-30 1:00 ` Jon Hunter
2009-06-04 19:29 ` Jon Hunter
2 siblings, 1 reply; 20+ messages in thread
From: Jon Hunter @ 2009-05-30 1:00 UTC (permalink / raw)
To: Thomas Gleixner; +Cc: john stultz, linux-kernel@vger.kernel.org, Ingo Molnar
Jon Hunter wrote:
> + * Calculate the time delta for the next timer event.
> + * If the time delta exceeds the maximum time delta
> + * permitted by the current clocksource then adjust
> + * the time delta accordingly to ensure the
> + * clocksource does not wrap.
> + */
> + time_delta = tick_period.tv64 * delta_jiffies;
Thinking about this more, although it is very unlikely, for 64-bit
machines there is a chance that the above multiply could overflow if
delta_jiffies is very large.
tick_period.tv64 should always be less than NSEC_PER_SEC and so you
would need delta_jiffies to be greater than 2^32 to cause overflow. On a
32-bit machine an unsigned long will not be greater than 2^32 as it is
only 32-bits but this would be possible on a 64-bit machines.
So to be safe we should make sure that delta_jiffies is not greater than
NEXT_TIMER_MAX_DELTA (2^30 - 1) before doing the multiply. If you
think that this is a valid concern, then I can re-work and re-post.
Sorry for not catching this before.
Jon
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH 1/2] Dynamic Tick: Prevent clocksource wrapping during idle
2009-05-30 1:00 ` Jon Hunter
@ 2009-06-04 19:29 ` Jon Hunter
2009-06-25 19:10 ` Jon Hunter
0 siblings, 1 reply; 20+ messages in thread
From: Jon Hunter @ 2009-06-04 19:29 UTC (permalink / raw)
To: Thomas Gleixner; +Cc: john stultz, linux-kernel@vger.kernel.org, Ingo Molnar
Jon Hunter wrote:
> Jon Hunter wrote:
>> + * Calculate the time delta for the next timer event.
>> + * If the time delta exceeds the maximum time delta
>> + * permitted by the current clocksource then adjust
>> + * the time delta accordingly to ensure the
>> + * clocksource does not wrap.
>> + */
>> + time_delta = tick_period.tv64 * delta_jiffies;
>
> Thinking about this more, although it is very unlikely, for 64-bit
> machines there is a chance that the above multiply could overflow if
> delta_jiffies is very large.
>
> tick_period.tv64 should always be less than NSEC_PER_SEC and so you
> would need delta_jiffies to be greater than 2^32 to cause overflow. On a
> 32-bit machine an unsigned long will not be greater than 2^32 as it is
> only 32-bits but this would be possible on a 64-bit machines.
>
> So to be safe we should make sure that delta_jiffies is not greater than
> NEXT_TIMER_MAX_DELTA (2^30 - 1) before doing the multiply. If you
> think that this is a valid concern, then I can re-work and re-post.
> Sorry for not catching this before.
With regard to the above, to ensure that there are no overflows with the
above calculation, I re-worked this patch a little. The below should be
equivalent to the current code, just re-organised a little. Let me know
if this would be acceptable or not.
Cheers
Jon
The dynamic tick allows the kernel to sleep for periods longer
than a single tick. This patch prevents that the kernel from
sleeping for a period longer than the maximum time that the
current clocksource can count. This ensures that the kernel will
not lose track of time. This patch adds a function called
"clocksource_max_deferment()" that calculates the maximum time the
kernel can sleep for a given clocksource and function called
"timekeeping_max_deferment()" that returns maximum time the kernel
can sleep for the current clocksource.
Signed-off-by: Jon Hunter <jon-hunter@ti.com>
---
include/linux/clocksource.h | 2 +
include/linux/time.h | 1 +
kernel/time/clocksource.c | 47 +++++++++++++++++++++++++++++++++++
kernel/time/tick-sched.c | 57
++++++++++++++++++++++++++++++++----------
kernel/time/timekeeping.c | 11 ++++++++
5 files changed, 104 insertions(+), 14 deletions(-)
diff --git a/include/linux/clocksource.h b/include/linux/clocksource.h
index 5a40d14..465af22 100644
--- a/include/linux/clocksource.h
+++ b/include/linux/clocksource.h
@@ -151,6 +151,7 @@ extern u64 timecounter_cyc2time(struct timecounter *tc,
* @mult: cycle to nanosecond multiplier (adjusted by NTP)
* @mult_orig: cycle to nanosecond multiplier (unadjusted by NTP)
* @shift: cycle to nanosecond divisor (power of two)
+ * @max_idle_ns: max idle time permitted by the clocksource (nsecs)
* @flags: flags describing special properties
* @vread: vsyscall based read
* @resume: resume function for the clocksource, if necessary
@@ -171,6 +172,7 @@ struct clocksource {
u32 mult;
u32 mult_orig;
u32 shift;
+ s64 max_idle_ns;
unsigned long flags;
cycle_t (*vread)(void);
void (*resume)(void);
diff --git a/include/linux/time.h b/include/linux/time.h
index 242f624..090be07 100644
--- a/include/linux/time.h
+++ b/include/linux/time.h
@@ -130,6 +130,7 @@ extern void monotonic_to_bootbased(struct timespec *ts);
extern struct timespec timespec_trunc(struct timespec t, unsigned gran);
extern int timekeeping_valid_for_hres(void);
+extern s64 timekeeping_max_deferment(void);
extern void update_wall_time(void);
extern void update_xtime_cache(u64 nsec);
diff --git a/kernel/time/clocksource.c b/kernel/time/clocksource.c
index ecfd7b5..18d2b9f 100644
--- a/kernel/time/clocksource.c
+++ b/kernel/time/clocksource.c
@@ -321,6 +321,50 @@ void clocksource_touch_watchdog(void)
}
/**
+ * clocksource_max_deferment - Returns max time the clocksource can be
deferred
+ * @cs: Pointer to clocksource
+ *
+ */
+static s64 clocksource_max_deferment(struct clocksource *cs)
+{
+ s64 max_nsecs;
+ u64 max_cycles;
+
+ /*
+ * Calculate the maximum number of cycles that we can pass to the
+ * cyc2ns function without overflowing a 64-bit signed result. The
+ * maximum number of cycles is equal to ULLONG_MAX/cs->mult which
+ * is equivalent to the below.
+ * max_cycles < (2^63)/cs->mult
+ * max_cycles < 2^(log2((2^63)/cs->mult))
+ * max_cycles < 2^(log2(2^63) - log2(cs->mult))
+ * max_cycles < 2^(63 - log2(cs->mult))
+ * max_cycles < 1 << (63 - log2(cs->mult))
+ * Please note that we add 1 to the result of the log2 to account for
+ * any rounding errors, ensure the above inequality is satisfied and
+ * no overflow will occur.
+ */
+ max_cycles = 1ULL << (63 - (ilog2(cs->mult) + 1));
+
+ /*
+ * The actual maximum number of cycles we can defer the clocksource is
+ * determined by the minimum of max_cycles and cs->mask.
+ */
+ max_cycles = min(max_cycles, cs->mask);
+ max_nsecs = cyc2ns(cs, max_cycles);
+
+ /*
+ * To ensure that the clocksource does not wrap whilst we are idle,
+ * limit the time the clocksource can be deferred by 12.5%. Please
+ * note a margin of 12.5% is used because this can be computed with
+ * a shift, versus say 10% which would require division.
+ */
+ max_nsecs = max_nsecs - (max_nsecs >> 5);
+
+ return max_nsecs;
+}
+
+/**
* clocksource_get_next - Returns the selected clocksource
*
*/
@@ -405,6 +449,9 @@ int clocksource_register(struct clocksource *c)
/* save mult_orig on registration */
c->mult_orig = c->mult;
+ /* calculate max idle time permitted for this clocksource */
+ c->max_idle_ns = clocksource_max_deferment(c);
+
spin_lock_irqsave(&clocksource_lock, flags);
ret = clocksource_enqueue(c);
if (!ret)
diff --git a/kernel/time/tick-sched.c b/kernel/time/tick-sched.c
index d3f1ef4..9988e5e 100644
--- a/kernel/time/tick-sched.c
+++ b/kernel/time/tick-sched.c
@@ -217,6 +217,7 @@ void tick_nohz_stop_sched_tick(int inidle)
ktime_t last_update, expires, now;
struct clock_event_device *dev = __get_cpu_var(tick_cpu_device).evtdev;
int cpu;
+ s64 time_delta, max_time_delta;
local_irq_save(flags);
@@ -264,6 +265,18 @@ void tick_nohz_stop_sched_tick(int inidle)
seq = read_seqbegin(&xtime_lock);
last_update = last_jiffies_update;
last_jiffies = jiffies;
+
+ /*
+ * On SMP we really should only care for the CPU which
+ * has the do_timer duty assigned. All other CPUs can
+ * sleep as long as they want.
+ */
+ if (cpu == tick_do_timer_cpu ||
+ tick_do_timer_cpu == TICK_DO_TIMER_NONE)
+ max_time_delta = timekeeping_max_deferment();
+ else
+ max_time_delta = KTIME_MAX;
+
} while (read_seqretry(&xtime_lock, seq));
/* Get the next timer wheel timer */
@@ -283,11 +296,30 @@ void tick_nohz_stop_sched_tick(int inidle)
if ((long)delta_jiffies >= 1) {
/*
- * calculate the expiry time for the next timer wheel
- * timer
- */
- expires = ktime_add_ns(last_update, tick_period.tv64 *
- delta_jiffies);
+ * calculate the expiry time for the next timer wheel
+ * timer. delta_jiffies >= NEXT_TIMER_MAX_DELTA signals
+ * that there is no timer pending or at least extremely
+ * far into the future (12 days for HZ=1000). In this
+ * case we set the expiry to the end of time.
+ */
+ if (likely(delta_jiffies < NEXT_TIMER_MAX_DELTA)) {
+
+ /*
+ * Calculate the time delta for the next timer event.
+ * If the time delta exceeds the maximum time delta
+ * permitted by the current clocksource then adjust
+ * the time delta accordingly to ensure the
+ * clocksource does not wrap.
+ */
+ time_delta = tick_period.tv64 * delta_jiffies;
+
+ if (time_delta > max_time_delta)
+ time_delta = max_time_delta;
+
+ expires = ktime_add_ns(last_update, time_delta);
+ } else {
+ expires.tv64 = KTIME_MAX;
+ }
/*
* If this cpu is the one which updates jiffies, then
@@ -331,22 +363,19 @@ void tick_nohz_stop_sched_tick(int inidle)
ts->idle_sleeps++;
+ /* Mark expires */
+ ts->idle_expires = expires;
+
/*
- * delta_jiffies >= NEXT_TIMER_MAX_DELTA signals that
- * there is no timer pending or at least extremly far
- * into the future (12 days for HZ=1000). In this case
- * we simply stop the tick timer:
+ * If the expiration time == KTIME_MAX, then
+ * in this case we simply stop the tick timer.
*/
- if (unlikely(delta_jiffies >= NEXT_TIMER_MAX_DELTA)) {
- ts->idle_expires.tv64 = KTIME_MAX;
+ if (unlikely(expires.tv64 == KTIME_MAX)) {
if (ts->nohz_mode == NOHZ_MODE_HIGHRES)
hrtimer_cancel(&ts->sched_timer);
goto out;
}
- /* Mark expiries */
- ts->idle_expires = expires;
-
if (ts->nohz_mode == NOHZ_MODE_HIGHRES) {
hrtimer_start(&ts->sched_timer, expires,
HRTIMER_MODE_ABS);
diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c
index 687dff4..659cae3 100644
--- a/kernel/time/timekeeping.c
+++ b/kernel/time/timekeeping.c
@@ -271,6 +271,17 @@ int timekeeping_valid_for_hres(void)
}
/**
+ * timekeeping_max_deferment - Returns max time the clocksource can be
deferred
+ *
+ * IMPORTANT: Caller must observe xtime_lock via
read_seqbegin/read_seqretry
+ * to ensure that the clocksource does not change!
+ */
+s64 timekeeping_max_deferment(void)
+{
+ return clock->max_idle_ns;
+}
+
+/**
* read_persistent_clock - Return time in seconds from the persistent
clock.
*
* Weak dummy function for arches that do not yet support it.
--
1.6.1
^ permalink raw reply related [flat|nested] 20+ messages in thread
* Re: [PATCH 1/2] Dynamic Tick: Prevent clocksource wrapping during idle
2009-06-04 19:29 ` Jon Hunter
@ 2009-06-25 19:10 ` Jon Hunter
0 siblings, 0 replies; 20+ messages in thread
From: Jon Hunter @ 2009-06-25 19:10 UTC (permalink / raw)
To: Thomas Gleixner; +Cc: john stultz, linux-kernel@vger.kernel.org, Ingo Molnar
Jon Hunter wrote:
> Jon Hunter wrote:
>> Jon Hunter wrote:
>>> + * Calculate the time delta for the next timer event.
>>> + * If the time delta exceeds the maximum time delta
>>> + * permitted by the current clocksource then adjust
>>> + * the time delta accordingly to ensure the
>>> + * clocksource does not wrap.
>>> + */
>>> + time_delta = tick_period.tv64 * delta_jiffies;
>> Thinking about this more, although it is very unlikely, for 64-bit
>> machines there is a chance that the above multiply could overflow if
>> delta_jiffies is very large.
>>
>> tick_period.tv64 should always be less than NSEC_PER_SEC and so you
>> would need delta_jiffies to be greater than 2^32 to cause overflow. On a
>> 32-bit machine an unsigned long will not be greater than 2^32 as it is
>> only 32-bits but this would be possible on a 64-bit machines.
>>
>> So to be safe we should make sure that delta_jiffies is not greater than
>> NEXT_TIMER_MAX_DELTA (2^30 - 1) before doing the multiply. If you
>> think that this is a valid concern, then I can re-work and re-post.
>> Sorry for not catching this before.
>
> With regard to the above, to ensure that there are no overflows with the
> above calculation, I re-worked this patch a little. The below should be
> equivalent to the current code, just re-organised a little. Let me know
> if this would be acceptable or not.
Hi Thomas, John,
Did you guys have chance to review this? Let me know if you have any
further comments/feedback.
Cheers
Jon
^ permalink raw reply [flat|nested] 20+ messages in thread
* [PATCH 1/2] Dynamic Tick: Prevent clocksource wrapping during idle
2009-07-28 0:00 [PATCH 0/2] Dynamic Tick: Enabling longer sleep times on 32-bit Jon Hunter
@ 2009-07-28 0:00 ` Jon Hunter
0 siblings, 0 replies; 20+ messages in thread
From: Jon Hunter @ 2009-07-28 0:00 UTC (permalink / raw)
To: linux-kernel; +Cc: Thomas Gleixner, John Stultz, Jon Hunter
From: Jon Hunter <jon-hunter@ti.com>
The dynamic tick allows the kernel to sleep for periods longer
than a single tick. This patch prevents that the kernel from
sleeping for a period longer than the maximum time that the
current clocksource can count. This ensures that the kernel will
not lose track of time. This patch adds a function called
"clocksource_max_deferment()" that calculates the maximum time the
kernel can sleep for a given clocksource and function called
"timekeeping_max_deferment()" that returns maximum time the kernel
can sleep for the current clocksource.
Signed-off-by: Jon Hunter <jon-hunter@ti.com>
---
include/linux/clocksource.h | 2 +
include/linux/time.h | 1 +
kernel/time/clocksource.c | 47 +++++++++++++++++++++++++++++++++++
kernel/time/tick-sched.c | 57 ++++++++++++++++++++++++++++++++----------
kernel/time/timekeeping.c | 11 ++++++++
5 files changed, 104 insertions(+), 14 deletions(-)
diff --git a/include/linux/clocksource.h b/include/linux/clocksource.h
index c56457c..5528090 100644
--- a/include/linux/clocksource.h
+++ b/include/linux/clocksource.h
@@ -151,6 +151,7 @@ extern u64 timecounter_cyc2time(struct timecounter *tc,
* @mult: cycle to nanosecond multiplier (adjusted by NTP)
* @mult_orig: cycle to nanosecond multiplier (unadjusted by NTP)
* @shift: cycle to nanosecond divisor (power of two)
+ * @max_idle_ns: max idle time permitted by the clocksource (nsecs)
* @flags: flags describing special properties
* @vread: vsyscall based read
* @resume: resume function for the clocksource, if necessary
@@ -171,6 +172,7 @@ struct clocksource {
u32 mult;
u32 mult_orig;
u32 shift;
+ s64 max_idle_ns;
unsigned long flags;
cycle_t (*vread)(void);
void (*resume)(void);
diff --git a/include/linux/time.h b/include/linux/time.h
index ea16c1a..ddcff53 100644
--- a/include/linux/time.h
+++ b/include/linux/time.h
@@ -145,6 +145,7 @@ extern void monotonic_to_bootbased(struct timespec *ts);
extern struct timespec timespec_trunc(struct timespec t, unsigned gran);
extern int timekeeping_valid_for_hres(void);
+extern s64 timekeeping_max_deferment(void);
extern void update_wall_time(void);
extern void update_xtime_cache(u64 nsec);
diff --git a/kernel/time/clocksource.c b/kernel/time/clocksource.c
index 7466cb8..fa28f29 100644
--- a/kernel/time/clocksource.c
+++ b/kernel/time/clocksource.c
@@ -321,6 +321,50 @@ void clocksource_touch_watchdog(void)
}
/**
+ * clocksource_max_deferment - Returns max time the clocksource can be deferred
+ * @cs: Pointer to clocksource
+ *
+ */
+static s64 clocksource_max_deferment(struct clocksource *cs)
+{
+ s64 max_nsecs;
+ u64 max_cycles;
+
+ /*
+ * Calculate the maximum number of cycles that we can pass to the
+ * cyc2ns function without overflowing a 64-bit signed result. The
+ * maximum number of cycles is equal to ULLONG_MAX/cs->mult which
+ * is equivalent to the below.
+ * max_cycles < (2^63)/cs->mult
+ * max_cycles < 2^(log2((2^63)/cs->mult))
+ * max_cycles < 2^(log2(2^63) - log2(cs->mult))
+ * max_cycles < 2^(63 - log2(cs->mult))
+ * max_cycles < 1 << (63 - log2(cs->mult))
+ * Please note that we add 1 to the result of the log2 to account for
+ * any rounding errors, ensure the above inequality is satisfied and
+ * no overflow will occur.
+ */
+ max_cycles = 1ULL << (63 - (ilog2(cs->mult) + 1));
+
+ /*
+ * The actual maximum number of cycles we can defer the clocksource is
+ * determined by the minimum of max_cycles and cs->mask.
+ */
+ max_cycles = min(max_cycles, cs->mask);
+ max_nsecs = cyc2ns(cs, max_cycles);
+
+ /*
+ * To ensure that the clocksource does not wrap whilst we are idle,
+ * limit the time the clocksource can be deferred by 12.5%. Please
+ * note a margin of 12.5% is used because this can be computed with
+ * a shift, versus say 10% which would require division.
+ */
+ max_nsecs = max_nsecs - (max_nsecs >> 5);
+
+ return max_nsecs;
+}
+
+/**
* clocksource_get_next - Returns the selected clocksource
*
*/
@@ -402,6 +446,9 @@ int clocksource_register(struct clocksource *c)
unsigned long flags;
int ret;
+ /* calculate max idle time permitted for this clocksource */
+ c->max_idle_ns = clocksource_max_deferment(c);
+
spin_lock_irqsave(&clocksource_lock, flags);
ret = clocksource_enqueue(c);
if (!ret)
diff --git a/kernel/time/tick-sched.c b/kernel/time/tick-sched.c
index e0f59a2..7a98e90 100644
--- a/kernel/time/tick-sched.c
+++ b/kernel/time/tick-sched.c
@@ -217,6 +217,7 @@ void tick_nohz_stop_sched_tick(int inidle)
ktime_t last_update, expires, now;
struct clock_event_device *dev = __get_cpu_var(tick_cpu_device).evtdev;
int cpu;
+ s64 time_delta, max_time_delta;
local_irq_save(flags);
@@ -270,6 +271,18 @@ void tick_nohz_stop_sched_tick(int inidle)
seq = read_seqbegin(&xtime_lock);
last_update = last_jiffies_update;
last_jiffies = jiffies;
+
+ /*
+ * On SMP we really should only care for the CPU which
+ * has the do_timer duty assigned. All other CPUs can
+ * sleep as long as they want.
+ */
+ if (cpu == tick_do_timer_cpu ||
+ tick_do_timer_cpu == TICK_DO_TIMER_NONE)
+ max_time_delta = timekeeping_max_deferment();
+ else
+ max_time_delta = KTIME_MAX;
+
} while (read_seqretry(&xtime_lock, seq));
/* Get the next timer wheel timer */
@@ -289,11 +302,30 @@ void tick_nohz_stop_sched_tick(int inidle)
if ((long)delta_jiffies >= 1) {
/*
- * calculate the expiry time for the next timer wheel
- * timer
- */
- expires = ktime_add_ns(last_update, tick_period.tv64 *
- delta_jiffies);
+ * calculate the expiry time for the next timer wheel
+ * timer. delta_jiffies >= NEXT_TIMER_MAX_DELTA signals
+ * that there is no timer pending or at least extremely
+ * far into the future (12 days for HZ=1000). In this
+ * case we set the expiry to the end of time.
+ */
+ if (likely(delta_jiffies < NEXT_TIMER_MAX_DELTA)) {
+
+ /*
+ * Calculate the time delta for the next timer event.
+ * If the time delta exceeds the maximum time delta
+ * permitted by the current clocksource then adjust
+ * the time delta accordingly to ensure the
+ * clocksource does not wrap.
+ */
+ time_delta = tick_period.tv64 * delta_jiffies;
+
+ if (time_delta > max_time_delta)
+ time_delta = max_time_delta;
+
+ expires = ktime_add_ns(last_update, time_delta);
+ } else {
+ expires.tv64 = KTIME_MAX;
+ }
/*
* If this cpu is the one which updates jiffies, then
@@ -337,22 +369,19 @@ void tick_nohz_stop_sched_tick(int inidle)
ts->idle_sleeps++;
+ /* Mark expires */
+ ts->idle_expires = expires;
+
/*
- * delta_jiffies >= NEXT_TIMER_MAX_DELTA signals that
- * there is no timer pending or at least extremly far
- * into the future (12 days for HZ=1000). In this case
- * we simply stop the tick timer:
+ * If the expiration time == KTIME_MAX, then
+ * in this case we simply stop the tick timer.
*/
- if (unlikely(delta_jiffies >= NEXT_TIMER_MAX_DELTA)) {
- ts->idle_expires.tv64 = KTIME_MAX;
+ if (unlikely(expires.tv64 == KTIME_MAX)) {
if (ts->nohz_mode == NOHZ_MODE_HIGHRES)
hrtimer_cancel(&ts->sched_timer);
goto out;
}
- /* Mark expiries */
- ts->idle_expires = expires;
-
if (ts->nohz_mode == NOHZ_MODE_HIGHRES) {
hrtimer_start(&ts->sched_timer, expires,
HRTIMER_MODE_ABS_PINNED);
diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c
index e8c77d9..cd1b110 100644
--- a/kernel/time/timekeeping.c
+++ b/kernel/time/timekeeping.c
@@ -278,6 +278,17 @@ int timekeeping_valid_for_hres(void)
}
/**
+ * timekeeping_max_deferment - Returns max time the clocksource can be deferred
+ *
+ * IMPORTANT: Caller must observe xtime_lock via read_seqbegin/read_seqretry
+ * to ensure that the clocksource does not change!
+ */
+s64 timekeeping_max_deferment(void)
+{
+ return clock->max_idle_ns;
+}
+
+/**
* read_persistent_clock - Return time in seconds from the persistent clock.
*
* Weak dummy function for arches that do not yet support it.
--
1.6.0.4
^ permalink raw reply related [flat|nested] 20+ messages in thread
* [PATCH 1/2] Dynamic Tick: Prevent clocksource wrapping during idle
2009-08-18 17:45 [PATCH 0/2] Dynamic Tick: Enabling longer sleep times on 32-bit machines Jon Hunter
@ 2009-08-18 17:45 ` Jon Hunter
2009-08-18 19:25 ` Thomas Gleixner
0 siblings, 1 reply; 20+ messages in thread
From: Jon Hunter @ 2009-08-18 17:45 UTC (permalink / raw)
To: linux-kernel; +Cc: Thomas Gleixner, John Stultz, Jon Hunter
From: Jon Hunter <jon-hunter@ti.com>
The dynamic tick allows the kernel to sleep for periods longer
than a single tick. This patch prevents that the kernel from
sleeping for a period longer than the maximum time that the
current clocksource can count. This ensures that the kernel will
not lose track of time. This patch adds a function called
"clocksource_max_deferment()" that calculates the maximum time the
kernel can sleep for a given clocksource and function called
"timekeeping_max_deferment()" that returns maximum time the kernel
can sleep for the current clocksource.
Signed-off-by: Jon Hunter <jon-hunter@ti.com>
---
include/linux/clocksource.h | 2 +
include/linux/time.h | 1 +
kernel/time/clocksource.c | 47 +++++++++++++++++++++++++++++++++++
kernel/time/tick-sched.c | 57 ++++++++++++++++++++++++++++++++----------
kernel/time/timekeeping.c | 11 ++++++++
5 files changed, 104 insertions(+), 14 deletions(-)
diff --git a/include/linux/clocksource.h b/include/linux/clocksource.h
index 9ea40ff..09ed7f1 100644
--- a/include/linux/clocksource.h
+++ b/include/linux/clocksource.h
@@ -151,6 +151,7 @@ extern u64 timecounter_cyc2time(struct timecounter *tc,
* subtraction of non 64 bit counters
* @mult: cycle to nanosecond multiplier
* @shift: cycle to nanosecond divisor (power of two)
+ * @max_idle_ns: max idle time permitted by the clocksource (nsecs)
* @flags: flags describing special properties
* @vread: vsyscall based read
* @resume: resume function for the clocksource, if necessary
@@ -168,6 +169,7 @@ struct clocksource {
cycle_t mask;
u32 mult;
u32 shift;
+ s64 max_idle_ns;
unsigned long flags;
cycle_t (*vread)(void);
void (*resume)(void);
diff --git a/include/linux/time.h b/include/linux/time.h
index f505988..e68a480 100644
--- a/include/linux/time.h
+++ b/include/linux/time.h
@@ -146,6 +146,7 @@ extern void monotonic_to_bootbased(struct timespec *ts);
extern struct timespec timespec_trunc(struct timespec t, unsigned gran);
extern int timekeeping_valid_for_hres(void);
+extern s64 timekeeping_max_deferment(void);
extern void update_wall_time(void);
extern void update_xtime_cache(u64 nsec);
extern void timekeeping_leap_insert(int leapsecond);
diff --git a/kernel/time/clocksource.c b/kernel/time/clocksource.c
index 02dc22d..7fffe54 100644
--- a/kernel/time/clocksource.c
+++ b/kernel/time/clocksource.c
@@ -369,6 +369,50 @@ void clocksource_touch_watchdog(void)
clocksource_resume_watchdog();
}
+/**
+ * clocksource_max_deferment - Returns max time the clocksource can be deferred
+ * @cs: Pointer to clocksource
+ *
+ */
+static s64 clocksource_max_deferment(struct clocksource *cs)
+{
+ s64 max_nsecs;
+ u64 max_cycles;
+
+ /*
+ * Calculate the maximum number of cycles that we can pass to the
+ * cyc2ns function without overflowing a 64-bit signed result. The
+ * maximum number of cycles is equal to ULLONG_MAX/cs->mult which
+ * is equivalent to the below.
+ * max_cycles < (2^63)/cs->mult
+ * max_cycles < 2^(log2((2^63)/cs->mult))
+ * max_cycles < 2^(log2(2^63) - log2(cs->mult))
+ * max_cycles < 2^(63 - log2(cs->mult))
+ * max_cycles < 1 << (63 - log2(cs->mult))
+ * Please note that we add 1 to the result of the log2 to account for
+ * any rounding errors, ensure the above inequality is satisfied and
+ * no overflow will occur.
+ */
+ max_cycles = 1ULL << (63 - (ilog2(cs->mult) + 1));
+
+ /*
+ * The actual maximum number of cycles we can defer the clocksource is
+ * determined by the minimum of max_cycles and cs->mask.
+ */
+ max_cycles = min(max_cycles, cs->mask);
+ max_nsecs = clocksource_cyc2ns(max_cycles, cs->mult, cs->shift);
+
+ /*
+ * To ensure that the clocksource does not wrap whilst we are idle,
+ * limit the time the clocksource can be deferred by 12.5%. Please
+ * note a margin of 12.5% is used because this can be computed with
+ * a shift, versus say 10% which would require division.
+ */
+ max_nsecs = max_nsecs - (max_nsecs >> 5);
+
+ return max_nsecs;
+}
+
#ifdef CONFIG_GENERIC_TIME
static int finished_booting;
@@ -461,6 +505,9 @@ static void clocksource_enqueue(struct clocksource *cs)
*/
int clocksource_register(struct clocksource *cs)
{
+ /* calculate max idle time permitted for this clocksource */
+ cs->max_idle_ns = clocksource_max_deferment(cs);
+
mutex_lock(&clocksource_mutex);
clocksource_enqueue(cs);
clocksource_select();
diff --git a/kernel/time/tick-sched.c b/kernel/time/tick-sched.c
index e0f59a2..7a98e90 100644
--- a/kernel/time/tick-sched.c
+++ b/kernel/time/tick-sched.c
@@ -217,6 +217,7 @@ void tick_nohz_stop_sched_tick(int inidle)
ktime_t last_update, expires, now;
struct clock_event_device *dev = __get_cpu_var(tick_cpu_device).evtdev;
int cpu;
+ s64 time_delta, max_time_delta;
local_irq_save(flags);
@@ -270,6 +271,18 @@ void tick_nohz_stop_sched_tick(int inidle)
seq = read_seqbegin(&xtime_lock);
last_update = last_jiffies_update;
last_jiffies = jiffies;
+
+ /*
+ * On SMP we really should only care for the CPU which
+ * has the do_timer duty assigned. All other CPUs can
+ * sleep as long as they want.
+ */
+ if (cpu == tick_do_timer_cpu ||
+ tick_do_timer_cpu == TICK_DO_TIMER_NONE)
+ max_time_delta = timekeeping_max_deferment();
+ else
+ max_time_delta = KTIME_MAX;
+
} while (read_seqretry(&xtime_lock, seq));
/* Get the next timer wheel timer */
@@ -289,11 +302,30 @@ void tick_nohz_stop_sched_tick(int inidle)
if ((long)delta_jiffies >= 1) {
/*
- * calculate the expiry time for the next timer wheel
- * timer
- */
- expires = ktime_add_ns(last_update, tick_period.tv64 *
- delta_jiffies);
+ * calculate the expiry time for the next timer wheel
+ * timer. delta_jiffies >= NEXT_TIMER_MAX_DELTA signals
+ * that there is no timer pending or at least extremely
+ * far into the future (12 days for HZ=1000). In this
+ * case we set the expiry to the end of time.
+ */
+ if (likely(delta_jiffies < NEXT_TIMER_MAX_DELTA)) {
+
+ /*
+ * Calculate the time delta for the next timer event.
+ * If the time delta exceeds the maximum time delta
+ * permitted by the current clocksource then adjust
+ * the time delta accordingly to ensure the
+ * clocksource does not wrap.
+ */
+ time_delta = tick_period.tv64 * delta_jiffies;
+
+ if (time_delta > max_time_delta)
+ time_delta = max_time_delta;
+
+ expires = ktime_add_ns(last_update, time_delta);
+ } else {
+ expires.tv64 = KTIME_MAX;
+ }
/*
* If this cpu is the one which updates jiffies, then
@@ -337,22 +369,19 @@ void tick_nohz_stop_sched_tick(int inidle)
ts->idle_sleeps++;
+ /* Mark expires */
+ ts->idle_expires = expires;
+
/*
- * delta_jiffies >= NEXT_TIMER_MAX_DELTA signals that
- * there is no timer pending or at least extremly far
- * into the future (12 days for HZ=1000). In this case
- * we simply stop the tick timer:
+ * If the expiration time == KTIME_MAX, then
+ * in this case we simply stop the tick timer.
*/
- if (unlikely(delta_jiffies >= NEXT_TIMER_MAX_DELTA)) {
- ts->idle_expires.tv64 = KTIME_MAX;
+ if (unlikely(expires.tv64 == KTIME_MAX)) {
if (ts->nohz_mode == NOHZ_MODE_HIGHRES)
hrtimer_cancel(&ts->sched_timer);
goto out;
}
- /* Mark expiries */
- ts->idle_expires = expires;
-
if (ts->nohz_mode == NOHZ_MODE_HIGHRES) {
hrtimer_start(&ts->sched_timer, expires,
HRTIMER_MODE_ABS_PINNED);
diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c
index 15e06de..2e57251 100644
--- a/kernel/time/timekeeping.c
+++ b/kernel/time/timekeeping.c
@@ -487,6 +487,17 @@ int timekeeping_valid_for_hres(void)
}
/**
+ * timekeeping_max_deferment - Returns max time the clocksource can be deferred
+ *
+ * IMPORTANT: Caller must observe xtime_lock via read_seqbegin/read_seqretry
+ * to ensure that the clocksource does not change!
+ */
+s64 timekeeping_max_deferment(void)
+{
+ return timekeeper.clock->max_idle_ns;
+}
+
+/**
* read_persistent_clock - Return time from the persistent clock.
*
* Weak dummy function for arches that do not yet support it.
--
1.6.0.4
^ permalink raw reply related [flat|nested] 20+ messages in thread
* Re: [PATCH 1/2] Dynamic Tick: Prevent clocksource wrapping during idle
2009-08-18 17:45 ` [PATCH 1/2] Dynamic Tick: Prevent clocksource wrapping during idle Jon Hunter
@ 2009-08-18 19:25 ` Thomas Gleixner
2009-08-18 20:42 ` Jon Hunter
0 siblings, 1 reply; 20+ messages in thread
From: Thomas Gleixner @ 2009-08-18 19:25 UTC (permalink / raw)
To: Jon Hunter; +Cc: linux-kernel, John Stultz
On Tue, 18 Aug 2009, Jon Hunter wrote:
> From: Jon Hunter <jon-hunter@ti.com>
>
> The dynamic tick allows the kernel to sleep for periods longer
> than a single tick. This patch prevents that the kernel from
> sleeping for a period longer than the maximum time that the
> current clocksource can count. This ensures that the kernel will
> not lose track of time. This patch adds a function called
> "clocksource_max_deferment()" that calculates the maximum time the
> kernel can sleep for a given clocksource and function called
> "timekeeping_max_deferment()" that returns maximum time the kernel
> can sleep for the current clocksource.
>
> Signed-off-by: Jon Hunter <jon-hunter@ti.com>
> ---
> include/linux/clocksource.h | 2 +
> include/linux/time.h | 1 +
> kernel/time/clocksource.c | 47 +++++++++++++++++++++++++++++++++++
> kernel/time/tick-sched.c | 57 ++++++++++++++++++++++++++++++++----------
> kernel/time/timekeeping.c | 11 ++++++++
> 5 files changed, 104 insertions(+), 14 deletions(-)
>
> diff --git a/include/linux/clocksource.h b/include/linux/clocksource.h
> index 9ea40ff..09ed7f1 100644
> --- a/include/linux/clocksource.h
> +++ b/include/linux/clocksource.h
> @@ -151,6 +151,7 @@ extern u64 timecounter_cyc2time(struct timecounter *tc,
> * subtraction of non 64 bit counters
> * @mult: cycle to nanosecond multiplier
> * @shift: cycle to nanosecond divisor (power of two)
> + * @max_idle_ns: max idle time permitted by the clocksource (nsecs)
> * @flags: flags describing special properties
> * @vread: vsyscall based read
> * @resume: resume function for the clocksource, if necessary
> @@ -168,6 +169,7 @@ struct clocksource {
> cycle_t mask;
> u32 mult;
> u32 shift;
> + s64 max_idle_ns;
I don't think we should move this to the clocksource. That should go
into the new struct timekeeper and initialized when a clocksource is
selected for timekeeping.
> diff --git a/kernel/time/tick-sched.c b/kernel/time/tick-sched.c
> index e0f59a2..7a98e90 100644
> --- a/kernel/time/tick-sched.c
> +++ b/kernel/time/tick-sched.c
> @@ -217,6 +217,7 @@ void tick_nohz_stop_sched_tick(int inidle)
> ktime_t last_update, expires, now;
> struct clock_event_device *dev = __get_cpu_var(tick_cpu_device).evtdev;
> int cpu;
> + s64 time_delta, max_time_delta;
>
> local_irq_save(flags);
>
> @@ -270,6 +271,18 @@ void tick_nohz_stop_sched_tick(int inidle)
> seq = read_seqbegin(&xtime_lock);
> last_update = last_jiffies_update;
> last_jiffies = jiffies;
> +
> + /*
> + * On SMP we really should only care for the CPU which
> + * has the do_timer duty assigned. All other CPUs can
> + * sleep as long as they want.
> + */
> + if (cpu == tick_do_timer_cpu ||
> + tick_do_timer_cpu == TICK_DO_TIMER_NONE)
> + max_time_delta = timekeeping_max_deferment();
> + else
> + max_time_delta = KTIME_MAX;
> +
Is it worth the extra check instead of always using
timekeeping_max_deferment() ?
> } while (read_seqretry(&xtime_lock, seq));
>
> /* Get the next timer wheel timer */
> @@ -289,11 +302,30 @@ void tick_nohz_stop_sched_tick(int inidle)
> if ((long)delta_jiffies >= 1) {
>
> /*
> - * calculate the expiry time for the next timer wheel
> - * timer
> - */
> - expires = ktime_add_ns(last_update, tick_period.tv64 *
> - delta_jiffies);
> + * calculate the expiry time for the next timer wheel
> + * timer. delta_jiffies >= NEXT_TIMER_MAX_DELTA signals
> + * that there is no timer pending or at least extremely
> + * far into the future (12 days for HZ=1000). In this
> + * case we set the expiry to the end of time.
> + */
> + if (likely(delta_jiffies < NEXT_TIMER_MAX_DELTA)) {
> +
> + /*
> + * Calculate the time delta for the next timer event.
> + * If the time delta exceeds the maximum time delta
> + * permitted by the current clocksource then adjust
> + * the time delta accordingly to ensure the
> + * clocksource does not wrap.
> + */
> + time_delta = tick_period.tv64 * delta_jiffies;
> +
> + if (time_delta > max_time_delta)
> + time_delta = max_time_delta;
> +
> + expires = ktime_add_ns(last_update, time_delta);
> + } else {
> + expires.tv64 = KTIME_MAX;
> + }
This looks incorrect. You set expires to KTIME_MAX when no timer is
pending, but that defeats the purpose of this patch. When we hit this
code path and the next interrupt comes in after the timekeeping
clocksource wrapped we are bust.
Thanks,
tglx
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH 1/2] Dynamic Tick: Prevent clocksource wrapping during idle
2009-08-18 19:25 ` Thomas Gleixner
@ 2009-08-18 20:42 ` Jon Hunter
0 siblings, 0 replies; 20+ messages in thread
From: Jon Hunter @ 2009-08-18 20:42 UTC (permalink / raw)
To: Thomas Gleixner; +Cc: john stultz, linux-kernel@vger.kernel.org
Thomas Gleixner wrote:
> On Tue, 18 Aug 2009, Jon Hunter wrote:
>
>> From: Jon Hunter <jon-hunter@ti.com>
>>
>> The dynamic tick allows the kernel to sleep for periods longer
>> than a single tick. This patch prevents that the kernel from
>> sleeping for a period longer than the maximum time that the
>> current clocksource can count. This ensures that the kernel will
>> not lose track of time. This patch adds a function called
>> "clocksource_max_deferment()" that calculates the maximum time the
>> kernel can sleep for a given clocksource and function called
>> "timekeeping_max_deferment()" that returns maximum time the kernel
>> can sleep for the current clocksource.
>>
>> Signed-off-by: Jon Hunter <jon-hunter@ti.com>
>> ---
>> include/linux/clocksource.h | 2 +
>> include/linux/time.h | 1 +
>> kernel/time/clocksource.c | 47 +++++++++++++++++++++++++++++++++++
>> kernel/time/tick-sched.c | 57 ++++++++++++++++++++++++++++++++----------
>> kernel/time/timekeeping.c | 11 ++++++++
>> 5 files changed, 104 insertions(+), 14 deletions(-)
>>
>> diff --git a/include/linux/clocksource.h b/include/linux/clocksource.h
>> index 9ea40ff..09ed7f1 100644
>> --- a/include/linux/clocksource.h
>> +++ b/include/linux/clocksource.h
>> @@ -151,6 +151,7 @@ extern u64 timecounter_cyc2time(struct timecounter *tc,
>> * subtraction of non 64 bit counters
>> * @mult: cycle to nanosecond multiplier
>> * @shift: cycle to nanosecond divisor (power of two)
>> + * @max_idle_ns: max idle time permitted by the clocksource (nsecs)
>> * @flags: flags describing special properties
>> * @vread: vsyscall based read
>> * @resume: resume function for the clocksource, if necessary
>> @@ -168,6 +169,7 @@ struct clocksource {
>> cycle_t mask;
>> u32 mult;
>> u32 shift;
>> + s64 max_idle_ns;
>
> I don't think we should move this to the clocksource. That should go
> into the new struct timekeeper and initialized when a clocksource is
> selected for timekeeping.
>
>> diff --git a/kernel/time/tick-sched.c b/kernel/time/tick-sched.c
>> index e0f59a2..7a98e90 100644
>> --- a/kernel/time/tick-sched.c
>> +++ b/kernel/time/tick-sched.c
>> @@ -217,6 +217,7 @@ void tick_nohz_stop_sched_tick(int inidle)
>> ktime_t last_update, expires, now;
>> struct clock_event_device *dev = __get_cpu_var(tick_cpu_device).evtdev;
>> int cpu;
>> + s64 time_delta, max_time_delta;
>>
>> local_irq_save(flags);
>>
>> @@ -270,6 +271,18 @@ void tick_nohz_stop_sched_tick(int inidle)
>> seq = read_seqbegin(&xtime_lock);
>> last_update = last_jiffies_update;
>> last_jiffies = jiffies;
>> +
>> + /*
>> + * On SMP we really should only care for the CPU which
>> + * has the do_timer duty assigned. All other CPUs can
>> + * sleep as long as they want.
>> + */
>> + if (cpu == tick_do_timer_cpu ||
>> + tick_do_timer_cpu == TICK_DO_TIMER_NONE)
>> + max_time_delta = timekeeping_max_deferment();
>> + else
>> + max_time_delta = KTIME_MAX;
>> +
>
> Is it worth the extra check instead of always using
> timekeeping_max_deferment() ?
>
>> } while (read_seqretry(&xtime_lock, seq));
>>
>> /* Get the next timer wheel timer */
>> @@ -289,11 +302,30 @@ void tick_nohz_stop_sched_tick(int inidle)
>> if ((long)delta_jiffies >= 1) {
>>
>> /*
>> - * calculate the expiry time for the next timer wheel
>> - * timer
>> - */
>> - expires = ktime_add_ns(last_update, tick_period.tv64 *
>> - delta_jiffies);
>> + * calculate the expiry time for the next timer wheel
>> + * timer. delta_jiffies >= NEXT_TIMER_MAX_DELTA signals
>> + * that there is no timer pending or at least extremely
>> + * far into the future (12 days for HZ=1000). In this
>> + * case we set the expiry to the end of time.
>> + */
>> + if (likely(delta_jiffies < NEXT_TIMER_MAX_DELTA)) {
>> +
>> + /*
>> + * Calculate the time delta for the next timer event.
>> + * If the time delta exceeds the maximum time delta
>> + * permitted by the current clocksource then adjust
>> + * the time delta accordingly to ensure the
>> + * clocksource does not wrap.
>> + */
>> + time_delta = tick_period.tv64 * delta_jiffies;
>> +
>> + if (time_delta > max_time_delta)
>> + time_delta = max_time_delta;
>> +
>> + expires = ktime_add_ns(last_update, time_delta);
>> + } else {
>> + expires.tv64 = KTIME_MAX;
>> + }
>
> This looks incorrect. You set expires to KTIME_MAX when no timer is
> pending, but that defeats the purpose of this patch. When we hit this
> code path and the next interrupt comes in after the timekeeping
> clocksource wrapped we are bust.
Right, so this is a bit of a grey area for me. When I first started
looking at this I was questioning the purpose of the following code that
exists today in the tick_nohz_stop_sched_tick() function:
/*
* delta_jiffies >= NEXT_TIMER_MAX_DELTA signals that
* there is no timer pending or at least extremly far
* into the future (12 days for HZ=1000). In this case
* we simply stop the tick timer:
*/
if (unlikely(delta_jiffies >= NEXT_TIMER_MAX_DELTA)) {
ts->idle_expires.tv64 = KTIME_MAX;
if (ts->nohz_mode == NOHZ_MODE_HIGHRES)
hrtimer_cancel(&ts->sched_timer);
goto out;
}
The above code checks to see delta_jiffies is greater than
NEXT_TIMER_MAX_DELTA, if so then sets expires to KTIME_MAX and disables
the timer. I had questioned this a few months ago, but I don't think
that John and I knew the history here. So for right or wrong, I left
this code alone. In the above patch it is still do the same thing if
delta_jiffies is indeed greater than NEXT_TIMER_MAX_DELTA.
If you agree that this code is not needed and that in the case where we
have no timers we should simply make the next timer event always occur
in max_time_delta ns later, then I can re-work it to do this.
Thanks
Jon
^ permalink raw reply [flat|nested] 20+ messages in thread
end of thread, other threads:[~2009-08-18 20:42 UTC | newest]
Thread overview: 20+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2009-05-27 14:49 [PATCH 1/2] Dynamic Tick: Prevent clocksource wrapping during idle Jon Hunter
2009-05-27 16:01 ` Thomas Gleixner
2009-05-27 20:20 ` john stultz
2009-05-27 20:32 ` Thomas Gleixner
2009-05-28 20:21 ` Jon Hunter
2009-05-28 20:36 ` Thomas Gleixner
2009-05-28 21:10 ` Jon Hunter
2009-05-28 21:43 ` John Stultz
2009-05-28 22:16 ` Thomas Gleixner
2009-05-29 19:43 ` Jon Hunter
2009-05-30 1:00 ` Jon Hunter
2009-06-04 19:29 ` Jon Hunter
2009-06-25 19:10 ` Jon Hunter
2009-05-27 18:15 ` john stultz
2009-05-27 20:54 ` Alok Kataria
2009-05-27 21:12 ` Thomas Gleixner
-- strict thread matches above, loose matches on Subject: below --
2009-07-28 0:00 [PATCH 0/2] Dynamic Tick: Enabling longer sleep times on 32-bit Jon Hunter
2009-07-28 0:00 ` [PATCH 1/2] Dynamic Tick: Prevent clocksource wrapping during idle Jon Hunter
2009-08-18 17:45 [PATCH 0/2] Dynamic Tick: Enabling longer sleep times on 32-bit machines Jon Hunter
2009-08-18 17:45 ` [PATCH 1/2] Dynamic Tick: Prevent clocksource wrapping during idle Jon Hunter
2009-08-18 19:25 ` Thomas Gleixner
2009-08-18 20:42 ` Jon Hunter
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox