Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

kvm: add halt-polling cpu usage stats

Two new stats for exposing halt-polling cpu usage:
halt_poll_success_ns
halt_poll_fail_ns

Thus sum of these 2 stats is the total cpu time spent polling. "success"
means the VCPU polled until a virtual interrupt was delivered. "fail"
means the VCPU had to schedule out (either because the maximum poll time
was reached or it needed to yield the CPU).

To avoid touching every arch's kvm_vcpu_stat struct, only update and
export halt-polling cpu usage stats if we're on x86.

Exporting cpu usage as a u64 and in nanoseconds means we will overflow at
~500 years, which seems reasonably large.

Signed-off-by: David Matlack <dmatlack@google.com>
Signed-off-by: Jon Cargille <jcargill@google.com>
Reviewed-by: Jim Mattson <jmattson@google.com>

Message-Id: <20200508182240.68440-1-jcargill@google.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>

authored by

David Matlack and committed by
Paolo Bonzini
cb953129 93dff2fe

+33 -3
+2
arch/arm64/include/asm/kvm_host.h
··· 415 415 struct kvm_vcpu_stat { 416 416 u64 halt_successful_poll; 417 417 u64 halt_attempted_poll; 418 + u64 halt_poll_success_ns; 419 + u64 halt_poll_fail_ns; 418 420 u64 halt_poll_invalid; 419 421 u64 halt_wakeup; 420 422 u64 hvc_exit_stat;
+2
arch/arm64/kvm/guest.c
··· 40 40 VCPU_STAT("mmio_exit_user", mmio_exit_user), 41 41 VCPU_STAT("mmio_exit_kernel", mmio_exit_kernel), 42 42 VCPU_STAT("exits", exits), 43 + VCPU_STAT("halt_poll_success_ns", halt_poll_success_ns), 44 + VCPU_STAT("halt_poll_fail_ns", halt_poll_fail_ns), 43 45 { NULL } 44 46 }; 45 47
+2
arch/mips/include/asm/kvm_host.h
··· 174 174 #endif 175 175 u64 halt_successful_poll; 176 176 u64 halt_attempted_poll; 177 + u64 halt_poll_success_ns; 178 + u64 halt_poll_fail_ns; 177 179 u64 halt_poll_invalid; 178 180 u64 halt_wakeup; 179 181 };
+2
arch/mips/kvm/mips.c
··· 72 72 VCPU_STAT("halt_attempted_poll", halt_attempted_poll), 73 73 VCPU_STAT("halt_poll_invalid", halt_poll_invalid), 74 74 VCPU_STAT("halt_wakeup", halt_wakeup), 75 + VCPU_STAT("halt_poll_success_ns", halt_poll_success_ns), 76 + VCPU_STAT("halt_poll_fail_ns", halt_poll_fail_ns), 75 77 {NULL} 76 78 }; 77 79
+2
arch/powerpc/kvm/booke.c
··· 54 54 VCPU_STAT("halt_wakeup", halt_wakeup), 55 55 VCPU_STAT("doorbell", dbell_exits), 56 56 VCPU_STAT("guest doorbell", gdbell_exits), 57 + VCPU_STAT("halt_poll_success_ns", halt_poll_success_ns), 58 + VCPU_STAT("halt_poll_fail_ns", halt_poll_fail_ns), 57 59 VM_STAT("remote_tlb_flush", remote_tlb_flush), 58 60 { NULL } 59 61 };
+2
arch/s390/include/asm/kvm_host.h
··· 375 375 u64 halt_poll_invalid; 376 376 u64 halt_no_poll_steal; 377 377 u64 halt_wakeup; 378 + u64 halt_poll_success_ns; 379 + u64 halt_poll_fail_ns; 378 380 u64 instruction_lctl; 379 381 u64 instruction_lctlg; 380 382 u64 instruction_stctl;
+2
arch/s390/kvm/kvm-s390.c
··· 75 75 VCPU_STAT("halt_poll_invalid", halt_poll_invalid), 76 76 VCPU_STAT("halt_no_poll_steal", halt_no_poll_steal), 77 77 VCPU_STAT("halt_wakeup", halt_wakeup), 78 + VCPU_STAT("halt_poll_success_ns", halt_poll_success_ns), 79 + VCPU_STAT("halt_poll_fail_ns", halt_poll_fail_ns), 78 80 VCPU_STAT("instruction_lctlg", instruction_lctlg), 79 81 VCPU_STAT("instruction_lctl", instruction_lctl), 80 82 VCPU_STAT("instruction_stctl", instruction_stctl),
+2
arch/x86/include/asm/kvm_host.h
··· 1031 1031 u64 irq_injections; 1032 1032 u64 nmi_injections; 1033 1033 u64 req_event; 1034 + u64 halt_poll_success_ns; 1035 + u64 halt_poll_fail_ns; 1034 1036 }; 1035 1037 1036 1038 struct x86_instruction_info;
+2
arch/x86/kvm/x86.c
··· 217 217 VCPU_STAT("nmi_injections", nmi_injections), 218 218 VCPU_STAT("req_event", req_event), 219 219 VCPU_STAT("l1d_flush", l1d_flush), 220 + VCPU_STAT("halt_poll_success_ns", halt_poll_success_ns), 221 + VCPU_STAT("halt_poll_fail_ns", halt_poll_fail_ns), 220 222 VM_STAT("mmu_shadow_zapped", mmu_shadow_zapped), 221 223 VM_STAT("mmu_pte_write", mmu_pte_write), 222 224 VM_STAT("mmu_pte_updated", mmu_pte_updated),
+15 -3
virt/kvm/kvm_main.c
··· 2667 2667 return ret; 2668 2668 } 2669 2669 2670 + static inline void 2671 + update_halt_poll_stats(struct kvm_vcpu *vcpu, u64 poll_ns, bool waited) 2672 + { 2673 + if (waited) 2674 + vcpu->stat.halt_poll_fail_ns += poll_ns; 2675 + else 2676 + vcpu->stat.halt_poll_success_ns += poll_ns; 2677 + } 2678 + 2670 2679 /* 2671 2680 * The vCPU has executed a HLT instruction with in-kernel mode enabled. 2672 2681 */ 2673 2682 void kvm_vcpu_block(struct kvm_vcpu *vcpu) 2674 2683 { 2675 - ktime_t start, cur; 2684 + ktime_t start, cur, poll_end; 2676 2685 bool waited = false; 2677 2686 u64 block_ns; 2678 2687 2679 2688 kvm_arch_vcpu_blocking(vcpu); 2680 2689 2681 - start = cur = ktime_get(); 2690 + start = cur = poll_end = ktime_get(); 2682 2691 if (vcpu->halt_poll_ns && !kvm_arch_no_poll(vcpu)) { 2683 2692 ktime_t stop = ktime_add_ns(ktime_get(), vcpu->halt_poll_ns); 2684 2693 ··· 2703 2694 ++vcpu->stat.halt_poll_invalid; 2704 2695 goto out; 2705 2696 } 2706 - cur = ktime_get(); 2697 + poll_end = cur = ktime_get(); 2707 2698 } while (single_task_running() && ktime_before(cur, stop)); 2708 2699 } 2709 2700 ··· 2722 2713 out: 2723 2714 kvm_arch_vcpu_unblocking(vcpu); 2724 2715 block_ns = ktime_to_ns(cur) - ktime_to_ns(start); 2716 + 2717 + update_halt_poll_stats( 2718 + vcpu, ktime_to_ns(ktime_sub(poll_end, start)), waited); 2725 2719 2726 2720 if (!kvm_arch_no_poll(vcpu)) { 2727 2721 if (!vcpu_valid_wakeup(vcpu)) {