From: Manali Shukla <manali.shu...@amd.com>

The interface is used to read the data values of a specified vcpu stat
from the currenly available binary stats interface.

Add a concatenation trickery to trigger compiler error if the stat
doesn't exist, so that it is not possible to pass a per-VM stat into
vcpu_get_stat().

Suggested-by: Sean Christopherson <sea...@google.com>
Signed-off-by: Manali Shukla <manali.shu...@amd.com>
---
 .../testing/selftests/kvm/include/kvm_util.h  | 52 +++++++++++++++++++
 .../kvm/include/x86_64/kvm_util_arch.h        | 36 +++++++++++++
 tools/testing/selftests/kvm/lib/kvm_util.c    | 40 ++++++++++++++
 3 files changed, 128 insertions(+)

diff --git a/tools/testing/selftests/kvm/include/kvm_util.h 
b/tools/testing/selftests/kvm/include/kvm_util.h
index bc7c242480d6..5dd3acf174f8 100644
--- a/tools/testing/selftests/kvm/include/kvm_util.h
+++ b/tools/testing/selftests/kvm/include/kvm_util.h
@@ -531,6 +531,14 @@ void read_stat_data(int stats_fd, struct kvm_stats_header 
*header,
                    struct kvm_stats_desc *desc, uint64_t *data,
                    size_t max_elements);
 
+#define DEFINE_CHECK_STAT(type, stat)                  \
+static inline int check_##type##_##stat##_exists(void) \
+{                                                      \
+       return 1;                                       \
+}                                                      \
+
+#define STAT_EXISTS(type, stat) (check_##type##_##stat##_exists())
+
 void __vm_get_stat(struct kvm_vm *vm, const char *stat_name, uint64_t *data,
                   size_t max_elements);
 
@@ -542,6 +550,50 @@ static inline uint64_t vm_get_stat(struct kvm_vm *vm, 
const char *stat_name)
        return data;
 }
 
+#define DEFINE_GENERIC_VCPU_STAT                               \
+       DEFINE_CHECK_STAT(vcpu, halt_successfull_poll)          \
+       DEFINE_CHECK_STAT(vcpu, halt_attempted_poll)            \
+       DEFINE_CHECK_STAT(vcpu, halt_poll_invalid)              \
+       DEFINE_CHECK_STAT(vcpu, halt_wakeup)                    \
+       DEFINE_CHECK_STAT(vcpu, halt_poll_success_ns)           \
+       DEFINE_CHECK_STAT(vcpu, halt_poll_fail_ns)              \
+       DEFINE_CHECK_STAT(vcpu, halt_wait_ns)                   \
+       DEFINE_CHECK_STAT(vcpu, halt_poll_success_hist)         \
+       DEFINE_CHECK_STAT(vcpu, halt_poll_fail_hist)            \
+       DEFINE_CHECK_STAT(vcpu, halt_wait_hist)                 \
+       DEFINE_CHECK_STAT(vcpu, blocking)                       \
+
+/*
+ * Define a default empty macro for architectures which do not specify
+ * arch specific vcpu stats
+ */
+
+#ifndef DEFINE_ARCH_VCPU_STAT
+#define DEFINE_ARCH_VCPU_STAT
+#endif
+
+DEFINE_GENERIC_VCPU_STAT
+DEFINE_ARCH_VCPU_STAT
+
+#undef DEFINE_CHECK_STAT
+#undef DEFINE_GENERIC_VCPU_STAT
+#undef DEFINE_ARCH_VCPU_STAT
+
+void __vcpu_get_stat(struct kvm_vcpu *vcpu, const char *stat_name, uint64_t 
*data,
+                  size_t max_elements);
+
+#define vcpu_get_stat(vcpu, stat_name)                         \
+({                                                             \
+       uint64_t data;                                          \
+                                                               \
+       STAT_EXISTS(vcpu, stat_name);                           \
+       __vcpu_get_stat(vcpu, #stat_name, &data, 1);            \
+       data;                                                   \
+})                                                             \
+
+#undef DEFINE_CHECK_STAT
+#undef DEFINE_GENERIC_VCPU_STAT
+
 void vm_create_irqchip(struct kvm_vm *vm);
 
 static inline int __vm_create_guest_memfd(struct kvm_vm *vm, uint64_t size,
diff --git a/tools/testing/selftests/kvm/include/x86_64/kvm_util_arch.h 
b/tools/testing/selftests/kvm/include/x86_64/kvm_util_arch.h
index 972bb1c4ab4c..3cdc3c856ed2 100644
--- a/tools/testing/selftests/kvm/include/x86_64/kvm_util_arch.h
+++ b/tools/testing/selftests/kvm/include/x86_64/kvm_util_arch.h
@@ -48,4 +48,40 @@ do {                                                         
                        \
        }                                                                       
        \
 } while (0)
 
+#define DEFINE_ARCH_VCPU_STAT                                  \
+       DEFINE_CHECK_STAT(vcpu, pf_taken)                       \
+       DEFINE_CHECK_STAT(vcpu, pf_fixed)                       \
+       DEFINE_CHECK_STAT(vcpu, pf_emulate)                     \
+       DEFINE_CHECK_STAT(vcpu, pf_spurious)                    \
+       DEFINE_CHECK_STAT(vcpu, pf_fast)                        \
+       DEFINE_CHECK_STAT(vcpu, pf_mmio_spte_created)           \
+       DEFINE_CHECK_STAT(vcpu, pf_guest)                       \
+       DEFINE_CHECK_STAT(vcpu, tlb_flush)                      \
+       DEFINE_CHECK_STAT(vcpu, invlpg)                         \
+       DEFINE_CHECK_STAT(vcpu, exits)                          \
+       DEFINE_CHECK_STAT(vcpu, io_exits)                       \
+       DEFINE_CHECK_STAT(vcpu, mmio_exits)                     \
+       DEFINE_CHECK_STAT(vcpu, signal_exits)                   \
+       DEFINE_CHECK_STAT(vcpu, irq_window_exits)               \
+       DEFINE_CHECK_STAT(vcpu, nmi_window_exits)               \
+       DEFINE_CHECK_STAT(vcpu, l1d_flush)                      \
+       DEFINE_CHECK_STAT(vcpu, halt_exits)                     \
+       DEFINE_CHECK_STAT(vcpu, request_irq_exits)              \
+       DEFINE_CHECK_STAT(vcpu, irq_exits)                      \
+       DEFINE_CHECK_STAT(vcpu, host_state_reload)              \
+       DEFINE_CHECK_STAT(vcpu, fpu_reload)                     \
+       DEFINE_CHECK_STAT(vcpu, insn_emulation)                 \
+       DEFINE_CHECK_STAT(vcpu, insn_emulation_fail)            \
+       DEFINE_CHECK_STAT(vcpu, hypercalls)                     \
+       DEFINE_CHECK_STAT(vcpu, irq_injections)                 \
+       DEFINE_CHECK_STAT(vcpu, nmi_injections)                 \
+       DEFINE_CHECK_STAT(vcpu, req_event)                      \
+       DEFINE_CHECK_STAT(vcpu, nested_run)                     \
+       DEFINE_CHECK_STAT(vcpu, directed_yield_attempted)       \
+       DEFINE_CHECK_STAT(vcpu, directed_yield_successful)      \
+       DEFINE_CHECK_STAT(vcpu, preemption_reported)            \
+       DEFINE_CHECK_STAT(vcpu, preemption_other)               \
+       DEFINE_CHECK_STAT(vcpu, guest_mode)                     \
+       DEFINE_CHECK_STAT(vcpu, notify_window_exits)            \
+
 #endif  // SELFTEST_KVM_UTIL_ARCH_H
diff --git a/tools/testing/selftests/kvm/lib/kvm_util.c 
b/tools/testing/selftests/kvm/lib/kvm_util.c
index a2b7df5f1d39..3ee84e117a04 100644
--- a/tools/testing/selftests/kvm/lib/kvm_util.c
+++ b/tools/testing/selftests/kvm/lib/kvm_util.c
@@ -2195,6 +2195,46 @@ void read_stat_data(int stats_fd, struct 
kvm_stats_header *header,
                    desc->name, size, ret);
 }
 
+/*
+ * Read the data of the named vcpu stat
+ *
+ * Input Args:
+ *   vcpu - the vcpu for which the stat should be read
+ *   stat_name - the name of the stat to read
+ *   max_elements - the maximum number of 8-byte values to read into data
+ *
+ * Output Args:
+ *   data - the buffer into which stat data should be read
+ *
+ * Read the data values of a specified stat from the binary stats interface.
+ */
+void __vcpu_get_stat(struct kvm_vcpu *vcpu, const char *stat_name, uint64_t 
*data,
+                  size_t max_elements)
+{
+       int vcpu_stats_fd;
+       struct kvm_stats_header header;
+       struct kvm_stats_desc *desc, *t_desc;
+       size_t size_desc;
+       int i;
+
+       vcpu_stats_fd = vcpu_get_stats_fd(vcpu);
+       read_stats_header(vcpu_stats_fd, &header);
+
+       desc = read_stats_descriptors(vcpu_stats_fd, &header);
+       size_desc = get_stats_descriptor_size(&header);
+
+       for (i = 0; i < header.num_desc; ++i) {
+               t_desc = (void *)desc + (i * size_desc);
+
+               if (strcmp(t_desc->name, stat_name))
+                       continue;
+
+               read_stat_data(vcpu_stats_fd, &header, t_desc,
+                              data, max_elements);
+               break;
+       }
+}
+
 /*
  * Read the data of the named stat
  *
-- 
2.34.1


Reply via email to