diff options
Diffstat (limited to 'kernel/time/tick-sched.c')
-rw-r--r-- | kernel/time/tick-sched.c | 164 |
1 files changed, 108 insertions, 56 deletions
diff --git a/kernel/time/tick-sched.c b/kernel/time/tick-sched.c index a4d219398167..8f3fc2582d38 100644 --- a/kernel/time/tick-sched.c +++ b/kernel/time/tick-sched.c | |||
@@ -155,7 +155,7 @@ void tick_nohz_update_jiffies(void) | |||
155 | touch_softlockup_watchdog(); | 155 | touch_softlockup_watchdog(); |
156 | } | 156 | } |
157 | 157 | ||
158 | void tick_nohz_stop_idle(int cpu) | 158 | static void tick_nohz_stop_idle(int cpu) |
159 | { | 159 | { |
160 | struct tick_sched *ts = &per_cpu(tick_cpu_sched, cpu); | 160 | struct tick_sched *ts = &per_cpu(tick_cpu_sched, cpu); |
161 | 161 | ||
@@ -247,7 +247,7 @@ void tick_nohz_stop_sched_tick(int inidle) | |||
247 | if (need_resched()) | 247 | if (need_resched()) |
248 | goto end; | 248 | goto end; |
249 | 249 | ||
250 | if (unlikely(local_softirq_pending())) { | 250 | if (unlikely(local_softirq_pending() && cpu_online(cpu))) { |
251 | static int ratelimit; | 251 | static int ratelimit; |
252 | 252 | ||
253 | if (ratelimit < 10) { | 253 | if (ratelimit < 10) { |
@@ -270,7 +270,7 @@ void tick_nohz_stop_sched_tick(int inidle) | |||
270 | next_jiffies = get_next_timer_interrupt(last_jiffies); | 270 | next_jiffies = get_next_timer_interrupt(last_jiffies); |
271 | delta_jiffies = next_jiffies - last_jiffies; | 271 | delta_jiffies = next_jiffies - last_jiffies; |
272 | 272 | ||
273 | if (rcu_needs_cpu(cpu)) | 273 | if (rcu_needs_cpu(cpu) || printk_needs_cpu(cpu)) |
274 | delta_jiffies = 1; | 274 | delta_jiffies = 1; |
275 | /* | 275 | /* |
276 | * Do not stop the tick, if we are only one off | 276 | * Do not stop the tick, if we are only one off |
@@ -282,8 +282,31 @@ void tick_nohz_stop_sched_tick(int inidle) | |||
282 | /* Schedule the tick, if we are at least one jiffie off */ | 282 | /* Schedule the tick, if we are at least one jiffie off */ |
283 | if ((long)delta_jiffies >= 1) { | 283 | if ((long)delta_jiffies >= 1) { |
284 | 284 | ||
285 | /* | ||
286 | * calculate the expiry time for the next timer wheel | ||
287 | * timer | ||
288 | */ | ||
289 | expires = ktime_add_ns(last_update, tick_period.tv64 * | ||
290 | delta_jiffies); | ||
291 | |||
292 | /* | ||
293 | * If this cpu is the one which updates jiffies, then | ||
294 | * give up the assignment and let it be taken by the | ||
295 | * cpu which runs the tick timer next, which might be | ||
296 | * this cpu as well. If we don't drop this here the | ||
297 | * jiffies might be stale and do_timer() never | ||
298 | * invoked. | ||
299 | */ | ||
300 | if (cpu == tick_do_timer_cpu) | ||
301 | tick_do_timer_cpu = TICK_DO_TIMER_NONE; | ||
302 | |||
285 | if (delta_jiffies > 1) | 303 | if (delta_jiffies > 1) |
286 | cpu_set(cpu, nohz_cpu_mask); | 304 | cpu_set(cpu, nohz_cpu_mask); |
305 | |||
306 | /* Skip reprogram of event if its not changed */ | ||
307 | if (ts->tick_stopped && ktime_equal(expires, dev->next_event)) | ||
308 | goto out; | ||
309 | |||
287 | /* | 310 | /* |
288 | * nohz_stop_sched_tick can be called several times before | 311 | * nohz_stop_sched_tick can be called several times before |
289 | * the nohz_restart_sched_tick is called. This happens when | 312 | * the nohz_restart_sched_tick is called. This happens when |
@@ -300,23 +323,12 @@ void tick_nohz_stop_sched_tick(int inidle) | |||
300 | goto out; | 323 | goto out; |
301 | } | 324 | } |
302 | 325 | ||
303 | ts->idle_tick = ts->sched_timer.expires; | 326 | ts->idle_tick = hrtimer_get_expires(&ts->sched_timer); |
304 | ts->tick_stopped = 1; | 327 | ts->tick_stopped = 1; |
305 | ts->idle_jiffies = last_jiffies; | 328 | ts->idle_jiffies = last_jiffies; |
306 | rcu_enter_nohz(); | 329 | rcu_enter_nohz(); |
307 | } | 330 | } |
308 | 331 | ||
309 | /* | ||
310 | * If this cpu is the one which updates jiffies, then | ||
311 | * give up the assignment and let it be taken by the | ||
312 | * cpu which runs the tick timer next, which might be | ||
313 | * this cpu as well. If we don't drop this here the | ||
314 | * jiffies might be stale and do_timer() never | ||
315 | * invoked. | ||
316 | */ | ||
317 | if (cpu == tick_do_timer_cpu) | ||
318 | tick_do_timer_cpu = TICK_DO_TIMER_NONE; | ||
319 | |||
320 | ts->idle_sleeps++; | 332 | ts->idle_sleeps++; |
321 | 333 | ||
322 | /* | 334 | /* |
@@ -332,12 +344,7 @@ void tick_nohz_stop_sched_tick(int inidle) | |||
332 | goto out; | 344 | goto out; |
333 | } | 345 | } |
334 | 346 | ||
335 | /* | 347 | /* Mark expiries */ |
336 | * calculate the expiry time for the next timer wheel | ||
337 | * timer | ||
338 | */ | ||
339 | expires = ktime_add_ns(last_update, tick_period.tv64 * | ||
340 | delta_jiffies); | ||
341 | ts->idle_expires = expires; | 348 | ts->idle_expires = expires; |
342 | 349 | ||
343 | if (ts->nohz_mode == NOHZ_MODE_HIGHRES) { | 350 | if (ts->nohz_mode == NOHZ_MODE_HIGHRES) { |
@@ -377,6 +384,32 @@ ktime_t tick_nohz_get_sleep_length(void) | |||
377 | return ts->sleep_length; | 384 | return ts->sleep_length; |
378 | } | 385 | } |
379 | 386 | ||
387 | static void tick_nohz_restart(struct tick_sched *ts, ktime_t now) | ||
388 | { | ||
389 | hrtimer_cancel(&ts->sched_timer); | ||
390 | hrtimer_set_expires(&ts->sched_timer, ts->idle_tick); | ||
391 | |||
392 | while (1) { | ||
393 | /* Forward the time to expire in the future */ | ||
394 | hrtimer_forward(&ts->sched_timer, now, tick_period); | ||
395 | |||
396 | if (ts->nohz_mode == NOHZ_MODE_HIGHRES) { | ||
397 | hrtimer_start_expires(&ts->sched_timer, | ||
398 | HRTIMER_MODE_ABS); | ||
399 | /* Check, if the timer was already in the past */ | ||
400 | if (hrtimer_active(&ts->sched_timer)) | ||
401 | break; | ||
402 | } else { | ||
403 | if (!tick_program_event( | ||
404 | hrtimer_get_expires(&ts->sched_timer), 0)) | ||
405 | break; | ||
406 | } | ||
407 | /* Update jiffies and reread time */ | ||
408 | tick_do_update_jiffies64(now); | ||
409 | now = ktime_get(); | ||
410 | } | ||
411 | } | ||
412 | |||
380 | /** | 413 | /** |
381 | * tick_nohz_restart_sched_tick - restart the idle tick from the idle task | 414 | * tick_nohz_restart_sched_tick - restart the idle tick from the idle task |
382 | * | 415 | * |
@@ -430,35 +463,16 @@ void tick_nohz_restart_sched_tick(void) | |||
430 | */ | 463 | */ |
431 | ts->tick_stopped = 0; | 464 | ts->tick_stopped = 0; |
432 | ts->idle_exittime = now; | 465 | ts->idle_exittime = now; |
433 | hrtimer_cancel(&ts->sched_timer); | ||
434 | ts->sched_timer.expires = ts->idle_tick; | ||
435 | 466 | ||
436 | while (1) { | 467 | tick_nohz_restart(ts, now); |
437 | /* Forward the time to expire in the future */ | ||
438 | hrtimer_forward(&ts->sched_timer, now, tick_period); | ||
439 | 468 | ||
440 | if (ts->nohz_mode == NOHZ_MODE_HIGHRES) { | ||
441 | hrtimer_start(&ts->sched_timer, | ||
442 | ts->sched_timer.expires, | ||
443 | HRTIMER_MODE_ABS); | ||
444 | /* Check, if the timer was already in the past */ | ||
445 | if (hrtimer_active(&ts->sched_timer)) | ||
446 | break; | ||
447 | } else { | ||
448 | if (!tick_program_event(ts->sched_timer.expires, 0)) | ||
449 | break; | ||
450 | } | ||
451 | /* Update jiffies and reread time */ | ||
452 | tick_do_update_jiffies64(now); | ||
453 | now = ktime_get(); | ||
454 | } | ||
455 | local_irq_enable(); | 469 | local_irq_enable(); |
456 | } | 470 | } |
457 | 471 | ||
458 | static int tick_nohz_reprogram(struct tick_sched *ts, ktime_t now) | 472 | static int tick_nohz_reprogram(struct tick_sched *ts, ktime_t now) |
459 | { | 473 | { |
460 | hrtimer_forward(&ts->sched_timer, now, tick_period); | 474 | hrtimer_forward(&ts->sched_timer, now, tick_period); |
461 | return tick_program_event(ts->sched_timer.expires, 0); | 475 | return tick_program_event(hrtimer_get_expires(&ts->sched_timer), 0); |
462 | } | 476 | } |
463 | 477 | ||
464 | /* | 478 | /* |
@@ -503,10 +517,6 @@ static void tick_nohz_handler(struct clock_event_device *dev) | |||
503 | update_process_times(user_mode(regs)); | 517 | update_process_times(user_mode(regs)); |
504 | profile_tick(CPU_PROFILING); | 518 | profile_tick(CPU_PROFILING); |
505 | 519 | ||
506 | /* Do not restart, when we are in the idle loop */ | ||
507 | if (ts->tick_stopped) | ||
508 | return; | ||
509 | |||
510 | while (tick_nohz_reprogram(ts, now)) { | 520 | while (tick_nohz_reprogram(ts, now)) { |
511 | now = ktime_get(); | 521 | now = ktime_get(); |
512 | tick_do_update_jiffies64(now); | 522 | tick_do_update_jiffies64(now); |
@@ -541,7 +551,7 @@ static void tick_nohz_switch_to_nohz(void) | |||
541 | next = tick_init_jiffy_update(); | 551 | next = tick_init_jiffy_update(); |
542 | 552 | ||
543 | for (;;) { | 553 | for (;;) { |
544 | ts->sched_timer.expires = next; | 554 | hrtimer_set_expires(&ts->sched_timer, next); |
545 | if (!tick_program_event(next, 0)) | 555 | if (!tick_program_event(next, 0)) |
546 | break; | 556 | break; |
547 | next = ktime_add(next, tick_period); | 557 | next = ktime_add(next, tick_period); |
@@ -552,6 +562,41 @@ static void tick_nohz_switch_to_nohz(void) | |||
552 | smp_processor_id()); | 562 | smp_processor_id()); |
553 | } | 563 | } |
554 | 564 | ||
565 | /* | ||
566 | * When NOHZ is enabled and the tick is stopped, we need to kick the | ||
567 | * tick timer from irq_enter() so that the jiffies update is kept | ||
568 | * alive during long running softirqs. That's ugly as hell, but | ||
569 | * correctness is key even if we need to fix the offending softirq in | ||
570 | * the first place. | ||
571 | * | ||
572 | * Note, this is different to tick_nohz_restart. We just kick the | ||
573 | * timer and do not touch the other magic bits which need to be done | ||
574 | * when idle is left. | ||
575 | */ | ||
576 | static void tick_nohz_kick_tick(int cpu) | ||
577 | { | ||
578 | #if 0 | ||
579 | /* Switch back to 2.6.27 behaviour */ | ||
580 | |||
581 | struct tick_sched *ts = &per_cpu(tick_cpu_sched, cpu); | ||
582 | ktime_t delta, now; | ||
583 | |||
584 | if (!ts->tick_stopped) | ||
585 | return; | ||
586 | |||
587 | /* | ||
588 | * Do not touch the tick device, when the next expiry is either | ||
589 | * already reached or less/equal than the tick period. | ||
590 | */ | ||
591 | now = ktime_get(); | ||
592 | delta = ktime_sub(hrtimer_get_expires(&ts->sched_timer), now); | ||
593 | if (delta.tv64 <= tick_period.tv64) | ||
594 | return; | ||
595 | |||
596 | tick_nohz_restart(ts, now); | ||
597 | #endif | ||
598 | } | ||
599 | |||
555 | #else | 600 | #else |
556 | 601 | ||
557 | static inline void tick_nohz_switch_to_nohz(void) { } | 602 | static inline void tick_nohz_switch_to_nohz(void) { } |
@@ -559,6 +604,19 @@ static inline void tick_nohz_switch_to_nohz(void) { } | |||
559 | #endif /* NO_HZ */ | 604 | #endif /* NO_HZ */ |
560 | 605 | ||
561 | /* | 606 | /* |
607 | * Called from irq_enter to notify about the possible interruption of idle() | ||
608 | */ | ||
609 | void tick_check_idle(int cpu) | ||
610 | { | ||
611 | tick_check_oneshot_broadcast(cpu); | ||
612 | #ifdef CONFIG_NO_HZ | ||
613 | tick_nohz_stop_idle(cpu); | ||
614 | tick_nohz_update_jiffies(); | ||
615 | tick_nohz_kick_tick(cpu); | ||
616 | #endif | ||
617 | } | ||
618 | |||
619 | /* | ||
562 | * High resolution timer specific code | 620 | * High resolution timer specific code |
563 | */ | 621 | */ |
564 | #ifdef CONFIG_HIGH_RES_TIMERS | 622 | #ifdef CONFIG_HIGH_RES_TIMERS |
@@ -611,10 +669,6 @@ static enum hrtimer_restart tick_sched_timer(struct hrtimer *timer) | |||
611 | profile_tick(CPU_PROFILING); | 669 | profile_tick(CPU_PROFILING); |
612 | } | 670 | } |
613 | 671 | ||
614 | /* Do not restart, when we are in the idle loop */ | ||
615 | if (ts->tick_stopped) | ||
616 | return HRTIMER_NORESTART; | ||
617 | |||
618 | hrtimer_forward(timer, now, tick_period); | 672 | hrtimer_forward(timer, now, tick_period); |
619 | 673 | ||
620 | return HRTIMER_RESTART; | 674 | return HRTIMER_RESTART; |
@@ -634,19 +688,17 @@ void tick_setup_sched_timer(void) | |||
634 | */ | 688 | */ |
635 | hrtimer_init(&ts->sched_timer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS); | 689 | hrtimer_init(&ts->sched_timer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS); |
636 | ts->sched_timer.function = tick_sched_timer; | 690 | ts->sched_timer.function = tick_sched_timer; |
637 | ts->sched_timer.cb_mode = HRTIMER_CB_IRQSAFE_PERCPU; | ||
638 | 691 | ||
639 | /* Get the next period (per cpu) */ | 692 | /* Get the next period (per cpu) */ |
640 | ts->sched_timer.expires = tick_init_jiffy_update(); | 693 | hrtimer_set_expires(&ts->sched_timer, tick_init_jiffy_update()); |
641 | offset = ktime_to_ns(tick_period) >> 1; | 694 | offset = ktime_to_ns(tick_period) >> 1; |
642 | do_div(offset, num_possible_cpus()); | 695 | do_div(offset, num_possible_cpus()); |
643 | offset *= smp_processor_id(); | 696 | offset *= smp_processor_id(); |
644 | ts->sched_timer.expires = ktime_add_ns(ts->sched_timer.expires, offset); | 697 | hrtimer_add_expires_ns(&ts->sched_timer, offset); |
645 | 698 | ||
646 | for (;;) { | 699 | for (;;) { |
647 | hrtimer_forward(&ts->sched_timer, now, tick_period); | 700 | hrtimer_forward(&ts->sched_timer, now, tick_period); |
648 | hrtimer_start(&ts->sched_timer, ts->sched_timer.expires, | 701 | hrtimer_start_expires(&ts->sched_timer, HRTIMER_MODE_ABS); |
649 | HRTIMER_MODE_ABS); | ||
650 | /* Check, if the timer was already in the past */ | 702 | /* Check, if the timer was already in the past */ |
651 | if (hrtimer_active(&ts->sched_timer)) | 703 | if (hrtimer_active(&ts->sched_timer)) |
652 | break; | 704 | break; |