diff options
author | John Stultz <john.stultz@linaro.org> | 2011-10-27 21:12:42 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2011-10-28 02:57:38 -0400 |
commit | c2bc11113c50449f23c40b724fe410fc2380a8e9 (patch) | |
tree | f5a6a5f9c199d6b3ed7a973dfb7556ad2af2bf5a /kernel | |
parent | e35f95b36e43f67a6f806172555a152c11ea0a78 (diff) |
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>
Diffstat (limited to 'kernel')
-rw-r--r-- | 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 2b021b0e8507..025e136f3881 100644 --- a/kernel/time/timekeeping.c +++ b/kernel/time/timekeeping.c | |||
@@ -802,14 +802,44 @@ static void timekeeping_adjust(s64 offset) | |||
802 | s64 error, interval = timekeeper.cycle_interval; | 802 | s64 error, interval = timekeeper.cycle_interval; |
803 | int adj; | 803 | int adj; |
804 | 804 | ||
805 | /* | ||
806 | * The point of this is to check if the error is greater then half | ||
807 | * an interval. | ||
808 | * | ||
809 | * First we shift it down from NTP_SHIFT to clocksource->shifted nsecs. | ||
810 | * | ||
811 | * Note we subtract one in the shift, so that error is really error*2. | ||
812 | * This "saves" dividing(shifting) intererval twice, but keeps the | ||
813 | * (error > interval) comparision as still measuring if error is | ||
814 | * larger then half an interval. | ||
815 | * | ||
816 | * Note: It does not "save" on aggrivation when reading the code. | ||
817 | */ | ||
805 | error = timekeeper.ntp_error >> (timekeeper.ntp_error_shift - 1); | 818 | error = timekeeper.ntp_error >> (timekeeper.ntp_error_shift - 1); |
806 | if (error > interval) { | 819 | if (error > interval) { |
820 | /* | ||
821 | * We now divide error by 4(via shift), which checks if | ||
822 | * the error is greater then twice the interval. | ||
823 | * If it is greater, we need a bigadjust, if its smaller, | ||
824 | * we can adjust by 1. | ||
825 | */ | ||
807 | error >>= 2; | 826 | error >>= 2; |
827 | /* | ||
828 | * XXX - In update_wall_time, we round up to the next | ||
829 | * nanosecond, and store the amount rounded up into | ||
830 | * the error. This causes the likely below to be unlikely. | ||
831 | * | ||
832 | * The properfix is to avoid rounding up by using | ||
833 | * the high precision timekeeper.xtime_nsec instead of | ||
834 | * xtime.tv_nsec everywhere. Fixing this will take some | ||
835 | * time. | ||
836 | */ | ||
808 | if (likely(error <= interval)) | 837 | if (likely(error <= interval)) |
809 | adj = 1; | 838 | adj = 1; |
810 | else | 839 | else |
811 | adj = timekeeping_bigadjust(error, &interval, &offset); | 840 | adj = timekeeping_bigadjust(error, &interval, &offset); |
812 | } else if (error < -interval) { | 841 | } else if (error < -interval) { |
842 | /* See comment above, this is just switched for the negative */ | ||
813 | error >>= 2; | 843 | error >>= 2; |
814 | if (likely(error >= -interval)) { | 844 | if (likely(error >= -interval)) { |
815 | adj = -1; | 845 | adj = -1; |
@@ -817,9 +847,58 @@ static void timekeeping_adjust(s64 offset) | |||
817 | offset = -offset; | 847 | offset = -offset; |
818 | } else | 848 | } else |
819 | adj = timekeeping_bigadjust(error, &interval, &offset); | 849 | adj = timekeeping_bigadjust(error, &interval, &offset); |
820 | } else | 850 | } else /* No adjustment needed */ |
821 | return; | 851 | return; |
822 | 852 | ||
853 | /* | ||
854 | * So the following can be confusing. | ||
855 | * | ||
856 | * To keep things simple, lets assume adj == 1 for now. | ||
857 | * | ||
858 | * When adj != 1, remember that the interval and offset values | ||
859 | * have been appropriately scaled so the math is the same. | ||
860 | * | ||
861 | * The basic idea here is that we're increasing the multiplier | ||
862 | * by one, this causes the xtime_interval to be incremented by | ||
863 | * one cycle_interval. This is because: | ||
864 | * xtime_interval = cycle_interval * mult | ||
865 | * So if mult is being incremented by one: | ||
866 | * xtime_interval = cycle_interval * (mult + 1) | ||
867 | * Its the same as: | ||
868 | * xtime_interval = (cycle_interval * mult) + cycle_interval | ||
869 | * Which can be shortened to: | ||
870 | * xtime_interval += cycle_interval | ||
871 | * | ||
872 | * So offset stores the non-accumulated cycles. Thus the current | ||
873 | * time (in shifted nanoseconds) is: | ||
874 | * now = (offset * adj) + xtime_nsec | ||
875 | * Now, even though we're adjusting the clock frequency, we have | ||
876 | * to keep time consistent. In other words, we can't jump back | ||
877 | * in time, and we also want to avoid jumping forward in time. | ||
878 | * | ||
879 | * So given the same offset value, we need the time to be the same | ||
880 | * both before and after the freq adjustment. | ||
881 | * now = (offset * adj_1) + xtime_nsec_1 | ||
882 | * now = (offset * adj_2) + xtime_nsec_2 | ||
883 | * So: | ||
884 | * (offset * adj_1) + xtime_nsec_1 = | ||
885 | * (offset * adj_2) + xtime_nsec_2 | ||
886 | * And we know: | ||
887 | * adj_2 = adj_1 + 1 | ||
888 | * So: | ||
889 | * (offset * adj_1) + xtime_nsec_1 = | ||
890 | * (offset * (adj_1+1)) + xtime_nsec_2 | ||
891 | * (offset * adj_1) + xtime_nsec_1 = | ||
892 | * (offset * adj_1) + offset + xtime_nsec_2 | ||
893 | * Canceling the sides: | ||
894 | * xtime_nsec_1 = offset + xtime_nsec_2 | ||
895 | * Which gives us: | ||
896 | * xtime_nsec_2 = xtime_nsec_1 - offset | ||
897 | * Which simplfies to: | ||
898 | * xtime_nsec -= offset | ||
899 | * | ||
900 | * XXX - TODO: Doc ntp_error calculation. | ||
901 | */ | ||
823 | timekeeper.mult += adj; | 902 | timekeeper.mult += adj; |
824 | timekeeper.xtime_interval += interval; | 903 | timekeeper.xtime_interval += interval; |
825 | timekeeper.xtime_nsec -= offset; | 904 | timekeeper.xtime_nsec -= offset; |