Skip to contentSkip to conversation

kvmclock: allow stable sched clock

PATCH Superseded Marcelo Tosatti 2 participants 6 messages May 28, 2015

Subsystems (5)
x86 KVM KVM x86 Xen hypervisor x86 +1 more subsystems

v1 of 2 Superseded Latest is v2 →

lore
Share & tools
lore
#0 lore raw

cover kvmclock: allow stable sched clock

kvmclock provides the behaviour sched_clock users expect. Mark it as stable allowing nohz_full in guests. See individual patches for more details.

#1 lore raw

PATCH 1/3 x86: kvmclock: add flag to indicate pvclock counts from zero

Setting sched clock stable for kvmclock causes the printk timestamps to not start from zero, which is different from baremetal and can possibly break userspace. Add a flag to indicate that hypervisor sets clock base at zero when kvmclock is initialized.

---
 arch/x86/include/asm/pvclock-abi.h |    1 +
 1 file changed, 1 insertion(+)
arch/x86/include/asm/pvclock-abi.h +1 -0
Index: kvm/arch/x86/include/asm/pvclock-abi.h
===================================================================
@@ -41,5 +41,6 @@
 
 #define PVCLOCK_TSC_STABLE_BIT	(1 << 0)
 #define PVCLOCK_GUEST_STOPPED	(1 << 1)
+#define PVCLOCK_COUNTS_FROM_ZERO (1 << 2)
 #endif /* __ASSEMBLY__ */
 #endif /* _ASM_X86_PVCLOCK_ABI_H */
#2 lore raw

PATCH 2/3 x86: kvmclock: set scheduler clock stable

In reply to Marcelo Tosatti

From: Luiz Capitulino <[email protected]>

If you try to enable NOHZ_FULL on a guest today, you'll get the following error when the guest tries to deactivate the scheduler tick:

 WARNING: CPU: 3 PID: 2182 at kernel/time/tick-sched.c:192 can_stop_full_tick+0xb9/0x290()
 NO_HZ FULL will not work with unstable sched clock
 CPU: 3 PID: 2182 Comm: kworker/3:1 Not tainted 4.0.0-10545-gb9bb6fb #204
 Hardware name: Bochs Bochs, BIOS Bochs 01/01/2011
 Workqueue: events flush_to_ldisc
  ffffffff8162a0c7 ffff88011f583e88 ffffffff814e6ba0 0000000000000002
  ffff88011f583ed8 ffff88011f583ec8 ffffffff8104d095 ffff88011f583eb8
  0000000000000000 0000000000000003 0000000000000001 0000000000000001
 Call Trace:
  <IRQ>  [<ffffffff814e6ba0>] dump_stack+0x4f/0x7b
  [<ffffffff8104d095>] warn_slowpath_common+0x85/0xc0
  [<ffffffff8104d146>] warn_slowpath_fmt+0x46/0x50
  [<ffffffff810bd2a9>] can_stop_full_tick+0xb9/0x290
  [<ffffffff810bd9ed>] tick_nohz_irq_exit+0x8d/0xb0
  [<ffffffff810511c5>] irq_exit+0xc5/0x130
  [<ffffffff814f180a>] smp_apic_timer_interrupt+0x4a/0x60
  [<ffffffff814eff5e>] apic_timer_interrupt+0x6e/0x80
  <EOI>  [<ffffffff814ee5d1>] ? _raw_spin_unlock_irqrestore+0x31/0x60
  [<ffffffff8108bbc8>] __wake_up+0x48/0x60
  [<ffffffff8134836c>] n_tty_receive_buf_common+0x49c/0xba0
  [<ffffffff8134a6bf>] ? tty_ldisc_ref+0x1f/0x70
  [<ffffffff81348a84>] n_tty_receive_buf2+0x14/0x20
  [<ffffffff8134b390>] flush_to_ldisc+0xe0/0x120
  [<ffffffff81064d05>] process_one_work+0x1d5/0x540
  [<ffffffff81064c81>] ? process_one_work+0x151/0x540
  [<ffffffff81065191>] worker_thread+0x121/0x470
  [<ffffffff81065070>] ? process_one_work+0x540/0x540
  [<ffffffff8106b4df>] kthread+0xef/0x110
  [<ffffffff8106b3f0>] ? __kthread_parkme+0xa0/0xa0
  [<ffffffff814ef4f2>] ret_from_fork+0x42/0x70
  [<ffffffff8106b3f0>] ? __kthread_parkme+0xa0/0xa0
 ---[ end trace 06e3507544a38866 ]---

However, it turns out that kvmclock does provide a stable sched_clock callback. So, let the scheduler know this which in turn makes NOHZ_FULL work in the guest.

---
 arch/x86/kernel/kvmclock.c |   17 +++++++++++++++--
 1 file changed, 15 insertions(+), 2 deletions(-)
arch/x86/kernel/kvmclock.c +15 -2
Index: kvm/arch/x86/kernel/kvmclock.c
===================================================================
@@ -24,6 +24,7 @@
 #include <linux/percpu.h>
 #include <linux/hardirq.h>
 #include <linux/memblock.h>
+#include <linux/sched.h>
 
 #include <asm/x86_init.h>
 #include <asm/reboot.h>
@@ -217,8 +218,10 @@
 
 void __init kvmclock_init(void)
 {
+	struct pvclock_vcpu_time_info *vcpu_time;
 	unsigned long mem;
-	int size;
+	int size, cpu;
+	u8 flags;
 
 	size = PAGE_ALIGN(sizeof(struct pvclock_vsyscall_time_info)*NR_CPUS);
 
@@ -263,8 +266,18 @@
 	clocksource_register_hz(&kvm_clock, NSEC_PER_SEC);
 	pv_info.name = "KVM";
 
+	flags = PVCLOCK_COUNTS_FROM_ZERO;
 	if (kvm_para_has_feature(KVM_FEATURE_CLOCKSOURCE_STABLE_BIT))
-		pvclock_set_flags(PVCLOCK_TSC_STABLE_BIT);
+		flags |= PVCLOCK_TSC_STABLE_BIT;
+
+	pvclock_set_flags(flags);
+
+	cpu = get_cpu();
+	vcpu_time = &hv_clock[cpu].pvti;
+	flags = pvclock_read_flags(vcpu_time);
+	if (flags & PVCLOCK_COUNTS_FROM_ZERO)
+		set_sched_clock_stable();
+	put_cpu();
 }
 
 int __init kvm_setup_vsyscall_timeinfo(void)
maintainer
#3 lore raw

Re: [patch 2/3] x86: kvmclock: set scheduler clock stable

arch/x86/kernel/kvmclock.c line 269

Quoted 1 line · Marcelo Tosatti
arch/x86/kernel/kvmclock.c +1 -0
+	flags = PVCLOCK_COUNTS_FROM_ZERO;

If the KVM_FEATURE_CLOCKSOURCE_STABLE_BIT bit is not set, we cannot trust flags at all. So let's just do...

arch/x86/kernel/kvmclock.c line 271

Quoted 3 lines
arch/x86/kernel/kvmclock.c +1 -1
 	if (kvm_para_has_feature(KVM_FEATURE_CLOCKSOURCE_STABLE_BIT))
-		pvclock_set_flags(PVCLOCK_TSC_STABLE_BIT);
+		flags |= PVCLOCK_TSC_STABLE_BIT;

- pvclock_set_flags(PVCLOCK_TSC_STABLE_BIT);
+ pvclock_set_flags(~0);

Otherwise looks good. Shall I do the above change and apply?

Paolo

Quoted 9 lines
arch/x86/kernel/kvmclock.c +8 -0
+	pvclock_set_flags(flags);
+
+	cpu = get_cpu();
+	vcpu_time = &hv_clock[cpu].pvti;
+	flags = pvclock_read_flags(vcpu_time);
+	if (flags & PVCLOCK_COUNTS_FROM_ZERO)
+		set_sched_clock_stable();
+	put_cpu();
 }
#4 lore raw

PATCH 3/3 KVM: x86: zero kvmclock_offset when vcpu0 initializes kvmclock system MSR

In reply to Marcelo Tosatti

Initialize kvmclock base, on kvmclock system MSR write time, so that the guest sees kvmclock counting from zero.

This matches baremetal behaviour when kvmclock in guest sets sched clock stable.

---
 arch/x86/kvm/x86.c |    5 +++++
 1 file changed, 5 insertions(+)
arch/x86/kvm/x86.c +5 -0
Index: kvm/arch/x86/kvm/x86.c
===================================================================
@@ -1703,6 +1703,8 @@
 	/* If the host uses TSC clocksource, then it is stable */
 	if (use_master_clock)
 		pvclock_flags |= PVCLOCK_TSC_STABLE_BIT;
+	if (ka->kvmclk_counts_from_zero)
+		pvclock_flags |= PVCLOCK_COUNTS_FROM_ZERO;
 
 	vcpu->hv_clock.flags = pvclock_flags;
 
@@ -2282,6 +2284,9 @@
 					&vcpu->requests);
 
 			ka->boot_vcpu_runs_old_kvmclock = tmp;
+
+			ka->kvmclock_offset = -get_kernel_ns();
+			ka->kvmclk_counts_from_zero = true;
 		}
 
 		vcpu->arch.time = data;
maintainer
#5 lore raw

Re: [patch 3/3] KVM: x86: zero kvmclock_offset when vcpu0 initializes kvmclock system MSR

Quoted 17 lines · Marcelo Tosatti

Initialize kvmclock base, on kvmclock system MSR write time, so that the guest sees kvmclock counting from zero.

This matches baremetal behaviour when kvmclock in guest sets sched clock stable.

---
 arch/x86/kvm/x86.c |    5 +++++
 1 file changed, 5 insertions(+)

Index: kvm/arch/x86/kvm/x86.c
===================================================================

arch/x86/kvm/x86.c line 1706

Quoted 4 lines
arch/x86/kvm/x86.c +1 -0
@@ -1703,6 +1703,8 @@
 	/* If the host uses TSC clocksource, then it is stable */
 	if (use_master_clock)
 		pvclock_flags |= PVCLOCK_TSC_STABLE_BIT;
+	if (ka->kvmclk_counts_from_zero)

Not defined anywhere.

arch/x86/kvm/x86.c line 1707

Quoted 1 line
arch/x86/kvm/x86.c +1 -0
+		pvclock_flags |= PVCLOCK_COUNTS_FROM_ZERO;

Why can't this be unconditional?

Paolo

Quoted 14 lines
arch/x86/kvm/x86.c +3 -0
 	vcpu->hv_clock.flags = pvclock_flags;
 
@@ -2282,6 +2284,9 @@
 					&vcpu->requests);
 
 			ka->boot_vcpu_runs_old_kvmclock = tmp;
+
+			ka->kvmclock_offset = -get_kernel_ns();
+			ka->kvmclk_counts_from_zero = true;
 		}
 
 		vcpu->arch.time = data;