diff options
author | Mike Galbraith <umgwanakikbuti@gmail.com> | 2014-06-24 01:49:40 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@kernel.org> | 2014-07-05 05:17:30 -0400 |
commit | 4036ac1567834222fc763ab18e3e17df93b4eaaf (patch) | |
tree | e5063b46415b169fbfa3895d5faa4008f003f402 | |
parent | c06f04c70489b9deea3212af8375e2f0c2f0b184 (diff) |
sched: Fix clock_gettime(CLOCK_[PROCESS/THREAD]_CPUTIME_ID) monotonicity
If a task has been dequeued, it has been accounted. Do not project
cycles that may or may not ever be accounted to a dequeued task, as
that may make clock_gettime() both inaccurate and non-monotonic.
Protect update_rq_clock() from slight TSC skew while at it.
Signed-off-by: Mike Galbraith <umgwanakikbuti@gmail.com>
Cc: kosaki.motohiro@jp.fujitsu.com
Cc: pjt@google.com
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Peter Zijlstra <peterz@infradead.org>
Link: http://lkml.kernel.org/r/1403588980.29711.11.camel@marge.simpson.net
Signed-off-by: Ingo Molnar <mingo@kernel.org>
-rw-r--r-- | kernel/sched/core.c | 13 |
1 files changed, 11 insertions, 2 deletions
diff --git a/kernel/sched/core.c b/kernel/sched/core.c index 866d840b99ca..e50234ba0b27 100644 --- a/kernel/sched/core.c +++ b/kernel/sched/core.c | |||
@@ -139,6 +139,8 @@ void update_rq_clock(struct rq *rq) | |||
139 | return; | 139 | return; |
140 | 140 | ||
141 | delta = sched_clock_cpu(cpu_of(rq)) - rq->clock; | 141 | delta = sched_clock_cpu(cpu_of(rq)) - rq->clock; |
142 | if (delta < 0) | ||
143 | return; | ||
142 | rq->clock += delta; | 144 | rq->clock += delta; |
143 | update_rq_clock_task(rq, delta); | 145 | update_rq_clock_task(rq, delta); |
144 | } | 146 | } |
@@ -2431,7 +2433,12 @@ static u64 do_task_delta_exec(struct task_struct *p, struct rq *rq) | |||
2431 | { | 2433 | { |
2432 | u64 ns = 0; | 2434 | u64 ns = 0; |
2433 | 2435 | ||
2434 | if (task_current(rq, p)) { | 2436 | /* |
2437 | * Must be ->curr _and_ ->on_rq. If dequeued, we would | ||
2438 | * project cycles that may never be accounted to this | ||
2439 | * thread, breaking clock_gettime(). | ||
2440 | */ | ||
2441 | if (task_current(rq, p) && p->on_rq) { | ||
2435 | update_rq_clock(rq); | 2442 | update_rq_clock(rq); |
2436 | ns = rq_clock_task(rq) - p->se.exec_start; | 2443 | ns = rq_clock_task(rq) - p->se.exec_start; |
2437 | if ((s64)ns < 0) | 2444 | if ((s64)ns < 0) |
@@ -2474,8 +2481,10 @@ unsigned long long task_sched_runtime(struct task_struct *p) | |||
2474 | * If we race with it leaving cpu, we'll take a lock. So we're correct. | 2481 | * If we race with it leaving cpu, we'll take a lock. So we're correct. |
2475 | * If we race with it entering cpu, unaccounted time is 0. This is | 2482 | * If we race with it entering cpu, unaccounted time is 0. This is |
2476 | * indistinguishable from the read occurring a few cycles earlier. | 2483 | * indistinguishable from the read occurring a few cycles earlier. |
2484 | * If we see ->on_cpu without ->on_rq, the task is leaving, and has | ||
2485 | * been accounted, so we're correct here as well. | ||
2477 | */ | 2486 | */ |
2478 | if (!p->on_cpu) | 2487 | if (!p->on_cpu || !p->on_rq) |
2479 | return p->se.sum_exec_runtime; | 2488 | return p->se.sum_exec_runtime; |
2480 | #endif | 2489 | #endif |
2481 | 2490 | ||