* [PATCH] time: Improve documentation of timekeeeping_adjust()
@ 2011-10-28 1:12 John Stultz
2011-10-28 6:05 ` Richard Cochran
` (2 more replies)
0 siblings, 3 replies; 6+ messages in thread
From: John Stultz @ 2011-10-28 1:12 UTC (permalink / raw)
To: LKML; +Cc: John Stultz, Chen Jie, Steven Rostedt, Thomas Gleixner
After getting a number of questions in private emails about the
math around admittedly very complex timekeeping_adjust() and
timekeeping_big_adjust(), I figure the code needs some better
comments.
Hopefully the explanations are clear enough and don't muddy the water
any worse.
Still needs documentation for ntp_error, but I couldn't recall
exactly the full explanation behind the code that's there (although
I do recall once working it out when Roman first proposed it).
Given a bit more time I can probably work it out, but I don't want to
hold back this documentation until then.
CC: Chen Jie <chenj@lemote.com>
CC: Steven Rostedt <rostedt@goodmis.org>
CC: Thomas Gleixner <tglx@linutronix.de>
Signed-off-by: John Stultz <john.stultz@linaro.org>
---
kernel/time/timekeeping.c | 81 ++++++++++++++++++++++++++++++++++++++++++++-
1 files changed, 80 insertions(+), 1 deletions(-)
diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c
index a5846a8..de8737e 100644
--- a/kernel/time/timekeeping.c
+++ b/kernel/time/timekeeping.c
@@ -802,14 +802,44 @@ static void timekeeping_adjust(s64 offset)
s64 error, interval = timekeeper.cycle_interval;
int adj;
+ /*
+ * The point of this is to check if the error is greater then half
+ * an interval.
+ *
+ * First we shift it down from NTP_SHIFT to clocksource->shifted nsecs.
+ *
+ * Note we subtract one in the shift, so that error is really error*2.
+ * This "saves" dividing(shifting) intererval twice, but keeps the
+ * (error > interval) comparision as still measuring if error is
+ * larger then half an interval.
+ *
+ * Note: It does not "save" on aggrivation when reading the code.
+ */
error = timekeeper.ntp_error >> (timekeeper.ntp_error_shift - 1);
if (error > interval) {
+ /*
+ * We now divide error by 4(via shift), which checks if
+ * the error is greater then twice the interval.
+ * If it is greater, we need a bigadjust, if its smaller,
+ * we can adjust by 1.
+ */
error >>= 2;
+ /*
+ * XXX - In update_wall_time, we round up to the next
+ * nanosecond, and store the amount rounded up into
+ * the error. This causes the likely below to be unlikely.
+ *
+ * The properfix is to avoid rounding up by using
+ * the high precision timekeeper.xtime_nsec instead of
+ * xtime.tv_nsec everywhere. Fixing this will take some
+ * time.
+ */
if (likely(error <= interval))
adj = 1;
else
adj = timekeeping_bigadjust(error, &interval, &offset);
} else if (error < -interval) {
+ /* See comment above, this is just switched for the negative */
error >>= 2;
if (likely(error >= -interval)) {
adj = -1;
@@ -817,9 +847,58 @@ static void timekeeping_adjust(s64 offset)
offset = -offset;
} else
adj = timekeeping_bigadjust(error, &interval, &offset);
- } else
+ } else /* No adjustment needed */
return;
+ /*
+ * So the following can be confusing.
+ *
+ * To keep things simple, lets assume adj == 1 for now.
+ *
+ * When adj != 1, remember that the interval and offset values
+ * have been appropriately scaled so the math is the same.
+ *
+ * The basic idea here is that we're increasing the multiplier
+ * by one, this causes the xtime_interval to be incremented by
+ * one cycle_interval. This is because:
+ * xtime_interval = cycle_interval * mult
+ * So if mult is being incremented by one:
+ * xtime_interval = cycle_interval * (mult + 1)
+ * Its the same as:
+ * xtime_interval = (cycle_interval * mult) + cycle_interval
+ * Which can be shortened to:
+ * xtime_interval += cycle_interval
+ *
+ * So offset stores the non-accumulated cycles. Thus the current
+ * time (in shifted nanoseconds) is:
+ * now = (offset * adj) + xtime_nsec
+ * Now, even though we're adjusting the clock frequency, we have
+ * to keep time consistent. In other words, we can't jump back
+ * in time, and we also want to avoid jumping forward in time.
+ *
+ * So given the same offset value, we need the time to be the same
+ * both before and after the freq adjustment.
+ * now = (offset * adj_1) + xtime_nsec_1
+ * now = (offset * adj_2) + xtime_nsec_2
+ * So:
+ * (offset * adj_1) + xtime_nsec_1 =
+ * (offset * adj_2) + xtime_nsec_2
+ * And we know:
+ * adj_2 = adj_1 + 1
+ * So:
+ * (offset * adj_1) + xtime_nsec_1 =
+ * (offset * (adj_1+1)) + xtime_nsec_2
+ * (offset * adj_1) + xtime_nsec_1 =
+ * (offset * adj_1) + offset + xtime_nsec_2
+ * Canceling the sides:
+ * xtime_nsec_1 = offset + xtime_nsec_2
+ * Which gives us:
+ * xtime_nsec_2 = xtime_nsec_1 - offset
+ * Which simplfies to:
+ * xtime_nsec -= offset
+ *
+ * XXX - TODO: Doc ntp_error calculation.
+ */
timekeeper.mult += adj;
timekeeper.xtime_interval += interval;
timekeeper.xtime_nsec -= offset;
--
1.7.3.2.146.gca209
^ permalink raw reply related [flat|nested] 6+ messages in thread
* Re: [PATCH] time: Improve documentation of timekeeeping_adjust()
2011-10-28 1:12 [PATCH] time: Improve documentation of timekeeeping_adjust() John Stultz
@ 2011-10-28 6:05 ` Richard Cochran
2011-10-28 7:02 ` John Stultz
2011-10-28 6:57 ` [PATCH] " Ingo Molnar
2011-11-18 23:04 ` [tip:timers/core] " tip-bot for John Stultz
2 siblings, 1 reply; 6+ messages in thread
From: Richard Cochran @ 2011-10-28 6:05 UTC (permalink / raw)
To: John Stultz; +Cc: LKML, Chen Jie, Steven Rostedt, Thomas Gleixner
On Thu, Oct 27, 2011 at 06:12:42PM -0700, John Stultz wrote:
> diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c
> index a5846a8..de8737e 100644
> --- a/kernel/time/timekeeping.c
> +++ b/kernel/time/timekeeping.c
> @@ -802,14 +802,44 @@ static void timekeeping_adjust(s64 offset)
> s64 error, interval = timekeeper.cycle_interval;
> int adj;
>
> + /*
> + * The point of this is to check if the error is greater then half
> + * an interval.
> + *
> + * First we shift it down from NTP_SHIFT to clocksource->shifted nsecs.
> + *
> + * Note we subtract one in the shift, so that error is really error*2.
> + * This "saves" dividing(shifting) intererval twice, but keeps the
> + * (error > interval) comparision as still measuring if error is
> + * larger then half an interval.
> + *
> + * Note: It does not "save" on aggrivation when reading the code.
... or on "aggravation" either :)
Thanks,
Richard
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH] time: Improve documentation of timekeeeping_adjust()
2011-10-28 1:12 [PATCH] time: Improve documentation of timekeeeping_adjust() John Stultz
2011-10-28 6:05 ` Richard Cochran
@ 2011-10-28 6:57 ` Ingo Molnar
2011-11-18 23:04 ` [tip:timers/core] " tip-bot for John Stultz
2 siblings, 0 replies; 6+ messages in thread
From: Ingo Molnar @ 2011-10-28 6:57 UTC (permalink / raw)
To: John Stultz; +Cc: LKML, Chen Jie, Steven Rostedt, Thomas Gleixner
* John Stultz <john.stultz@linaro.org> wrote:
> After getting a number of questions in private emails about the
> math around admittedly very complex timekeeping_adjust() and
> timekeeping_big_adjust(), I figure the code needs some better
> comments.
>
> Hopefully the explanations are clear enough and don't muddy the water
> any worse.
>
> Still needs documentation for ntp_error, but I couldn't recall
> exactly the full explanation behind the code that's there (although
> I do recall once working it out when Roman first proposed it).
> Given a bit more time I can probably work it out, but I don't want to
> hold back this documentation until then.
>
> CC: Chen Jie <chenj@lemote.com>
> CC: Steven Rostedt <rostedt@goodmis.org>
> CC: Thomas Gleixner <tglx@linutronix.de>
> Signed-off-by: John Stultz <john.stultz@linaro.org>
> ---
> kernel/time/timekeeping.c | 81 ++++++++++++++++++++++++++++++++++++++++++++-
> 1 files changed, 80 insertions(+), 1 deletions(-)
Applied to tip:timers/core, thanks John.
Ingo
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH] time: Improve documentation of timekeeeping_adjust()
2011-10-28 6:05 ` Richard Cochran
@ 2011-10-28 7:02 ` John Stultz
2011-10-30 17:14 ` Andy Moreton
0 siblings, 1 reply; 6+ messages in thread
From: John Stultz @ 2011-10-28 7:02 UTC (permalink / raw)
To: Richard Cochran; +Cc: LKML, Chen Jie, Steven Rostedt, Thomas Gleixner
On Fri, 2011-10-28 at 08:05 +0200, Richard Cochran wrote:
> On Thu, Oct 27, 2011 at 06:12:42PM -0700, John Stultz wrote:
> > diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c
> > index a5846a8..de8737e 100644
> > --- a/kernel/time/timekeeping.c
> > +++ b/kernel/time/timekeeping.c
> > @@ -802,14 +802,44 @@ static void timekeeping_adjust(s64 offset)
> > s64 error, interval = timekeeper.cycle_interval;
> > int adj;
> >
> > + /*
> > + * The point of this is to check if the error is greater then half
> > + * an interval.
> > + *
> > + * First we shift it down from NTP_SHIFT to clocksource->shifted nsecs.
> > + *
> > + * Note we subtract one in the shift, so that error is really error*2.
> > + * This "saves" dividing(shifting) intererval twice, but keeps the
> > + * (error > interval) comparision as still measuring if error is
> > + * larger then half an interval.
> > + *
> > + * Note: It does not "save" on aggrivation when reading the code.
>
> ... or on "aggravation" either :)
Sigh. I do need to start using an editor with built in spell checking.
I'm so poor of a speller (and a typist) its really amazing its not
worse.
Thanks for catching that.
-john
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: time: Improve documentation of timekeeeping_adjust()
2011-10-28 7:02 ` John Stultz
@ 2011-10-30 17:14 ` Andy Moreton
0 siblings, 0 replies; 6+ messages in thread
From: Andy Moreton @ 2011-10-30 17:14 UTC (permalink / raw)
To: linux-kernel
On Fri 28 Oct 2011, John Stultz wrote:
> On Fri, 2011-10-28 at 08:05 +0200, Richard Cochran wrote:
>> On Thu, Oct 27, 2011 at 06:12:42PM -0700, John Stultz wrote:
>> > diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c
>> > index a5846a8..de8737e 100644
>> > --- a/kernel/time/timekeeping.c
>> > +++ b/kernel/time/timekeeping.c
>> > @@ -802,14 +802,44 @@ static void timekeeping_adjust(s64 offset)
>> > s64 error, interval = timekeeper.cycle_interval;
>> > int adj;
>> >
>> > + /*
>> > + * The point of this is to check if the error is greater then half
>> > + * an interval.
>> > + *
>> > + * First we shift it down from NTP_SHIFT to clocksource->shifted nsecs.
>> > + *
>> > + * Note we subtract one in the shift, so that error is really error*2.
>> > + * This "saves" dividing(shifting) intererval twice, but keeps the
>> > + * (error > interval) comparision as still measuring if error is
>> > + * larger then half an interval.
>> > + *
>> > + * Note: It does not "save" on aggrivation when reading the code.
>>
>> ... or on "aggravation" either :)
>
> Sigh. I do need to start using an editor with built in spell checking.
> I'm so poor of a speller (and a typist) its really amazing its not
> worse.
>
> Thanks for catching that.
> -john
s/intererval/interval/
AndyM
^ permalink raw reply [flat|nested] 6+ messages in thread
* [tip:timers/core] time: Improve documentation of timekeeeping_adjust()
2011-10-28 1:12 [PATCH] time: Improve documentation of timekeeeping_adjust() John Stultz
2011-10-28 6:05 ` Richard Cochran
2011-10-28 6:57 ` [PATCH] " Ingo Molnar
@ 2011-11-18 23:04 ` tip-bot for John Stultz
2 siblings, 0 replies; 6+ messages in thread
From: tip-bot for John Stultz @ 2011-11-18 23:04 UTC (permalink / raw)
To: linux-tip-commits
Cc: linux-kernel, john.stultz, hpa, mingo, rostedt, chenj, tglx,
mingo
Commit-ID: c2bc11113c50449f23c40b724fe410fc2380a8e9
Gitweb: http://git.kernel.org/tip/c2bc11113c50449f23c40b724fe410fc2380a8e9
Author: John Stultz <john.stultz@linaro.org>
AuthorDate: Thu, 27 Oct 2011 18:12:42 -0700
Committer: Ingo Molnar <mingo@elte.hu>
CommitDate: Fri, 28 Oct 2011 08:57:38 +0200
time: Improve documentation of timekeeeping_adjust()
After getting a number of questions in private emails about the
math around admittedly very complex timekeeping_adjust() and
timekeeping_big_adjust(), I figure the code needs some better
comments.
Hopefully the explanations are clear enough and don't muddy the
water any worse.
Still needs documentation for ntp_error, but I couldn't recall
exactly the full explanation behind the code that's there
(although I do recall once working it out when Roman first
proposed it). Given a bit more time I can probably work it out,
but I don't want to hold back this documentation until then.
Signed-off-by: John Stultz <john.stultz@linaro.org>
Cc: Chen Jie <chenj@lemote.com>
Cc: Steven Rostedt <rostedt@goodmis.org>
Link: http://lkml.kernel.org/r/1319764362-32367-1-git-send-email-john.stultz@linaro.org
Signed-off-by: Ingo Molnar <mingo@elte.hu>
---
kernel/time/timekeeping.c | 81 ++++++++++++++++++++++++++++++++++++++++++++-
1 files changed, 80 insertions(+), 1 deletions(-)
diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c
index 2b021b0e..025e136 100644
--- a/kernel/time/timekeeping.c
+++ b/kernel/time/timekeeping.c
@@ -802,14 +802,44 @@ static void timekeeping_adjust(s64 offset)
s64 error, interval = timekeeper.cycle_interval;
int adj;
+ /*
+ * The point of this is to check if the error is greater then half
+ * an interval.
+ *
+ * First we shift it down from NTP_SHIFT to clocksource->shifted nsecs.
+ *
+ * Note we subtract one in the shift, so that error is really error*2.
+ * This "saves" dividing(shifting) intererval twice, but keeps the
+ * (error > interval) comparision as still measuring if error is
+ * larger then half an interval.
+ *
+ * Note: It does not "save" on aggrivation when reading the code.
+ */
error = timekeeper.ntp_error >> (timekeeper.ntp_error_shift - 1);
if (error > interval) {
+ /*
+ * We now divide error by 4(via shift), which checks if
+ * the error is greater then twice the interval.
+ * If it is greater, we need a bigadjust, if its smaller,
+ * we can adjust by 1.
+ */
error >>= 2;
+ /*
+ * XXX - In update_wall_time, we round up to the next
+ * nanosecond, and store the amount rounded up into
+ * the error. This causes the likely below to be unlikely.
+ *
+ * The properfix is to avoid rounding up by using
+ * the high precision timekeeper.xtime_nsec instead of
+ * xtime.tv_nsec everywhere. Fixing this will take some
+ * time.
+ */
if (likely(error <= interval))
adj = 1;
else
adj = timekeeping_bigadjust(error, &interval, &offset);
} else if (error < -interval) {
+ /* See comment above, this is just switched for the negative */
error >>= 2;
if (likely(error >= -interval)) {
adj = -1;
@@ -817,9 +847,58 @@ static void timekeeping_adjust(s64 offset)
offset = -offset;
} else
adj = timekeeping_bigadjust(error, &interval, &offset);
- } else
+ } else /* No adjustment needed */
return;
+ /*
+ * So the following can be confusing.
+ *
+ * To keep things simple, lets assume adj == 1 for now.
+ *
+ * When adj != 1, remember that the interval and offset values
+ * have been appropriately scaled so the math is the same.
+ *
+ * The basic idea here is that we're increasing the multiplier
+ * by one, this causes the xtime_interval to be incremented by
+ * one cycle_interval. This is because:
+ * xtime_interval = cycle_interval * mult
+ * So if mult is being incremented by one:
+ * xtime_interval = cycle_interval * (mult + 1)
+ * Its the same as:
+ * xtime_interval = (cycle_interval * mult) + cycle_interval
+ * Which can be shortened to:
+ * xtime_interval += cycle_interval
+ *
+ * So offset stores the non-accumulated cycles. Thus the current
+ * time (in shifted nanoseconds) is:
+ * now = (offset * adj) + xtime_nsec
+ * Now, even though we're adjusting the clock frequency, we have
+ * to keep time consistent. In other words, we can't jump back
+ * in time, and we also want to avoid jumping forward in time.
+ *
+ * So given the same offset value, we need the time to be the same
+ * both before and after the freq adjustment.
+ * now = (offset * adj_1) + xtime_nsec_1
+ * now = (offset * adj_2) + xtime_nsec_2
+ * So:
+ * (offset * adj_1) + xtime_nsec_1 =
+ * (offset * adj_2) + xtime_nsec_2
+ * And we know:
+ * adj_2 = adj_1 + 1
+ * So:
+ * (offset * adj_1) + xtime_nsec_1 =
+ * (offset * (adj_1+1)) + xtime_nsec_2
+ * (offset * adj_1) + xtime_nsec_1 =
+ * (offset * adj_1) + offset + xtime_nsec_2
+ * Canceling the sides:
+ * xtime_nsec_1 = offset + xtime_nsec_2
+ * Which gives us:
+ * xtime_nsec_2 = xtime_nsec_1 - offset
+ * Which simplfies to:
+ * xtime_nsec -= offset
+ *
+ * XXX - TODO: Doc ntp_error calculation.
+ */
timekeeper.mult += adj;
timekeeper.xtime_interval += interval;
timekeeper.xtime_nsec -= offset;
^ permalink raw reply related [flat|nested] 6+ messages in thread
end of thread, other threads:[~2011-11-18 23:04 UTC | newest]
Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2011-10-28 1:12 [PATCH] time: Improve documentation of timekeeeping_adjust() John Stultz
2011-10-28 6:05 ` Richard Cochran
2011-10-28 7:02 ` John Stultz
2011-10-30 17:14 ` Andy Moreton
2011-10-28 6:57 ` [PATCH] " Ingo Molnar
2011-11-18 23:04 ` [tip:timers/core] " tip-bot for John Stultz
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.