diff options
author | Thomas Gleixner <tglx@linutronix.de> | 2015-04-14 17:08:37 -0400 |
---|---|---|
committer | Thomas Gleixner <tglx@linutronix.de> | 2015-04-22 11:06:49 -0400 |
commit | 868a3e915f7f5eba8f8cb4f7da2276760807c51c (patch) | |
tree | dcec10d02c9613b5cad4f32d6d3ed7352825b1c8 | |
parent | 21d6d52a1b7028e6a6840bd82e354aefa9a5e203 (diff) |
hrtimer: Make offset update smarter
On every tick/hrtimer interrupt we update the offset variables of the
clock bases. That's silly because these offsets change very seldom.
Add a sequence counter to the time keeping code which keeps track of
the offset updates (clock_was_set()). Have a sequence cache in the
hrtimer cpu bases to evaluate whether the offsets must be updated or
not. This allows us later to avoid pointless cacheline pollution.
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Reviewed-by: Preeti U Murthy <preeti@linux.vnet.ibm.com>
Acked-by: Peter Zijlstra <peterz@infradead.org>
Cc: Viresh Kumar <viresh.kumar@linaro.org>
Cc: Marcelo Tosatti <mtosatti@redhat.com>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Cc: John Stultz <john.stultz@linaro.org>
Link: http://lkml.kernel.org/r/20150414203501.132820245@linutronix.de
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Cc: John Stultz <john.stultz@linaro.org>
-rw-r--r-- | include/linux/hrtimer.h | 4 | ||||
-rw-r--r-- | include/linux/timekeeper_internal.h | 2 | ||||
-rw-r--r-- | kernel/time/hrtimer.c | 3 | ||||
-rw-r--r-- | kernel/time/timekeeping.c | 23 | ||||
-rw-r--r-- | kernel/time/timekeeping.h | 7 |
5 files changed, 26 insertions, 13 deletions
diff --git a/include/linux/hrtimer.h b/include/linux/hrtimer.h index e292830b58f0..5e04f8fc26f6 100644 --- a/include/linux/hrtimer.h +++ b/include/linux/hrtimer.h | |||
@@ -163,7 +163,7 @@ enum hrtimer_base_type { | |||
163 | * and timers | 163 | * and timers |
164 | * @cpu: cpu number | 164 | * @cpu: cpu number |
165 | * @active_bases: Bitfield to mark bases with active timers | 165 | * @active_bases: Bitfield to mark bases with active timers |
166 | * @clock_was_set: Indicates that clock was set from irq context. | 166 | * @clock_was_set_seq: Sequence counter of clock was set events |
167 | * @expires_next: absolute time of the next event which was scheduled | 167 | * @expires_next: absolute time of the next event which was scheduled |
168 | * via clock_set_next_event() | 168 | * via clock_set_next_event() |
169 | * @in_hrtirq: hrtimer_interrupt() is currently executing | 169 | * @in_hrtirq: hrtimer_interrupt() is currently executing |
@@ -179,7 +179,7 @@ struct hrtimer_cpu_base { | |||
179 | raw_spinlock_t lock; | 179 | raw_spinlock_t lock; |
180 | unsigned int cpu; | 180 | unsigned int cpu; |
181 | unsigned int active_bases; | 181 | unsigned int active_bases; |
182 | unsigned int clock_was_set; | 182 | unsigned int clock_was_set_seq; |
183 | #ifdef CONFIG_HIGH_RES_TIMERS | 183 | #ifdef CONFIG_HIGH_RES_TIMERS |
184 | ktime_t expires_next; | 184 | ktime_t expires_next; |
185 | int in_hrtirq; | 185 | int in_hrtirq; |
diff --git a/include/linux/timekeeper_internal.h b/include/linux/timekeeper_internal.h index fb86963859c7..6f8276ae579c 100644 --- a/include/linux/timekeeper_internal.h +++ b/include/linux/timekeeper_internal.h | |||
@@ -49,6 +49,7 @@ struct tk_read_base { | |||
49 | * @offs_boot: Offset clock monotonic -> clock boottime | 49 | * @offs_boot: Offset clock monotonic -> clock boottime |
50 | * @offs_tai: Offset clock monotonic -> clock tai | 50 | * @offs_tai: Offset clock monotonic -> clock tai |
51 | * @tai_offset: The current UTC to TAI offset in seconds | 51 | * @tai_offset: The current UTC to TAI offset in seconds |
52 | * @clock_was_set_seq: The sequence number of clock was set events | ||
52 | * @raw_time: Monotonic raw base time in timespec64 format | 53 | * @raw_time: Monotonic raw base time in timespec64 format |
53 | * @cycle_interval: Number of clock cycles in one NTP interval | 54 | * @cycle_interval: Number of clock cycles in one NTP interval |
54 | * @xtime_interval: Number of clock shifted nano seconds in one NTP | 55 | * @xtime_interval: Number of clock shifted nano seconds in one NTP |
@@ -85,6 +86,7 @@ struct timekeeper { | |||
85 | ktime_t offs_boot; | 86 | ktime_t offs_boot; |
86 | ktime_t offs_tai; | 87 | ktime_t offs_tai; |
87 | s32 tai_offset; | 88 | s32 tai_offset; |
89 | unsigned int clock_was_set_seq; | ||
88 | struct timespec64 raw_time; | 90 | struct timespec64 raw_time; |
89 | 91 | ||
90 | /* The following members are for timekeeping internal use */ | 92 | /* The following members are for timekeeping internal use */ |
diff --git a/kernel/time/hrtimer.c b/kernel/time/hrtimer.c index 9e111dd83ca3..8ce9b3138017 100644 --- a/kernel/time/hrtimer.c +++ b/kernel/time/hrtimer.c | |||
@@ -451,7 +451,8 @@ static inline ktime_t hrtimer_update_base(struct hrtimer_cpu_base *base) | |||
451 | ktime_t *offs_boot = &base->clock_base[HRTIMER_BASE_BOOTTIME].offset; | 451 | ktime_t *offs_boot = &base->clock_base[HRTIMER_BASE_BOOTTIME].offset; |
452 | ktime_t *offs_tai = &base->clock_base[HRTIMER_BASE_TAI].offset; | 452 | ktime_t *offs_tai = &base->clock_base[HRTIMER_BASE_TAI].offset; |
453 | 453 | ||
454 | return ktime_get_update_offsets_now(offs_real, offs_boot, offs_tai); | 454 | return ktime_get_update_offsets_now(&base->clock_was_set_seq, |
455 | offs_real, offs_boot, offs_tai); | ||
455 | } | 456 | } |
456 | 457 | ||
457 | /* High resolution timer related functions */ | 458 | /* High resolution timer related functions */ |
diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c index dd1efa6a4ea4..3365e32dc208 100644 --- a/kernel/time/timekeeping.c +++ b/kernel/time/timekeeping.c | |||
@@ -602,6 +602,9 @@ static void timekeeping_update(struct timekeeper *tk, unsigned int action) | |||
602 | 602 | ||
603 | update_fast_timekeeper(&tk->tkr_mono, &tk_fast_mono); | 603 | update_fast_timekeeper(&tk->tkr_mono, &tk_fast_mono); |
604 | update_fast_timekeeper(&tk->tkr_raw, &tk_fast_raw); | 604 | update_fast_timekeeper(&tk->tkr_raw, &tk_fast_raw); |
605 | |||
606 | if (action & TK_CLOCK_WAS_SET) | ||
607 | tk->clock_was_set_seq++; | ||
605 | } | 608 | } |
606 | 609 | ||
607 | /** | 610 | /** |
@@ -1927,15 +1930,19 @@ void do_timer(unsigned long ticks) | |||
1927 | 1930 | ||
1928 | /** | 1931 | /** |
1929 | * ktime_get_update_offsets_now - hrtimer helper | 1932 | * ktime_get_update_offsets_now - hrtimer helper |
1933 | * @cwsseq: pointer to check and store the clock was set sequence number | ||
1930 | * @offs_real: pointer to storage for monotonic -> realtime offset | 1934 | * @offs_real: pointer to storage for monotonic -> realtime offset |
1931 | * @offs_boot: pointer to storage for monotonic -> boottime offset | 1935 | * @offs_boot: pointer to storage for monotonic -> boottime offset |
1932 | * @offs_tai: pointer to storage for monotonic -> clock tai offset | 1936 | * @offs_tai: pointer to storage for monotonic -> clock tai offset |
1933 | * | 1937 | * |
1934 | * Returns current monotonic time and updates the offsets | 1938 | * Returns current monotonic time and updates the offsets if the |
1939 | * sequence number in @cwsseq and timekeeper.clock_was_set_seq are | ||
1940 | * different. | ||
1941 | * | ||
1935 | * Called from hrtimer_interrupt() or retrigger_next_event() | 1942 | * Called from hrtimer_interrupt() or retrigger_next_event() |
1936 | */ | 1943 | */ |
1937 | ktime_t ktime_get_update_offsets_now(ktime_t *offs_real, ktime_t *offs_boot, | 1944 | ktime_t ktime_get_update_offsets_now(unsigned int *cwsseq, ktime_t *offs_real, |
1938 | ktime_t *offs_tai) | 1945 | ktime_t *offs_boot, ktime_t *offs_tai) |
1939 | { | 1946 | { |
1940 | struct timekeeper *tk = &tk_core.timekeeper; | 1947 | struct timekeeper *tk = &tk_core.timekeeper; |
1941 | unsigned int seq; | 1948 | unsigned int seq; |
@@ -1947,10 +1954,12 @@ ktime_t ktime_get_update_offsets_now(ktime_t *offs_real, ktime_t *offs_boot, | |||
1947 | 1954 | ||
1948 | base = tk->tkr_mono.base; | 1955 | base = tk->tkr_mono.base; |
1949 | nsecs = timekeeping_get_ns(&tk->tkr_mono); | 1956 | nsecs = timekeeping_get_ns(&tk->tkr_mono); |
1950 | 1957 | if (*cwsseq != tk->clock_was_set_seq) { | |
1951 | *offs_real = tk->offs_real; | 1958 | *cwsseq = tk->clock_was_set_seq; |
1952 | *offs_boot = tk->offs_boot; | 1959 | *offs_real = tk->offs_real; |
1953 | *offs_tai = tk->offs_tai; | 1960 | *offs_boot = tk->offs_boot; |
1961 | *offs_tai = tk->offs_tai; | ||
1962 | } | ||
1954 | } while (read_seqcount_retry(&tk_core.seq, seq)); | 1963 | } while (read_seqcount_retry(&tk_core.seq, seq)); |
1955 | 1964 | ||
1956 | return ktime_add_ns(base, nsecs); | 1965 | return ktime_add_ns(base, nsecs); |
diff --git a/kernel/time/timekeeping.h b/kernel/time/timekeeping.h index 4d177fce37d5..704f595ce83f 100644 --- a/kernel/time/timekeeping.h +++ b/kernel/time/timekeeping.h | |||
@@ -3,9 +3,10 @@ | |||
3 | /* | 3 | /* |
4 | * Internal interfaces for kernel/time/ | 4 | * Internal interfaces for kernel/time/ |
5 | */ | 5 | */ |
6 | extern ktime_t ktime_get_update_offsets_now(ktime_t *offs_real, | 6 | extern ktime_t ktime_get_update_offsets_now(unsigned int *cwsseq, |
7 | ktime_t *offs_boot, | 7 | ktime_t *offs_real, |
8 | ktime_t *offs_tai); | 8 | ktime_t *offs_boot, |
9 | ktime_t *offs_tai); | ||
9 | 10 | ||
10 | extern int timekeeping_valid_for_hres(void); | 11 | extern int timekeeping_valid_for_hres(void); |
11 | extern u64 timekeeping_max_deferment(void); | 12 | extern u64 timekeeping_max_deferment(void); |