aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/sched/cputime.c
diff options
context:
space:
mode:
authorFrederic Weisbecker <fweisbec@gmail.com>2014-03-05 11:02:22 -0500
committerFrederic Weisbecker <fweisbec@gmail.com>2014-03-13 10:56:44 -0400
commitdee08a72deefac251267ed2717717596aa8b6818 (patch)
tree33334d1764905dbbac0d795f2086b03d91ebe8da /kernel/sched/cputime.c
parentd8a9ce3f8ad2b546b9ebaf65de809da0793f11c5 (diff)
cputime: Fix jiffies based cputime assumption on steal accounting
The steal guest time accounting code assumes that cputime_t is based on jiffies. So when CONFIG_NO_HZ_FULL=y, which implies that cputime_t is based on nsecs, steal_account_process_tick() passes the delta in jiffies to account_steal_time() which then accounts it as if it's a value in nsecs. As a result, accounting 1 second of steal time (with HZ=100 that would be 100 jiffies) is spuriously accounted as 100 nsecs. As such /proc/stat may report 0 values of steal time even when two guests have run concurrently for a few seconds on the same host and same CPU. In order to fix this, lets convert the nsecs based steal delta to cputime instead of jiffies by using the right conversion API. Given that the steal time is stored in cputime_t and this type can have a smaller granularity than nsecs, we only account the rounded converted value and leave the remaining nsecs for the next deltas. Reported-by: Huiqingding <huding@redhat.com> Reported-by: Marcelo Tosatti <mtosatti@redhat.com> Cc: Ingo Molnar <mingo@kernel.org> Cc: Marcelo Tosatti <mtosatti@redhat.com> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Thomas Gleixner <tglx@linutronix.de> Acked-by: Rik van Riel <riel@redhat.com> Signed-off-by: Frederic Weisbecker <fweisbec@gmail.com>
Diffstat (limited to 'kernel/sched/cputime.c')
-rw-r--r--kernel/sched/cputime.c16
1 files changed, 11 insertions, 5 deletions
diff --git a/kernel/sched/cputime.c b/kernel/sched/cputime.c
index 99947919e30b..c91b09770ebd 100644
--- a/kernel/sched/cputime.c
+++ b/kernel/sched/cputime.c
@@ -258,16 +258,22 @@ static __always_inline bool steal_account_process_tick(void)
258{ 258{
259#ifdef CONFIG_PARAVIRT 259#ifdef CONFIG_PARAVIRT
260 if (static_key_false(&paravirt_steal_enabled)) { 260 if (static_key_false(&paravirt_steal_enabled)) {
261 u64 steal, st = 0; 261 u64 steal;
262 cputime_t steal_ct;
262 263
263 steal = paravirt_steal_clock(smp_processor_id()); 264 steal = paravirt_steal_clock(smp_processor_id());
264 steal -= this_rq()->prev_steal_time; 265 steal -= this_rq()->prev_steal_time;
265 266
266 st = steal_ticks(steal); 267 /*
267 this_rq()->prev_steal_time += st * TICK_NSEC; 268 * cputime_t may be less precise than nsecs (eg: if it's
269 * based on jiffies). Lets cast the result to cputime
270 * granularity and account the rest on the next rounds.
271 */
272 steal_ct = nsecs_to_cputime(steal);
273 this_rq()->prev_steal_time += cputime_to_nsecs(steal_ct);
268 274
269 account_steal_time(st); 275 account_steal_time(steal_ct);
270 return st; 276 return steal_ct;
271 } 277 }
272#endif 278#endif
273 return false; 279 return false;