aboutsummaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
authorFrederic Weisbecker <fweisbec@gmail.com>2011-07-27 22:00:47 -0400
committerFrederic Weisbecker <fweisbec@gmail.com>2012-06-11 14:07:16 -0400
commit2ac0d98fd624ae50f5e6ae9c800977a9dbbfcde6 (patch)
treef2572ed41b36509862384c134ff7e467077d6902 /kernel
parent19f5f7364a1cc770b14692f609bb9b802fc334d5 (diff)
nohz: Make nohz API agnostic against idle ticks cputime accounting
When the timer tick fires, it accounts the new jiffy as either part of system, user or idle time. This is how we record the cputime statistics. But when the tick is stopped from the idle task, we still need to record the number of jiffies spent tickless until we restart the tick and fall back to traditional tick-based cputime accounting. To do this, we take a snapshot of jiffies when the tick is stopped and compute the difference against the new value of jiffies when the tick is restarted. Then we account this whole difference to the idle cputime. However we are preparing to be able to stop the tick from other places than idle. So this idle time accounting needs to be performed from the callers of nohz APIs, not from the nohz APIs themselves because we now want them to be agnostic against places that stop/restart tick. Therefore, we pull the tickless idle time accounting out of generic nohz helpers up to idle entry/exit callers. Signed-off-by: Frederic Weisbecker <fweisbec@gmail.com> Cc: Alessio Igor Bogani <abogani@kernel.org> Cc: Andrew Morton <akpm@linux-foundation.org> Cc: Avi Kivity <avi@redhat.com> Cc: Chris Metcalf <cmetcalf@tilera.com> Cc: Christoph Lameter <cl@linux.com> Cc: Daniel Lezcano <daniel.lezcano@linaro.org> Cc: Geoff Levand <geoff@infradead.org> Cc: Gilad Ben Yossef <gilad@benyossef.com> Cc: Hakan Akkan <hakanakkan@gmail.com> Cc: Ingo Molnar <mingo@kernel.org> Cc: Kevin Hilman <khilman@ti.com> Cc: Max Krasnyansky <maxk@qualcomm.com> Cc: Paul E. McKenney <paulmck@linux.vnet.ibm.com> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Stephen Hemminger <shemminger@vyatta.com> Cc: Steven Rostedt <rostedt@goodmis.org> Cc: Sven-Thorsten Dietrich <thebigcorporation@gmail.com> Cc: Thomas Gleixner <tglx@linutronix.de>
Diffstat (limited to 'kernel')
-rw-r--r--kernel/time/tick-sched.c37
1 files changed, 22 insertions, 15 deletions
diff --git a/kernel/time/tick-sched.c b/kernel/time/tick-sched.c
index 81409bba2425..911834b33b8a 100644
--- a/kernel/time/tick-sched.c
+++ b/kernel/time/tick-sched.c
@@ -402,7 +402,6 @@ static void tick_nohz_stop_sched_tick(struct tick_sched *ts, ktime_t now)
402 402
403 ts->idle_tick = hrtimer_get_expires(&ts->sched_timer); 403 ts->idle_tick = hrtimer_get_expires(&ts->sched_timer);
404 ts->tick_stopped = 1; 404 ts->tick_stopped = 1;
405 ts->idle_jiffies = last_jiffies;
406 } 405 }
407 406
408 ts->idle_sleeps++; 407 ts->idle_sleeps++;
@@ -445,9 +444,13 @@ out:
445static void __tick_nohz_idle_enter(struct tick_sched *ts) 444static void __tick_nohz_idle_enter(struct tick_sched *ts)
446{ 445{
447 ktime_t now; 446 ktime_t now;
447 int was_stopped = ts->tick_stopped;
448 448
449 now = tick_nohz_start_idle(smp_processor_id(), ts); 449 now = tick_nohz_start_idle(smp_processor_id(), ts);
450 tick_nohz_stop_sched_tick(ts, now); 450 tick_nohz_stop_sched_tick(ts, now);
451
452 if (!was_stopped && ts->tick_stopped)
453 ts->idle_jiffies = ts->last_jiffies;
451} 454}
452 455
453/** 456/**
@@ -548,15 +551,25 @@ static void tick_nohz_restart(struct tick_sched *ts, ktime_t now)
548 551
549static void tick_nohz_restart_sched_tick(struct tick_sched *ts, ktime_t now) 552static void tick_nohz_restart_sched_tick(struct tick_sched *ts, ktime_t now)
550{ 553{
551#ifndef CONFIG_VIRT_CPU_ACCOUNTING
552 unsigned long ticks;
553#endif
554 /* Update jiffies first */ 554 /* Update jiffies first */
555 select_nohz_load_balancer(0); 555 select_nohz_load_balancer(0);
556 tick_do_update_jiffies64(now); 556 tick_do_update_jiffies64(now);
557 update_cpu_load_nohz(); 557 update_cpu_load_nohz();
558 558
559 touch_softlockup_watchdog();
560 /*
561 * Cancel the scheduled timer and restore the tick
562 */
563 ts->tick_stopped = 0;
564 ts->idle_exittime = now;
565
566 tick_nohz_restart(ts, now);
567}
568
569static void tick_nohz_account_idle_ticks(struct tick_sched *ts)
570{
559#ifndef CONFIG_VIRT_CPU_ACCOUNTING 571#ifndef CONFIG_VIRT_CPU_ACCOUNTING
572 unsigned long ticks;
560 /* 573 /*
561 * We stopped the tick in idle. Update process times would miss the 574 * We stopped the tick in idle. Update process times would miss the
562 * time we slept as update_process_times does only a 1 tick 575 * time we slept as update_process_times does only a 1 tick
@@ -569,15 +582,6 @@ static void tick_nohz_restart_sched_tick(struct tick_sched *ts, ktime_t now)
569 if (ticks && ticks < LONG_MAX) 582 if (ticks && ticks < LONG_MAX)
570 account_idle_ticks(ticks); 583 account_idle_ticks(ticks);
571#endif 584#endif
572
573 touch_softlockup_watchdog();
574 /*
575 * Cancel the scheduled timer and restore the tick
576 */
577 ts->tick_stopped = 0;
578 ts->idle_exittime = now;
579
580 tick_nohz_restart(ts, now);
581} 585}
582 586
583/** 587/**
@@ -605,8 +609,10 @@ void tick_nohz_idle_exit(void)
605 if (ts->idle_active) 609 if (ts->idle_active)
606 tick_nohz_stop_idle(cpu, now); 610 tick_nohz_stop_idle(cpu, now);
607 611
608 if (ts->tick_stopped) 612 if (ts->tick_stopped) {
609 tick_nohz_restart_sched_tick(ts, now); 613 tick_nohz_restart_sched_tick(ts, now);
614 tick_nohz_account_idle_ticks(ts);
615 }
610 616
611 local_irq_enable(); 617 local_irq_enable();
612} 618}
@@ -811,7 +817,8 @@ static enum hrtimer_restart tick_sched_timer(struct hrtimer *timer)
811 */ 817 */
812 if (ts->tick_stopped) { 818 if (ts->tick_stopped) {
813 touch_softlockup_watchdog(); 819 touch_softlockup_watchdog();
814 ts->idle_jiffies++; 820 if (idle_cpu(cpu))
821 ts->idle_jiffies++;
815 } 822 }
816 update_process_times(user_mode(regs)); 823 update_process_times(user_mode(regs));
817 profile_tick(CPU_PROFILING); 824 profile_tick(CPU_PROFILING);