From patchwork Thu Apr 15 15:17:38 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jing Zhang X-Patchwork-Id: 1466685 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=vger.kernel.org (client-ip=23.128.96.18; helo=vger.kernel.org; envelope-from=kvm-ppc-owner@vger.kernel.org; receiver=) Authentication-Results: ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=google.com header.i=@google.com header.a=rsa-sha256 header.s=20161025 header.b=C5QvjsMm; dkim-atps=neutral Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by ozlabs.org (Postfix) with ESMTP id 4FLjhP6Yppz9sRK for ; Fri, 16 Apr 2021 01:20:21 +1000 (AEST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S234172AbhDOPUl (ORCPT ); Thu, 15 Apr 2021 11:20:41 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:48906 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S236912AbhDOPUS (ORCPT ); Thu, 15 Apr 2021 11:20:18 -0400 Received: from mail-qk1-x74a.google.com (mail-qk1-x74a.google.com [IPv6:2607:f8b0:4864:20::74a]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id DC125C06136F for ; Thu, 15 Apr 2021 08:17:46 -0700 (PDT) Received: by mail-qk1-x74a.google.com with SMTP id c9so1727114qkm.11 for ; Thu, 15 Apr 2021 08:17:46 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20161025; h=date:in-reply-to:message-id:mime-version:references:subject:from:to :cc; bh=mlpq2JOS6LVo7hR/1JUgyMS7GDNYOTEdrZCVhgUJoZk=; b=C5QvjsMmtJ9feDzYR887MMwiqH1nEUYVC+yy6hcAyh86E+5yIP30YgA/UAHL1n3/Ja tQfHKpGCnul+SI1Bavpha03DyMiJwKHLYhflaVQn8JMwtRRN6htqpE0wXY9EF6c4dygY 6ZWO8zY1nNOsCxh8CR1YLsTZcZGYsWOXwRpjS/VYT9v2m795COAo0zrjUUQ7ZZqfoZYi PxFn75NeQqA+TarRUdbDZami5XU/ATbqxhaMOaJidr7H29uo5FhZ3DO2tiwSftyp9MCk 92wj85zNXV0iO8vVhgOCf0LyCuNf6yWNc8RQI7QmF37YKKcONa/OpoQUEq8TXtHTciYn fxug== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:date:in-reply-to:message-id:mime-version :references:subject:from:to:cc; bh=mlpq2JOS6LVo7hR/1JUgyMS7GDNYOTEdrZCVhgUJoZk=; b=kPwuA2i7xuQI5CHcjgqWEE0ryAQ/7iCo/9jz01NOlZiDoImJIglORf9a9llM2wlmGj gtT+lCxVvAMmd5Gi5QSnVUlFWDvoRXShYI9nWcUG5+VUcVYaRbOZmzJesNSW7MVAZyNc YEAQOUizsrKYvR3iLOQM80PqbpLzvLV5Anrg7ozdTKeTI959r/EKcEcEPa3Bawhdxf8m f7Sz4/QtnkhND3YnbH+VC8zg3n2lpCCKOYkcDbs8WvYxM1mMf8y6vfBDzEITtUh/EzOy CS7RX7S3bqtsrbL1wNSjiic2p9nKauY0sLkWIChYtxucn1qW7H65zjYOEA2upRRnCvQ7 fiVw== X-Gm-Message-State: AOAM531jX9ixJMQlHaboG1f5oIpjqHweX1Z0AD0Kw5ANj4X6jYFynVmL r1O/VTW/AxKh5qI4tS7u7qRPvCz2cS7yw1F6uA== X-Google-Smtp-Source: ABdhPJwrC+nyGQM9VZ9qcUYBJx+Xihn39yLQfi83D/lOKULB5hUpQ+ZZwIdkvGHaw/py2K7TofFgNDQDY2eZkcldog== X-Received: from jgzg.c.googlers.com ([fda3:e722:ac3:10:7f:e700:c0a8:1acf]) (user=jingzhangos job=sendgmr) by 2002:ad4:576e:: with SMTP id r14mr3740970qvx.13.1618499866086; Thu, 15 Apr 2021 08:17:46 -0700 (PDT) Date: Thu, 15 Apr 2021 15:17:38 +0000 In-Reply-To: <20210415151741.1607806-1-jingzhangos@google.com> Message-Id: <20210415151741.1607806-2-jingzhangos@google.com> Mime-Version: 1.0 References: <20210415151741.1607806-1-jingzhangos@google.com> X-Mailer: git-send-email 2.31.1.295.g9ea45b61b8-goog Subject: [PATCH v2 1/4] KVM: stats: Separate common stats from architecture specific ones From: Jing Zhang To: KVM , KVMARM , LinuxMIPS , KVMPPC , LinuxS390 , Linuxkselftest , Paolo Bonzini , Marc Zyngier , James Morse , Julien Thierry , Suzuki K Poulose , Will Deacon , Huacai Chen , Aleksandar Markovic , Thomas Bogendoerfer , Paul Mackerras , Christian Borntraeger , Janosch Frank , David Hildenbrand , Cornelia Huck , Claudio Imbrenda , Sean Christopherson , Vitaly Kuznetsov , Jim Mattson , Peter Shier , Oliver Upton , David Rientjes , Emanuele Giuseppe Esposito Cc: Jing Zhang Precedence: bulk List-ID: X-Mailing-List: kvm-ppc@vger.kernel.org Put all common statistics in a separate structure to ease statistics handling for the incoming new statistics API. No functional change intended. Signed-off-by: Jing Zhang --- arch/arm64/include/asm/kvm_host.h | 9 ++------- arch/arm64/kvm/guest.c | 12 ++++++------ arch/mips/include/asm/kvm_host.h | 9 ++------- arch/mips/kvm/mips.c | 12 ++++++------ arch/powerpc/include/asm/kvm_host.h | 9 ++------- arch/powerpc/kvm/book3s.c | 12 ++++++------ arch/powerpc/kvm/book3s_hv.c | 12 ++++++------ arch/powerpc/kvm/book3s_pr.c | 2 +- arch/powerpc/kvm/book3s_pr_papr.c | 2 +- arch/powerpc/kvm/booke.c | 14 +++++++------- arch/s390/include/asm/kvm_host.h | 9 ++------- arch/s390/kvm/kvm-s390.c | 12 ++++++------ arch/x86/include/asm/kvm_host.h | 9 ++------- arch/x86/kvm/x86.c | 14 +++++++------- include/linux/kvm_host.h | 5 +++++ include/linux/kvm_types.h | 12 ++++++++++++ virt/kvm/kvm_main.c | 14 +++++++------- 17 files changed, 80 insertions(+), 88 deletions(-) diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h index 72e6b4600264..442e447e05d3 100644 --- a/arch/arm64/include/asm/kvm_host.h +++ b/arch/arm64/include/asm/kvm_host.h @@ -546,16 +546,11 @@ static inline bool __vcpu_write_sys_reg_to_cpu(u64 val, int reg) } struct kvm_vm_stat { - ulong remote_tlb_flush; + struct kvm_vm_stat_common common; }; struct kvm_vcpu_stat { - u64 halt_successful_poll; - u64 halt_attempted_poll; - u64 halt_poll_success_ns; - u64 halt_poll_fail_ns; - u64 halt_poll_invalid; - u64 halt_wakeup; + struct kvm_vcpu_stat_common common; u64 hvc_exit_stat; u64 wfe_exit_stat; u64 wfi_exit_stat; diff --git a/arch/arm64/kvm/guest.c b/arch/arm64/kvm/guest.c index 9bbd30e62799..cc5b1e2fdbd0 100644 --- a/arch/arm64/kvm/guest.c +++ b/arch/arm64/kvm/guest.c @@ -29,18 +29,18 @@ #include "trace.h" struct kvm_stats_debugfs_item debugfs_entries[] = { - VCPU_STAT("halt_successful_poll", halt_successful_poll), - VCPU_STAT("halt_attempted_poll", halt_attempted_poll), - VCPU_STAT("halt_poll_invalid", halt_poll_invalid), - VCPU_STAT("halt_wakeup", halt_wakeup), + VCPU_STAT_COM("halt_successful_poll", halt_successful_poll), + VCPU_STAT_COM("halt_attempted_poll", halt_attempted_poll), + VCPU_STAT_COM("halt_poll_invalid", halt_poll_invalid), + VCPU_STAT_COM("halt_wakeup", halt_wakeup), VCPU_STAT("hvc_exit_stat", hvc_exit_stat), VCPU_STAT("wfe_exit_stat", wfe_exit_stat), VCPU_STAT("wfi_exit_stat", wfi_exit_stat), VCPU_STAT("mmio_exit_user", mmio_exit_user), VCPU_STAT("mmio_exit_kernel", mmio_exit_kernel), VCPU_STAT("exits", exits), - VCPU_STAT("halt_poll_success_ns", halt_poll_success_ns), - VCPU_STAT("halt_poll_fail_ns", halt_poll_fail_ns), + VCPU_STAT_COM("halt_poll_success_ns", halt_poll_success_ns), + VCPU_STAT_COM("halt_poll_fail_ns", halt_poll_fail_ns), { NULL } }; diff --git a/arch/mips/include/asm/kvm_host.h b/arch/mips/include/asm/kvm_host.h index feaa77036b67..291a453ab447 100644 --- a/arch/mips/include/asm/kvm_host.h +++ b/arch/mips/include/asm/kvm_host.h @@ -143,10 +143,11 @@ static inline bool kvm_is_error_hva(unsigned long addr) } struct kvm_vm_stat { - ulong remote_tlb_flush; + struct kvm_vm_stat_common common; }; struct kvm_vcpu_stat { + struct kvm_vcpu_stat_common common; u64 wait_exits; u64 cache_exits; u64 signal_exits; @@ -178,12 +179,6 @@ struct kvm_vcpu_stat { u64 vz_cpucfg_exits; #endif #endif - u64 halt_successful_poll; - u64 halt_attempted_poll; - u64 halt_poll_success_ns; - u64 halt_poll_fail_ns; - u64 halt_poll_invalid; - u64 halt_wakeup; }; struct kvm_arch_memory_slot { diff --git a/arch/mips/kvm/mips.c b/arch/mips/kvm/mips.c index 58a8812e2fa5..d78820777de1 100644 --- a/arch/mips/kvm/mips.c +++ b/arch/mips/kvm/mips.c @@ -71,12 +71,12 @@ struct kvm_stats_debugfs_item debugfs_entries[] = { VCPU_STAT("vz_cpucfg", vz_cpucfg_exits), #endif #endif - VCPU_STAT("halt_successful_poll", halt_successful_poll), - VCPU_STAT("halt_attempted_poll", halt_attempted_poll), - VCPU_STAT("halt_poll_invalid", halt_poll_invalid), - VCPU_STAT("halt_wakeup", halt_wakeup), - VCPU_STAT("halt_poll_success_ns", halt_poll_success_ns), - VCPU_STAT("halt_poll_fail_ns", halt_poll_fail_ns), + VCPU_STAT_COM("halt_successful_poll", halt_successful_poll), + VCPU_STAT_COM("halt_attempted_poll", halt_attempted_poll), + VCPU_STAT_COM("halt_poll_invalid", halt_poll_invalid), + VCPU_STAT_COM("halt_wakeup", halt_wakeup), + VCPU_STAT_COM("halt_poll_success_ns", halt_poll_success_ns), + VCPU_STAT_COM("halt_poll_fail_ns", halt_poll_fail_ns), {NULL} }; diff --git a/arch/powerpc/include/asm/kvm_host.h b/arch/powerpc/include/asm/kvm_host.h index 1e83359f286b..473d9d0804ff 100644 --- a/arch/powerpc/include/asm/kvm_host.h +++ b/arch/powerpc/include/asm/kvm_host.h @@ -80,12 +80,13 @@ struct kvmppc_book3s_shadow_vcpu; struct kvm_nested_guest; struct kvm_vm_stat { - ulong remote_tlb_flush; + struct kvm_vm_stat_common common; ulong num_2M_pages; ulong num_1G_pages; }; struct kvm_vcpu_stat { + struct kvm_vcpu_stat_common common; u64 sum_exits; u64 mmio_exits; u64 signal_exits; @@ -101,14 +102,8 @@ struct kvm_vcpu_stat { u64 emulated_inst_exits; u64 dec_exits; u64 ext_intr_exits; - u64 halt_poll_success_ns; - u64 halt_poll_fail_ns; u64 halt_wait_ns; - u64 halt_successful_poll; - u64 halt_attempted_poll; u64 halt_successful_wait; - u64 halt_poll_invalid; - u64 halt_wakeup; u64 dbell_exits; u64 gdbell_exits; u64 ld; diff --git a/arch/powerpc/kvm/book3s.c b/arch/powerpc/kvm/book3s.c index 44bf567b6589..d799029f2e55 100644 --- a/arch/powerpc/kvm/book3s.c +++ b/arch/powerpc/kvm/book3s.c @@ -47,14 +47,14 @@ struct kvm_stats_debugfs_item debugfs_entries[] = { VCPU_STAT("dec", dec_exits), VCPU_STAT("ext_intr", ext_intr_exits), VCPU_STAT("queue_intr", queue_intr), - VCPU_STAT("halt_poll_success_ns", halt_poll_success_ns), - VCPU_STAT("halt_poll_fail_ns", halt_poll_fail_ns), + VCPU_STAT_COM("halt_poll_success_ns", halt_poll_success_ns), + VCPU_STAT_COM("halt_poll_fail_ns", halt_poll_fail_ns), VCPU_STAT("halt_wait_ns", halt_wait_ns), - VCPU_STAT("halt_successful_poll", halt_successful_poll), - VCPU_STAT("halt_attempted_poll", halt_attempted_poll), + VCPU_STAT_COM("halt_successful_poll", halt_successful_poll), + VCPU_STAT_COM("halt_attempted_poll", halt_attempted_poll), VCPU_STAT("halt_successful_wait", halt_successful_wait), - VCPU_STAT("halt_poll_invalid", halt_poll_invalid), - VCPU_STAT("halt_wakeup", halt_wakeup), + VCPU_STAT_COM("halt_poll_invalid", halt_poll_invalid), + VCPU_STAT_COM("halt_wakeup", halt_wakeup), VCPU_STAT("pf_storage", pf_storage), VCPU_STAT("sp_storage", sp_storage), VCPU_STAT("pf_instruc", pf_instruc), diff --git a/arch/powerpc/kvm/book3s_hv.c b/arch/powerpc/kvm/book3s_hv.c index 13bad6bf4c95..ecc50a689bc5 100644 --- a/arch/powerpc/kvm/book3s_hv.c +++ b/arch/powerpc/kvm/book3s_hv.c @@ -236,7 +236,7 @@ static void kvmppc_fast_vcpu_kick_hv(struct kvm_vcpu *vcpu) waitp = kvm_arch_vcpu_get_wait(vcpu); if (rcuwait_wake_up(waitp)) - ++vcpu->stat.halt_wakeup; + ++vcpu->stat.common.halt_wakeup; cpu = READ_ONCE(vcpu->arch.thread_cpu); if (cpu >= 0 && kvmppc_ipi_thread(cpu)) @@ -3885,7 +3885,7 @@ static void kvmppc_vcore_blocked(struct kvmppc_vcore *vc) cur = start_poll = ktime_get(); if (vc->halt_poll_ns) { ktime_t stop = ktime_add_ns(start_poll, vc->halt_poll_ns); - ++vc->runner->stat.halt_attempted_poll; + ++vc->runner->stat.common.halt_attempted_poll; vc->vcore_state = VCORE_POLLING; spin_unlock(&vc->lock); @@ -3902,7 +3902,7 @@ static void kvmppc_vcore_blocked(struct kvmppc_vcore *vc) vc->vcore_state = VCORE_INACTIVE; if (!do_sleep) { - ++vc->runner->stat.halt_successful_poll; + ++vc->runner->stat.common.halt_successful_poll; goto out; } } @@ -3914,7 +3914,7 @@ static void kvmppc_vcore_blocked(struct kvmppc_vcore *vc) do_sleep = 0; /* If we polled, count this as a successful poll */ if (vc->halt_poll_ns) - ++vc->runner->stat.halt_successful_poll; + ++vc->runner->stat.common.halt_successful_poll; goto out; } @@ -3941,13 +3941,13 @@ static void kvmppc_vcore_blocked(struct kvmppc_vcore *vc) ktime_to_ns(cur) - ktime_to_ns(start_wait); /* Attribute failed poll time */ if (vc->halt_poll_ns) - vc->runner->stat.halt_poll_fail_ns += + vc->runner->stat.common.halt_poll_fail_ns += ktime_to_ns(start_wait) - ktime_to_ns(start_poll); } else { /* Attribute successful poll time */ if (vc->halt_poll_ns) - vc->runner->stat.halt_poll_success_ns += + vc->runner->stat.common.halt_poll_success_ns += ktime_to_ns(cur) - ktime_to_ns(start_poll); } diff --git a/arch/powerpc/kvm/book3s_pr.c b/arch/powerpc/kvm/book3s_pr.c index 913944dc3620..0d6be10d19ae 100644 --- a/arch/powerpc/kvm/book3s_pr.c +++ b/arch/powerpc/kvm/book3s_pr.c @@ -515,7 +515,7 @@ static void kvmppc_set_msr_pr(struct kvm_vcpu *vcpu, u64 msr) if (!vcpu->arch.pending_exceptions) { kvm_vcpu_block(vcpu); kvm_clear_request(KVM_REQ_UNHALT, vcpu); - vcpu->stat.halt_wakeup++; + vcpu->stat.common.halt_wakeup++; /* Unset POW bit after we woke up */ msr &= ~MSR_POW; diff --git a/arch/powerpc/kvm/book3s_pr_papr.c b/arch/powerpc/kvm/book3s_pr_papr.c index 031c8015864a..9384625c8051 100644 --- a/arch/powerpc/kvm/book3s_pr_papr.c +++ b/arch/powerpc/kvm/book3s_pr_papr.c @@ -378,7 +378,7 @@ int kvmppc_h_pr(struct kvm_vcpu *vcpu, unsigned long cmd) kvmppc_set_msr_fast(vcpu, kvmppc_get_msr(vcpu) | MSR_EE); kvm_vcpu_block(vcpu); kvm_clear_request(KVM_REQ_UNHALT, vcpu); - vcpu->stat.halt_wakeup++; + vcpu->stat.common.halt_wakeup++; return EMULATE_DONE; case H_LOGICAL_CI_LOAD: return kvmppc_h_pr_logical_ci_load(vcpu); diff --git a/arch/powerpc/kvm/booke.c b/arch/powerpc/kvm/booke.c index 7d5fe43f85c4..07fdd7a1254a 100644 --- a/arch/powerpc/kvm/booke.c +++ b/arch/powerpc/kvm/booke.c @@ -49,15 +49,15 @@ struct kvm_stats_debugfs_item debugfs_entries[] = { VCPU_STAT("inst_emu", emulated_inst_exits), VCPU_STAT("dec", dec_exits), VCPU_STAT("ext_intr", ext_intr_exits), - VCPU_STAT("halt_successful_poll", halt_successful_poll), - VCPU_STAT("halt_attempted_poll", halt_attempted_poll), - VCPU_STAT("halt_poll_invalid", halt_poll_invalid), - VCPU_STAT("halt_wakeup", halt_wakeup), + VCPU_STAT_COM("halt_successful_poll", halt_successful_poll), + VCPU_STAT_COM("halt_attempted_poll", halt_attempted_poll), + VCPU_STAT_COM("halt_poll_invalid", halt_poll_invalid), + VCPU_STAT_COM("halt_wakeup", halt_wakeup), VCPU_STAT("doorbell", dbell_exits), VCPU_STAT("guest doorbell", gdbell_exits), - VCPU_STAT("halt_poll_success_ns", halt_poll_success_ns), - VCPU_STAT("halt_poll_fail_ns", halt_poll_fail_ns), - VM_STAT("remote_tlb_flush", remote_tlb_flush), + VCPU_STAT_COM("halt_poll_success_ns", halt_poll_success_ns), + VCPU_STAT_COM("halt_poll_fail_ns", halt_poll_fail_ns), + VM_STAT_COM("remote_tlb_flush", remote_tlb_flush), { NULL } }; diff --git a/arch/s390/include/asm/kvm_host.h b/arch/s390/include/asm/kvm_host.h index 6bcfc5614bbc..3b45476e70f6 100644 --- a/arch/s390/include/asm/kvm_host.h +++ b/arch/s390/include/asm/kvm_host.h @@ -361,6 +361,7 @@ struct sie_page { }; struct kvm_vcpu_stat { + struct kvm_vcpu_stat_common common; u64 exit_userspace; u64 exit_null; u64 exit_external_request; @@ -370,13 +371,7 @@ struct kvm_vcpu_stat { u64 exit_validity; u64 exit_instruction; u64 exit_pei; - u64 halt_successful_poll; - u64 halt_attempted_poll; - u64 halt_poll_invalid; u64 halt_no_poll_steal; - u64 halt_wakeup; - u64 halt_poll_success_ns; - u64 halt_poll_fail_ns; u64 instruction_lctl; u64 instruction_lctlg; u64 instruction_stctl; @@ -750,12 +745,12 @@ struct kvm_vcpu_arch { }; struct kvm_vm_stat { + struct kvm_vm_stat_common common; u64 inject_io; u64 inject_float_mchk; u64 inject_pfault_done; u64 inject_service_signal; u64 inject_virtio; - u64 remote_tlb_flush; }; struct kvm_arch_memory_slot { diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c index 2f09e9d7dc95..14399985b7de 100644 --- a/arch/s390/kvm/kvm-s390.c +++ b/arch/s390/kvm/kvm-s390.c @@ -72,13 +72,13 @@ struct kvm_stats_debugfs_item debugfs_entries[] = { VCPU_STAT("exit_program_interruption", exit_program_interruption), VCPU_STAT("exit_instr_and_program_int", exit_instr_and_program), VCPU_STAT("exit_operation_exception", exit_operation_exception), - VCPU_STAT("halt_successful_poll", halt_successful_poll), - VCPU_STAT("halt_attempted_poll", halt_attempted_poll), - VCPU_STAT("halt_poll_invalid", halt_poll_invalid), + VCPU_STAT_COM("halt_successful_poll", halt_successful_poll), + VCPU_STAT_COM("halt_attempted_poll", halt_attempted_poll), + VCPU_STAT_COM("halt_poll_invalid", halt_poll_invalid), VCPU_STAT("halt_no_poll_steal", halt_no_poll_steal), - VCPU_STAT("halt_wakeup", halt_wakeup), - VCPU_STAT("halt_poll_success_ns", halt_poll_success_ns), - VCPU_STAT("halt_poll_fail_ns", halt_poll_fail_ns), + VCPU_STAT_COM("halt_wakeup", halt_wakeup), + VCPU_STAT_COM("halt_poll_success_ns", halt_poll_success_ns), + VCPU_STAT_COM("halt_poll_fail_ns", halt_poll_fail_ns), VCPU_STAT("instruction_lctlg", instruction_lctlg), VCPU_STAT("instruction_lctl", instruction_lctl), VCPU_STAT("instruction_stctl", instruction_stctl), diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h index 44f893043a3c..74bce65a0802 100644 --- a/arch/x86/include/asm/kvm_host.h +++ b/arch/x86/include/asm/kvm_host.h @@ -1082,6 +1082,7 @@ struct kvm_arch { }; struct kvm_vm_stat { + struct kvm_vm_stat_common common; ulong mmu_shadow_zapped; ulong mmu_pte_write; ulong mmu_pde_zapped; @@ -1089,13 +1090,13 @@ struct kvm_vm_stat { ulong mmu_recycled; ulong mmu_cache_miss; ulong mmu_unsync; - ulong remote_tlb_flush; ulong lpages; ulong nx_lpage_splits; ulong max_mmu_page_hash_collisions; }; struct kvm_vcpu_stat { + struct kvm_vcpu_stat_common common; u64 pf_fixed; u64 pf_guest; u64 tlb_flush; @@ -1109,10 +1110,6 @@ struct kvm_vcpu_stat { u64 nmi_window_exits; u64 l1d_flush; u64 halt_exits; - u64 halt_successful_poll; - u64 halt_attempted_poll; - u64 halt_poll_invalid; - u64 halt_wakeup; u64 request_irq_exits; u64 irq_exits; u64 host_state_reload; @@ -1123,8 +1120,6 @@ struct kvm_vcpu_stat { u64 irq_injections; u64 nmi_injections; u64 req_event; - u64 halt_poll_success_ns; - u64 halt_poll_fail_ns; u64 nested_run; }; diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 16fb39503296..5d5d4806e93b 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -228,10 +228,10 @@ struct kvm_stats_debugfs_item debugfs_entries[] = { VCPU_STAT("irq_window", irq_window_exits), VCPU_STAT("nmi_window", nmi_window_exits), VCPU_STAT("halt_exits", halt_exits), - VCPU_STAT("halt_successful_poll", halt_successful_poll), - VCPU_STAT("halt_attempted_poll", halt_attempted_poll), - VCPU_STAT("halt_poll_invalid", halt_poll_invalid), - VCPU_STAT("halt_wakeup", halt_wakeup), + VCPU_STAT_COM("halt_successful_poll", halt_successful_poll), + VCPU_STAT_COM("halt_attempted_poll", halt_attempted_poll), + VCPU_STAT_COM("halt_poll_invalid", halt_poll_invalid), + VCPU_STAT_COM("halt_wakeup", halt_wakeup), VCPU_STAT("hypercalls", hypercalls), VCPU_STAT("request_irq", request_irq_exits), VCPU_STAT("irq_exits", irq_exits), @@ -243,8 +243,8 @@ struct kvm_stats_debugfs_item debugfs_entries[] = { VCPU_STAT("nmi_injections", nmi_injections), VCPU_STAT("req_event", req_event), VCPU_STAT("l1d_flush", l1d_flush), - VCPU_STAT("halt_poll_success_ns", halt_poll_success_ns), - VCPU_STAT("halt_poll_fail_ns", halt_poll_fail_ns), + VCPU_STAT_COM("halt_poll_success_ns", halt_poll_success_ns), + VCPU_STAT_COM("halt_poll_fail_ns", halt_poll_fail_ns), VCPU_STAT("nested_run", nested_run), VM_STAT("mmu_shadow_zapped", mmu_shadow_zapped), VM_STAT("mmu_pte_write", mmu_pte_write), @@ -253,7 +253,7 @@ struct kvm_stats_debugfs_item debugfs_entries[] = { VM_STAT("mmu_recycled", mmu_recycled), VM_STAT("mmu_cache_miss", mmu_cache_miss), VM_STAT("mmu_unsync", mmu_unsync), - VM_STAT("remote_tlb_flush", remote_tlb_flush), + VM_STAT_COM("remote_tlb_flush", remote_tlb_flush), VM_STAT("largepages", lpages, .mode = 0444), VM_STAT("nx_largepages_splitted", nx_lpage_splits, .mode = 0444), VM_STAT("max_mmu_page_hash_collisions", max_mmu_page_hash_collisions), diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h index 3b06d12ec37e..53428b01224e 100644 --- a/include/linux/kvm_host.h +++ b/include/linux/kvm_host.h @@ -1195,6 +1195,11 @@ struct kvm_stats_debugfs_item { { n, offsetof(struct kvm, stat.x), KVM_STAT_VM, ## __VA_ARGS__ } #define VCPU_STAT(n, x, ...) \ { n, offsetof(struct kvm_vcpu, stat.x), KVM_STAT_VCPU, ## __VA_ARGS__ } +#define VM_STAT_COM(n, x, ...) \ + { n, offsetof(struct kvm, stat.common.x), KVM_STAT_VM, ## __VA_ARGS__ } +#define VCPU_STAT_COM(n, x, ...) \ + { n, offsetof(struct kvm_vcpu, stat.common.x), \ + KVM_STAT_VCPU, ## __VA_ARGS__ } extern struct kvm_stats_debugfs_item debugfs_entries[]; extern struct dentry *kvm_debugfs_dir; diff --git a/include/linux/kvm_types.h b/include/linux/kvm_types.h index a7580f69dda0..87eb05ad678b 100644 --- a/include/linux/kvm_types.h +++ b/include/linux/kvm_types.h @@ -76,5 +76,17 @@ struct kvm_mmu_memory_cache { }; #endif +struct kvm_vm_stat_common { + ulong remote_tlb_flush; +}; + +struct kvm_vcpu_stat_common { + u64 halt_successful_poll; + u64 halt_attempted_poll; + u64 halt_poll_invalid; + u64 halt_wakeup; + u64 halt_poll_success_ns; + u64 halt_poll_fail_ns; +}; #endif /* __KVM_TYPES_H__ */ diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c index 0a481e7780f0..2c4205ccf3dd 100644 --- a/virt/kvm/kvm_main.c +++ b/virt/kvm/kvm_main.c @@ -330,7 +330,7 @@ void kvm_flush_remote_tlbs(struct kvm *kvm) */ if (!kvm_arch_flush_remote_tlb(kvm) || kvm_make_all_cpus_request(kvm, KVM_REQ_TLB_FLUSH)) - ++kvm->stat.remote_tlb_flush; + ++kvm->stat.common.remote_tlb_flush; cmpxchg(&kvm->tlbs_dirty, dirty_count, 0); } EXPORT_SYMBOL_GPL(kvm_flush_remote_tlbs); @@ -2815,9 +2815,9 @@ static inline void update_halt_poll_stats(struct kvm_vcpu *vcpu, u64 poll_ns, bool waited) { if (waited) - vcpu->stat.halt_poll_fail_ns += poll_ns; + vcpu->stat.common.halt_poll_fail_ns += poll_ns; else - vcpu->stat.halt_poll_success_ns += poll_ns; + vcpu->stat.common.halt_poll_success_ns += poll_ns; } /* @@ -2835,16 +2835,16 @@ void kvm_vcpu_block(struct kvm_vcpu *vcpu) if (vcpu->halt_poll_ns && !kvm_arch_no_poll(vcpu)) { ktime_t stop = ktime_add_ns(ktime_get(), vcpu->halt_poll_ns); - ++vcpu->stat.halt_attempted_poll; + ++vcpu->stat.common.halt_attempted_poll; do { /* * This sets KVM_REQ_UNHALT if an interrupt * arrives. */ if (kvm_vcpu_check_block(vcpu) < 0) { - ++vcpu->stat.halt_successful_poll; + ++vcpu->stat.common.halt_successful_poll; if (!vcpu_valid_wakeup(vcpu)) - ++vcpu->stat.halt_poll_invalid; + ++vcpu->stat.common.halt_poll_invalid; goto out; } poll_end = cur = ktime_get(); @@ -2901,7 +2901,7 @@ bool kvm_vcpu_wake_up(struct kvm_vcpu *vcpu) waitp = kvm_arch_vcpu_get_wait(vcpu); if (rcuwait_wake_up(waitp)) { WRITE_ONCE(vcpu->ready, true); - ++vcpu->stat.halt_wakeup; + ++vcpu->stat.common.halt_wakeup; return true; } From patchwork Thu Apr 15 15:17:39 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jing Zhang X-Patchwork-Id: 1466686 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=vger.kernel.org (client-ip=23.128.96.18; helo=vger.kernel.org; envelope-from=kvm-ppc-owner@vger.kernel.org; receiver=) Authentication-Results: ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=google.com header.i=@google.com header.a=rsa-sha256 header.s=20161025 header.b=hgir0LzA; dkim-atps=neutral Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by ozlabs.org (Postfix) with ESMTP id 4FLjhX4N2hz9sSC for ; Fri, 16 Apr 2021 01:20:28 +1000 (AEST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S234348AbhDOPUs (ORCPT ); Thu, 15 Apr 2021 11:20:48 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:48978 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S236952AbhDOPUT (ORCPT ); Thu, 15 Apr 2021 11:20:19 -0400 Received: from mail-yb1-xb4a.google.com (mail-yb1-xb4a.google.com [IPv6:2607:f8b0:4864:20::b4a]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id AE06AC061376 for ; Thu, 15 Apr 2021 08:17:48 -0700 (PDT) Received: by mail-yb1-xb4a.google.com with SMTP id n13so2859784ybp.14 for ; Thu, 15 Apr 2021 08:17:48 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20161025; h=date:in-reply-to:message-id:mime-version:references:subject:from:to :cc; bh=fCJMDCUkECLfp63xeGmZWAqAva+4TURc2g0u3qOya1g=; b=hgir0LzAcd/bam+AEzUd7MPIvjSTu3r/VHZqNqH2zGuz3g4p0j223eVCujFYEaWFve uhmxGvT7FgZTJEy9CQRkIASMJYAWsVGNE43sT/c02Qbxgb/EqgoWOAui+9sNo5suJ3E8 UskS57LTjcWHu6JYhR/0zkqJLrwPpQdGvZeACzfZjVtySkb1MduVGRzEQngCo4An1Qm7 3fyd55k4g0wRm6i4+JVcXKet3aX0t7OpXVsRAcX1hmqvROd7TW4m76uRuTrZXYCaZh4D fiDL9l9p9eIn+WXY4t6dVNN3SGA3mXz0s2pRBqVamyZS9RiTTA8wTJulV54oGNnS6E8d sMew== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:date:in-reply-to:message-id:mime-version :references:subject:from:to:cc; bh=fCJMDCUkECLfp63xeGmZWAqAva+4TURc2g0u3qOya1g=; b=ZaWc9GOUsJ0uaW6sHl0kfxRMOFMEhN4O/bL6D0lnQAeoHJoKpakEtSlvLNFiH74/Te d/SONzZ5C58lvtYEppxJe/LhPTqhcHIGntiwPieg4+NvEgyqBIIMDgppxB9vdTmpgi39 8IRENDGb51RMEwet9x5+ueT0r4fH7E+91uIW0Lc14uZ9O/kG8kv6KVptDOsSW2fTrT+L l0yDZCHe+bJzoY2JPZgKWWydpuxk14sa3R392pafSEZqwWAWFnxO6O1hCe1xHtVG5qCn BzXJeBDgm8Uv2DSie9bYdcJZVon2lpafaCVQwYxmbN/Rz6KfUiOw7/hsqn8nSxyIhJ+f iizQ== X-Gm-Message-State: AOAM533bejX8a7Ub9SviNuinQ+7tcqhQhoDss9RT/eMyCbSaaFr4kqMV eIKZM+/T0W08xk3S0Xh9RbdhI7p9/95YrP7EvQ== X-Google-Smtp-Source: ABdhPJzr7gZ2tkQdCymzdtPbZx5IBC7nEO/V59Rshve/UFsOwldv/f7snuCeA/dJwN+zYkRiY2QTHB18sHI63FdkYg== X-Received: from jgzg.c.googlers.com ([fda3:e722:ac3:10:7f:e700:c0a8:1acf]) (user=jingzhangos job=sendgmr) by 2002:a25:38c6:: with SMTP id f189mr5257064yba.183.1618499867791; Thu, 15 Apr 2021 08:17:47 -0700 (PDT) Date: Thu, 15 Apr 2021 15:17:39 +0000 In-Reply-To: <20210415151741.1607806-1-jingzhangos@google.com> Message-Id: <20210415151741.1607806-3-jingzhangos@google.com> Mime-Version: 1.0 References: <20210415151741.1607806-1-jingzhangos@google.com> X-Mailer: git-send-email 2.31.1.295.g9ea45b61b8-goog Subject: [PATCH v2 2/4] KVM: stats: Add fd-based API to read binary stats data From: Jing Zhang To: KVM , KVMARM , LinuxMIPS , KVMPPC , LinuxS390 , Linuxkselftest , Paolo Bonzini , Marc Zyngier , James Morse , Julien Thierry , Suzuki K Poulose , Will Deacon , Huacai Chen , Aleksandar Markovic , Thomas Bogendoerfer , Paul Mackerras , Christian Borntraeger , Janosch Frank , David Hildenbrand , Cornelia Huck , Claudio Imbrenda , Sean Christopherson , Vitaly Kuznetsov , Jim Mattson , Peter Shier , Oliver Upton , David Rientjes , Emanuele Giuseppe Esposito Cc: Jing Zhang Precedence: bulk List-ID: X-Mailing-List: kvm-ppc@vger.kernel.org Provides a file descriptor per VM to read VM stats info/data. Provides a file descriptor per vCPU to read vCPU stats info/data. Signed-off-by: Jing Zhang --- arch/arm64/kvm/guest.c | 30 +++++ arch/mips/kvm/mips.c | 55 ++++++++++ arch/powerpc/kvm/book3s.c | 56 ++++++++++ arch/powerpc/kvm/booke.c | 49 +++++++++ arch/s390/kvm/kvm-s390.c | 121 +++++++++++++++++++++ arch/x86/kvm/x86.c | 57 ++++++++++ include/linux/kvm_host.h | 127 +++++++++++++++++++++- include/uapi/linux/kvm.h | 48 ++++++++ virt/kvm/kvm_main.c | 223 ++++++++++++++++++++++++++++++++++++++ 9 files changed, 764 insertions(+), 2 deletions(-) diff --git a/arch/arm64/kvm/guest.c b/arch/arm64/kvm/guest.c index cc5b1e2fdbd0..6286a9011002 100644 --- a/arch/arm64/kvm/guest.c +++ b/arch/arm64/kvm/guest.c @@ -28,6 +28,36 @@ #include "trace.h" +struct _kvm_stats_desc kvm_vm_stats_desc[] = { + STATS_VM_COMMON, +}; + +struct _kvm_stats_header kvm_vm_stats_header = { + .name_size = KVM_STATS_NAME_LEN, + .count = ARRAY_SIZE(kvm_vm_stats_desc), + .desc_offset = sizeof(struct kvm_stats_header), + .data_offset = sizeof(struct kvm_stats_header) + + sizeof(kvm_vm_stats_desc), +}; + +struct _kvm_stats_desc kvm_vcpu_stats_desc[] = { + STATS_VCPU_COMMON, + STATS_DESC_COUNTER("hvc_exit_stat"), + STATS_DESC_COUNTER("wfe_exit_stat"), + STATS_DESC_COUNTER("wfi_exit_stat"), + STATS_DESC_COUNTER("mmio_exit_user"), + STATS_DESC_COUNTER("mmio_exit_kernel"), + STATS_DESC_COUNTER("exits"), +}; + +struct _kvm_stats_header kvm_vcpu_stats_header = { + .name_size = KVM_STATS_NAME_LEN, + .count = ARRAY_SIZE(kvm_vcpu_stats_desc), + .desc_offset = sizeof(struct kvm_stats_header), + .data_offset = sizeof(struct kvm_stats_header) + + sizeof(kvm_vcpu_stats_desc), +}; + struct kvm_stats_debugfs_item debugfs_entries[] = { VCPU_STAT_COM("halt_successful_poll", halt_successful_poll), VCPU_STAT_COM("halt_attempted_poll", halt_attempted_poll), diff --git a/arch/mips/kvm/mips.c b/arch/mips/kvm/mips.c index d78820777de1..3073886d37f9 100644 --- a/arch/mips/kvm/mips.c +++ b/arch/mips/kvm/mips.c @@ -39,6 +39,61 @@ #define VECTORSPACING 0x100 /* for EI/VI mode */ #endif +struct _kvm_stats_desc kvm_vm_stats_desc[] = { + STATS_VM_COMMON, +}; + +struct _kvm_stats_header kvm_vm_stats_header = { + .name_size = KVM_STATS_NAME_LEN, + .count = ARRAY_SIZE(kvm_vm_stats_desc), + .desc_offset = sizeof(struct kvm_stats_header), + .data_offset = sizeof(struct kvm_stats_header) + + sizeof(kvm_vm_stats_desc), +}; + +struct _kvm_stats_desc kvm_vcpu_stats_desc[] = { + STATS_VCPU_COMMON, + STATS_DESC_COUNTER("wait_exits"), + STATS_DESC_COUNTER("cache_exits"), + STATS_DESC_COUNTER("signal_exits"), + STATS_DESC_COUNTER("int_exits"), + STATS_DESC_COUNTER("cop_unusable_exits"), + STATS_DESC_COUNTER("tlbmod_exits"), + STATS_DESC_COUNTER("tlbmiss_ld_exits"), + STATS_DESC_COUNTER("tlbmiss_st_exits"), + STATS_DESC_COUNTER("addrerr_st_exits"), + STATS_DESC_COUNTER("addrerr_ld_exits"), + STATS_DESC_COUNTER("syscall_exits"), + STATS_DESC_COUNTER("resvd_inst_exits"), + STATS_DESC_COUNTER("break_inst_exits"), + STATS_DESC_COUNTER("trap_inst_exits"), + STATS_DESC_COUNTER("msa_fpe_exits"), + STATS_DESC_COUNTER("fpe_exits"), + STATS_DESC_COUNTER("msa_disabled_exits"), + STATS_DESC_COUNTER("flush_dcache_exits"), +#ifdef CONFIG_KVM_MIPS_VZ + STATS_DESC_COUNTER("vz_gpsi_exits"), + STATS_DESC_COUNTER("vz_gsfc_exits"), + STATS_DESC_COUNTER("vz_hc_exits"), + STATS_DESC_COUNTER("vz_grr_exits"), + STATS_DESC_COUNTER("vz_gva_exits"), + STATS_DESC_COUNTER("vz_ghfc_exits"), + STATS_DESC_COUNTER("vz_gpa_exits"), + STATS_DESC_COUNTER("vz_resvd_exits"), +#ifdef CONFIG_CPU_LOONGSON64 + STATS_DESC_COUNTER("vz_cpucfg_exits"), +#endif +#endif +}; + +struct _kvm_stats_header kvm_vcpu_stats_header = { + .name_size = KVM_STATS_NAME_LEN, + .count = ARRAY_SIZE(kvm_vcpu_stats_desc), + .desc_offset = sizeof(struct kvm_stats_header), + .data_offset = sizeof(struct kvm_stats_header) + + sizeof(kvm_vcpu_stats_desc), +}; + struct kvm_stats_debugfs_item debugfs_entries[] = { VCPU_STAT("wait", wait_exits), VCPU_STAT("cache", cache_exits), diff --git a/arch/powerpc/kvm/book3s.c b/arch/powerpc/kvm/book3s.c index d799029f2e55..7c24ad66fa38 100644 --- a/arch/powerpc/kvm/book3s.c +++ b/arch/powerpc/kvm/book3s.c @@ -38,6 +38,62 @@ /* #define EXIT_DEBUG */ +struct _kvm_stats_desc kvm_vm_stats_desc[] = { + STATS_VM_COMMON, + STATS_DESC_ICOUNTER("num_2M_pages"), + STATS_DESC_ICOUNTER("num_1G_pages"), +}; + +struct _kvm_stats_header kvm_vm_stats_header = { + .name_size = KVM_STATS_NAME_LEN, + .count = ARRAY_SIZE(kvm_vm_stats_desc), + .desc_offset = sizeof(struct kvm_stats_header), + .data_offset = sizeof(struct kvm_stats_header) + + sizeof(kvm_vm_stats_desc), +}; + +struct _kvm_stats_desc kvm_vcpu_stats_desc[] = { + STATS_VCPU_COMMON, + STATS_DESC_COUNTER("sum_exits"), + STATS_DESC_COUNTER("mmio_exits"), + STATS_DESC_COUNTER("signal_exits"), + STATS_DESC_COUNTER("light_exits"), + STATS_DESC_COUNTER("itlb_real_miss_exits"), + STATS_DESC_COUNTER("itlb_virt_miss_exits"), + STATS_DESC_COUNTER("dtlb_real_miss_exits"), + STATS_DESC_COUNTER("dtlb_virt_miss_exits"), + STATS_DESC_COUNTER("syscall_exits"), + STATS_DESC_COUNTER("isi_exits"), + STATS_DESC_COUNTER("dsi_exits"), + STATS_DESC_COUNTER("emulated_inst_exits"), + STATS_DESC_COUNTER("dec_exits"), + STATS_DESC_COUNTER("ext_intr_exits"), + STATS_DESC_TIME_NSEC("halt_wait_ns"), + STATS_DESC_COUNTER("halt_successful_wait"), + STATS_DESC_COUNTER("dbell_exits"), + STATS_DESC_COUNTER("gdbell_exits"), + STATS_DESC_COUNTER("ld"), + STATS_DESC_COUNTER("st"), + STATS_DESC_COUNTER("pf_storage"), + STATS_DESC_COUNTER("pf_instruc"), + STATS_DESC_COUNTER("sp_storage"), + STATS_DESC_COUNTER("sp_instruc"), + STATS_DESC_COUNTER("queue_intr"), + STATS_DESC_COUNTER("ld_slow"), + STATS_DESC_COUNTER("st_slow"), + STATS_DESC_COUNTER("pthru_all"), + STATS_DESC_COUNTER("pthru_host"), + STATS_DESC_COUNTER("pthru_bad_aff"), +}; + +struct _kvm_stats_header kvm_vcpu_stats_header = { + .name_size = KVM_STATS_NAME_LEN, + .count = ARRAY_SIZE(kvm_vcpu_stats_desc), + .desc_offset = sizeof(struct kvm_stats_header), + .data_offset = sizeof(struct kvm_stats_header) + + sizeof(kvm_vcpu_stats_desc), +}; + struct kvm_stats_debugfs_item debugfs_entries[] = { VCPU_STAT("exits", sum_exits), VCPU_STAT("mmio", mmio_exits), diff --git a/arch/powerpc/kvm/booke.c b/arch/powerpc/kvm/booke.c index 07fdd7a1254a..e9ffcf0f022d 100644 --- a/arch/powerpc/kvm/booke.c +++ b/arch/powerpc/kvm/booke.c @@ -36,6 +36,55 @@ unsigned long kvmppc_booke_handlers; +struct _kvm_stats_desc kvm_vm_stats_desc[] = { + STATS_VM_COMMON, + STATS_DESC_ICOUNTER("num_2M_pages",), + STATS_DESC_ICOUNTER("num_1G_pages",), +}; + +struct _kvm_stats_header kvm_vm_stats_header = { + .name_size = KVM_STATS_NAME_LEN, + .count = ARRAY_SIZE(kvm_vm_stats_desc), + .desc_offset = sizeof(struct kvm_stats_header), + .data_offset = sizeof(struct kvm_stats_header) + + sizeof(kvm_vm_stats_desc), +}; + +struct _kvm_stats_desc kvm_vcpu_stats_desc[] = { + STATS_VCPU_COMMON, + STATS_DESC_COUNTER("sum_exits"), + STATS_DESC_COUNTER("mmio_exits"), + STATS_DESC_COUNTER("signal_exits"), + STATS_DESC_COUNTER("light_exits"), + STATS_DESC_COUNTER("itlb_real_miss_exits"), + STATS_DESC_COUNTER("itlb_virt_miss_exits"), + STATS_DESC_COUNTER("dtlb_real_miss_exits"), + STATS_DESC_COUNTER("dtlb_virt_miss_exits"), + STATS_DESC_COUNTER("syscall_exits"), + STATS_DESC_COUNTER("isi_exits"), + STATS_DESC_COUNTER("dsi_exits"), + STATS_DESC_COUNTER("emulated_inst_exits"), + STATS_DESC_COUNTER("dec_exits"), + STATS_DESC_COUNTER("ext_intr_exits"), + STATS_DESC_TIME_NSEC("halt_wait_ns"), + STATS_DESC_COUNTER("halt_successful_wait"), + STATS_DESC_COUNTER("dbell_exits"), + STATS_DESC_COUNTER("gdbell_exits"), + STATS_DESC_COUNTER("ld"), + STATS_DESC_COUNTER("st"), + STATS_DESC_COUNTER("pthru_all"), + STATS_DESC_COUNTER("pthru_host"), + STATS_DESC_COUNTER("pthru_bad_aff"), +}; + +struct _kvm_stats_header kvm_vcpu_stats_header = { + .name_size = KVM_STATS_NAME_LEN, + .count = ARRAY_SIZE(kvm_vcpu_stats_desc), + .desc_offset = sizeof(struct kvm_stats_header), + .data_offset = sizeof(struct kvm_stats_header) + + sizeof(kvm_vcpu_stats_desc), +}; + struct kvm_stats_debugfs_item debugfs_entries[] = { VCPU_STAT("mmio", mmio_exits), VCPU_STAT("sig", signal_exits), diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c index 14399985b7de..c34620e6886f 100644 --- a/arch/s390/kvm/kvm-s390.c +++ b/arch/s390/kvm/kvm-s390.c @@ -58,6 +58,127 @@ #define VCPU_IRQS_MAX_BUF (sizeof(struct kvm_s390_irq) * \ (KVM_MAX_VCPUS + LOCAL_IRQS)) +struct _kvm_stats_desc kvm_vm_stats_desc[] = { + STATS_VM_COMMON, + STATS_DESC_COUNTER("inject_io"), + STATS_DESC_COUNTER("inject_float_mchk"), + STATS_DESC_COUNTER("inject_pfault_done"), + STATS_DESC_COUNTER("inject_service_signal"), + STATS_DESC_COUNTER("inject_virtio"), +}; + +struct _kvm_stats_header kvm_vm_stats_header = { + .name_size = KVM_STATS_NAME_LEN, + .count = ARRAY_SIZE(kvm_vm_stats_desc), + .desc_offset = sizeof(struct kvm_stats_header), + .data_offset = sizeof(struct kvm_stats_header) + + sizeof(kvm_vm_stats_desc), +}; + +struct _kvm_stats_desc kvm_vcpu_stats_desc[] = { + STATS_VCPU_COMMON, + STATS_DESC_COUNTER("exit_userspace"), + STATS_DESC_COUNTER("exit_null"), + STATS_DESC_COUNTER("exit_external_request"), + STATS_DESC_COUNTER("exit_io_request"), + STATS_DESC_COUNTER("exit_external_interrupt"), + STATS_DESC_COUNTER("exit_stop_request"), + STATS_DESC_COUNTER("exit_validity"), + STATS_DESC_COUNTER("exit_instruction"), + STATS_DESC_COUNTER("exit_pei"), + STATS_DESC_COUNTER("halt_no_poll_steal"), + STATS_DESC_COUNTER("instruction_lctl"), + STATS_DESC_COUNTER("instruction_lctlg"), + STATS_DESC_COUNTER("instruction_stctl"), + STATS_DESC_COUNTER("instruction_stctg"), + STATS_DESC_COUNTER("exit_program_interruption"), + STATS_DESC_COUNTER("exit_instr_and_program"), + STATS_DESC_COUNTER("exit_operation_exception"), + STATS_DESC_COUNTER("deliver_ckc"), + STATS_DESC_COUNTER("deliver_cputm"), + STATS_DESC_COUNTER("deliver_external_call"), + STATS_DESC_COUNTER("deliver_emergency_signal"), + STATS_DESC_COUNTER("deliver_service_signal"), + STATS_DESC_COUNTER("deliver_virtio"), + STATS_DESC_COUNTER("deliver_stop_signal"), + STATS_DESC_COUNTER("deliver_prefix_signal"), + STATS_DESC_COUNTER("deliver_restart_signal"), + STATS_DESC_COUNTER("deliver_program"), + STATS_DESC_COUNTER("deliver_io"), + STATS_DESC_COUNTER("deliver_machine_check"), + STATS_DESC_COUNTER("exit_wait_state"), + STATS_DESC_COUNTER("inject_ckc"), + STATS_DESC_COUNTER("inject_cputm"), + STATS_DESC_COUNTER("inject_external_call"), + STATS_DESC_COUNTER("inject_emergency_signal"), + STATS_DESC_COUNTER("inject_mchk"), + STATS_DESC_COUNTER("inject_pfault_init"), + STATS_DESC_COUNTER("inject_program"), + STATS_DESC_COUNTER("inject_restart"), + STATS_DESC_COUNTER("inject_set_prefix"), + STATS_DESC_COUNTER("inject_stop_signal"), + STATS_DESC_COUNTER("instruction_epsw"), + STATS_DESC_COUNTER("instruction_gs"), + STATS_DESC_COUNTER("instruction_io_other"), + STATS_DESC_COUNTER("instruction_lpsw"), + STATS_DESC_COUNTER("instruction_lpswe"), + STATS_DESC_COUNTER("instruction_pfmf"), + STATS_DESC_COUNTER("instruction_ptff"), + STATS_DESC_COUNTER("instruction_sck"), + STATS_DESC_COUNTER("instruction_sckpf"), + STATS_DESC_COUNTER("instruction_stidp"), + STATS_DESC_COUNTER("instruction_spx"), + STATS_DESC_COUNTER("instruction_stpx"), + STATS_DESC_COUNTER("instruction_stap"), + STATS_DESC_COUNTER("instruction_iske"), + STATS_DESC_COUNTER("instruction_ri"), + STATS_DESC_COUNTER("instruction_rrbe"), + STATS_DESC_COUNTER("instruction_sske"), + STATS_DESC_COUNTER("instruction_ipte_interlock"), + STATS_DESC_COUNTER("instruction_stsi"), + STATS_DESC_COUNTER("instruction_stfl"), + STATS_DESC_COUNTER("instruction_tb"), + STATS_DESC_COUNTER("instruction_tpi"), + STATS_DESC_COUNTER("instruction_tprot"), + STATS_DESC_COUNTER("instruction_tsch"), + STATS_DESC_COUNTER("instruction_sie"), + STATS_DESC_COUNTER("instruction_essa"), + STATS_DESC_COUNTER("instruction_sthyi"), + STATS_DESC_COUNTER("instruction_sigp_sense"), + STATS_DESC_COUNTER("instruction_sigp_sense_running"), + STATS_DESC_COUNTER("instruction_sigp_external_call"), + STATS_DESC_COUNTER("instruction_sigp_emergency"), + STATS_DESC_COUNTER("instruction_sigp_cond_emergency"), + STATS_DESC_COUNTER("instruction_sigp_start"), + STATS_DESC_COUNTER("instruction_sigp_stop"), + STATS_DESC_COUNTER("instruction_sigp_stop_store_status"), + STATS_DESC_COUNTER("instruction_sigp_store_status"), + STATS_DESC_COUNTER("instruction_sigp_store_adtl_status"), + STATS_DESC_COUNTER("instruction_sigp_arch"), + STATS_DESC_COUNTER("instruction_sigp_prefix"), + STATS_DESC_COUNTER("instruction_sigp_restart"), + STATS_DESC_COUNTER("instruction_sigp_init_cpu_reset"), + STATS_DESC_COUNTER("instruction_sigp_cpu_reset"), + STATS_DESC_COUNTER("instruction_sigp_unknown"), + STATS_DESC_COUNTER("diagnose_10"), + STATS_DESC_COUNTER("diagnose_44"), + STATS_DESC_COUNTER("diagnose_9c"), + STATS_DESC_COUNTER("diagnose_9c_ignored"), + STATS_DESC_COUNTER("diagnose_258"), + STATS_DESC_COUNTER("diagnose_308"), + STATS_DESC_COUNTER("diagnose_500"), + STATS_DESC_COUNTER("diagnose_other"), + STATS_DESC_COUNTER("pfault_sync"), +}; + +struct _kvm_stats_header kvm_vcpu_stats_header = { + .name_size = KVM_STATS_NAME_LEN, + .count = ARRAY_SIZE(kvm_vcpu_stats_desc), + .desc_offset = sizeof(struct kvm_stats_header), + .data_offset = sizeof(struct kvm_stats_header) + + sizeof(kvm_vcpu_stats_desc), +}; + struct kvm_stats_debugfs_item debugfs_entries[] = { VCPU_STAT("userspace_handled", exit_userspace), VCPU_STAT("exit_null", exit_null), diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 5d5d4806e93b..04becbb441ee 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -216,6 +216,63 @@ EXPORT_SYMBOL_GPL(host_xss); u64 __read_mostly supported_xss; EXPORT_SYMBOL_GPL(supported_xss); +struct _kvm_stats_desc kvm_vm_stats_desc[] = { + STATS_VM_COMMON, + STATS_DESC_COUNTER("mmu_shadow_zapped"), + STATS_DESC_COUNTER("mmu_pte_write"), + STATS_DESC_COUNTER("mmu_pde_zapped"), + STATS_DESC_COUNTER("mmu_flooded"), + STATS_DESC_COUNTER("mmu_recycled"), + STATS_DESC_COUNTER("mmu_cache_miss"), + STATS_DESC_ICOUNTER("mmu_unsync"), + STATS_DESC_ICOUNTER("largepages"), + STATS_DESC_ICOUNTER("nx_largepages_splits"), + STATS_DESC_ICOUNTER("max_mmu_page_hash_collisions"), +}; + +struct _kvm_stats_header kvm_vm_stats_header = { + .name_size = KVM_STATS_NAME_LEN, + .count = ARRAY_SIZE(kvm_vm_stats_desc), + .desc_offset = sizeof(struct kvm_stats_header), + .data_offset = sizeof(struct kvm_stats_header) + + sizeof(kvm_vm_stats_desc), +}; + +struct _kvm_stats_desc kvm_vcpu_stats_desc[] = { + STATS_VCPU_COMMON, + STATS_DESC_COUNTER("pf_fixed"), + STATS_DESC_COUNTER("pf_guest"), + STATS_DESC_COUNTER("tlb_flush"), + STATS_DESC_COUNTER("invlpg"), + STATS_DESC_COUNTER("exits"), + STATS_DESC_COUNTER("io_exits"), + STATS_DESC_COUNTER("mmio_exits"), + STATS_DESC_COUNTER("signal_exits"), + STATS_DESC_COUNTER("irq_window_exits"), + STATS_DESC_COUNTER("nmi_window_exits"), + STATS_DESC_COUNTER("l1d_flush"), + STATS_DESC_COUNTER("halt_exits"), + STATS_DESC_COUNTER("request_irq_exits"), + STATS_DESC_COUNTER("irq_exits"), + STATS_DESC_COUNTER("host_state_reload"), + STATS_DESC_COUNTER("fpu_reload"), + STATS_DESC_COUNTER("insn_emulation"), + STATS_DESC_COUNTER("insn_emulation_fail"), + STATS_DESC_COUNTER("hypercalls"), + STATS_DESC_COUNTER("irq_injections"), + STATS_DESC_COUNTER("nmi_injections"), + STATS_DESC_COUNTER("req_event"), + STATS_DESC_COUNTER("nested_run"), +}; + +struct _kvm_stats_header kvm_vcpu_stats_header = { + .name_size = KVM_STATS_NAME_LEN, + .count = sizeof(kvm_vcpu_stats_desc), + .desc_offset = sizeof(struct kvm_stats_header), + .data_offset = sizeof(struct kvm_stats_header) + + sizeof(kvm_vcpu_stats_desc), +}; + struct kvm_stats_debugfs_item debugfs_entries[] = { VCPU_STAT("pf_fixed", pf_fixed), VCPU_STAT("pf_guest", pf_guest), diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h index 53428b01224e..f909195710db 100644 --- a/include/linux/kvm_host.h +++ b/include/linux/kvm_host.h @@ -1188,12 +1188,25 @@ struct kvm_stats_debugfs_item { int mode; }; +struct _kvm_stats_header { + __u32 name_size; + __u32 count; + __u32 desc_offset; + __u32 data_offset; +}; + +#define KVM_STATS_NAME_LEN 32 +struct _kvm_stats_desc { + struct kvm_stats_desc desc; + char name[KVM_STATS_NAME_LEN]; +}; + #define KVM_DBGFS_GET_MODE(dbgfs_item) \ ((dbgfs_item)->mode ? (dbgfs_item)->mode : 0644) -#define VM_STAT(n, x, ...) \ +#define VM_STAT(n, x, ...) \ { n, offsetof(struct kvm, stat.x), KVM_STAT_VM, ## __VA_ARGS__ } -#define VCPU_STAT(n, x, ...) \ +#define VCPU_STAT(n, x, ...) \ { n, offsetof(struct kvm_vcpu, stat.x), KVM_STAT_VCPU, ## __VA_ARGS__ } #define VM_STAT_COM(n, x, ...) \ { n, offsetof(struct kvm, stat.common.x), KVM_STAT_VM, ## __VA_ARGS__ } @@ -1201,8 +1214,118 @@ struct kvm_stats_debugfs_item { { n, offsetof(struct kvm_vcpu, stat.common.x), \ KVM_STAT_VCPU, ## __VA_ARGS__ } +#define STATS_DESC(name, type, unit, scale, exponent) \ + { \ + {type | unit | scale, exponent, 1}, name, \ + } +#define STATS_DESC_CUMULATIVE(name, unit, scale, exponent) \ + STATS_DESC(name, KVM_STATS_TYPE_CUMULATIVE, unit, scale, exponent) +#define STATS_DESC_INSTANT(name, unit, scale, exponent) \ + STATS_DESC(name, KVM_STATS_TYPE_INSTANT, unit, scale, exponent) + +// Cumulative counter +#define STATS_DESC_COUNTER(name) \ + STATS_DESC_CUMULATIVE(name, KVM_STATS_UNIT_NONE, \ + KVM_STATS_SCALE_POW10, 0) +// Instantaneous counter +#define STATS_DESC_ICOUNTER(name) \ + STATS_DESC_INSTANT(name, KVM_STATS_UNIT_NONE, \ + KVM_STATS_SCALE_POW10, 0) + +// Cumulative clock cycles +#define STATS_DESC_CYCLE(name) \ + STATS_DESC_CUMULATIVE(name, KVM_STATS_UNIT_CYCLES, \ + KVM_STATS_SCALE_POW10, 0) +// Instantaneous clock cycles +#define STATS_DESC_ICYCLE(name) \ + STATS_DESC_INSTANT(name, KVM_STATS_UNIT_CYCLES, \ + KVM_STATS_SCALE_POW10, 0) + +// Cumulative memory size in Byte +#define STATS_DESC_SIZE_BYTE(name) \ + STATS_DESC_CUMULATIVE(name, KVM_STATS_UNIT_BYTES, \ + KVM_STATS_SCALE_POW2, 0) +// Cumulative memory size in KiByte +#define STATS_DESC_SIZE_KBYTE(name) \ + STATS_DESC_CUMULATIVE(name, KVM_STATS_UNIT_BYTES, \ + KVM_STATS_SCALE_POW2, 10) +// Cumulative memory size in MiByte +#define STATS_DESC_SIZE_MBYTE(name) \ + STATS_DESC_CUMULATIVE(name, KVM_STATS_UNIT_BYTES, \ + KVM_STATS_SCALE_POW2, 20) +// Cumulative memory size in GiByte +#define STATS_DESC_SIZE_GBYTE(name) \ + STATS_DESC_CUMULATIVE(name, KVM_STATS_UNIT_BYTES, \ + KVM_STATS_SCALE_POW2, 30) + +// Instantaneous memory size in Byte +#define STATS_DESC_ISIZE_BYTE(name) \ + STATS_DESC_INSTANT(name, KVM_STATS_UNIT_BYTES, \ + KVM_STATS_SCALE_POW2, 0) +// Instantaneous memory size in KiByte +#define STATS_DESC_ISIZE_KBYTE(name) \ + STATS_DESC_INSTANT(name, KVM_STATS_UNIT_BYTES, \ + KVM_STATS_SCALE_POW2, 10) +// Instantaneous memory size in MiByte +#define STATS_DESC_ISIZE_MBYTE(name) \ + STATS_DESC_INSTANT(name, KVM_STATS_UNIT_BYTES, \ + KVM_STATS_SCALE_POW2, 20) +// Instantaneous memory size in GiByte +#define STATS_DESC_ISIZE_GBYTE(name) \ + STATS_DESC_INSTANT(name, KVM_STATS_UNIT_BYTES, \ + KVM_STATS_SCALE_POW2, 30) + +// Cumulative time in second +#define STATS_DESC_TIME_SEC(name) \ + STATS_DESC_CUMULATIVE(name, KVM_STATS_UNIT_SECONDS, \ + KVM_STATS_SCALE_POW10, 0) +// Cumulative time in millisecond +#define STATS_DESC_TIME_MSEC(name) \ + STATS_DESC_CUMULATIVE(name, KVM_STATS_UNIT_SECONDS, \ + KVM_STATS_SCALE_POW10, -3) +// Cumulative time in microsecond +#define STATS_DESC_TIME_USEC(name) \ + STATS_DESC_CUMULATIVE(name, KVM_STATS_UNIT_SECONDS, \ + KVM_STATS_SCALE_POW10, -6) +// Cumulative time in nanosecond +#define STATS_DESC_TIME_NSEC(name) \ + STATS_DESC_CUMULATIVE(name, KVM_STATS_UNIT_SECONDS, \ + KVM_STATS_SCALE_POW10, -9) + +// Instantaneous time in second +#define STATS_DESC_ITIME_SEC(name) \ + STATS_DESC_INSTANT(name, KVM_STATS_UNIT_SECONDS, \ + KVM_STATS_SCALE_POW10, 0) +// Instantaneous time in millisecond +#define STATS_DESC_ITIME_MSEC(name) \ + STATS_DESC_INSTANT(name, KVM_STATS_UNIT_SECONDS, \ + KVM_STATS_SCALE_POW10, -3) +// Instantaneous time in microsecond +#define STATS_DESC_ITIME_USEC(name) \ + STATS_DESC_INSTANT(name, KVM_STATS_UNIT_SECONDS, \ + KVM_STATS_SCALE_POW10, -6) +// Instantaneous time in nanosecond +#define STATS_DESC_ITIME_NSEC(name) \ + STATS_DESC_INSTANT(name, KVM_STATS_UNIT_SECONDS, \ + KVM_STATS_SCALE_POW10, -9) + +#define STATS_VM_COMMON \ + STATS_DESC_COUNTER("remote_tlb_flush") + +#define STATS_VCPU_COMMON \ + STATS_DESC_COUNTER("halt_successful_poll"), \ + STATS_DESC_COUNTER("halt_attempted_poll"), \ + STATS_DESC_COUNTER("halt_poll_invalid"), \ + STATS_DESC_COUNTER("halt_wakeup"), \ + STATS_DESC_TIME_NSEC("halt_poll_success_ns"), \ + STATS_DESC_TIME_NSEC("halt_poll_fail_ns") + extern struct kvm_stats_debugfs_item debugfs_entries[]; extern struct dentry *kvm_debugfs_dir; +extern struct _kvm_stats_header kvm_vm_stats_header; +extern struct _kvm_stats_header kvm_vcpu_stats_header; +extern struct _kvm_stats_desc kvm_vm_stats_desc[]; +extern struct _kvm_stats_desc kvm_vcpu_stats_desc[]; #if defined(CONFIG_MMU_NOTIFIER) && defined(KVM_ARCH_WANT_MMU_NOTIFIER) static inline int mmu_notifier_retry(struct kvm *kvm, unsigned long mmu_seq) diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h index 424b12658923..d60f4ca8d4fe 100644 --- a/include/uapi/linux/kvm.h +++ b/include/uapi/linux/kvm.h @@ -1079,6 +1079,7 @@ struct kvm_ppc_resize_hpt { #define KVM_CAP_X86_BUS_LOCK_EXIT 193 #define KVM_CAP_PPC_DAWR1 194 #define KVM_CAP_VM_COPY_ENC_CONTEXT_FROM 195 +#define KVM_CAP_STATS_BINARY_FD 196 #ifdef KVM_CAP_IRQ_ROUTING @@ -1854,4 +1855,51 @@ struct kvm_dirty_gfn { #define KVM_BUS_LOCK_DETECTION_OFF (1 << 0) #define KVM_BUS_LOCK_DETECTION_EXIT (1 << 1) +#define KVM_STATS_ID_MAXLEN 64 +struct kvm_stats_header { + char id[KVM_STATS_ID_MAXLEN]; + __u32 name_size; + __u32 count; + __u32 desc_offset; + __u32 data_offset; +}; + +#define KVM_STATS_TYPE_SHIFT 0 +#define KVM_STATS_TYPE_MASK (0xF << KVM_STATS_TYPE_SHIFT) +#define KVM_STATS_TYPE_CUMULATIVE (0x0 << KVM_STATS_TYPE_SHIFT) +#define KVM_STATS_TYPE_INSTANT (0x1 << KVM_STATS_TYPE_SHIFT) +#define KVM_STATS_TYPE_MAX KVM_STATS_TYPE_INSTANT + +#define KVM_STATS_UNIT_SHIFT 4 +#define KVM_STATS_UNIT_MASK (0xF << KVM_STATS_UNIT_SHIFT) +#define KVM_STATS_UNIT_NONE (0x0 << KVM_STATS_UNIT_SHIFT) +#define KVM_STATS_UNIT_BYTES (0x1 << KVM_STATS_UNIT_SHIFT) +#define KVM_STATS_UNIT_SECONDS (0x2 << KVM_STATS_UNIT_SHIFT) +#define KVM_STATS_UNIT_CYCLES (0x3 << KVM_STATS_UNIT_SHIFT) +#define KVM_STATS_UNIT_MAX KVM_STATS_UNIT_CYCLES + +#define KVM_STATS_SCALE_SHIFT 8 +#define KVM_STATS_SCALE_MASK (0xF << KVM_STATS_SCALE_SHIFT) +#define KVM_STATS_SCALE_POW10 (0x0 << KVM_STATS_SCALE_SHIFT) +#define KVM_STATS_SCALE_POW2 (0x1 << KVM_STATS_SCALE_SHIFT) +#define KVM_STATS_SCALE_MAX KVM_STATS_SCALE_POW2 +struct kvm_stats_desc { + __u32 flags; + __s16 exponent; + __u16 size; + __u32 unused1; + __u32 unused2; + char name[0]; +}; + +struct kvm_vm_stats_data { + unsigned long value[0]; +}; + +struct kvm_vcpu_stats_data { + __u64 value[0]; +}; + +#define KVM_STATS_GETFD _IOR(KVMIO, 0xcc, struct kvm_stats_header) + #endif /* __LINUX_KVM_H */ diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c index 2c4205ccf3dd..a16018aca696 100644 --- a/virt/kvm/kvm_main.c +++ b/virt/kvm/kvm_main.c @@ -3277,6 +3277,115 @@ static int kvm_vcpu_ioctl_set_sigmask(struct kvm_vcpu *vcpu, sigset_t *sigset) return 0; } +static ssize_t kvm_vcpu_stats_read(struct file *file, char __user *user_buffer, + size_t size, loff_t *offset) +{ + char id[KVM_STATS_ID_MAXLEN]; + struct kvm_vcpu *vcpu = file->private_data; + ssize_t copylen, len, remain = size; + size_t size_header, size_desc, size_stats; + loff_t pos = *offset; + char __user *dest = user_buffer; + void *src; + + snprintf(id, sizeof(id), "kvm-%d/vcpu-%d", + task_pid_nr(current), vcpu->vcpu_id); + size_header = sizeof(kvm_vcpu_stats_header); + size_desc = + kvm_vcpu_stats_header.count * sizeof(struct _kvm_stats_desc); + size_stats = sizeof(vcpu->stat); + + len = sizeof(id) + size_header + size_desc + size_stats - pos; + len = min(len, remain); + if (len <= 0) + return 0; + remain = len; + + // Copy kvm vcpu stats header id string + copylen = sizeof(id) - pos; + copylen = min(copylen, remain); + if (copylen > 0) { + src = (void *)id + pos; + if (copy_to_user(dest, src, copylen)) + return -EFAULT; + remain -= copylen; + pos += copylen; + dest += copylen; + } + // Copy kvm vcpu stats header + copylen = sizeof(id) + size_header - pos; + copylen = min(copylen, remain); + if (copylen > 0) { + src = (void *)&kvm_vcpu_stats_header; + src += pos - sizeof(id); + if (copy_to_user(dest, src, copylen)) + return -EFAULT; + remain -= copylen; + pos += copylen; + dest += copylen; + } + // Copy kvm vcpu stats descriptors + copylen = kvm_vcpu_stats_header.desc_offset + size_desc - pos; + copylen = min(copylen, remain); + if (copylen > 0) { + src = (void *)&kvm_vcpu_stats_desc; + src += pos - kvm_vcpu_stats_header.desc_offset; + if (copy_to_user(dest, src, copylen)) + return -EFAULT; + remain -= copylen; + pos += copylen; + dest += copylen; + } + // Copy kvm vcpu stats values + copylen = kvm_vcpu_stats_header.data_offset + size_stats - pos; + copylen = min(copylen, remain); + if (copylen > 0) { + src = (void *)&vcpu->stat; + src += pos - kvm_vcpu_stats_header.data_offset; + if (copy_to_user(dest, src, copylen)) + return -EFAULT; + remain -= copylen; + pos += copylen; + dest += copylen; + } + + *offset = pos; + return len; +} + +static struct file_operations kvm_vcpu_stats_fops = { + .read = kvm_vcpu_stats_read, + .llseek = noop_llseek, +}; + +static int kvm_vcpu_ioctl_get_statsfd(struct kvm_vcpu *vcpu) +{ + int error, fd; + struct file *file; + char name[15 + ITOA_MAX_LEN + 1]; + + snprintf(name, sizeof(name), "kvm-vcpu-stats:%d", vcpu->vcpu_id); + + error = get_unused_fd_flags(O_CLOEXEC); + if (error < 0) + return error; + fd = error; + + file = anon_inode_getfile(name, &kvm_vcpu_stats_fops, vcpu, O_RDONLY); + if (IS_ERR(file)) { + error = PTR_ERR(file); + goto err_put_unused_fd; + } + file->f_mode |= FMODE_PREAD; + fd_install(fd, file); + + return fd; + +err_put_unused_fd: + put_unused_fd(fd); + return error; +} + static long kvm_vcpu_ioctl(struct file *filp, unsigned int ioctl, unsigned long arg) { @@ -3474,6 +3583,10 @@ static long kvm_vcpu_ioctl(struct file *filp, r = kvm_arch_vcpu_ioctl_set_fpu(vcpu, fpu); break; } + case KVM_STATS_GETFD: { + r = kvm_vcpu_ioctl_get_statsfd(vcpu); + break; + } default: r = kvm_arch_vcpu_ioctl(filp, ioctl, arg); } @@ -3732,6 +3845,8 @@ static long kvm_vm_ioctl_check_extension_generic(struct kvm *kvm, long arg) #else return 0; #endif + case KVM_CAP_STATS_BINARY_FD: + return 1; default: break; } @@ -3835,6 +3950,111 @@ static int kvm_vm_ioctl_enable_cap_generic(struct kvm *kvm, } } +static ssize_t kvm_vm_stats_read(struct file *file, char __user *user_buffer, + size_t size, loff_t *offset) +{ + char id[KVM_STATS_ID_MAXLEN]; + struct kvm *kvm = file->private_data; + ssize_t copylen, len, remain = size; + size_t size_header, size_desc, size_stats; + loff_t pos = *offset; + char __user *dest = user_buffer; + void *src; + + snprintf(id, sizeof(id), "kvm-%d", task_pid_nr(current)); + size_header = sizeof(kvm_vm_stats_header); + size_desc = kvm_vm_stats_header.count * sizeof(struct _kvm_stats_desc); + size_stats = sizeof(kvm->stat); + + len = sizeof(id) + size_header + size_desc + size_stats - pos; + len = min(len, remain); + if (len <= 0) + return 0; + remain = len; + + // Copy kvm vm stats header id string + copylen = sizeof(id) - pos; + copylen = min(copylen, remain); + if (copylen > 0) { + src = (void *)id + pos; + if (copy_to_user(dest, src, copylen)) + return -EFAULT; + remain -= copylen; + pos += copylen; + dest += copylen; + } + // Copy kvm vm stats header + copylen = sizeof(id) + size_header - pos; + copylen = min(copylen, remain); + if (copylen > 0) { + src = (void *)&kvm_vm_stats_header; + src += pos - sizeof(id); + if (copy_to_user(dest, src, copylen)) + return -EFAULT; + remain -= copylen; + pos += copylen; + dest += copylen; + } + // Copy kvm vm stats descriptors + copylen = kvm_vm_stats_header.desc_offset + size_desc - pos; + copylen = min(copylen, remain); + if (copylen > 0) { + src = (void *)&kvm_vm_stats_desc; + src += pos - kvm_vm_stats_header.desc_offset; + if (copy_to_user(dest, src, copylen)) + return -EFAULT; + remain -= copylen; + pos += copylen; + dest += copylen; + } + // Copy kvm vm stats values + copylen = kvm_vm_stats_header.data_offset + size_stats - pos; + copylen = min(copylen, remain); + if (copylen > 0) { + src = (void *)&kvm->stat; + src += pos - kvm_vm_stats_header.data_offset; + if (copy_to_user(dest, src, copylen)) + return -EFAULT; + remain -= copylen; + pos += copylen; + dest += copylen; + } + + *offset = pos; + return len; +} + +static struct file_operations kvm_vm_stats_fops = { + .read = kvm_vm_stats_read, + .llseek = noop_llseek, +}; + +static int kvm_vm_ioctl_get_statsfd(struct kvm *kvm) +{ + int error, fd; + struct file *file; + + error = get_unused_fd_flags(O_CLOEXEC); + if (error < 0) + return error; + fd = error; + + file = anon_inode_getfile("kvm-vm-stats", + &kvm_vm_stats_fops, kvm, O_RDONLY); + if (IS_ERR(file)) { + error = PTR_ERR(file); + goto err_put_unused_fd; + } + file->f_mode |= FMODE_PREAD; + fd_install(fd, file); + + return fd; + +err_put_unused_fd: + put_unused_fd(fd); + return error; +} + static long kvm_vm_ioctl(struct file *filp, unsigned int ioctl, unsigned long arg) { @@ -4017,6 +4237,9 @@ static long kvm_vm_ioctl(struct file *filp, case KVM_RESET_DIRTY_RINGS: r = kvm_vm_ioctl_reset_dirty_pages(kvm); break; + case KVM_STATS_GETFD: + r = kvm_vm_ioctl_get_statsfd(kvm); + break; default: r = kvm_arch_vm_ioctl(filp, ioctl, arg); } From patchwork Thu Apr 15 15:17:40 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jing Zhang X-Patchwork-Id: 1466687 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=vger.kernel.org (client-ip=23.128.96.18; helo=vger.kernel.org; envelope-from=kvm-ppc-owner@vger.kernel.org; receiver=) Authentication-Results: ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=google.com header.i=@google.com header.a=rsa-sha256 header.s=20161025 header.b=rnpow5Oi; dkim-atps=neutral Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by ozlabs.org (Postfix) with ESMTP id 4FLjhp6Gm8z9sW5 for ; Fri, 16 Apr 2021 01:20:42 +1000 (AEST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S234451AbhDOPUv (ORCPT ); Thu, 15 Apr 2021 11:20:51 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:49284 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S236998AbhDOPUT (ORCPT ); Thu, 15 Apr 2021 11:20:19 -0400 Received: from mail-pj1-x1049.google.com (mail-pj1-x1049.google.com [IPv6:2607:f8b0:4864:20::1049]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id CBB88C06137C for ; Thu, 15 Apr 2021 08:17:49 -0700 (PDT) Received: by mail-pj1-x1049.google.com with SMTP id cm5-20020a17090afa05b029014dcddf9939so12119778pjb.2 for ; Thu, 15 Apr 2021 08:17:49 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20161025; h=date:in-reply-to:message-id:mime-version:references:subject:from:to :cc; bh=4bEYToUiSzx4jvGze0oAT/9T9N0VJu3uEs4vfGgJGYk=; b=rnpow5OigxcqKFzjW9IvQlfp5gL82oUI+j90z0oIhF5lrTwp3AqB5hNgIfZv7a5xIN xZhpBJnJmjGODjfLhwJYdN2hEjMf6ht50K5L4FF+RYvbnSkEjCMptzGcGc9PqeNj7dr3 xKxME63RkoMGOwywe4moluNAmO71yS4qXDHaFVhEKR6qAjB4oeFKEJJ4CXlLRh6LFBFZ x1usF7aJcHEVGz/TTtd3NpwCA5XoDH7Asl/w/4vDw8AOkRq2Jj64/ZnXxOemHKvBQM8R i3I98gxlxedMo4Oi3WsXaIcW2KOaq8LFlyGTXdbBBTz0IP0WxWiuNJ6VEJBifIMlG4Bq 95yw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:date:in-reply-to:message-id:mime-version :references:subject:from:to:cc; bh=4bEYToUiSzx4jvGze0oAT/9T9N0VJu3uEs4vfGgJGYk=; b=Nsnz9tsgzT1iLzWtNnnKYGPubSnXw8/l7DbVfyO/biwReKlRaeQgO9Ihia4s2B6zUr /x8255rGR9fpx6jY9bhEG68kjWXqHvEghe59nPo6FJ4N+APboyTMdc16oSb6KMZQAWHt SFKUPo0dQGCXHz3g4g6fcJwtVwv/DjYvjCnpd8e1TnoL2Lr5Jok/n8PgsUw0iFxLk2/x YKwwfrP9kAeeLyDlEWfn41omE7LPs0TU+yl9Gis+Q7GcOC7qE8JaeHpHe5UStfge/vbL Dzaw8sq8EcT10jR1o9HuLiu5QjevTIJa9uoFA6Kg/66gtNhN26nkzVn9UE+644VB7LHk hXwA== X-Gm-Message-State: AOAM533EUmDwoFvPk22GJ3dD88xlqouY9vC8iOkuuxr4NPVVywhbhDod CgJB2BEWTGXSAXhHE8pDyIzssVSUn3kUJHzAFg== X-Google-Smtp-Source: ABdhPJx8NYZux0cV7fjUPkGAed6Mo6/BT2uK28bE6NrbyvBt3YyQLXqELL5nqmVrKsoQiudDB360655zh1583ghmpQ== X-Received: from jgzg.c.googlers.com ([fda3:e722:ac3:10:7f:e700:c0a8:1acf]) (user=jingzhangos job=sendgmr) by 2002:aa7:828f:0:b029:200:6e27:8c8f with SMTP id s15-20020aa7828f0000b02902006e278c8fmr3478907pfm.44.1618499869288; Thu, 15 Apr 2021 08:17:49 -0700 (PDT) Date: Thu, 15 Apr 2021 15:17:40 +0000 In-Reply-To: <20210415151741.1607806-1-jingzhangos@google.com> Message-Id: <20210415151741.1607806-4-jingzhangos@google.com> Mime-Version: 1.0 References: <20210415151741.1607806-1-jingzhangos@google.com> X-Mailer: git-send-email 2.31.1.295.g9ea45b61b8-goog Subject: [PATCH v2 3/4] KVM: stats: Add documentation for statistics data binary interface From: Jing Zhang To: KVM , KVMARM , LinuxMIPS , KVMPPC , LinuxS390 , Linuxkselftest , Paolo Bonzini , Marc Zyngier , James Morse , Julien Thierry , Suzuki K Poulose , Will Deacon , Huacai Chen , Aleksandar Markovic , Thomas Bogendoerfer , Paul Mackerras , Christian Borntraeger , Janosch Frank , David Hildenbrand , Cornelia Huck , Claudio Imbrenda , Sean Christopherson , Vitaly Kuznetsov , Jim Mattson , Peter Shier , Oliver Upton , David Rientjes , Emanuele Giuseppe Esposito Cc: Jing Zhang Precedence: bulk List-ID: X-Mailing-List: kvm-ppc@vger.kernel.org Signed-off-by: Jing Zhang --- Documentation/virt/kvm/api.rst | 169 +++++++++++++++++++++++++++++++++ 1 file changed, 169 insertions(+) diff --git a/Documentation/virt/kvm/api.rst b/Documentation/virt/kvm/api.rst index 2c4253718881..6474c31a4436 100644 --- a/Documentation/virt/kvm/api.rst +++ b/Documentation/virt/kvm/api.rst @@ -4941,6 +4941,167 @@ see KVM_XEN_VCPU_SET_ATTR above. The KVM_XEN_VCPU_ATTR_TYPE_RUNSTATE_ADJUST type may not be used with the KVM_XEN_VCPU_GET_ATTR ioctl. +4.131 KVM_STATS_GETFD +--------------------- + +:Capability: KVM_CAP_STATS_BINARY_FD +:Architectures: all +:Type: vm ioctl, vcpu ioctl +:Parameters: none +:Returns: statistics file descriptor on success, < 0 on error + +Errors: + + ====== ====================================================== + ENOMEM if the fd could not be created due to lack of memory + EMFILE if the number of opened files exceeds the limit + ====== ====================================================== + +The file descriptor can be used to read VM/vCPU statistics data in binary +format. The file data is organized into three blocks as below: ++-------------+ +| Header | ++-------------+ +| Descriptors | ++-------------+ +| Stats Data | ++-------------+ + +The Header block is always at the start of the file. It is only needed to be +read one time after a system boot. +It is in the form of ``struct kvm_stats_header`` as below:: + + #define KVM_STATS_ID_MAXLEN 64 + struct kvm_stats_header { + char id[KVM_STATS_ID_MAXLEN]; + __u32 name_size; + __u32 count; + __u32 desc_offset; + __u32 data_offset; + }; + +The ``id`` field is identification for the corresponding KVM statistics. For +KVM statistics, it is in the form of "kvm-{kvm pid}", like "kvm-12345". For +VCPU statistics, it is in the form of "kvm-{kvm pid}/vcpu-{vcpu id}", like +"kvm-12345/vcpu-12". + +The ``name_size`` field is the size (byte) of the statistics name string +(including trailing '\0') appended to the end of every statistics descriptor. + +The ``count`` field is the number of statistics. + +The ``desc_offset`` field is the offset of the Descriptors block from the start +of the file indicated by the file descriptor. + +The ``data_offset`` field is the offset of the Stats Data block from the start +of the file indicated by the file descriptor. + +The Descriptors block is only needed to be read once after a system boot. It is +an array of ``struct kvm_stats_desc`` as below:: + + #define KVM_STATS_TYPE_SHIFT 0 + #define KVM_STATS_TYPE_MASK (0xF << KVM_STATS_TYPE_SHIFT) + #define KVM_STATS_TYPE_CUMULATIVE (0x0 << KVM_STATS_TYPE_SHIFT) + #define KVM_STATS_TYPE_INSTANT (0x1 << KVM_STATS_TYPE_SHIFT) + #define KVM_STATS_TYPE_MAX KVM_STATS_TYPE_INSTANT + + #define KVM_STATS_UNIT_SHIFT 4 + #define KVM_STATS_UNIT_MASK (0xF << KVM_STATS_UNIT_SHIFT) + #define KVM_STATS_UNIT_NONE (0x0 << KVM_STATS_UNIT_SHIFT) + #define KVM_STATS_UNIT_BYTES (0x1 << KVM_STATS_UNIT_SHIFT) + #define KVM_STATS_UNIT_SECONDS (0x2 << KVM_STATS_UNIT_SHIFT) + #define KVM_STATS_UNIT_CYCLES (0x3 << KVM_STATS_UNIT_SHIFT) + #define KVM_STATS_UNIT_MAX KVM_STATS_UNIT_CYCLES + + #define KVM_STATS_SCALE_SHIFT 8 + #define KVM_STATS_SCALE_MASK (0xF << KVM_STATS_SCALE_SHIFT) + #define KVM_STATS_SCALE_POW10 (0x0 << KVM_STATS_SCALE_SHIFT) + #define KVM_STATS_SCALE_POW2 (0x1 << KVM_STATS_SCALE_SHIFT) + #define KVM_STATS_SCALE_MAX KVM_STATS_SCALE_POW2 + struct kvm_stats_desc { + __u32 flags; + __s16 exponent; + __u16 size; + __u32 unused1; + __u32 unused2; + __u8 name[0]; + }; + +The ``flags`` field contains the type and unit of the statistics data described +by this descriptor. The following flags are supported: + * ``KVM_STATS_TYPE_CUMULATIVE`` + The statistics data is cumulative. The value of data can only be increased. + Most of the counters used in KVM are of this type. + The corresponding ``count`` filed for this type is always 1. + * ``KVM_STATS_TYPE_INSTANT`` + The statistics data is instantaneous. Its value can be increased or + decreased. This type is usually used as a measurement of some resources, + like the number of dirty pages, the number of large pages, etc. + The corresponding ``count`` field for this type is always 1. + * ``KVM_STATS_UNIT_NONE`` + There is no unit for the value of statistics data. This usually means that + the value is a simple counter of an event. + * ``KVM_STATS_UNIT_BYTES`` + It indicates that the statistics data is used to measure memory size, in the + unit of Byte, KiByte, MiByte, GiByte, etc. The unit of the data is + determined by the ``exponent`` field in the descriptor. The + ``KVM_STATS_SCALE_POW2`` flag is valid in this case. The unit of the data is + determined by ``pow(2, exponent)``. For example, if value is 10, + ``exponent`` is 20, which means the unit of statistics data is MiByte, we + can get the statistics data in the unit of Byte by + ``value * pow(2, exponent) = 10 * pow(2, 20) = 10 MiByte`` which is + 10 * 1024 * 1024 Bytes. + * ``KVM_STATS_UNIT_SECONDS`` + It indicates that the statistics data is used to measure time/latency, in + the unit of nanosecond, microsecond, millisecond and second. The unit of the + data is determined by the ``exponent`` field in the descriptor. The + ``KVM_STATS_SCALE_POW10`` flag is valid in this case. The unit of the data + is determined by ``pow(10, exponent)``. For example, if value is 2000000, + ``exponent`` is -6, which means the unit of statistics data is microsecond, + we can get the statistics data in the unit of second by + ``value * pow(10, exponent) = 2000000 * pow(10, -6) = 2 seconds``. + * ``KVM_STATS_UNIT_CYCLES`` + It indicates that the statistics data is used to measure CPU clock cycles. + The ``KVM_STATS_SCALE_POW10`` flag is valid in this case. For example, if + value is 200, ``exponent`` is 4, we can get the number of CPU clock cycles + by ``value * pow(10, exponent) = 200 * pow(10, 4) = 2000000``. + +The ``exponent`` field is the scale of corresponding statistics data. It has two +values as follows: + * ``KVM_STATS_SCALE_POW10`` + The scale is based on power of 10. It is used for measurement of time and + CPU clock cycles. + * ``KVM_STATS_SCALE_POW2`` + The scale is based on power of 2. It is used for measurement of memory size. + +The ``size`` field is the number of values of this statistics data. It is in the +unit of ``unsigned long`` for VCPU or ``__u64`` for VM. + +The ``unused1`` and ``unused2`` fields are reserved for future +support for other types of statistics data, like log/linear histogram. + +The ``name`` field points to the name string of the statistics data. The name +string starts at the end of ``struct kvm_stats_desc``. +The maximum length (including trailing '\0') is indicated by ``name_size`` +in ``struct kvm_stats_header``. + +The Stats Data block contains an array of data values of type ``struct +kvm_vm_stats_data`` or ``struct kvm_vcpu_stats_data``. It would be read by +user space periodically to pull statistics data. +The order of data value in Stats Data block is the same as the order of +descriptors in Descriptors block. + * Statistics data for VM:: + + struct kvm_vm_stats_data { + unsigned long value[0]; + }; + + * Statistics data for VCPU:: + + struct kvm_vcpu_stats_data { + __u64 value[0]; + }; + 5. The kvm_run structure ======================== @@ -6740,3 +6901,11 @@ vcpu_info is set. The KVM_XEN_HVM_CONFIG_RUNSTATE flag indicates that the runstate-related features KVM_XEN_VCPU_ATTR_TYPE_RUNSTATE_ADDR/_CURRENT/_DATA/_ADJUST are supported by the KVM_XEN_VCPU_SET_ATTR/KVM_XEN_VCPU_GET_ATTR ioctls. + +8.31 KVM_CAP_STATS_BINARY_FD +---------------------------- + +:Architectures: all + +This capability indicates the feature that user space can create get a file +descriptor for every VM and VCPU to read statistics data in binary format. From patchwork Thu Apr 15 15:17:41 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jing Zhang X-Patchwork-Id: 1466688 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=vger.kernel.org (client-ip=23.128.96.18; helo=vger.kernel.org; envelope-from=kvm-ppc-owner@vger.kernel.org; receiver=) Authentication-Results: ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=google.com header.i=@google.com header.a=rsa-sha256 header.s=20161025 header.b=Mxcuusbs; dkim-atps=neutral Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by ozlabs.org (Postfix) with ESMTP id 4FLjhq5tydz9sWK for ; Fri, 16 Apr 2021 01:20:43 +1000 (AEST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S234549AbhDOPVF (ORCPT ); Thu, 15 Apr 2021 11:21:05 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:49292 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S237000AbhDOPUU (ORCPT ); Thu, 15 Apr 2021 11:20:20 -0400 Received: from mail-pj1-x104a.google.com (mail-pj1-x104a.google.com [IPv6:2607:f8b0:4864:20::104a]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 9EC2BC06137E for ; Thu, 15 Apr 2021 08:17:51 -0700 (PDT) Received: by mail-pj1-x104a.google.com with SMTP id e2-20020a17090a7c42b029014d9d6b18afso12422511pjl.8 for ; Thu, 15 Apr 2021 08:17:51 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20161025; h=date:in-reply-to:message-id:mime-version:references:subject:from:to :cc; bh=0LO6oJg1J/PSbt/I1DJNWKL6xWFnsibne8UGI7p/X7U=; b=Mxcuusbsyo3Hl7tLG2sqa6ebs88NwSJ47Ssw0ntnprM1yBUVQTYoGiYaT7IVcN8enV Et7Heq4PwuGsI4sU4wtvBKP0RU8RETkruYd8jp3wxMeEX3Rrh4FRkXaNL6Mp+0+loAGY VOK4KMSLZROyyT71mB4atCNV1zgjB9z6R7NB0dR7rTTV7AeB6OTX+gYJ81BgZ3jfvbxv YxM4vqy2JbWTvfTLZCfqqaSEkZSpq5HLFQCVLgi9yXI2Imc+aObITAsQTUkQKusGf1SX PcQvltSBhN5/S5oM+O8OeYNUCQL2oftlq5fiVpfrFRWPhwiYJktSRAUb9geOOfrcGEDY EW6g== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:date:in-reply-to:message-id:mime-version :references:subject:from:to:cc; bh=0LO6oJg1J/PSbt/I1DJNWKL6xWFnsibne8UGI7p/X7U=; b=GLo1szUZEvIF7ru0piSts/EqcuBWcf/27xQ3TrIKP4LpyKQcRMGal/4LWG1qrYjHDP MKxcH5wJ/T7yuy593TFhO96MB6+vfGZbUiHNghvSW8UszJRbxIi/yt8a4pbtqnCE6SW+ ACL/Tefxkln7+kI4Qnbk9KcTIsNM/P2U7pi5Tm9arQJHVW+B9o/MBqrp3+k+sq+X4vRS UzJstOA90ZE1XVrCGR7y7C/6QGmTqc1BXfK9eqP08U57BHFRSKLXtzMb4EfusFdII0uN p8X2UreyOfmkMsHPA+BcNBh8un757t8jpdlMduejPhyoVKOLO79N/tghvOMxnbSITQCm I2xw== X-Gm-Message-State: AOAM5305gD/0Fu128tAz2YokMIS5lW709Ef3r+kUgDCmt5f69ODy7UE+ z+2xnretz08EmKnPYo73bPa7CNmJS65MgISr6w== X-Google-Smtp-Source: ABdhPJwino7iFjPKYYpune4AXyYUAIecsYG/l/m+KwgdSssG8W9x6U3tXbrfRzAa5LUdbWxs4Db0400ixbOyeMTLsw== X-Received: from jgzg.c.googlers.com ([fda3:e722:ac3:10:7f:e700:c0a8:1acf]) (user=jingzhangos job=sendgmr) by 2002:a17:90a:bf84:: with SMTP id d4mr4390986pjs.118.1618499871205; Thu, 15 Apr 2021 08:17:51 -0700 (PDT) Date: Thu, 15 Apr 2021 15:17:41 +0000 In-Reply-To: <20210415151741.1607806-1-jingzhangos@google.com> Message-Id: <20210415151741.1607806-5-jingzhangos@google.com> Mime-Version: 1.0 References: <20210415151741.1607806-1-jingzhangos@google.com> X-Mailer: git-send-email 2.31.1.295.g9ea45b61b8-goog Subject: [PATCH v2 4/4] KVM: selftests: Add selftest for KVM statistics data binary interface From: Jing Zhang To: KVM , KVMARM , LinuxMIPS , KVMPPC , LinuxS390 , Linuxkselftest , Paolo Bonzini , Marc Zyngier , James Morse , Julien Thierry , Suzuki K Poulose , Will Deacon , Huacai Chen , Aleksandar Markovic , Thomas Bogendoerfer , Paul Mackerras , Christian Borntraeger , Janosch Frank , David Hildenbrand , Cornelia Huck , Claudio Imbrenda , Sean Christopherson , Vitaly Kuznetsov , Jim Mattson , Peter Shier , Oliver Upton , David Rientjes , Emanuele Giuseppe Esposito Cc: Jing Zhang Precedence: bulk List-ID: X-Mailing-List: kvm-ppc@vger.kernel.org Signed-off-by: Jing Zhang --- tools/testing/selftests/kvm/.gitignore | 1 + tools/testing/selftests/kvm/Makefile | 3 + .../testing/selftests/kvm/include/kvm_util.h | 3 + .../selftests/kvm/kvm_bin_form_stats.c | 370 ++++++++++++++++++ tools/testing/selftests/kvm/lib/kvm_util.c | 11 + 5 files changed, 388 insertions(+) create mode 100644 tools/testing/selftests/kvm/kvm_bin_form_stats.c diff --git a/tools/testing/selftests/kvm/.gitignore b/tools/testing/selftests/kvm/.gitignore index 32b87cc77c8e..0c8241bd9a17 100644 --- a/tools/testing/selftests/kvm/.gitignore +++ b/tools/testing/selftests/kvm/.gitignore @@ -38,3 +38,4 @@ /memslot_modification_stress_test /set_memory_region_test /steal_time +/kvm_bin_form_stats diff --git a/tools/testing/selftests/kvm/Makefile b/tools/testing/selftests/kvm/Makefile index a6d61f451f88..5cdd52ccedf2 100644 --- a/tools/testing/selftests/kvm/Makefile +++ b/tools/testing/selftests/kvm/Makefile @@ -72,6 +72,7 @@ TEST_GEN_PROGS_x86_64 += kvm_create_max_vcpus TEST_GEN_PROGS_x86_64 += memslot_modification_stress_test TEST_GEN_PROGS_x86_64 += set_memory_region_test TEST_GEN_PROGS_x86_64 += steal_time +TEST_GEN_PROGS_x86_64 += kvm_bin_form_stats TEST_GEN_PROGS_aarch64 += aarch64/get-reg-list TEST_GEN_PROGS_aarch64 += aarch64/get-reg-list-sve @@ -81,6 +82,7 @@ TEST_GEN_PROGS_aarch64 += dirty_log_perf_test TEST_GEN_PROGS_aarch64 += kvm_create_max_vcpus TEST_GEN_PROGS_aarch64 += set_memory_region_test TEST_GEN_PROGS_aarch64 += steal_time +TEST_GEN_PROGS_aarch64 += kvm_bin_form_stats TEST_GEN_PROGS_s390x = s390x/memop TEST_GEN_PROGS_s390x += s390x/resets @@ -89,6 +91,7 @@ TEST_GEN_PROGS_s390x += demand_paging_test TEST_GEN_PROGS_s390x += dirty_log_test TEST_GEN_PROGS_s390x += kvm_create_max_vcpus TEST_GEN_PROGS_s390x += set_memory_region_test +TEST_GEN_PROGS_s390x += kvm_bin_form_stats TEST_GEN_PROGS += $(TEST_GEN_PROGS_$(UNAME_M)) LIBKVM += $(LIBKVM_$(UNAME_M)) diff --git a/tools/testing/selftests/kvm/include/kvm_util.h b/tools/testing/selftests/kvm/include/kvm_util.h index 2d7eb6989e83..407f3a35ed3b 100644 --- a/tools/testing/selftests/kvm/include/kvm_util.h +++ b/tools/testing/selftests/kvm/include/kvm_util.h @@ -378,4 +378,7 @@ uint64_t get_ucall(struct kvm_vm *vm, uint32_t vcpu_id, struct ucall *uc); #define GUEST_ASSERT_4(_condition, arg1, arg2, arg3, arg4) \ __GUEST_ASSERT((_condition), 4, (arg1), (arg2), (arg3), (arg4)) +int vm_get_statsfd(struct kvm_vm *vm); +int vcpu_get_statsfd(struct kvm_vm *vm, uint32_t vcpuid); + #endif /* SELFTEST_KVM_UTIL_H */ diff --git a/tools/testing/selftests/kvm/kvm_bin_form_stats.c b/tools/testing/selftests/kvm/kvm_bin_form_stats.c new file mode 100644 index 000000000000..5ed2fe74ce55 --- /dev/null +++ b/tools/testing/selftests/kvm/kvm_bin_form_stats.c @@ -0,0 +1,370 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * kvm_bin_form_stats + * + * Copyright (C) 2021, Google LLC. + * + * Test the fd-based interface for KVM statistics. + */ + +#define _GNU_SOURCE /* for program_invocation_short_name */ +#include +#include +#include +#include +#include + +#include "test_util.h" + +#include "kvm_util.h" +#include "asm/kvm.h" +#include "linux/kvm.h" + +int vm_stats_test(struct kvm_vm *vm) +{ + ssize_t ret; + int i, stats_fd, err = -1; + size_t size_desc, size_data = 0; + struct kvm_stats_header header; + struct kvm_stats_desc *stats_desc, *pdesc; + struct kvm_vm_stats_data *stats_data; + + // Get fd for VM stats + stats_fd = vm_get_statsfd(vm); + if (stats_fd < 0) { + perror("Get VM stats fd"); + return err; + } + // Read kvm vm stats header + ret = read(stats_fd, &header, sizeof(header)); + if (ret != sizeof(header)) { + perror("Read VM stats header"); + goto out_close_fd; + } + size_desc = sizeof(*stats_desc) + header.name_size; + // Check id string in header, that should start with "kvm" + if (strncmp(header.id, "kvm", 3) || + strlen(header.id) >= KVM_STATS_ID_MAXLEN) { + printf("Invalid KVM VM stats type!\n"); + goto out_close_fd; + } + // Sanity check for other fields in header + if (header.count == 0) { + err = 0; + goto out_close_fd; + } + // Check overlap + if (header.desc_offset == 0 || header.data_offset == 0 || + header.desc_offset < sizeof(header) || + header.data_offset < sizeof(header)) { + printf("Invalid offset fields in header!\n"); + goto out_close_fd; + } + if (header.desc_offset < header.data_offset && + (header.desc_offset + size_desc * header.count > + header.data_offset)) { + printf("Descriptor block is overlapped with data block!\n"); + goto out_close_fd; + } + + // Allocate memory for stats descriptors + stats_desc = calloc(header.count, size_desc); + if (!stats_desc) { + perror("Allocate memory for VM stats descriptors"); + goto out_close_fd; + } + // Read kvm vm stats descriptors + ret = pread(stats_fd, stats_desc, + size_desc * header.count, header.desc_offset); + if (ret != size_desc * header.count) { + perror("Read KVM VM stats descriptors"); + goto out_free_desc; + } + // Sanity check for fields in descriptors + for (i = 0; i < header.count; ++i) { + pdesc = (void *)stats_desc + i * size_desc; + // Check type,unit,scale boundaries + if ((pdesc->flags & KVM_STATS_TYPE_MASK) > KVM_STATS_TYPE_MAX) { + printf("Unknown KVM stats type!\n"); + goto out_free_desc; + } + if ((pdesc->flags & KVM_STATS_UNIT_MASK) > KVM_STATS_UNIT_MAX) { + printf("Unknown KVM stats unit!\n"); + goto out_free_desc; + } + if ((pdesc->flags & KVM_STATS_SCALE_MASK) > + KVM_STATS_SCALE_MAX) { + printf("Unknown KVM stats scale!\n"); + goto out_free_desc; + } + /* Check exponent for stats unit + * Exponent for counter should be greater than or equal to 0 + * Exponent for unit bytes should be greater than or equal to 0 + * Exponent for unit seconds should be less than or equal to 0 + * Exponent for unit clock cycles should be greater than or + * equal to 0 + */ + switch (pdesc->flags & KVM_STATS_UNIT_MASK) { + case KVM_STATS_UNIT_NONE: + case KVM_STATS_UNIT_BYTES: + case KVM_STATS_UNIT_CYCLES: + if (pdesc->exponent < 0) { + printf("Unsupported KVM stats unit!\n"); + goto out_free_desc; + } + break; + case KVM_STATS_UNIT_SECONDS: + if (pdesc->exponent > 0) { + printf("Unsupported KVM stats unit!\n"); + goto out_free_desc; + } + break; + } + // Check name string + if (strlen(pdesc->name) >= header.name_size) { + printf("KVM stats name(%s) too long!\n", pdesc->name); + goto out_free_desc; + } + // Check size field, which should not be zero + if (pdesc->size == 0) { + printf("KVM descriptor(%s) with size of 0!\n", + pdesc->name); + goto out_free_desc; + } + size_data = pdesc->size * sizeof(stats_data->value[0]); + } + // Check overlap + if (header.data_offset < header.desc_offset && + header.data_offset + size_data > header.desc_offset) { + printf("Data block is overlapped with Descriptor block!\n"); + goto out_free_desc; + } + + // Allocate memory for stats data + stats_data = malloc(size_data); + if (!stats_data) { + perror("Allocate memory for VM stats data"); + goto out_free_desc; + } + // Read kvm vm stats data + ret = pread(stats_fd, stats_data, size_data, header.data_offset); + if (ret != size_data) { + perror("Read KVM VM stats data"); + goto out_free_data; + } + + err = 0; +out_free_data: + free(stats_data); +out_free_desc: + free(stats_desc); +out_close_fd: + close(stats_fd); + return err; +} + +int vcpu_stats_test(struct kvm_vm *vm, int vcpu_id) +{ + ssize_t ret; + int i, stats_fd, err = -1; + size_t size_desc, size_data = 0; + struct kvm_stats_header header; + struct kvm_stats_desc *stats_desc, *pdesc; + struct kvm_vcpu_stats_data *stats_data; + + // Get fd for VCPU stats + stats_fd = vcpu_get_statsfd(vm, vcpu_id); + if (stats_fd < 0) { + perror("Get VCPU stats fd"); + return err; + } + // Read kvm vcpu stats header + ret = read(stats_fd, &header, sizeof(header)); + if (ret != sizeof(header)) { + perror("Read VCPU stats header"); + goto out_close_fd; + } + size_desc = sizeof(*stats_desc) + header.name_size; + // Check id string in header, that should start with "kvm" + if (strncmp(header.id, "kvm", 3) || + strlen(header.id) >= KVM_STATS_ID_MAXLEN) { + printf("Invalid KVM VCPU stats type!\n"); + goto out_close_fd; + } + // Sanity check for other fields in header + if (header.count == 0) { + err = 0; + goto out_close_fd; + } + // Check overlap + if (header.desc_offset == 0 || header.data_offset == 0 || + header.desc_offset < sizeof(header) || + header.data_offset < sizeof(header)) { + printf("Invalid offset fields in header!\n"); + goto out_close_fd; + } + if (header.desc_offset < header.data_offset && + (header.desc_offset + size_desc * header.count > + header.data_offset)) { + printf("Descriptor block is overlapped with data block!\n"); + goto out_close_fd; + } + + // Allocate memory for stats descriptors + stats_desc = calloc(header.count, size_desc); + if (!stats_desc) { + perror("Allocate memory for VCPU stats descriptors"); + goto out_close_fd; + } + // Read kvm vcpu stats descriptors + ret = pread(stats_fd, stats_desc, + size_desc * header.count, header.desc_offset); + if (ret != size_desc * header.count) { + perror("Read KVM VCPU stats descriptors"); + goto out_free_desc; + } + // Sanity check for fields in descriptors + for (i = 0; i < header.count; ++i) { + pdesc = (void *)stats_desc + i * size_desc; + // Check boundaries + if ((pdesc->flags & KVM_STATS_TYPE_MASK) > KVM_STATS_TYPE_MAX) { + printf("Unknown KVM stats type!\n"); + goto out_free_desc; + } + if ((pdesc->flags & KVM_STATS_UNIT_MASK) > KVM_STATS_UNIT_MAX) { + printf("Unknown KVM stats unit!\n"); + goto out_free_desc; + } + if ((pdesc->flags & KVM_STATS_SCALE_MASK) > + KVM_STATS_SCALE_MAX) { + printf("Unknown KVM stats scale!\n"); + goto out_free_desc; + } + /* Check exponent for stats unit + * Exponent for counter should be greater than or equal to 0 + * Exponent for unit bytes should be greater than or equal to 0 + * Exponent for unit seconds should be less than or equal to 0 + * Exponent for unit clock cycles should be greater than or + * equal to 0 + */ + switch (pdesc->flags & KVM_STATS_UNIT_MASK) { + case KVM_STATS_UNIT_NONE: + case KVM_STATS_UNIT_BYTES: + case KVM_STATS_UNIT_CYCLES: + if (pdesc->exponent < 0) { + printf("Unsupported KVM stats unit!\n"); + goto out_free_desc; + } + break; + case KVM_STATS_UNIT_SECONDS: + if (pdesc->exponent > 0) { + printf("Unsupported KVM stats unit!\n"); + goto out_free_desc; + } + break; + } + // Check name string + if (strlen(pdesc->name) >= header.name_size) { + printf("KVM stats name(%s) too long!\n", pdesc->name); + goto out_free_desc; + } + // Check size field, which should not be zero + if (pdesc->size == 0) { + printf("KVM descriptor(%s) with size of 0!\n", + pdesc->name); + goto out_free_desc; + } + size_data = pdesc->size * sizeof(stats_data->value[0]); + } + // Check overlap + if (header.data_offset < header.desc_offset && + header.data_offset + size_data > header.desc_offset) { + printf("Data block is overlapped with Descriptor block!\n"); + goto out_free_desc; + } + + // Allocate memory for stats data + stats_data = malloc(size_data); + if (!stats_data) { + perror("Allocate memory for VCPU stats data"); + goto out_free_desc; + } + // Read kvm vcpu stats data + ret = pread(stats_fd, stats_data, size_data, header.data_offset); + if (ret != size_data) { + perror("Read KVM VCPU stats data"); + goto out_free_data; + } + + err = 0; +out_free_data: + free(stats_data); +out_free_desc: + free(stats_desc); +out_close_fd: + close(stats_fd); + return err; +} + +/* + * Usage: kvm_bin_form_stats [#vm] [#vcpu] + * The first parameter #vm set the number of VMs being created. + * The second parameter #vcpu set the number of VCPUs being created. + * By default, 1 VM and 1 VCPU for the VM would be created for testing. + */ + +int main(int argc, char *argv[]) +{ + int max_vm = 1, max_vcpu = 1, ret, i, j, err = -1; + struct kvm_vm **vms; + + // Get the number of VMs and VCPUs that would be created for testing. + if (argc > 1) { + max_vm = strtol(argv[1], NULL, 0); + if (max_vm <= 0) + max_vm = 1; + } + if (argc > 2 ) { + max_vcpu = strtol(argv[2], NULL, 0); + if (max_vcpu <= 0) + max_vcpu = 1; + } + + // Check the extension for binary stats + ret = kvm_check_cap(KVM_CAP_STATS_BINARY_FD); + if (ret < 0) { + printf("Binary form statistics interface is not supported!\n"); + return err; + } + + // Create VMs and VCPUs + vms = malloc(sizeof(vms[0]) * max_vm); + if (!vms) { + perror("Allocate memory for storing VM pointers"); + return err; + } + for (i = 0; i < max_vm; ++i) { + vms[i] = vm_create(VM_MODE_DEFAULT, + DEFAULT_GUEST_PHY_PAGES, O_RDWR); + for (j = 0; j < max_vcpu; ++j) { + vm_vcpu_add(vms[i], j); + } + } + + // Check stats read for every VM and VCPU + for (i = 0; i < max_vm; ++i) { + if (vm_stats_test(vms[i])) + goto out_free_vm; + for (j = 0; j < max_vcpu; ++j) { + if (vcpu_stats_test(vms[i], j)) + goto out_free_vm; + } + } + + err = 0; +out_free_vm: + for (i = 0; i < max_vm; ++i) + kvm_vm_free(vms[i]); + free(vms); + return err; +} diff --git a/tools/testing/selftests/kvm/lib/kvm_util.c b/tools/testing/selftests/kvm/lib/kvm_util.c index e5fbf16f725b..be305e7b54ca 100644 --- a/tools/testing/selftests/kvm/lib/kvm_util.c +++ b/tools/testing/selftests/kvm/lib/kvm_util.c @@ -2013,3 +2013,14 @@ unsigned int vm_calc_num_guest_pages(enum vm_guest_mode mode, size_t size) n = DIV_ROUND_UP(size, vm_guest_mode_params[mode].page_size); return vm_adjust_num_guest_pages(mode, n); } + +int vm_get_statsfd(struct kvm_vm *vm) +{ + return ioctl(vm->fd, KVM_STATS_GETFD, NULL); +} + +int vcpu_get_statsfd(struct kvm_vm *vm, uint32_t vcpuid) +{ + struct vcpu *vcpu = vcpu_find(vm, vcpuid); + return ioctl(vcpu->fd, KVM_STATS_GETFD, NULL); +}