diff options
author | Ingo Molnar <mingo@kernel.org> | 2012-10-30 03:33:01 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@kernel.org> | 2012-10-30 03:33:01 -0400 |
commit | 38ca9c927c7d3db61f57e3d3a9334958c3af6e9a (patch) | |
tree | 58be18cf3dce7a407c84ab2532e92bdb8b7ee067 | |
parent | e9c84cb8d5f1b1ea6fcbe6190d51dc84b6975938 (diff) | |
parent | 3e1df4f506836e6bea1ab61cf88c75c8b1840643 (diff) |
Merge tag 'cputime-cleanups-for-mingo' of git://git.kernel.org/pub/scm/linux/kernel/git/frederic/linux-dynticks into sched/core
Pull cputime cleanups and optimizations from Frederic Weisbecker:
* Gather vtime headers that were a bit scattered around
* Separate irqtime and vtime namespaces that were
colliding, resulting in useless calls to irqtime accounting.
* Slightly optimize irq and guest vtime accounting.
Signed-off-by: Frederic Weisbecker <fweisbec@gmail.com>
Signed-off-by: Ingo Molnar <mingo@kernel.org>
-rw-r--r-- | arch/ia64/kernel/time.c | 8 | ||||
-rw-r--r-- | arch/powerpc/kernel/time.c | 4 | ||||
-rw-r--r-- | arch/s390/kernel/vtime.c | 4 | ||||
-rw-r--r-- | arch/s390/kvm/kvm-s390.c | 4 | ||||
-rw-r--r-- | include/linux/hardirq.h | 15 | ||||
-rw-r--r-- | include/linux/kernel_stat.h | 9 | ||||
-rw-r--r-- | include/linux/kvm_host.h | 12 | ||||
-rw-r--r-- | include/linux/vtime.h | 47 | ||||
-rw-r--r-- | kernel/sched/cputime.c | 20 | ||||
-rw-r--r-- | kernel/softirq.c | 6 |
10 files changed, 89 insertions, 40 deletions
diff --git a/arch/ia64/kernel/time.c b/arch/ia64/kernel/time.c index f6388216080d..5e4850305d3f 100644 --- a/arch/ia64/kernel/time.c +++ b/arch/ia64/kernel/time.c | |||
@@ -106,9 +106,9 @@ void vtime_task_switch(struct task_struct *prev) | |||
106 | struct thread_info *ni = task_thread_info(current); | 106 | struct thread_info *ni = task_thread_info(current); |
107 | 107 | ||
108 | if (idle_task(smp_processor_id()) != prev) | 108 | if (idle_task(smp_processor_id()) != prev) |
109 | vtime_account_system(prev); | 109 | __vtime_account_system(prev); |
110 | else | 110 | else |
111 | vtime_account_idle(prev); | 111 | __vtime_account_idle(prev); |
112 | 112 | ||
113 | vtime_account_user(prev); | 113 | vtime_account_user(prev); |
114 | 114 | ||
@@ -135,14 +135,14 @@ static cputime_t vtime_delta(struct task_struct *tsk) | |||
135 | return delta_stime; | 135 | return delta_stime; |
136 | } | 136 | } |
137 | 137 | ||
138 | void vtime_account_system(struct task_struct *tsk) | 138 | void __vtime_account_system(struct task_struct *tsk) |
139 | { | 139 | { |
140 | cputime_t delta = vtime_delta(tsk); | 140 | cputime_t delta = vtime_delta(tsk); |
141 | 141 | ||
142 | account_system_time(tsk, 0, delta, delta); | 142 | account_system_time(tsk, 0, delta, delta); |
143 | } | 143 | } |
144 | 144 | ||
145 | void vtime_account_idle(struct task_struct *tsk) | 145 | void __vtime_account_idle(struct task_struct *tsk) |
146 | { | 146 | { |
147 | account_idle_time(vtime_delta(tsk)); | 147 | account_idle_time(vtime_delta(tsk)); |
148 | } | 148 | } |
diff --git a/arch/powerpc/kernel/time.c b/arch/powerpc/kernel/time.c index ce4cb772dc78..0db456f30d45 100644 --- a/arch/powerpc/kernel/time.c +++ b/arch/powerpc/kernel/time.c | |||
@@ -336,7 +336,7 @@ static u64 vtime_delta(struct task_struct *tsk, | |||
336 | return delta; | 336 | return delta; |
337 | } | 337 | } |
338 | 338 | ||
339 | void vtime_account_system(struct task_struct *tsk) | 339 | void __vtime_account_system(struct task_struct *tsk) |
340 | { | 340 | { |
341 | u64 delta, sys_scaled, stolen; | 341 | u64 delta, sys_scaled, stolen; |
342 | 342 | ||
@@ -346,7 +346,7 @@ void vtime_account_system(struct task_struct *tsk) | |||
346 | account_steal_time(stolen); | 346 | account_steal_time(stolen); |
347 | } | 347 | } |
348 | 348 | ||
349 | void vtime_account_idle(struct task_struct *tsk) | 349 | void __vtime_account_idle(struct task_struct *tsk) |
350 | { | 350 | { |
351 | u64 delta, sys_scaled, stolen; | 351 | u64 delta, sys_scaled, stolen; |
352 | 352 | ||
diff --git a/arch/s390/kernel/vtime.c b/arch/s390/kernel/vtime.c index 790334427895..783e988c4e1e 100644 --- a/arch/s390/kernel/vtime.c +++ b/arch/s390/kernel/vtime.c | |||
@@ -140,6 +140,10 @@ void vtime_account(struct task_struct *tsk) | |||
140 | } | 140 | } |
141 | EXPORT_SYMBOL_GPL(vtime_account); | 141 | EXPORT_SYMBOL_GPL(vtime_account); |
142 | 142 | ||
143 | void __vtime_account_system(struct task_struct *tsk) | ||
144 | __attribute__((alias("vtime_account"))); | ||
145 | EXPORT_SYMBOL_GPL(__vtime_account_system); | ||
146 | |||
143 | void __kprobes vtime_stop_cpu(void) | 147 | void __kprobes vtime_stop_cpu(void) |
144 | { | 148 | { |
145 | struct s390_idle_data *idle = &__get_cpu_var(s390_idle); | 149 | struct s390_idle_data *idle = &__get_cpu_var(s390_idle); |
diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c index ecced9d18986..d91a95568002 100644 --- a/arch/s390/kvm/kvm-s390.c +++ b/arch/s390/kvm/kvm-s390.c | |||
@@ -608,9 +608,7 @@ static int __vcpu_run(struct kvm_vcpu *vcpu) | |||
608 | kvm_s390_deliver_pending_interrupts(vcpu); | 608 | kvm_s390_deliver_pending_interrupts(vcpu); |
609 | 609 | ||
610 | vcpu->arch.sie_block->icptcode = 0; | 610 | vcpu->arch.sie_block->icptcode = 0; |
611 | local_irq_disable(); | ||
612 | kvm_guest_enter(); | 611 | kvm_guest_enter(); |
613 | local_irq_enable(); | ||
614 | VCPU_EVENT(vcpu, 6, "entering sie flags %x", | 612 | VCPU_EVENT(vcpu, 6, "entering sie flags %x", |
615 | atomic_read(&vcpu->arch.sie_block->cpuflags)); | 613 | atomic_read(&vcpu->arch.sie_block->cpuflags)); |
616 | trace_kvm_s390_sie_enter(vcpu, | 614 | trace_kvm_s390_sie_enter(vcpu, |
@@ -629,9 +627,7 @@ static int __vcpu_run(struct kvm_vcpu *vcpu) | |||
629 | VCPU_EVENT(vcpu, 6, "exit sie icptcode %d", | 627 | VCPU_EVENT(vcpu, 6, "exit sie icptcode %d", |
630 | vcpu->arch.sie_block->icptcode); | 628 | vcpu->arch.sie_block->icptcode); |
631 | trace_kvm_s390_sie_exit(vcpu, vcpu->arch.sie_block->icptcode); | 629 | trace_kvm_s390_sie_exit(vcpu, vcpu->arch.sie_block->icptcode); |
632 | local_irq_disable(); | ||
633 | kvm_guest_exit(); | 630 | kvm_guest_exit(); |
634 | local_irq_enable(); | ||
635 | 631 | ||
636 | memcpy(&vcpu->run->s.regs.gprs[14], &vcpu->arch.sie_block->gg14, 16); | 632 | memcpy(&vcpu->run->s.regs.gprs[14], &vcpu->arch.sie_block->gg14, 16); |
637 | return rc; | 633 | return rc; |
diff --git a/include/linux/hardirq.h b/include/linux/hardirq.h index cab3da3d0949..624ef3f45c8e 100644 --- a/include/linux/hardirq.h +++ b/include/linux/hardirq.h | |||
@@ -4,6 +4,7 @@ | |||
4 | #include <linux/preempt.h> | 4 | #include <linux/preempt.h> |
5 | #include <linux/lockdep.h> | 5 | #include <linux/lockdep.h> |
6 | #include <linux/ftrace_irq.h> | 6 | #include <linux/ftrace_irq.h> |
7 | #include <linux/vtime.h> | ||
7 | #include <asm/hardirq.h> | 8 | #include <asm/hardirq.h> |
8 | 9 | ||
9 | /* | 10 | /* |
@@ -129,16 +130,6 @@ extern void synchronize_irq(unsigned int irq); | |||
129 | # define synchronize_irq(irq) barrier() | 130 | # define synchronize_irq(irq) barrier() |
130 | #endif | 131 | #endif |
131 | 132 | ||
132 | struct task_struct; | ||
133 | |||
134 | #if !defined(CONFIG_VIRT_CPU_ACCOUNTING) && !defined(CONFIG_IRQ_TIME_ACCOUNTING) | ||
135 | static inline void vtime_account(struct task_struct *tsk) | ||
136 | { | ||
137 | } | ||
138 | #else | ||
139 | extern void vtime_account(struct task_struct *tsk); | ||
140 | #endif | ||
141 | |||
142 | #if defined(CONFIG_TINY_RCU) || defined(CONFIG_TINY_PREEMPT_RCU) | 133 | #if defined(CONFIG_TINY_RCU) || defined(CONFIG_TINY_PREEMPT_RCU) |
143 | 134 | ||
144 | static inline void rcu_nmi_enter(void) | 135 | static inline void rcu_nmi_enter(void) |
@@ -162,7 +153,7 @@ extern void rcu_nmi_exit(void); | |||
162 | */ | 153 | */ |
163 | #define __irq_enter() \ | 154 | #define __irq_enter() \ |
164 | do { \ | 155 | do { \ |
165 | vtime_account(current); \ | 156 | vtime_account_irq_enter(current); \ |
166 | add_preempt_count(HARDIRQ_OFFSET); \ | 157 | add_preempt_count(HARDIRQ_OFFSET); \ |
167 | trace_hardirq_enter(); \ | 158 | trace_hardirq_enter(); \ |
168 | } while (0) | 159 | } while (0) |
@@ -178,7 +169,7 @@ extern void irq_enter(void); | |||
178 | #define __irq_exit() \ | 169 | #define __irq_exit() \ |
179 | do { \ | 170 | do { \ |
180 | trace_hardirq_exit(); \ | 171 | trace_hardirq_exit(); \ |
181 | vtime_account(current); \ | 172 | vtime_account_irq_exit(current); \ |
182 | sub_preempt_count(HARDIRQ_OFFSET); \ | 173 | sub_preempt_count(HARDIRQ_OFFSET); \ |
183 | } while (0) | 174 | } while (0) |
184 | 175 | ||
diff --git a/include/linux/kernel_stat.h b/include/linux/kernel_stat.h index 36d12f0884c3..1865b1f29770 100644 --- a/include/linux/kernel_stat.h +++ b/include/linux/kernel_stat.h | |||
@@ -7,6 +7,7 @@ | |||
7 | #include <linux/cpumask.h> | 7 | #include <linux/cpumask.h> |
8 | #include <linux/interrupt.h> | 8 | #include <linux/interrupt.h> |
9 | #include <linux/sched.h> | 9 | #include <linux/sched.h> |
10 | #include <linux/vtime.h> | ||
10 | #include <asm/irq.h> | 11 | #include <asm/irq.h> |
11 | #include <asm/cputime.h> | 12 | #include <asm/cputime.h> |
12 | 13 | ||
@@ -130,12 +131,4 @@ extern void account_process_tick(struct task_struct *, int user); | |||
130 | extern void account_steal_ticks(unsigned long ticks); | 131 | extern void account_steal_ticks(unsigned long ticks); |
131 | extern void account_idle_ticks(unsigned long ticks); | 132 | extern void account_idle_ticks(unsigned long ticks); |
132 | 133 | ||
133 | #ifdef CONFIG_VIRT_CPU_ACCOUNTING | ||
134 | extern void vtime_task_switch(struct task_struct *prev); | ||
135 | extern void vtime_account_system(struct task_struct *tsk); | ||
136 | extern void vtime_account_idle(struct task_struct *tsk); | ||
137 | #else | ||
138 | static inline void vtime_task_switch(struct task_struct *prev) { } | ||
139 | #endif | ||
140 | |||
141 | #endif /* _LINUX_KERNEL_STAT_H */ | 134 | #endif /* _LINUX_KERNEL_STAT_H */ |
diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h index 93bfc9f9815c..0e2212fe4784 100644 --- a/include/linux/kvm_host.h +++ b/include/linux/kvm_host.h | |||
@@ -737,7 +737,11 @@ static inline int kvm_deassign_device(struct kvm *kvm, | |||
737 | static inline void kvm_guest_enter(void) | 737 | static inline void kvm_guest_enter(void) |
738 | { | 738 | { |
739 | BUG_ON(preemptible()); | 739 | BUG_ON(preemptible()); |
740 | vtime_account(current); | 740 | /* |
741 | * This is running in ioctl context so we can avoid | ||
742 | * the call to vtime_account() with its unnecessary idle check. | ||
743 | */ | ||
744 | vtime_account_system(current); | ||
741 | current->flags |= PF_VCPU; | 745 | current->flags |= PF_VCPU; |
742 | /* KVM does not hold any references to rcu protected data when it | 746 | /* KVM does not hold any references to rcu protected data when it |
743 | * switches CPU into a guest mode. In fact switching to a guest mode | 747 | * switches CPU into a guest mode. In fact switching to a guest mode |
@@ -751,7 +755,11 @@ static inline void kvm_guest_enter(void) | |||
751 | 755 | ||
752 | static inline void kvm_guest_exit(void) | 756 | static inline void kvm_guest_exit(void) |
753 | { | 757 | { |
754 | vtime_account(current); | 758 | /* |
759 | * This is running in ioctl context so we can avoid | ||
760 | * the call to vtime_account() with its unnecessary idle check. | ||
761 | */ | ||
762 | vtime_account_system(current); | ||
755 | current->flags &= ~PF_VCPU; | 763 | current->flags &= ~PF_VCPU; |
756 | } | 764 | } |
757 | 765 | ||
diff --git a/include/linux/vtime.h b/include/linux/vtime.h new file mode 100644 index 000000000000..0c2a2d303020 --- /dev/null +++ b/include/linux/vtime.h | |||
@@ -0,0 +1,47 @@ | |||
1 | #ifndef _LINUX_KERNEL_VTIME_H | ||
2 | #define _LINUX_KERNEL_VTIME_H | ||
3 | |||
4 | struct task_struct; | ||
5 | |||
6 | #ifdef CONFIG_VIRT_CPU_ACCOUNTING | ||
7 | extern void vtime_task_switch(struct task_struct *prev); | ||
8 | extern void __vtime_account_system(struct task_struct *tsk); | ||
9 | extern void vtime_account_system(struct task_struct *tsk); | ||
10 | extern void __vtime_account_idle(struct task_struct *tsk); | ||
11 | extern void vtime_account(struct task_struct *tsk); | ||
12 | #else | ||
13 | static inline void vtime_task_switch(struct task_struct *prev) { } | ||
14 | static inline void __vtime_account_system(struct task_struct *tsk) { } | ||
15 | static inline void vtime_account_system(struct task_struct *tsk) { } | ||
16 | static inline void vtime_account(struct task_struct *tsk) { } | ||
17 | #endif | ||
18 | |||
19 | #ifdef CONFIG_IRQ_TIME_ACCOUNTING | ||
20 | extern void irqtime_account_irq(struct task_struct *tsk); | ||
21 | #else | ||
22 | static inline void irqtime_account_irq(struct task_struct *tsk) { } | ||
23 | #endif | ||
24 | |||
25 | static inline void vtime_account_irq_enter(struct task_struct *tsk) | ||
26 | { | ||
27 | /* | ||
28 | * Hardirq can interrupt idle task anytime. So we need vtime_account() | ||
29 | * that performs the idle check in CONFIG_VIRT_CPU_ACCOUNTING. | ||
30 | * Softirq can also interrupt idle task directly if it calls | ||
31 | * local_bh_enable(). Such case probably don't exist but we never know. | ||
32 | * Ksoftirqd is not concerned because idle time is flushed on context | ||
33 | * switch. Softirqs in the end of hardirqs are also not a problem because | ||
34 | * the idle time is flushed on hardirq time already. | ||
35 | */ | ||
36 | vtime_account(tsk); | ||
37 | irqtime_account_irq(tsk); | ||
38 | } | ||
39 | |||
40 | static inline void vtime_account_irq_exit(struct task_struct *tsk) | ||
41 | { | ||
42 | /* On hard|softirq exit we always account to hard|softirq cputime */ | ||
43 | __vtime_account_system(tsk); | ||
44 | irqtime_account_irq(tsk); | ||
45 | } | ||
46 | |||
47 | #endif /* _LINUX_KERNEL_VTIME_H */ | ||
diff --git a/kernel/sched/cputime.c b/kernel/sched/cputime.c index 81b763ba58a6..8d859dae5bed 100644 --- a/kernel/sched/cputime.c +++ b/kernel/sched/cputime.c | |||
@@ -43,7 +43,7 @@ DEFINE_PER_CPU(seqcount_t, irq_time_seq); | |||
43 | * Called before incrementing preempt_count on {soft,}irq_enter | 43 | * Called before incrementing preempt_count on {soft,}irq_enter |
44 | * and before decrementing preempt_count on {soft,}irq_exit. | 44 | * and before decrementing preempt_count on {soft,}irq_exit. |
45 | */ | 45 | */ |
46 | void vtime_account(struct task_struct *curr) | 46 | void irqtime_account_irq(struct task_struct *curr) |
47 | { | 47 | { |
48 | unsigned long flags; | 48 | unsigned long flags; |
49 | s64 delta; | 49 | s64 delta; |
@@ -73,7 +73,7 @@ void vtime_account(struct task_struct *curr) | |||
73 | irq_time_write_end(); | 73 | irq_time_write_end(); |
74 | local_irq_restore(flags); | 74 | local_irq_restore(flags); |
75 | } | 75 | } |
76 | EXPORT_SYMBOL_GPL(vtime_account); | 76 | EXPORT_SYMBOL_GPL(irqtime_account_irq); |
77 | 77 | ||
78 | static int irqtime_account_hi_update(void) | 78 | static int irqtime_account_hi_update(void) |
79 | { | 79 | { |
@@ -433,10 +433,20 @@ void thread_group_times(struct task_struct *p, cputime_t *ut, cputime_t *st) | |||
433 | *st = cputime.stime; | 433 | *st = cputime.stime; |
434 | } | 434 | } |
435 | 435 | ||
436 | void vtime_account_system(struct task_struct *tsk) | ||
437 | { | ||
438 | unsigned long flags; | ||
439 | |||
440 | local_irq_save(flags); | ||
441 | __vtime_account_system(tsk); | ||
442 | local_irq_restore(flags); | ||
443 | } | ||
444 | EXPORT_SYMBOL_GPL(vtime_account_system); | ||
445 | |||
436 | /* | 446 | /* |
437 | * Archs that account the whole time spent in the idle task | 447 | * Archs that account the whole time spent in the idle task |
438 | * (outside irq) as idle time can rely on this and just implement | 448 | * (outside irq) as idle time can rely on this and just implement |
439 | * vtime_account_system() and vtime_account_idle(). Archs that | 449 | * __vtime_account_system() and __vtime_account_idle(). Archs that |
440 | * have other meaning of the idle time (s390 only includes the | 450 | * have other meaning of the idle time (s390 only includes the |
441 | * time spent by the CPU when it's in low power mode) must override | 451 | * time spent by the CPU when it's in low power mode) must override |
442 | * vtime_account(). | 452 | * vtime_account(). |
@@ -449,9 +459,9 @@ void vtime_account(struct task_struct *tsk) | |||
449 | local_irq_save(flags); | 459 | local_irq_save(flags); |
450 | 460 | ||
451 | if (in_interrupt() || !is_idle_task(tsk)) | 461 | if (in_interrupt() || !is_idle_task(tsk)) |
452 | vtime_account_system(tsk); | 462 | __vtime_account_system(tsk); |
453 | else | 463 | else |
454 | vtime_account_idle(tsk); | 464 | __vtime_account_idle(tsk); |
455 | 465 | ||
456 | local_irq_restore(flags); | 466 | local_irq_restore(flags); |
457 | } | 467 | } |
diff --git a/kernel/softirq.c b/kernel/softirq.c index cc96bdc0c2c9..ed567babe789 100644 --- a/kernel/softirq.c +++ b/kernel/softirq.c | |||
@@ -221,7 +221,7 @@ asmlinkage void __do_softirq(void) | |||
221 | current->flags &= ~PF_MEMALLOC; | 221 | current->flags &= ~PF_MEMALLOC; |
222 | 222 | ||
223 | pending = local_softirq_pending(); | 223 | pending = local_softirq_pending(); |
224 | vtime_account(current); | 224 | vtime_account_irq_enter(current); |
225 | 225 | ||
226 | __local_bh_disable((unsigned long)__builtin_return_address(0), | 226 | __local_bh_disable((unsigned long)__builtin_return_address(0), |
227 | SOFTIRQ_OFFSET); | 227 | SOFTIRQ_OFFSET); |
@@ -272,7 +272,7 @@ restart: | |||
272 | 272 | ||
273 | lockdep_softirq_exit(); | 273 | lockdep_softirq_exit(); |
274 | 274 | ||
275 | vtime_account(current); | 275 | vtime_account_irq_exit(current); |
276 | __local_bh_enable(SOFTIRQ_OFFSET); | 276 | __local_bh_enable(SOFTIRQ_OFFSET); |
277 | tsk_restore_flags(current, old_flags, PF_MEMALLOC); | 277 | tsk_restore_flags(current, old_flags, PF_MEMALLOC); |
278 | } | 278 | } |
@@ -341,7 +341,7 @@ static inline void invoke_softirq(void) | |||
341 | */ | 341 | */ |
342 | void irq_exit(void) | 342 | void irq_exit(void) |
343 | { | 343 | { |
344 | vtime_account(current); | 344 | vtime_account_irq_exit(current); |
345 | trace_hardirq_exit(); | 345 | trace_hardirq_exit(); |
346 | sub_preempt_count(IRQ_EXIT_OFFSET); | 346 | sub_preempt_count(IRQ_EXIT_OFFSET); |
347 | if (!in_interrupt() && local_softirq_pending()) | 347 | if (!in_interrupt() && local_softirq_pending()) |