Re: [PATCH v7 2/4] KVM: stats: Add fd-based API to read binary stats data

2021-06-08 Thread Krish Sadhukhan
CLES  (0x3 << KVM_STATS_UNIT_SHIFT)
+#define KVM_STATS_UNIT_MAX KVM_STATS_UNIT_CYCLES
+
+#define KVM_STATS_BASE_SHIFT   8
+#define KVM_STATS_BASE_MASK(0xF << KVM_STATS_BASE_SHIFT)
+#define KVM_STATS_BASE_POW10   (0x0 << KVM_STATS_BASE_SHIFT)
+#define KVM_STATS_BASE_POW2(0x1 << KVM_STATS_BASE_SHIFT)
+#define KVM_STATS_BASE_MAX KVM_STATS_BASE_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_GET_STATS_FD  _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 f6ad5b080994..d84bb17bdea8 100644
--- a/virt/kvm/kvm_main.c
+++ b/virt/kvm/kvm_main.c
@@ -3409,6 +3409,115 @@ static int kvm_vcpu_ioctl_set_sigmask(struct kvm_vcpu 
*vcpu, sigset_t *sigset)
return 0;
  }
  
+static ssize_t kvm_stats_read(char *id, struct _kvm_stats_header *header,

+   struct _kvm_stats_desc *desc, void *stats, size_t size_stats,
+   char __user *user_buffer, size_t size, loff_t *offset)
+{
+   ssize_t copylen, len, remain = size;
+   size_t size_header, size_desc;
+   loff_t pos = *offset;
+   char __user *dest = user_buffer;
+   void *src;
+
+   size_header = sizeof(*header);
+   size_desc = header->count * sizeof(*desc);
+
+   len = KVM_STATS_ID_MAXLEN + size_header + size_desc + size_stats - pos;
+   len = min(len, remain);
+   if (len <= 0)
+   return 0;
+   remain = len;
+
+   /* Copy kvm stats header id string */
+   copylen = KVM_STATS_ID_MAXLEN - pos;
+   copylen = min(copylen, remain);
+   if (copylen > 0) {
+   src = id + pos;
+   if (copy_to_user(dest, src, copylen))
+   return -EFAULT;
+   remain -= copylen;
+   pos += copylen;
+   dest += copylen;
+   }
+   /* Copy kvm stats header */
+   copylen = KVM_STATS_ID_MAXLEN + size_header - pos;
+   copylen = min(copylen, remain);
+   if (copylen > 0) {
+   src = header + pos - KVM_STATS_ID_MAXLEN;
+   if (copy_to_user(dest, src, copylen))
+   return -EFAULT;
+   remain -= copylen;
+   pos += copylen;
+   dest += copylen;
+   }
+   /* Copy kvm stats descriptors */
+   copylen = header->desc_offset + size_desc - pos;
+   copylen = min(copylen, remain);
+   if (copylen > 0) {
+   src = desc + pos - header->desc_offset;
+   if (copy_to_user(dest, src, copylen))
+   return -EFAULT;
+   remain -= copylen;
+   pos += copylen;
+   dest += copylen;
+   }
+   /* Copy kvm stats values */
+   copylen = header->data_offset + size_stats - pos;
+   copylen = min(copylen, remain);
+   if (copylen > 0) {
+   src = stats + pos - header->data_offset;
+   if (copy_to_user(dest, src, copylen))
+   return -EFAULT;
+   remain -= copylen;
+   pos += copylen;
+   dest += copylen;
+   }
+
+   *offset = pos;
+   return len;
+}
+
+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;
+
+   snprintf(id, sizeof(id), "kvm-%d/vcpu-%d",
+   task_pid_nr(current), vcpu->vcpu_id);
+   return kvm_stats_read(id, &kvm_vcpu_stats_header,
+   &kvm_vcpu_stats_desc[0], &vcpu->stat,
+   sizeof(vcpu->stat), user_buffer, size, offset);
+}
+
+static const struct file_operations kvm_vcpu_stats_fops = {
+   .read = kvm_vcpu_stats_read,
+   .llseek = noop_llseek,
+};
+
+static int kvm_vcpu_ioctl_get_stats_fd(struct kvm_vcpu *vcpu)
+{
+   int fd;
+   struct file *file;
+   char name[15 + ITOA_MAX_LEN + 1];
+
+   snprintf(name, sizeof(name), "kvm-vcpu-stats:%d", vcpu->vcpu_id);
+
+   fd = get_unused_fd_flags(O_CLOEXEC);
+   if (fd < 0)
+   return fd;
+
+   file = anon_inode_getfile(name, &kvm_vcpu_stats_fops, vcpu, O_RDONLY);
+   if (IS_ERR(file)) {
+   put_unused_fd(fd);
+   return PTR_ERR(file);
+   }
+   file->f_mode |= FMODE_PREAD;
+   fd_install(fd, file);
+
+   return fd;
+}
+
  static long kvm_vcpu_ioctl(struct file *filp,
   unsigned int ioctl, unsigned long arg)
  {
@@ -3606,6 +3715,10 @@ static long kvm_vcpu_ioctl(struct file *filp,
r = kvm_arch_vcpu_ioctl_set_fpu(vcpu, fpu);
break;
}
+   case KVM_GET_STATS_FD: {
+   r = kvm_vcpu_ioctl_get_stats_fd(vcpu);
+   break;
+   }
default:
r = kvm_arch_vcpu_ioctl(filp, ioctl, arg);
}
@@ -3864,6 +3977,8 @@ static long kvm_vm_ioctl_check_extension_generic(struct 
kvm *kvm, long arg)
  #else
return 0;
  #endif
+   case KVM_CAP_STATS_BINARY_FD:


Nit:   KVM_CAP_BINARY_STATS_FD


+   return 1;
default:
break;
}
@@ -3967,6 +4082,43 @@ 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;
+
+   snprintf(id, sizeof(id), "kvm-%d", task_pid_nr(current));
+   return kvm_stats_read(id, &kvm_vm_stats_header, &kvm_vm_stats_desc[0],
+   &kvm->stat, sizeof(kvm->stat), user_buffer, size, offset);
+}
+
+static const struct file_operations kvm_vm_stats_fops = {
+   .read = kvm_vm_stats_read,
+   .llseek = noop_llseek,
+};
+
+static int kvm_vm_ioctl_get_stats_fd(struct kvm *kvm)
+{
+   int fd;
+   struct file *file;
+
+   fd = get_unused_fd_flags(O_CLOEXEC);
+   if (fd < 0)
+   return fd;
+
+   file = anon_inode_getfile("kvm-vm-stats",
+   &kvm_vm_stats_fops, kvm, O_RDONLY);
+   if (IS_ERR(file)) {
+   put_unused_fd(fd);
+   return PTR_ERR(file);
+   }
+   file->f_mode |= FMODE_PREAD;
+   fd_install(fd, file);
+
+   return fd;
+}
+
  static long kvm_vm_ioctl(struct file *filp,
   unsigned int ioctl, unsigned long arg)
  {
@@ -4149,6 +4301,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_GET_STATS_FD:
+   r = kvm_vm_ioctl_get_stats_fd(kvm);
+   break;
default:
r = kvm_arch_vm_ioctl(filp, ioctl, arg);
}

Reviewed-by: Krish Sadhukhan 
___
kvmarm mailing list
kvmarm@lists.cs.columbia.edu
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm


Re: [PATCH v7 4/4] KVM: selftests: Add selftest for KVM statistics data binary interface

2021-06-08 Thread Krish Sadhukhan
;Stats fd not freed");
+}
+
+#define DEFAULT_NUM_VM 4
+#define DEFAULT_NUM_VCPU   4
+
+/*
+ * 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, DEFAULT_NUM_VM VM and DEFAULT_NUM_VCPU VCPU for the VM would be
+ * created for testing.
+ */
+
+int main(int argc, char *argv[])
+{
+   int max_vm = DEFAULT_NUM_VM, max_vcpu = DEFAULT_NUM_VCPU, ret, i, j;
+   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 = DEFAULT_NUM_VM;
+   }
+   if (argc > 2) {
+   max_vcpu = strtol(argv[2], NULL, 0);
+   if (max_vcpu <= 0)
+   max_vcpu = DEFAULT_NUM_VCPU;
+   }
+
+   /* Check the extension for binary stats */
+   ret = kvm_check_cap(KVM_CAP_STATS_BINARY_FD);
+   TEST_ASSERT(ret >= 0,
+   "Binary form statistics interface is not supported");
+
+   /* Create VMs and VCPUs */
+   vms = malloc(sizeof(vms[0]) * max_vm);
+   TEST_ASSERT(vms, "Allocate memory for storing VM pointers");
+   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) {
+   vm_stats_test(vms[i]);
+   for (j = 0; j < max_vcpu; ++j)
+   vcpu_stats_test(vms[i], j);
+   }
+
+   for (i = 0; i < max_vm; ++i)
+   kvm_vm_free(vms[i]);
+   free(vms);
+   return 0;
+}
diff --git a/tools/testing/selftests/kvm/lib/kvm_util.c 
b/tools/testing/selftests/kvm/lib/kvm_util.c
index fc83f6c5902d..10385b76fe11 100644
--- a/tools/testing/selftests/kvm/lib/kvm_util.c
+++ b/tools/testing/selftests/kvm/lib/kvm_util.c
@@ -2090,3 +2090,15 @@ 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_stats_fd(struct kvm_vm *vm)
+{
+   return ioctl(vm->fd, KVM_GET_STATS_FD, NULL);
+}
+
+int vcpu_get_stats_fd(struct kvm_vm *vm, uint32_t vcpuid)
+{
+   struct vcpu *vcpu = vcpu_find(vm, vcpuid);
+
+   return ioctl(vcpu->fd, KVM_GET_STATS_FD, NULL);
+}


We don't want to add a test case for testing the fd interface on a 
deleted VM and a deleted VCPU ?


Anyway, for the current content,

Reviewed-by: Krish Sadhukhan 

___
kvmarm mailing list
kvmarm@lists.cs.columbia.edu
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm


Re: [PATCH v7 3/4] KVM: stats: Add documentation for statistics data binary interface

2021-06-08 Thread Krish Sadhukhan
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.
+
+Bits 4-7 of ``flags`` encode the unit:
+  * ``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_BASE_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_BASE_POW10`` flag is valid in this case. The unit of the data
+is determined by ``pow(10, exponent)``. For example, if value is 200,
+``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) = 200 * 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_BASE_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) = 200``.
+
+Bits 7-11 of ``flags`` encode the base:
+  * ``KVM_STATS_BASE_POW10``
+The scale is based on power of 10. It is used for measurement of time and
+CPU clock cycles.
+  * ``KVM_STATS_BASE_POW2``
+The scale is based on power of 2. It is used for measurement of memory 
size.
+
+The ``exponent`` field is the scale of corresponding statistics data. For
+example, if the unit is ``KVM_STATS_UNIT_BYTES``, the base is
+``KVM_STATS_BASE_POW2``, the ``exponent`` is 10, then we know that the real
+unit of the statistics data is KBytes a.k.a pow(2, 10) = 1024 bytes.
+
+The ``size`` field is the number of values of this statistics data. It is in 
the
+unit of ``unsigned long`` for VM or ``__u64`` for VCPU.
+
+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
  
  
@@ -6891,3 +7063,11 @@ This capability is always enabled.

  This capability indicates that the KVM virtual PTP service is
  supported in the host. A VMM can check whether the service is
  available to the guest on migration.
+
+8.33 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.



Reviewed-by: Krish Sadhukhan 

___
kvmarm mailing list
kvmarm@lists.cs.columbia.edu
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm


Re: [PATCH v7 1/4] KVM: stats: Separate generic stats from architecture specific ones

2021-06-08 Thread Krish Sadhukhan
uot;directed_yield_successful", directed_yield_successful),
@@ -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_GENERIC("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 2f34487e21f2..1870fa928762 100644
--- a/include/linux/kvm_host.h
+++ b/include/linux/kvm_host.h
@@ -1243,10 +1243,15 @@ struct kvm_stats_debugfs_item {
  #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_GENERIC(n, x, ...)\
+   { n, offsetof(struct kvm, stat.generic.x), KVM_STAT_VM, ## __VA_ARGS__ }
+#define VCPU_STAT_GENERIC(n, x, ...)  \
+   { n, offsetof(struct kvm_vcpu, stat.generic.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..7c39489f9953 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_generic {

+   ulong remote_tlb_flush;
+};
+
+struct kvm_vcpu_stat_generic {
+   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 6b4feb92dc79..f6ad5b080994 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.generic.remote_tlb_flush;
cmpxchg(&kvm->tlbs_dirty, dirty_count, 0);
  }
  EXPORT_SYMBOL_GPL(kvm_flush_remote_tlbs);
@@ -2940,9 +2940,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.generic.halt_poll_fail_ns += poll_ns;
else
-   vcpu->stat.halt_poll_success_ns += poll_ns;
+   vcpu->stat.generic.halt_poll_success_ns += poll_ns;
  }
  
  /*

@@ -2960,16 +2960,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.generic.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.generic.halt_successful_poll;
if (!vcpu_valid_wakeup(vcpu))
-   ++vcpu->stat.halt_poll_invalid;
+   ++vcpu->stat.generic.halt_poll_invalid;
goto out;
}
poll_end = cur = ktime_get();
@@ -3027,7 +3027,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.generic.halt_wakeup;
return true;
}
  


Reviewed-by: Krish Sadhukhan 

___
kvmarm mailing list
kvmarm@lists.cs.columbia.edu
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm


Re: [PATCH v6 4/4] KVM: selftests: Add selftest for KVM statistics data binary interface

2021-05-27 Thread Krish Sadhukhan


On 5/24/21 8:18 AM, Jing Zhang wrote:

Add selftest to check KVM stats descriptors validity.

Reviewed-by: David Matlack 
Reviewed-by: Ricardo Koller 
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| 216 ++
  tools/testing/selftests/kvm/lib/kvm_util.c|  12 +
  5 files changed, 235 insertions(+)
  create mode 100644 tools/testing/selftests/kvm/kvm_bin_form_stats.c



We should probably follow the naming convention for the majority of the 
files in the kvm directory and name it kvm_stats_read_test.c or 
kvm_stats_test.c or something like that.




diff --git a/tools/testing/selftests/kvm/.gitignore 
b/tools/testing/selftests/kvm/.gitignore
index bd83158e0e0b..35796667c944 100644
--- a/tools/testing/selftests/kvm/.gitignore
+++ b/tools/testing/selftests/kvm/.gitignore
@@ -43,3 +43,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 e439d027939d..2984c86c848a 100644
--- a/tools/testing/selftests/kvm/Makefile
+++ b/tools/testing/selftests/kvm/Makefile
@@ -76,6 +76,7 @@ TEST_GEN_PROGS_x86_64 += kvm_page_table_test
  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
@@ -87,6 +88,7 @@ TEST_GEN_PROGS_aarch64 += kvm_create_max_vcpus
  TEST_GEN_PROGS_aarch64 += kvm_page_table_test
  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
@@ -96,6 +98,7 @@ TEST_GEN_PROGS_s390x += dirty_log_test
  TEST_GEN_PROGS_s390x += kvm_create_max_vcpus
  TEST_GEN_PROGS_s390x += kvm_page_table_test
  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 a8f022794ce3..ee01a67022d9 100644
--- a/tools/testing/selftests/kvm/include/kvm_util.h
+++ b/tools/testing/selftests/kvm/include/kvm_util.h
@@ -387,4 +387,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 ..09e12c5838af
--- /dev/null
+++ b/tools/testing/selftests/kvm/kvm_bin_form_stats.c
@@ -0,0 +1,216 @@
+// 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 stats_test(int stats_fd, int size_stat)



The return value is not used by the caller. Perhaps make it a void ?


+{
+   ssize_t ret;
+   int i;
+   size_t size_desc, size_data = 0;
+   struct kvm_stats_header header;
+   struct kvm_stats_desc *stats_desc, *pdesc;
+   void *stats_data;
+
+   /* Read kvm stats header */
+   ret = read(stats_fd, &header, sizeof(header));
+   TEST_ASSERT(ret == sizeof(header), "Read stats header");
+   size_desc = sizeof(*stats_desc) + header.name_size;
+
+   /* Check id string in header, that should start with "kvm" */
+   TEST_ASSERT(!strncmp(header.id, "kvm", 3) &&
+   strlen(header.id) < KVM_STATS_ID_MAXLEN,
+   "Invalid KVM stats type");
+
+   /* Sanity check for other fields in header */
+   if (header.count == 0)



Does this need a message as to why count is zero ?


+   return 0;
+   /* Check overlap */
+   TEST_ASSERT(header.desc_offset > 0 && header.data_offset > 0
+   && header.desc_offset >= sizeof(header)
+   && header.data_offset >= sizeof(header),
+   "Invalid offset fields in header");
+   TEST_ASSERT(header.desc_offset > header.data_offset
+   || (header.desc_offset + size_desc * header.count <=
+ 

Re: [PATCH v6 2/4] KVM: stats: Add fd-based API to read binary stats data

2021-05-27 Thread Krish Sadhukhan


On 5/24/21 8:18 AM, Jing Zhang wrote:

Provides a file descriptor per VM to read VM stats info/data.
Provides a file descriptor per vCPU to read vCPU stats info/data.

Reviewed-by: David Matlack
Reviewed-by: Ricardo Koller
Signed-off-by: Jing Zhang
---
  arch/arm64/kvm/guest.c|  26 ++
  arch/mips/kvm/mips.c  |  52 
  arch/powerpc/kvm/book3s.c |  52 
  arch/powerpc/kvm/booke.c  |  45 +++
  arch/s390/kvm/kvm-s390.c  | 117 +++
  arch/x86/kvm/x86.c|  53 
  include/linux/kvm_host.h  | 132 ++
  include/uapi/linux/kvm.h  |  50 
  virt/kvm/kvm_main.c   | 165 ++
  9 files changed, 692 insertions(+)

diff --git a/arch/arm64/kvm/guest.c b/arch/arm64/kvm/guest.c
index 0e41331b0911..1cc1d83630ac 100644
--- a/arch/arm64/kvm/guest.c
+++ b/arch/arm64/kvm/guest.c
@@ -28,6 +28,32 @@
  
  #include "trace.h"
  
+struct _kvm_stats_desc kvm_vm_stats_desc[] = DEFINE_VM_STATS_DESC();

+
+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[] = DEFINE_VCPU_STATS_DESC(
+   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 f4fc60c05e9c..f17a65743ccd 100644 --- 
a/arch/mips/kvm/mips.c +++ b/arch/mips/kvm/mips.c @@ -38,6 +38,58 @@ 
#define VECTORSPACING 0x100 /* for EI/VI mode */ #endif +struct 
_kvm_stats_desc kvm_vm_stats_desc[] = DEFINE_VM_STATS_DESC(); + 
+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[] = 
DEFINE_VCPU_STATS_DESC( + 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 bd3a10e1fdaf..5e8ee0d39ef9 100644
--- a/arch/powerpc/kvm/book3s.c
+++ b/arch/powerpc/kvm/book3s.c
@@ -38,6 +38,58 @@
  
  /* #define EXIT_DEBUG */
  
+struct _kvm_stats_desc kvm_vm_stats_desc[] = DEFINE_VM_STATS_DESC(

+   STATS_DESC_ICOUNTER("num_2M_pages"),
+   STATS_DESC_ICOUNTER("num_1G_pages"));
+
+struct _kvm_stats_header kvm_vm_sta

Re: [PATCH v6 1/4] KVM: stats: Separate common stats from architecture specific ones

2021-05-26 Thread Krish Sadhukhan


On 5/24/21 8:18 AM, Jing Zhang wrote:

Put all common statistics in a separate structure to ease
statistics handling for the incoming new statistics API.

No functional change intended.

Reviewed-by: David Matlack 
Reviewed-by: Ricardo Koller 
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|  9 +++--
  include/linux/kvm_types.h   | 12 
  virt/kvm/kvm_main.c | 14 +++---
  17 files changed, 82 insertions(+), 90 deletions(-)

diff --git a/arch/arm64/include/asm/kvm_host.h 
b/arch/arm64/include/asm/kvm_host.h
index 7cd7d5c8c4bc..f3ad7a20b0af 100644
--- a/arch/arm64/include/asm/kvm_host.h
+++ b/arch/arm64/include/asm/kvm_host.h
@@ -556,16 +556,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 5cb4a1cd5603..0e41331b0911 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 fca4547d580f..6f610fbcd8d1 100644
--- a/arch/mips/include/asm/kvm_host.h
+++ b/arch/mips/include/asm/kvm_host.h
@@ -109,10 +109,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;
@@ -142,12 +143,6 @@ struct kvm_vcpu_stat {
  #ifdef CONFIG_CPU_LOONGSON64
u64 vz_cpucfg_exits;
  #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 4d4af97dcc88..f4fc60c05e9c 100644
--- a/arch/mips/kvm/mips.c
+++ b/arch/mips/kvm/mips.c
@@ -68,12 +68,12 @@ struct kvm_stats_debugfs_item debugfs_entries[] = {
  #ifdef CONFIG_CPU_LOONGSON64
VCPU_STAT("vz_cpucfg", vz_cpucfg_exits),
  #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)

Re: [PATCH v5 1/4] KVM: stats: Separate common stats from architecture specific ones

2021-05-18 Thread Krish Sadhukhan



On 5/18/21 10:25 AM, Jing Zhang wrote:

Hi David,

On Tue, May 18, 2021 at 11:27 AM David Matlack  wrote:

On Mon, May 17, 2021 at 5:10 PM Jing Zhang  wrote:


Actually the definition of kvm_{vcpu,vm}_stat are arch specific. There is
no real structure for arch agnostic stats. Most of the stats in common
structures are arch agnostic, but not all of them.
There are some benefits to put all common stats in a separate structure.
e.g. if we want to add a stat in kvm_main.c, we only need to add this stat
in the common structure, don't have to update all kvm_{vcpu,vm}_stat
definition for all architectures.

I meant rename the existing arch-specific struct kvm_{vcpu,vm}_stat to
kvm_{vcpu,vm}_stat_arch and rename struct kvm_{vcpu,vm}_stat_common to
kvm_{vcpu,vm}_stat.

So in  include/linux/kvm_types.h you'd have:

struct kvm_vm_stat {
   ulong remote_tlb_flush;
   struct kvm_vm_stat_arch arch;
};

struct kvm_vcpu_stat {
   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;
   struct kvm_vcpu_stat_arch arch;
};

And in arch/x86/include/asm/kvm_host.h you'd have:

struct kvm_vm_stat_arch {
   ulong mmu_shadow_zapped;
   ...
};

struct kvm_vcpu_stat_arch {
   u64 pf_fixed;
   u64 pf_guest;
   u64 tlb_flush;
   ...
};

You still have the same benefits of having an arch-neutral place to
store stats but the struct layout more closely resembles struct
kvm_vcpu and struct kvm.

You are right. This is a more reasonable way to layout the structures.
I remember that I didn't choose this way is only because that it needs
touching every arch specific stats in all architectures (stat.name ->
stat.arch.name) instead of only touching arch neutral stats.
Let's see if there is any vote from others about this.



+1



Thanks,
Jing

___
kvmarm mailing list
kvmarm@lists.cs.columbia.edu
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm