report stolen time via pvclock
Subsystems (4)
cover report stolen time via pvclock
Stolen time can be useful diagnostic information when available to guests. Xen provides it for sometime, so recent vmstat versions already display it.
Also increases guests sched_clock accuracy.
PATCH 1/5 KVM: x86: report stolen time
Report stolen time (run_delay field from schedstat) to guests via pvclock.
Signed-off-by Marcelo Tosatti <[email protected]>
arch/x86/include/asm/kvm_para.h +7 -0
@@ -15,9 +15,11 @@#define KVM_FEATURE_CLOCKSOURCE 0#define KVM_FEATURE_NOP_IO_DELAY 1#define KVM_FEATURE_MMU_OP 2 +#define KVM_FEATURE_RUNTIME_INFO 3#define MSR_KVM_WALL_CLOCK 0x11#define MSR_KVM_SYSTEM_TIME 0x12 +#define MSR_KVM_RUN_TIME 0x13#define KVM_MAX_MMU_OP_BATCH 32
@@ -50,6 +52,11 @@ struct kvm_mmu_op_release_pt {#ifdef __KERNEL__#include <asm/processor.h> +struct kvm_vcpu_runtime_info { +u64 stolen_time;/* time spent starving */ +u64 reserved[3 ];/* for future use */ +}; +extern void kvmclock_init (void );
arch/x86/include/asm/kvm_host.h +4 -0
@@ -354,6 +354,10 @@ struct kvm_vcpu_arch {unsigned int time_offset;struct page *time_page; +bool stolen_time_enable; +struct kvm_vcpu_runtime_info stolen_time; +unsigned int stolen_time_offset; +bool singlestep;/* guest is single stepped by KVM */ bool nmi_pending;bool nmi_injected;
arch/x86/kvm/x86.c +40 -2
79 lines not on this page · raw message
arch/x86/kvm/Kconfig +1 -0
@@ -28,6 +28,7 @@ config KVM select HAVE_KVM_IRQCHIP select HAVE_KVM_EVENTFD select KVM_APIC_ARCHITECTURE + select SCHEDSTATS ---help--- Support hosting fully virtualized guest machines using hardware virtualization extensions. You will need a fairly recent
include/linux/kvm.h +1 -0
@@ -436,6 +436,7 @@ struct kvm_ioeventfd {#endif #define KVM_CAP_IOEVENTFD 36#define KVM_CAP_SET_IDENTITY_MAP_ADDR 37 +#define KVM_CAP_PVCLOCK_RUNTIME 38#ifdef KVM_CAP_IRQ_ROUTING
PATCH 2/5 pvclock: move code to pvclock.h
In reply to Marcelo TosattiTo be used by kvmclock.c.
Signed-off-by Marcelo Tosatti <[email protected]>
arch/x86/include/asm/pvclock.h +18 -0
@@ -4,6 +4,20 @@#include <linux/clocksource.h> #include <asm/pvclock-abi.h> +/* +* These are perodically updated +* xen: magic shared_info page +* kvm: gpa registered via msr +* and then copied here. +*/ +struct pvclock_shadow_time { +u64 tsc_timestamp;/* TSC at last update of time vals. */ +u64 system_timestamp;/* Time, in nanosecs, since boot. */ +u32 tsc_to_nsec_mul; +int tsc_shift; +u32 version; +}; +/* some helper functions for xen and kvm pv clock sources */ cycle_t pvclock_clocksource_read (struct pvclock_vcpu_time_info *src);unsigned long pvclock_tsc_khz (struct pvclock_vcpu_time_info *src);
@@ -11,4 +25,8 @@ void pvclock_read_wallclock(struct pvclostruct pvclock_vcpu_time_info *vcpu, struct timespec *ts); +u64 pvclock_get_nsec_offset (struct pvclock_shadow_time *shadow); +unsigned pvclock_get_time_values (struct pvclock_shadow_time *dst, +struct pvclock_vcpu_time_info *src); +#endif /* _ASM_X86_PVCLOCK_H */
arch/x86/kernel/pvclock.c +3 -17
@@ -20,20 +20,6 @@#include <asm/pvclock.h> /* -* These are perodically updated -* xen: magic shared_info page -* kvm: gpa registered via msr -* and then copied here. -*/ -struct pvclock_shadow_time { -u64 tsc_timestamp;/* TSC at last update of time vals. */ -u64 system_timestamp;/* Time, in nanosecs, since boot. */ -u32 tsc_to_nsec_mul; -int tsc_shift; -u32 version; -}; - -/* * Scale a 64-bit delta by scaling and multiplying by a 32-bit fraction, * yielding a 64-bit result. */
@@ -71,7 +57,7 @@ static inline u64 scale_delta(u64 delta,return product; } -static u64 pvclock_get_nsec_offset (struct pvclock_shadow_time *shadow) +u64 pvclock_get_nsec_offset (struct pvclock_shadow_time *shadow) {u64 delta =native_read_tsc () - shadow->tsc_timestamp;return scale_delta (delta, shadow->tsc_to_nsec_mul, shadow->tsc_shift);
@@ -81,8 +67,8 @@ static u64 pvclock_get_nsec_offset(struc* Reads a consistent set of time-base values from hypervisor, * into a shadow data area. */ -static unsigned pvclock_get_time_values (struct pvclock_shadow_time *dst, -struct pvclock_vcpu_time_info *src) +unsigned pvclock_get_time_values (struct pvclock_shadow_time *dst, +struct pvclock_vcpu_time_info *src) { do { dst->version = src->version;
PATCH 3/5 kvmclock: stolen time aware sched_clock
In reply to Marcelo Tosattisched_clock() should time the vcpu run time. Subtract stolen time from realtime pvclock.
Signed-off-by Marcelo Tosatti <[email protected]>
arch/x86/kernel/kvmclock.c +68 -3
@@ -38,7 +38,16 @@ static int parse_no_kvmclock(char *arg)early_param ("no-kvmclock" , parse_no_kvmclock);/* The hypervisor will put information about time periodically here */ -static DEFINE_PER_CPU_SHARED_ALIGNED(struct pvclock_vcpu_time_info, hv_clock); +struct time_info { +struct pvclock_vcpu_time_info hv_clock; +struct kvm_vcpu_runtime_info run_info; +}; + +static DEFINE_PER_CPU_SHARED_ALIGNED(struct time_info, time_info); + +#define hv_clock time_info.hv_clock +#define run_info time_info.run_info +static struct pvclock_wall_clock wall_clock;/*
@@ -84,6 +93,40 @@ static cycle_t kvm_clock_get_cycles(strureturn kvm_clock_read (); } +cycle_t kvm_runtime_read (struct pvclock_vcpu_time_info *src, +struct kvm_vcpu_runtime_info *rinfo) +{ +struct pvclock_shadow_time shadow; +unsigned version; +cycle_t ret, offset; +unsigned long long stolen; + +do { + version =pvclock_get_time_values (&shadow, src); +barrier (); + offset =pvclock_get_nsec_offset (&shadow); + stolen = rinfo->stolen_time; + ret = shadow.system_timestamp + offset - stolen; +barrier (); + }while (version != src->version); + +return ret; +} + +static cycle_t kvm_clock_read_unstolen (void ) +{ +struct pvclock_vcpu_time_info *src; +struct kvm_vcpu_runtime_info *rinfo; +cycle_t ret; + + src = &get_cpu_var (hv_clock); + rinfo = &get_cpu_var (run_info); + ret =kvm_runtime_read (src, rinfo); +put_cpu_var (run_info); +put_cpu_var (hv_clock); +return ret; +} +/* * If we don't do that, there is the possibility that the guest * will calibrate under heavy load - thus, getting a lower lpj -
@@ -133,14 +176,30 @@ static int kvm_register_clock(char *txt)return native_write_msr_safe (MSR_KVM_SYSTEM_TIME , low, high); } +static int kvm_register_run_info (char *txt) +{ +int cpu =smp_processor_id (); +int low, high; + + low = (int )__pa (&per_cpu (run_info, cpu)) |1 ; + high = ((u64 )__pa (&per_cpu (run_info, cpu)) >>32 ); +printk (KERN_INFO "kvm-runtime-info: cpu %d, msr %x:%x, %s\n" , + cpu, high, low, txt); +return native_write_msr_safe (MSR_KVM_RUN_TIME , low, high); +} +#ifdef CONFIG_X86_LOCAL_APIC static void __cpuinit kvm_setup_secondary_clock (void ) { +char *txt ="secondary cpu clock" ; +/* * Now that the first cpu already had this clocksource initialized, * we shouldn't fail. */ -WARN_ON (kvm_register_clock ("secondary cpu clock" )); +WARN_ON (kvm_register_clock (txt)); +if (kvm_para_has_feature (KVM_FEATURE_RUNTIME_INFO )) +kvm_register_run_info (txt);/* ok, done with our trickery, call native */ setup_secondary_APIC_clock (); }
@@ -149,7 +208,11 @@ static void __cpuinit kvm_setup_secondar#ifdef CONFIG_SMP static void __init kvm_smp_prepare_boot_cpu (void ) { -WARN_ON (kvm_register_clock ("primary cpu clock" )); +char *txt ="primary cpu clock" ; + +WARN_ON (kvm_register_clock (txt)); +if (kvm_para_has_feature (KVM_FEATURE_RUNTIME_INFO )) +kvm_register_run_info (txt);native_smp_prepare_boot_cpu (); }#endif
@@ -204,4 +267,6 @@ void __init kvmclock_init(void) pv_info.paravirt_enabled =1 ; pv_info.name ="KVM" ; } +if (kvm_para_has_feature (KVM_FEATURE_RUNTIME_INFO )) + pv_time_ops.sched_clock = kvm_clock_read_unstolen; }
PATCH 4/5 kvmclock: account stolen time
In reply to Marcelo TosattiWhich makes stolen time information available in procfs/vmstat.
Signed-off-by Marcelo Tosatti <[email protected]>
arch/x86/kernel/kvmclock.c +26 -0
@@ -22,11 +22,14 @@#include <asm/msr.h> #include <asm/apic.h> #include <linux/percpu.h> +#include <linux/kernel_stat.h> #include <asm/x86_init.h> #include <asm/reboot.h> +#include <asm/cputime.h> #define KVM_SCALE 22 +#define NS_PER_TICK (1000000000LL / HZ)static int kvmclock =1 ;
@@ -50,6 +53,29 @@ static DEFINE_PER_CPU_SHARED_ALIGNED(strstatic struct pvclock_wall_clock wall_clock; +static DEFINE_PER_CPU(u64, total_stolen); +static DEFINE_PER_CPU(u64, residual_stolen); + +void kvm_account_steal_time (void ) +{ +struct kvm_vcpu_runtime_info *rinfo; +cputime_t ticks; +u64 stolen_time, stolen_delta; + + rinfo = &get_cpu_var (run_info); + stolen_time = rinfo->stolen_time; + stolen_delta = stolen_time -__get_cpu_var (total_stolen); + +__get_cpu_var (total_stolen) = stolen_time; +put_cpu_var (rinfo); + + stolen_delta +=__get_cpu_var (residual_stolen); + + ticks =iter_div_u64_rem (stolen_delta,NS_PER_TICK , &stolen_delta); +__get_cpu_var (residual_stolen) = stolen_delta; +account_steal_ticks (ticks); +} +/* * The wallclock is the time of day when we booted. Since then, some time may * have elapsed since the hypervisor wrote the data. So we try to account for
kernel/sched.c +6 -0
@@ -74,6 +74,9 @@#include <asm/tlb.h> #include <asm/irq_regs.h> +#ifdef CONFIG_KVM_CLOCK +#include <asm/kvm_para.h> +#endif #include "sched_cpupri.h"
@@ -5102,6 +5105,9 @@ void account_process_tick(struct task_st one_jiffy_scaled); elseaccount_idle_time (cputime_one_jiffy ); +#ifdef CONFIG_KVM_CLOCK +kvm_account_steal_time (); +#endif }/*
arch/x86/include/asm/kvm_para.h +1 -0
@@ -58,6 +58,7 @@ struct kvm_vcpu_runtime_info { };extern void kvmclock_init (void ); +extern void kvm_account_steal_time (void );/* This instruction is vmcall. On non-VT architectures, it will generate a
PATCH 5/5 qemu-kvm-x86: report pvclock runtime capability
In reply to Marcelo TosattiSigned-off-by Marcelo Tosatti <[email protected]>
qemu-kvm-x86.c +3 -0
@@ -1223,6 +1223,9 @@ struct kvm_para_features { #ifdef KVM_CAP_CR3_CACHE { KVM_CAP_CR3_CACHE, KVM_FEATURE_CR3_CACHE }, #endif +#ifdef KVM_CAP_PVCLOCK_RUNTIME + { KVM_CAP_PVCLOCK_RUNTIME, KVM_FEATURE_RUNTIME_INFO }, +#endif { -1, -1 } };