Skip to content

Commit 80e9a4f

Browse files
Alexey MakhalovKAGA-KOKO
authored andcommitted
x86/vmware: Add paravirt sched clock
The default sched_clock() implementation is native_sched_clock(). It contains code to handle non constant frequency TSCs, which creates overhead for systems with constant frequency TSCs. The vmware hypervisor guarantees a constant frequency TSC, so native_sched_clock() is not required and slower than a dedicated function which operates with one time calculated conversion factors. Calculate the conversion factors at boot time from the tsc frequency and install an optimized sched_clock() function via paravirt ops. The paravirtualized clock can be disabled on the kernel command line with the new 'no-vmw-sched-clock' option. Signed-off-by: Alexey Makhalov <amakhalov@vmware.com> Acked-by: Alok N Kataria <akataria@vmware.com> Cc: linux-doc@vger.kernel.org Cc: pv-drivers@vmware.com Cc: corbet@lwn.net Cc: virtualization@lists.linux-foundation.org Link: http://lkml.kernel.org/r/20161028075432.90579-4-amakhalov@vmware.com Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
1 parent 91d1e54 commit 80e9a4f

File tree

2 files changed

+46
-0
lines changed

2 files changed

+46
-0
lines changed

Documentation/kernel-parameters.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2754,6 +2754,10 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
27542754
no-kvmapf [X86,KVM] Disable paravirtualized asynchronous page
27552755
fault handling.
27562756

2757+
no-vmw-sched-clock
2758+
[X86,PV_OPS] Disable paravirtualized VMware scheduler
2759+
clock and use the default one.
2760+
27572761
no-steal-acc [X86,KVM] Disable paravirtualized steal time accounting.
27582762
steal time is computed, but won't influence scheduler
27592763
behaviour

arch/x86/kernel/cpu/vmware.c

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,10 +24,15 @@
2424
#include <linux/dmi.h>
2525
#include <linux/init.h>
2626
#include <linux/export.h>
27+
#include <linux/clocksource.h>
2728
#include <asm/div64.h>
2829
#include <asm/x86_init.h>
2930
#include <asm/hypervisor.h>
3031
#include <asm/apic.h>
32+
#include <asm/timer.h>
33+
34+
#undef pr_fmt
35+
#define pr_fmt(fmt) "vmware: " fmt
3136

3237
#define CPUID_VMWARE_INFO_LEAF 0x40000000
3338
#define VMWARE_HYPERVISOR_MAGIC 0x564D5868
@@ -62,10 +67,47 @@ static unsigned long vmware_get_tsc_khz(void)
6267
}
6368

6469
#ifdef CONFIG_PARAVIRT
70+
static struct cyc2ns_data vmware_cyc2ns __ro_after_init;
71+
static int vmw_sched_clock __initdata = 1;
72+
73+
static __init int setup_vmw_sched_clock(char *s)
74+
{
75+
vmw_sched_clock = 0;
76+
return 0;
77+
}
78+
early_param("no-vmw-sched-clock", setup_vmw_sched_clock);
79+
80+
static unsigned long long vmware_sched_clock(void)
81+
{
82+
unsigned long long ns;
83+
84+
ns = mul_u64_u32_shr(rdtsc(), vmware_cyc2ns.cyc2ns_mul,
85+
vmware_cyc2ns.cyc2ns_shift);
86+
ns -= vmware_cyc2ns.cyc2ns_offset;
87+
return ns;
88+
}
89+
90+
static void __init vmware_sched_clock_setup(void)
91+
{
92+
struct cyc2ns_data *d = &vmware_cyc2ns;
93+
unsigned long long tsc_now = rdtsc();
94+
95+
clocks_calc_mult_shift(&d->cyc2ns_mul, &d->cyc2ns_shift,
96+
vmware_tsc_khz, NSEC_PER_MSEC, 0);
97+
d->cyc2ns_offset = mul_u64_u32_shr(tsc_now, d->cyc2ns_mul,
98+
d->cyc2ns_shift);
99+
100+
pv_time_ops.sched_clock = vmware_sched_clock;
101+
pr_info("using sched offset of %llu ns\n", d->cyc2ns_offset);
102+
}
103+
65104
static void __init vmware_paravirt_ops_setup(void)
66105
{
67106
pv_info.name = "VMware hypervisor";
68107
pv_cpu_ops.io_delay = paravirt_nop;
108+
109+
if (vmware_tsc_khz && vmw_sched_clock)
110+
vmware_sched_clock_setup();
69111
}
70112
#else
71113
#define vmware_paravirt_ops_setup() do {} while (0)

0 commit comments

Comments
 (0)