diff options
Diffstat (limited to 'kernel/time/tick-sched.c')
-rw-r--r-- | kernel/time/tick-sched.c | 28 |
1 files changed, 27 insertions, 1 deletions
diff --git a/kernel/time/tick-sched.c b/kernel/time/tick-sched.c index 6a3a5b9ff561..4a08472c3ca7 100644 --- a/kernel/time/tick-sched.c +++ b/kernel/time/tick-sched.c | |||
@@ -274,6 +274,7 @@ EXPORT_SYMBOL_GPL(get_cpu_iowait_time_us); | |||
274 | static void tick_nohz_stop_sched_tick(struct tick_sched *ts) | 274 | static void tick_nohz_stop_sched_tick(struct tick_sched *ts) |
275 | { | 275 | { |
276 | unsigned long seq, last_jiffies, next_jiffies, delta_jiffies; | 276 | unsigned long seq, last_jiffies, next_jiffies, delta_jiffies; |
277 | unsigned long rcu_delta_jiffies; | ||
277 | ktime_t last_update, expires, now; | 278 | ktime_t last_update, expires, now; |
278 | struct clock_event_device *dev = __get_cpu_var(tick_cpu_device).evtdev; | 279 | struct clock_event_device *dev = __get_cpu_var(tick_cpu_device).evtdev; |
279 | u64 time_delta; | 280 | u64 time_delta; |
@@ -322,7 +323,7 @@ static void tick_nohz_stop_sched_tick(struct tick_sched *ts) | |||
322 | time_delta = timekeeping_max_deferment(); | 323 | time_delta = timekeeping_max_deferment(); |
323 | } while (read_seqretry(&xtime_lock, seq)); | 324 | } while (read_seqretry(&xtime_lock, seq)); |
324 | 325 | ||
325 | if (rcu_needs_cpu(cpu) || printk_needs_cpu(cpu) || | 326 | if (rcu_needs_cpu(cpu, &rcu_delta_jiffies) || printk_needs_cpu(cpu) || |
326 | arch_needs_cpu(cpu)) { | 327 | arch_needs_cpu(cpu)) { |
327 | next_jiffies = last_jiffies + 1; | 328 | next_jiffies = last_jiffies + 1; |
328 | delta_jiffies = 1; | 329 | delta_jiffies = 1; |
@@ -330,6 +331,10 @@ static void tick_nohz_stop_sched_tick(struct tick_sched *ts) | |||
330 | /* Get the next timer wheel timer */ | 331 | /* Get the next timer wheel timer */ |
331 | next_jiffies = get_next_timer_interrupt(last_jiffies); | 332 | next_jiffies = get_next_timer_interrupt(last_jiffies); |
332 | delta_jiffies = next_jiffies - last_jiffies; | 333 | delta_jiffies = next_jiffies - last_jiffies; |
334 | if (rcu_delta_jiffies < delta_jiffies) { | ||
335 | next_jiffies = last_jiffies + rcu_delta_jiffies; | ||
336 | delta_jiffies = rcu_delta_jiffies; | ||
337 | } | ||
333 | } | 338 | } |
334 | /* | 339 | /* |
335 | * Do not stop the tick, if we are only one off | 340 | * Do not stop the tick, if we are only one off |
@@ -401,6 +406,7 @@ static void tick_nohz_stop_sched_tick(struct tick_sched *ts) | |||
401 | */ | 406 | */ |
402 | if (!ts->tick_stopped) { | 407 | if (!ts->tick_stopped) { |
403 | select_nohz_load_balancer(1); | 408 | select_nohz_load_balancer(1); |
409 | calc_load_enter_idle(); | ||
404 | 410 | ||
405 | ts->idle_tick = hrtimer_get_expires(&ts->sched_timer); | 411 | ts->idle_tick = hrtimer_get_expires(&ts->sched_timer); |
406 | ts->tick_stopped = 1; | 412 | ts->tick_stopped = 1; |
@@ -576,6 +582,7 @@ void tick_nohz_idle_exit(void) | |||
576 | /* Update jiffies first */ | 582 | /* Update jiffies first */ |
577 | select_nohz_load_balancer(0); | 583 | select_nohz_load_balancer(0); |
578 | tick_do_update_jiffies64(now); | 584 | tick_do_update_jiffies64(now); |
585 | update_cpu_load_nohz(); | ||
579 | 586 | ||
580 | #ifndef CONFIG_VIRT_CPU_ACCOUNTING | 587 | #ifndef CONFIG_VIRT_CPU_ACCOUNTING |
581 | /* | 588 | /* |
@@ -591,6 +598,7 @@ void tick_nohz_idle_exit(void) | |||
591 | account_idle_ticks(ticks); | 598 | account_idle_ticks(ticks); |
592 | #endif | 599 | #endif |
593 | 600 | ||
601 | calc_load_exit_idle(); | ||
594 | touch_softlockup_watchdog(); | 602 | touch_softlockup_watchdog(); |
595 | /* | 603 | /* |
596 | * Cancel the scheduled timer and restore the tick | 604 | * Cancel the scheduled timer and restore the tick |
@@ -814,6 +822,16 @@ static enum hrtimer_restart tick_sched_timer(struct hrtimer *timer) | |||
814 | return HRTIMER_RESTART; | 822 | return HRTIMER_RESTART; |
815 | } | 823 | } |
816 | 824 | ||
825 | static int sched_skew_tick; | ||
826 | |||
827 | static int __init skew_tick(char *str) | ||
828 | { | ||
829 | get_option(&str, &sched_skew_tick); | ||
830 | |||
831 | return 0; | ||
832 | } | ||
833 | early_param("skew_tick", skew_tick); | ||
834 | |||
817 | /** | 835 | /** |
818 | * tick_setup_sched_timer - setup the tick emulation timer | 836 | * tick_setup_sched_timer - setup the tick emulation timer |
819 | */ | 837 | */ |
@@ -831,6 +849,14 @@ void tick_setup_sched_timer(void) | |||
831 | /* Get the next period (per cpu) */ | 849 | /* Get the next period (per cpu) */ |
832 | hrtimer_set_expires(&ts->sched_timer, tick_init_jiffy_update()); | 850 | hrtimer_set_expires(&ts->sched_timer, tick_init_jiffy_update()); |
833 | 851 | ||
852 | /* Offset the tick to avert xtime_lock contention. */ | ||
853 | if (sched_skew_tick) { | ||
854 | u64 offset = ktime_to_ns(tick_period) >> 1; | ||
855 | do_div(offset, num_possible_cpus()); | ||
856 | offset *= smp_processor_id(); | ||
857 | hrtimer_add_expires_ns(&ts->sched_timer, offset); | ||
858 | } | ||
859 | |||
834 | for (;;) { | 860 | for (;;) { |
835 | hrtimer_forward(&ts->sched_timer, now, tick_period); | 861 | hrtimer_forward(&ts->sched_timer, now, tick_period); |
836 | hrtimer_start_expires(&ts->sched_timer, | 862 | hrtimer_start_expires(&ts->sched_timer, |