linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).