diff options
author | Juergen Gross <jgross@suse.com> | 2016-05-20 03:26:48 -0400 |
---|---|---|
committer | David Vrabel <david.vrabel@citrix.com> | 2016-07-06 05:34:48 -0400 |
commit | ecb23dc6f2eff0ce64dd60351a81f376f13b12cc (patch) | |
tree | 09536e5db2dc00af9dd5209fef72a1e1222f6cf2 | |
parent | c7ebf9d9c6b4e9402b978da0b0785db4129c1f79 (diff) |
xen: add steal_clock support on x86
The pv_time_ops structure contains a function pointer for the
"steal_clock" functionality used only by KVM and Xen on ARM. Xen on x86
uses its own mechanism to account for the "stolen" time a thread wasn't
able to run due to hypervisor scheduling.
Add support in Xen arch independent time handling for this feature by
moving it out of the arm arch into drivers/xen and remove the x86 Xen
hack.
Signed-off-by: Juergen Gross <jgross@suse.com>
Reviewed-by: Boris Ostrovsky <boris.ostrovsky@oracle.com>
Reviewed-by: Stefano Stabellini <sstabellini@kernel.org>
Signed-off-by: David Vrabel <david.vrabel@citrix.com>
-rw-r--r-- | arch/arm/xen/enlighten.c | 18 | ||||
-rw-r--r-- | arch/x86/xen/time.c | 44 | ||||
-rw-r--r-- | drivers/xen/time.c | 20 | ||||
-rw-r--r-- | include/linux/kernel_stat.h | 1 | ||||
-rw-r--r-- | include/xen/xen-ops.h | 1 | ||||
-rw-r--r-- | kernel/sched/cputime.c | 10 |
6 files changed, 25 insertions, 69 deletions
diff --git a/arch/arm/xen/enlighten.c b/arch/arm/xen/enlighten.c index d4f36eba3499..47acb3613f40 100644 --- a/arch/arm/xen/enlighten.c +++ b/arch/arm/xen/enlighten.c | |||
@@ -12,7 +12,6 @@ | |||
12 | #include <xen/page.h> | 12 | #include <xen/page.h> |
13 | #include <xen/interface/sched.h> | 13 | #include <xen/interface/sched.h> |
14 | #include <xen/xen-ops.h> | 14 | #include <xen/xen-ops.h> |
15 | #include <asm/paravirt.h> | ||
16 | #include <asm/xen/hypervisor.h> | 15 | #include <asm/xen/hypervisor.h> |
17 | #include <asm/xen/hypercall.h> | 16 | #include <asm/xen/hypercall.h> |
18 | #include <asm/xen/xen-ops.h> | 17 | #include <asm/xen/xen-ops.h> |
@@ -86,19 +85,6 @@ int xen_unmap_domain_gfn_range(struct vm_area_struct *vma, | |||
86 | } | 85 | } |
87 | EXPORT_SYMBOL_GPL(xen_unmap_domain_gfn_range); | 86 | EXPORT_SYMBOL_GPL(xen_unmap_domain_gfn_range); |
88 | 87 | ||
89 | static unsigned long long xen_stolen_accounting(int cpu) | ||
90 | { | ||
91 | struct vcpu_runstate_info state; | ||
92 | |||
93 | BUG_ON(cpu != smp_processor_id()); | ||
94 | |||
95 | xen_get_runstate_snapshot(&state); | ||
96 | |||
97 | WARN_ON(state.state != RUNSTATE_running); | ||
98 | |||
99 | return state.time[RUNSTATE_runnable] + state.time[RUNSTATE_offline]; | ||
100 | } | ||
101 | |||
102 | static void xen_read_wallclock(struct timespec64 *ts) | 88 | static void xen_read_wallclock(struct timespec64 *ts) |
103 | { | 89 | { |
104 | u32 version; | 90 | u32 version; |
@@ -432,8 +418,8 @@ static int __init xen_guest_init(void) | |||
432 | 418 | ||
433 | register_cpu_notifier(&xen_cpu_notifier); | 419 | register_cpu_notifier(&xen_cpu_notifier); |
434 | 420 | ||
435 | pv_time_ops.steal_clock = xen_stolen_accounting; | 421 | xen_time_setup_guest(); |
436 | static_key_slow_inc(¶virt_steal_enabled); | 422 | |
437 | if (xen_initial_domain()) | 423 | if (xen_initial_domain()) |
438 | pvclock_gtod_register_notifier(&xen_pvclock_gtod_notifier); | 424 | pvclock_gtod_register_notifier(&xen_pvclock_gtod_notifier); |
439 | 425 | ||
diff --git a/arch/x86/xen/time.c b/arch/x86/xen/time.c index 6deba5bc7e34..c31006f0f37f 100644 --- a/arch/x86/xen/time.c +++ b/arch/x86/xen/time.c | |||
@@ -11,8 +11,6 @@ | |||
11 | #include <linux/interrupt.h> | 11 | #include <linux/interrupt.h> |
12 | #include <linux/clocksource.h> | 12 | #include <linux/clocksource.h> |
13 | #include <linux/clockchips.h> | 13 | #include <linux/clockchips.h> |
14 | #include <linux/kernel_stat.h> | ||
15 | #include <linux/math64.h> | ||
16 | #include <linux/gfp.h> | 14 | #include <linux/gfp.h> |
17 | #include <linux/slab.h> | 15 | #include <linux/slab.h> |
18 | #include <linux/pvclock_gtod.h> | 16 | #include <linux/pvclock_gtod.h> |
@@ -31,44 +29,6 @@ | |||
31 | 29 | ||
32 | /* Xen may fire a timer up to this many ns early */ | 30 | /* Xen may fire a timer up to this many ns early */ |
33 | #define TIMER_SLOP 100000 | 31 | #define TIMER_SLOP 100000 |
34 | #define NS_PER_TICK (1000000000LL / HZ) | ||
35 | |||
36 | /* snapshots of runstate info */ | ||
37 | static DEFINE_PER_CPU(struct vcpu_runstate_info, xen_runstate_snapshot); | ||
38 | |||
39 | /* unused ns of stolen time */ | ||
40 | static DEFINE_PER_CPU(u64, xen_residual_stolen); | ||
41 | |||
42 | static void do_stolen_accounting(void) | ||
43 | { | ||
44 | struct vcpu_runstate_info state; | ||
45 | struct vcpu_runstate_info *snap; | ||
46 | s64 runnable, offline, stolen; | ||
47 | cputime_t ticks; | ||
48 | |||
49 | xen_get_runstate_snapshot(&state); | ||
50 | |||
51 | WARN_ON(state.state != RUNSTATE_running); | ||
52 | |||
53 | snap = this_cpu_ptr(&xen_runstate_snapshot); | ||
54 | |||
55 | /* work out how much time the VCPU has not been runn*ing* */ | ||
56 | runnable = state.time[RUNSTATE_runnable] - snap->time[RUNSTATE_runnable]; | ||
57 | offline = state.time[RUNSTATE_offline] - snap->time[RUNSTATE_offline]; | ||
58 | |||
59 | *snap = state; | ||
60 | |||
61 | /* Add the appropriate number of ticks of stolen time, | ||
62 | including any left-overs from last time. */ | ||
63 | stolen = runnable + offline + __this_cpu_read(xen_residual_stolen); | ||
64 | |||
65 | if (stolen < 0) | ||
66 | stolen = 0; | ||
67 | |||
68 | ticks = iter_div_u64_rem(stolen, NS_PER_TICK, &stolen); | ||
69 | __this_cpu_write(xen_residual_stolen, stolen); | ||
70 | account_steal_ticks(ticks); | ||
71 | } | ||
72 | 32 | ||
73 | /* Get the TSC speed from Xen */ | 33 | /* Get the TSC speed from Xen */ |
74 | static unsigned long xen_tsc_khz(void) | 34 | static unsigned long xen_tsc_khz(void) |
@@ -335,8 +295,6 @@ static irqreturn_t xen_timer_interrupt(int irq, void *dev_id) | |||
335 | ret = IRQ_HANDLED; | 295 | ret = IRQ_HANDLED; |
336 | } | 296 | } |
337 | 297 | ||
338 | do_stolen_accounting(); | ||
339 | |||
340 | return ret; | 298 | return ret; |
341 | } | 299 | } |
342 | 300 | ||
@@ -431,6 +389,8 @@ static void __init xen_time_init(void) | |||
431 | xen_setup_timer(cpu); | 389 | xen_setup_timer(cpu); |
432 | xen_setup_cpu_clockevents(); | 390 | xen_setup_cpu_clockevents(); |
433 | 391 | ||
392 | xen_time_setup_guest(); | ||
393 | |||
434 | if (xen_initial_domain()) | 394 | if (xen_initial_domain()) |
435 | pvclock_gtod_register_notifier(&xen_pvclock_gtod_notifier); | 395 | pvclock_gtod_register_notifier(&xen_pvclock_gtod_notifier); |
436 | } | 396 | } |
diff --git a/drivers/xen/time.c b/drivers/xen/time.c index 71078425c9ea..2257b6663766 100644 --- a/drivers/xen/time.c +++ b/drivers/xen/time.c | |||
@@ -6,6 +6,7 @@ | |||
6 | #include <linux/math64.h> | 6 | #include <linux/math64.h> |
7 | #include <linux/gfp.h> | 7 | #include <linux/gfp.h> |
8 | 8 | ||
9 | #include <asm/paravirt.h> | ||
9 | #include <asm/xen/hypervisor.h> | 10 | #include <asm/xen/hypervisor.h> |
10 | #include <asm/xen/hypercall.h> | 11 | #include <asm/xen/hypercall.h> |
11 | 12 | ||
@@ -75,6 +76,15 @@ bool xen_vcpu_stolen(int vcpu) | |||
75 | return per_cpu(xen_runstate, vcpu).state == RUNSTATE_runnable; | 76 | return per_cpu(xen_runstate, vcpu).state == RUNSTATE_runnable; |
76 | } | 77 | } |
77 | 78 | ||
79 | static u64 xen_steal_clock(int cpu) | ||
80 | { | ||
81 | struct vcpu_runstate_info state; | ||
82 | |||
83 | BUG_ON(cpu != smp_processor_id()); | ||
84 | xen_get_runstate_snapshot(&state); | ||
85 | return state.time[RUNSTATE_runnable] + state.time[RUNSTATE_offline]; | ||
86 | } | ||
87 | |||
78 | void xen_setup_runstate_info(int cpu) | 88 | void xen_setup_runstate_info(int cpu) |
79 | { | 89 | { |
80 | struct vcpu_register_runstate_memory_area area; | 90 | struct vcpu_register_runstate_memory_area area; |
@@ -86,3 +96,13 @@ void xen_setup_runstate_info(int cpu) | |||
86 | BUG(); | 96 | BUG(); |
87 | } | 97 | } |
88 | 98 | ||
99 | void __init xen_time_setup_guest(void) | ||
100 | { | ||
101 | pv_time_ops.steal_clock = xen_steal_clock; | ||
102 | |||
103 | static_key_slow_inc(¶virt_steal_enabled); | ||
104 | /* | ||
105 | * We can't set paravirt_steal_rq_enabled as this would require the | ||
106 | * capability to read another cpu's runstate info. | ||
107 | */ | ||
108 | } | ||
diff --git a/include/linux/kernel_stat.h b/include/linux/kernel_stat.h index 25a822f6f000..44fda64ad434 100644 --- a/include/linux/kernel_stat.h +++ b/include/linux/kernel_stat.h | |||
@@ -92,7 +92,6 @@ static inline void account_process_tick(struct task_struct *tsk, int user) | |||
92 | extern void account_process_tick(struct task_struct *, int user); | 92 | extern void account_process_tick(struct task_struct *, int user); |
93 | #endif | 93 | #endif |
94 | 94 | ||
95 | extern void account_steal_ticks(unsigned long ticks); | ||
96 | extern void account_idle_ticks(unsigned long ticks); | 95 | extern void account_idle_ticks(unsigned long ticks); |
97 | 96 | ||
98 | #endif /* _LINUX_KERNEL_STAT_H */ | 97 | #endif /* _LINUX_KERNEL_STAT_H */ |
diff --git a/include/xen/xen-ops.h b/include/xen/xen-ops.h index 3491582bf50a..355275bad2cf 100644 --- a/include/xen/xen-ops.h +++ b/include/xen/xen-ops.h | |||
@@ -21,6 +21,7 @@ void xen_resume_notifier_unregister(struct notifier_block *nb); | |||
21 | 21 | ||
22 | bool xen_vcpu_stolen(int vcpu); | 22 | bool xen_vcpu_stolen(int vcpu); |
23 | void xen_setup_runstate_info(int cpu); | 23 | void xen_setup_runstate_info(int cpu); |
24 | void xen_time_setup_guest(void); | ||
24 | void xen_get_runstate_snapshot(struct vcpu_runstate_info *res); | 25 | void xen_get_runstate_snapshot(struct vcpu_runstate_info *res); |
25 | 26 | ||
26 | int xen_setup_shutdown_event(void); | 27 | int xen_setup_shutdown_event(void); |
diff --git a/kernel/sched/cputime.c b/kernel/sched/cputime.c index 75f98c5498d5..8c4c6dcc052c 100644 --- a/kernel/sched/cputime.c +++ b/kernel/sched/cputime.c | |||
@@ -490,16 +490,6 @@ void account_process_tick(struct task_struct *p, int user_tick) | |||
490 | } | 490 | } |
491 | 491 | ||
492 | /* | 492 | /* |
493 | * Account multiple ticks of steal time. | ||
494 | * @p: the process from which the cpu time has been stolen | ||
495 | * @ticks: number of stolen ticks | ||
496 | */ | ||
497 | void account_steal_ticks(unsigned long ticks) | ||
498 | { | ||
499 | account_steal_time(jiffies_to_cputime(ticks)); | ||
500 | } | ||
501 | |||
502 | /* | ||
503 | * Account multiple ticks of idle time. | 493 | * Account multiple ticks of idle time. |
504 | * @ticks: number of stolen ticks | 494 | * @ticks: number of stolen ticks |
505 | */ | 495 | */ |