diff options
author | Frederic Weisbecker <fweisbec@gmail.com> | 2012-12-16 14:00:34 -0500 |
---|---|---|
committer | Frederic Weisbecker <fweisbec@gmail.com> | 2013-01-27 14:35:47 -0500 |
commit | 6a61671bb2f3a1bd12cd17b8fca811a624782632 (patch) | |
tree | 0afc2915fb7e517472710a49a524510322dd5baa /include/linux/vtime.h | |
parent | c11f11fcbdb5be790c565aed46411486a7586afc (diff) |
cputime: Safely read cputime of full dynticks CPUs
While remotely reading the cputime of a task running in a
full dynticks CPU, the values stored in utime/stime fields
of struct task_struct may be stale. Its values may be those
of the last kernel <-> user transition time snapshot and
we need to add the tickless time spent since this snapshot.
To fix this, flush the cputime of the dynticks CPUs on
kernel <-> user transition and record the time / context
where we did this. Then on top of this snapshot and the current
time, perform the fixup on the reader side from task_times()
accessors.
Signed-off-by: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: Ingo Molnar <mingo@kernel.org>
Cc: Li Zhong <zhong@linux.vnet.ibm.com>
Cc: Namhyung Kim <namhyung.kim@lge.com>
Cc: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
Cc: Paul Gortmaker <paul.gortmaker@windriver.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Steven Rostedt <rostedt@goodmis.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
[fixed kvm module related build errors]
Signed-off-by: Sedat Dilek <sedat.dilek@gmail.com>
Diffstat (limited to 'include/linux/vtime.h')
-rw-r--r-- | include/linux/vtime.h | 47 |
1 files changed, 23 insertions, 24 deletions
diff --git a/include/linux/vtime.h b/include/linux/vtime.h index bb50c3ca0d79..71a5782d8c59 100644 --- a/include/linux/vtime.h +++ b/include/linux/vtime.h | |||
@@ -8,35 +8,44 @@ extern void vtime_task_switch(struct task_struct *prev); | |||
8 | extern void vtime_account_system(struct task_struct *tsk); | 8 | extern void vtime_account_system(struct task_struct *tsk); |
9 | extern void vtime_account_idle(struct task_struct *tsk); | 9 | extern void vtime_account_idle(struct task_struct *tsk); |
10 | extern void vtime_account_user(struct task_struct *tsk); | 10 | extern void vtime_account_user(struct task_struct *tsk); |
11 | extern void vtime_account(struct task_struct *tsk); | 11 | extern void vtime_account_irq_enter(struct task_struct *tsk); |
12 | 12 | ||
13 | #ifdef CONFIG_VIRT_CPU_ACCOUNTING_GEN | 13 | #ifdef CONFIG_VIRT_CPU_ACCOUNTING_NATIVE |
14 | extern bool vtime_accounting_enabled(void); | ||
15 | #else | ||
16 | static inline bool vtime_accounting_enabled(void) { return true; } | 14 | static inline bool vtime_accounting_enabled(void) { return true; } |
17 | #endif | 15 | #endif |
18 | 16 | ||
19 | #else /* !CONFIG_VIRT_CPU_ACCOUNTING */ | 17 | #else /* !CONFIG_VIRT_CPU_ACCOUNTING */ |
18 | |||
20 | static inline void vtime_task_switch(struct task_struct *prev) { } | 19 | static inline void vtime_task_switch(struct task_struct *prev) { } |
21 | static inline void vtime_account_system(struct task_struct *tsk) { } | 20 | static inline void vtime_account_system(struct task_struct *tsk) { } |
22 | static inline void vtime_account_user(struct task_struct *tsk) { } | 21 | static inline void vtime_account_user(struct task_struct *tsk) { } |
23 | static inline void vtime_account(struct task_struct *tsk) { } | 22 | static inline void vtime_account_irq_enter(struct task_struct *tsk) { } |
24 | static inline bool vtime_accounting_enabled(void) { return false; } | 23 | static inline bool vtime_accounting_enabled(void) { return false; } |
25 | #endif | 24 | #endif |
26 | 25 | ||
27 | #ifdef CONFIG_VIRT_CPU_ACCOUNTING_GEN | 26 | #ifdef CONFIG_VIRT_CPU_ACCOUNTING_GEN |
28 | static inline void arch_vtime_task_switch(struct task_struct *tsk) { } | 27 | extern void arch_vtime_task_switch(struct task_struct *tsk); |
29 | static inline void vtime_user_enter(struct task_struct *tsk) | 28 | extern void vtime_account_irq_exit(struct task_struct *tsk); |
30 | { | 29 | extern bool vtime_accounting_enabled(void); |
31 | vtime_account_system(tsk); | 30 | extern void vtime_user_enter(struct task_struct *tsk); |
32 | } | ||
33 | static inline void vtime_user_exit(struct task_struct *tsk) | 31 | static inline void vtime_user_exit(struct task_struct *tsk) |
34 | { | 32 | { |
35 | vtime_account_user(tsk); | 33 | vtime_account_user(tsk); |
36 | } | 34 | } |
35 | extern void vtime_guest_enter(struct task_struct *tsk); | ||
36 | extern void vtime_guest_exit(struct task_struct *tsk); | ||
37 | extern void vtime_init_idle(struct task_struct *tsk); | ||
37 | #else | 38 | #else |
39 | static inline void vtime_account_irq_exit(struct task_struct *tsk) | ||
40 | { | ||
41 | /* On hard|softirq exit we always account to hard|softirq cputime */ | ||
42 | vtime_account_system(tsk); | ||
43 | } | ||
38 | static inline void vtime_user_enter(struct task_struct *tsk) { } | 44 | static inline void vtime_user_enter(struct task_struct *tsk) { } |
39 | static inline void vtime_user_exit(struct task_struct *tsk) { } | 45 | static inline void vtime_user_exit(struct task_struct *tsk) { } |
46 | static inline void vtime_guest_enter(struct task_struct *tsk) { } | ||
47 | static inline void vtime_guest_exit(struct task_struct *tsk) { } | ||
48 | static inline void vtime_init_idle(struct task_struct *tsk) { } | ||
40 | #endif | 49 | #endif |
41 | 50 | ||
42 | #ifdef CONFIG_IRQ_TIME_ACCOUNTING | 51 | #ifdef CONFIG_IRQ_TIME_ACCOUNTING |
@@ -45,25 +54,15 @@ extern void irqtime_account_irq(struct task_struct *tsk); | |||
45 | static inline void irqtime_account_irq(struct task_struct *tsk) { } | 54 | static inline void irqtime_account_irq(struct task_struct *tsk) { } |
46 | #endif | 55 | #endif |
47 | 56 | ||
48 | static inline void vtime_account_irq_enter(struct task_struct *tsk) | 57 | static inline void account_irq_enter_time(struct task_struct *tsk) |
49 | { | 58 | { |
50 | /* | 59 | vtime_account_irq_enter(tsk); |
51 | * Hardirq can interrupt idle task anytime. So we need vtime_account() | ||
52 | * that performs the idle check in CONFIG_VIRT_CPU_ACCOUNTING. | ||
53 | * Softirq can also interrupt idle task directly if it calls | ||
54 | * local_bh_enable(). Such case probably don't exist but we never know. | ||
55 | * Ksoftirqd is not concerned because idle time is flushed on context | ||
56 | * switch. Softirqs in the end of hardirqs are also not a problem because | ||
57 | * the idle time is flushed on hardirq time already. | ||
58 | */ | ||
59 | vtime_account(tsk); | ||
60 | irqtime_account_irq(tsk); | 60 | irqtime_account_irq(tsk); |
61 | } | 61 | } |
62 | 62 | ||
63 | static inline void vtime_account_irq_exit(struct task_struct *tsk) | 63 | static inline void account_irq_exit_time(struct task_struct *tsk) |
64 | { | 64 | { |
65 | /* On hard|softirq exit we always account to hard|softirq cputime */ | 65 | vtime_account_irq_exit(tsk); |
66 | vtime_account_system(tsk); | ||
67 | irqtime_account_irq(tsk); | 66 | irqtime_account_irq(tsk); |
68 | } | 67 | } |
69 | 68 | ||