diff options
-rw-r--r-- | kernel/sched_clock.c | 40 |
1 files changed, 37 insertions, 3 deletions
diff --git a/kernel/sched_clock.c b/kernel/sched_clock.c index 28ff6bf5e02b..8affbfd0cdb0 100644 --- a/kernel/sched_clock.c +++ b/kernel/sched_clock.c | |||
@@ -3,6 +3,9 @@ | |||
3 | * | 3 | * |
4 | * Copyright (C) 2008 Red Hat, Inc., Peter Zijlstra <pzijlstr@redhat.com> | 4 | * Copyright (C) 2008 Red Hat, Inc., Peter Zijlstra <pzijlstr@redhat.com> |
5 | * | 5 | * |
6 | * Updates and enhancements: | ||
7 | * Copyright (C) 2008 Red Hat, Inc. Steven Rostedt <srostedt@redhat.com> | ||
8 | * | ||
6 | * Based on code by: | 9 | * Based on code by: |
7 | * Ingo Molnar <mingo@redhat.com> | 10 | * Ingo Molnar <mingo@redhat.com> |
8 | * Guillaume Chazarain <guichaz@gmail.com> | 11 | * Guillaume Chazarain <guichaz@gmail.com> |
@@ -32,6 +35,11 @@ | |||
32 | 35 | ||
33 | #ifdef CONFIG_HAVE_UNSTABLE_SCHED_CLOCK | 36 | #ifdef CONFIG_HAVE_UNSTABLE_SCHED_CLOCK |
34 | 37 | ||
38 | #define MULTI_SHIFT 15 | ||
39 | /* Max is double, Min is 1/2 */ | ||
40 | #define MAX_MULTI (2LL << MULTI_SHIFT) | ||
41 | #define MIN_MULTI (1LL << (MULTI_SHIFT-1)) | ||
42 | |||
35 | struct sched_clock_data { | 43 | struct sched_clock_data { |
36 | /* | 44 | /* |
37 | * Raw spinlock - this is a special case: this might be called | 45 | * Raw spinlock - this is a special case: this might be called |
@@ -45,6 +53,7 @@ struct sched_clock_data { | |||
45 | u64 tick_raw; | 53 | u64 tick_raw; |
46 | u64 tick_gtod; | 54 | u64 tick_gtod; |
47 | u64 clock; | 55 | u64 clock; |
56 | s64 multi; | ||
48 | #ifdef CONFIG_NO_HZ | 57 | #ifdef CONFIG_NO_HZ |
49 | int check_max; | 58 | int check_max; |
50 | #endif | 59 | #endif |
@@ -79,6 +88,7 @@ void sched_clock_init(void) | |||
79 | scd->tick_raw = 0; | 88 | scd->tick_raw = 0; |
80 | scd->tick_gtod = ktime_now; | 89 | scd->tick_gtod = ktime_now; |
81 | scd->clock = ktime_now; | 90 | scd->clock = ktime_now; |
91 | scd->multi = 1 << MULTI_SHIFT; | ||
82 | #ifdef CONFIG_NO_HZ | 92 | #ifdef CONFIG_NO_HZ |
83 | scd->check_max = 1; | 93 | scd->check_max = 1; |
84 | #endif | 94 | #endif |
@@ -134,8 +144,13 @@ static void __update_sched_clock(struct sched_clock_data *scd, u64 now, u64 *tim | |||
134 | 144 | ||
135 | WARN_ON_ONCE(!irqs_disabled()); | 145 | WARN_ON_ONCE(!irqs_disabled()); |
136 | 146 | ||
137 | min_clock = scd->tick_gtod + | 147 | /* |
138 | (delta_jiffies ? delta_jiffies - 1 : 0) * TICK_NSEC; | 148 | * At schedule tick the clock can be just under the gtod. We don't |
149 | * want to push it too prematurely. | ||
150 | */ | ||
151 | min_clock = scd->tick_gtod + (delta_jiffies * TICK_NSEC); | ||
152 | if (min_clock > TICK_NSEC) | ||
153 | min_clock -= TICK_NSEC / 2; | ||
139 | 154 | ||
140 | if (unlikely(delta < 0)) { | 155 | if (unlikely(delta < 0)) { |
141 | clock++; | 156 | clock++; |
@@ -149,6 +164,9 @@ static void __update_sched_clock(struct sched_clock_data *scd, u64 now, u64 *tim | |||
149 | */ | 164 | */ |
150 | max_clock = scd->tick_gtod + (2 + delta_jiffies) * TICK_NSEC; | 165 | max_clock = scd->tick_gtod + (2 + delta_jiffies) * TICK_NSEC; |
151 | 166 | ||
167 | delta *= scd->multi; | ||
168 | delta >>= MULTI_SHIFT; | ||
169 | |||
152 | if (unlikely(clock + delta > max_clock) && check_max(scd)) { | 170 | if (unlikely(clock + delta > max_clock) && check_max(scd)) { |
153 | if (clock < max_clock) | 171 | if (clock < max_clock) |
154 | clock = max_clock; | 172 | clock = max_clock; |
@@ -230,6 +248,7 @@ void sched_clock_tick(void) | |||
230 | { | 248 | { |
231 | struct sched_clock_data *scd = this_scd(); | 249 | struct sched_clock_data *scd = this_scd(); |
232 | unsigned long now_jiffies = jiffies; | 250 | unsigned long now_jiffies = jiffies; |
251 | s64 mult, delta_gtod, delta_raw; | ||
233 | u64 now, now_gtod; | 252 | u64 now, now_gtod; |
234 | 253 | ||
235 | if (unlikely(!sched_clock_running)) | 254 | if (unlikely(!sched_clock_running)) |
@@ -247,9 +266,23 @@ void sched_clock_tick(void) | |||
247 | * already observe 1 new jiffy; adding a new tick_gtod to that would | 266 | * already observe 1 new jiffy; adding a new tick_gtod to that would |
248 | * increase the clock 2 jiffies. | 267 | * increase the clock 2 jiffies. |
249 | */ | 268 | */ |
250 | scd->tick_jiffies = now_jiffies; | 269 | delta_gtod = now_gtod - scd->tick_gtod; |
270 | delta_raw = now - scd->tick_raw; | ||
271 | |||
272 | if ((long)delta_raw > 0) { | ||
273 | mult = delta_gtod << MULTI_SHIFT; | ||
274 | do_div(mult, delta_raw); | ||
275 | scd->multi = mult; | ||
276 | if (scd->multi > MAX_MULTI) | ||
277 | scd->multi = MAX_MULTI; | ||
278 | else if (scd->multi < MIN_MULTI) | ||
279 | scd->multi = MIN_MULTI; | ||
280 | } else | ||
281 | scd->multi = 1 << MULTI_SHIFT; | ||
282 | |||
251 | scd->tick_raw = now; | 283 | scd->tick_raw = now; |
252 | scd->tick_gtod = now_gtod; | 284 | scd->tick_gtod = now_gtod; |
285 | scd->tick_jiffies = now_jiffies; | ||
253 | __raw_spin_unlock(&scd->lock); | 286 | __raw_spin_unlock(&scd->lock); |
254 | } | 287 | } |
255 | 288 | ||
@@ -279,6 +312,7 @@ void sched_clock_idle_wakeup_event(u64 delta_ns) | |||
279 | __raw_spin_lock(&scd->lock); | 312 | __raw_spin_lock(&scd->lock); |
280 | scd->prev_raw = now; | 313 | scd->prev_raw = now; |
281 | scd->clock += delta_ns; | 314 | scd->clock += delta_ns; |
315 | scd->multi = 1 << MULTI_SHIFT; | ||
282 | __raw_spin_unlock(&scd->lock); | 316 | __raw_spin_unlock(&scd->lock); |
283 | 317 | ||
284 | touch_softlockup_watchdog(); | 318 | touch_softlockup_watchdog(); |