Commit f95937cc authored by Jing Zhang's avatar Jing Zhang Committed by Paolo Bonzini

KVM: stats: Support linear and logarithmic histogram statistics

Add new types of KVM stats, linear and logarithmic histogram.
Histogram are very useful for observing the value distribution
of time or size related stats.
Signed-off-by: default avatarJing Zhang <jingzhangos@google.com>
Message-Id: <20210802165633.1866976-2-jingzhangos@google.com>
Signed-off-by: default avatarPaolo Bonzini <pbonzini@redhat.com>
parent 73143035
...@@ -31,8 +31,6 @@ ...@@ -31,8 +31,6 @@
const struct _kvm_stats_desc kvm_vm_stats_desc[] = { const struct _kvm_stats_desc kvm_vm_stats_desc[] = {
KVM_GENERIC_VM_STATS() KVM_GENERIC_VM_STATS()
}; };
static_assert(ARRAY_SIZE(kvm_vm_stats_desc) ==
sizeof(struct kvm_vm_stat) / sizeof(u64));
const struct kvm_stats_header kvm_vm_stats_header = { const struct kvm_stats_header kvm_vm_stats_header = {
.name_size = KVM_STATS_NAME_SIZE, .name_size = KVM_STATS_NAME_SIZE,
...@@ -52,8 +50,6 @@ const struct _kvm_stats_desc kvm_vcpu_stats_desc[] = { ...@@ -52,8 +50,6 @@ const struct _kvm_stats_desc kvm_vcpu_stats_desc[] = {
STATS_DESC_COUNTER(VCPU, mmio_exit_kernel), STATS_DESC_COUNTER(VCPU, mmio_exit_kernel),
STATS_DESC_COUNTER(VCPU, exits) STATS_DESC_COUNTER(VCPU, exits)
}; };
static_assert(ARRAY_SIZE(kvm_vcpu_stats_desc) ==
sizeof(struct kvm_vcpu_stat) / sizeof(u64));
const struct kvm_stats_header kvm_vcpu_stats_header = { const struct kvm_stats_header kvm_vcpu_stats_header = {
.name_size = KVM_STATS_NAME_SIZE, .name_size = KVM_STATS_NAME_SIZE,
......
...@@ -41,8 +41,6 @@ ...@@ -41,8 +41,6 @@
const struct _kvm_stats_desc kvm_vm_stats_desc[] = { const struct _kvm_stats_desc kvm_vm_stats_desc[] = {
KVM_GENERIC_VM_STATS() KVM_GENERIC_VM_STATS()
}; };
static_assert(ARRAY_SIZE(kvm_vm_stats_desc) ==
sizeof(struct kvm_vm_stat) / sizeof(u64));
const struct kvm_stats_header kvm_vm_stats_header = { const struct kvm_stats_header kvm_vm_stats_header = {
.name_size = KVM_STATS_NAME_SIZE, .name_size = KVM_STATS_NAME_SIZE,
...@@ -85,8 +83,6 @@ const struct _kvm_stats_desc kvm_vcpu_stats_desc[] = { ...@@ -85,8 +83,6 @@ const struct _kvm_stats_desc kvm_vcpu_stats_desc[] = {
STATS_DESC_COUNTER(VCPU, vz_cpucfg_exits), STATS_DESC_COUNTER(VCPU, vz_cpucfg_exits),
#endif #endif
}; };
static_assert(ARRAY_SIZE(kvm_vcpu_stats_desc) ==
sizeof(struct kvm_vcpu_stat) / sizeof(u64));
const struct kvm_stats_header kvm_vcpu_stats_header = { const struct kvm_stats_header kvm_vcpu_stats_header = {
.name_size = KVM_STATS_NAME_SIZE, .name_size = KVM_STATS_NAME_SIZE,
......
...@@ -43,8 +43,6 @@ const struct _kvm_stats_desc kvm_vm_stats_desc[] = { ...@@ -43,8 +43,6 @@ const struct _kvm_stats_desc kvm_vm_stats_desc[] = {
STATS_DESC_ICOUNTER(VM, num_2M_pages), STATS_DESC_ICOUNTER(VM, num_2M_pages),
STATS_DESC_ICOUNTER(VM, num_1G_pages) STATS_DESC_ICOUNTER(VM, num_1G_pages)
}; };
static_assert(ARRAY_SIZE(kvm_vm_stats_desc) ==
sizeof(struct kvm_vm_stat) / sizeof(u64));
const struct kvm_stats_header kvm_vm_stats_header = { const struct kvm_stats_header kvm_vm_stats_header = {
.name_size = KVM_STATS_NAME_SIZE, .name_size = KVM_STATS_NAME_SIZE,
...@@ -88,8 +86,6 @@ const struct _kvm_stats_desc kvm_vcpu_stats_desc[] = { ...@@ -88,8 +86,6 @@ const struct _kvm_stats_desc kvm_vcpu_stats_desc[] = {
STATS_DESC_COUNTER(VCPU, pthru_host), STATS_DESC_COUNTER(VCPU, pthru_host),
STATS_DESC_COUNTER(VCPU, pthru_bad_aff) STATS_DESC_COUNTER(VCPU, pthru_bad_aff)
}; };
static_assert(ARRAY_SIZE(kvm_vcpu_stats_desc) ==
sizeof(struct kvm_vcpu_stat) / sizeof(u64));
const struct kvm_stats_header kvm_vcpu_stats_header = { const struct kvm_stats_header kvm_vcpu_stats_header = {
.name_size = KVM_STATS_NAME_SIZE, .name_size = KVM_STATS_NAME_SIZE,
......
...@@ -41,8 +41,6 @@ const struct _kvm_stats_desc kvm_vm_stats_desc[] = { ...@@ -41,8 +41,6 @@ const struct _kvm_stats_desc kvm_vm_stats_desc[] = {
STATS_DESC_ICOUNTER(VM, num_2M_pages), STATS_DESC_ICOUNTER(VM, num_2M_pages),
STATS_DESC_ICOUNTER(VM, num_1G_pages) STATS_DESC_ICOUNTER(VM, num_1G_pages)
}; };
static_assert(ARRAY_SIZE(kvm_vm_stats_desc) ==
sizeof(struct kvm_vm_stat) / sizeof(u64));
const struct kvm_stats_header kvm_vm_stats_header = { const struct kvm_stats_header kvm_vm_stats_header = {
.name_size = KVM_STATS_NAME_SIZE, .name_size = KVM_STATS_NAME_SIZE,
...@@ -79,8 +77,6 @@ const struct _kvm_stats_desc kvm_vcpu_stats_desc[] = { ...@@ -79,8 +77,6 @@ const struct _kvm_stats_desc kvm_vcpu_stats_desc[] = {
STATS_DESC_COUNTER(VCPU, pthru_host), STATS_DESC_COUNTER(VCPU, pthru_host),
STATS_DESC_COUNTER(VCPU, pthru_bad_aff) STATS_DESC_COUNTER(VCPU, pthru_bad_aff)
}; };
static_assert(ARRAY_SIZE(kvm_vcpu_stats_desc) ==
sizeof(struct kvm_vcpu_stat) / sizeof(u64));
const struct kvm_stats_header kvm_vcpu_stats_header = { const struct kvm_stats_header kvm_vcpu_stats_header = {
.name_size = KVM_STATS_NAME_SIZE, .name_size = KVM_STATS_NAME_SIZE,
......
...@@ -66,8 +66,6 @@ const struct _kvm_stats_desc kvm_vm_stats_desc[] = { ...@@ -66,8 +66,6 @@ const struct _kvm_stats_desc kvm_vm_stats_desc[] = {
STATS_DESC_COUNTER(VM, inject_service_signal), STATS_DESC_COUNTER(VM, inject_service_signal),
STATS_DESC_COUNTER(VM, inject_virtio) STATS_DESC_COUNTER(VM, inject_virtio)
}; };
static_assert(ARRAY_SIZE(kvm_vm_stats_desc) ==
sizeof(struct kvm_vm_stat) / sizeof(u64));
const struct kvm_stats_header kvm_vm_stats_header = { const struct kvm_stats_header kvm_vm_stats_header = {
.name_size = KVM_STATS_NAME_SIZE, .name_size = KVM_STATS_NAME_SIZE,
...@@ -174,8 +172,6 @@ const struct _kvm_stats_desc kvm_vcpu_stats_desc[] = { ...@@ -174,8 +172,6 @@ const struct _kvm_stats_desc kvm_vcpu_stats_desc[] = {
STATS_DESC_COUNTER(VCPU, instruction_diagnose_other), STATS_DESC_COUNTER(VCPU, instruction_diagnose_other),
STATS_DESC_COUNTER(VCPU, pfault_sync) STATS_DESC_COUNTER(VCPU, pfault_sync)
}; };
static_assert(ARRAY_SIZE(kvm_vcpu_stats_desc) ==
sizeof(struct kvm_vcpu_stat) / sizeof(u64));
const struct kvm_stats_header kvm_vcpu_stats_header = { const struct kvm_stats_header kvm_vcpu_stats_header = {
.name_size = KVM_STATS_NAME_SIZE, .name_size = KVM_STATS_NAME_SIZE,
......
...@@ -238,8 +238,6 @@ const struct _kvm_stats_desc kvm_vm_stats_desc[] = { ...@@ -238,8 +238,6 @@ const struct _kvm_stats_desc kvm_vm_stats_desc[] = {
STATS_DESC_PCOUNTER(VM, max_mmu_rmap_size), STATS_DESC_PCOUNTER(VM, max_mmu_rmap_size),
STATS_DESC_PCOUNTER(VM, max_mmu_page_hash_collisions) STATS_DESC_PCOUNTER(VM, max_mmu_page_hash_collisions)
}; };
static_assert(ARRAY_SIZE(kvm_vm_stats_desc) ==
sizeof(struct kvm_vm_stat) / sizeof(u64));
const struct kvm_stats_header kvm_vm_stats_header = { const struct kvm_stats_header kvm_vm_stats_header = {
.name_size = KVM_STATS_NAME_SIZE, .name_size = KVM_STATS_NAME_SIZE,
...@@ -279,8 +277,6 @@ const struct _kvm_stats_desc kvm_vcpu_stats_desc[] = { ...@@ -279,8 +277,6 @@ const struct _kvm_stats_desc kvm_vcpu_stats_desc[] = {
STATS_DESC_COUNTER(VCPU, directed_yield_successful), STATS_DESC_COUNTER(VCPU, directed_yield_successful),
STATS_DESC_ICOUNTER(VCPU, guest_mode) STATS_DESC_ICOUNTER(VCPU, guest_mode)
}; };
static_assert(ARRAY_SIZE(kvm_vcpu_stats_desc) ==
sizeof(struct kvm_vcpu_stat) / sizeof(u64));
const struct kvm_stats_header kvm_vcpu_stats_header = { const struct kvm_stats_header kvm_vcpu_stats_header = {
.name_size = KVM_STATS_NAME_SIZE, .name_size = KVM_STATS_NAME_SIZE,
......
...@@ -1356,56 +1356,66 @@ struct _kvm_stats_desc { ...@@ -1356,56 +1356,66 @@ struct _kvm_stats_desc {
char name[KVM_STATS_NAME_SIZE]; char name[KVM_STATS_NAME_SIZE];
}; };
#define STATS_DESC_COMMON(type, unit, base, exp) \ #define STATS_DESC_COMMON(type, unit, base, exp, sz, bsz) \
.flags = type | unit | base | \ .flags = type | unit | base | \
BUILD_BUG_ON_ZERO(type & ~KVM_STATS_TYPE_MASK) | \ BUILD_BUG_ON_ZERO(type & ~KVM_STATS_TYPE_MASK) | \
BUILD_BUG_ON_ZERO(unit & ~KVM_STATS_UNIT_MASK) | \ BUILD_BUG_ON_ZERO(unit & ~KVM_STATS_UNIT_MASK) | \
BUILD_BUG_ON_ZERO(base & ~KVM_STATS_BASE_MASK), \ BUILD_BUG_ON_ZERO(base & ~KVM_STATS_BASE_MASK), \
.exponent = exp, \ .exponent = exp, \
.size = 1 .size = sz, \
.bucket_size = bsz
#define VM_GENERIC_STATS_DESC(stat, type, unit, base, exp) \ #define VM_GENERIC_STATS_DESC(stat, type, unit, base, exp, sz, bsz) \
{ \ { \
{ \ { \
STATS_DESC_COMMON(type, unit, base, exp), \ STATS_DESC_COMMON(type, unit, base, exp, sz, bsz), \
.offset = offsetof(struct kvm_vm_stat, generic.stat) \ .offset = offsetof(struct kvm_vm_stat, generic.stat) \
}, \ }, \
.name = #stat, \ .name = #stat, \
} }
#define VCPU_GENERIC_STATS_DESC(stat, type, unit, base, exp) \ #define VCPU_GENERIC_STATS_DESC(stat, type, unit, base, exp, sz, bsz) \
{ \ { \
{ \ { \
STATS_DESC_COMMON(type, unit, base, exp), \ STATS_DESC_COMMON(type, unit, base, exp, sz, bsz), \
.offset = offsetof(struct kvm_vcpu_stat, generic.stat) \ .offset = offsetof(struct kvm_vcpu_stat, generic.stat) \
}, \ }, \
.name = #stat, \ .name = #stat, \
} }
#define VM_STATS_DESC(stat, type, unit, base, exp) \ #define VM_STATS_DESC(stat, type, unit, base, exp, sz, bsz) \
{ \ { \
{ \ { \
STATS_DESC_COMMON(type, unit, base, exp), \ STATS_DESC_COMMON(type, unit, base, exp, sz, bsz), \
.offset = offsetof(struct kvm_vm_stat, stat) \ .offset = offsetof(struct kvm_vm_stat, stat) \
}, \ }, \
.name = #stat, \ .name = #stat, \
} }
#define VCPU_STATS_DESC(stat, type, unit, base, exp) \ #define VCPU_STATS_DESC(stat, type, unit, base, exp, sz, bsz) \
{ \ { \
{ \ { \
STATS_DESC_COMMON(type, unit, base, exp), \ STATS_DESC_COMMON(type, unit, base, exp, sz, bsz), \
.offset = offsetof(struct kvm_vcpu_stat, stat) \ .offset = offsetof(struct kvm_vcpu_stat, stat) \
}, \ }, \
.name = #stat, \ .name = #stat, \
} }
/* SCOPE: VM, VM_GENERIC, VCPU, VCPU_GENERIC */ /* SCOPE: VM, VM_GENERIC, VCPU, VCPU_GENERIC */
#define STATS_DESC(SCOPE, stat, type, unit, base, exp) \ #define STATS_DESC(SCOPE, stat, type, unit, base, exp, sz, bsz) \
SCOPE##_STATS_DESC(stat, type, unit, base, exp) SCOPE##_STATS_DESC(stat, type, unit, base, exp, sz, bsz)
#define STATS_DESC_CUMULATIVE(SCOPE, name, unit, base, exponent) \ #define STATS_DESC_CUMULATIVE(SCOPE, name, unit, base, exponent) \
STATS_DESC(SCOPE, name, KVM_STATS_TYPE_CUMULATIVE, unit, base, exponent) STATS_DESC(SCOPE, name, KVM_STATS_TYPE_CUMULATIVE, \
unit, base, exponent, 1, 0)
#define STATS_DESC_INSTANT(SCOPE, name, unit, base, exponent) \ #define STATS_DESC_INSTANT(SCOPE, name, unit, base, exponent) \
STATS_DESC(SCOPE, name, KVM_STATS_TYPE_INSTANT, unit, base, exponent) STATS_DESC(SCOPE, name, KVM_STATS_TYPE_INSTANT, \
unit, base, exponent, 1, 0)
#define STATS_DESC_PEAK(SCOPE, name, unit, base, exponent) \ #define STATS_DESC_PEAK(SCOPE, name, unit, base, exponent) \
STATS_DESC(SCOPE, name, KVM_STATS_TYPE_PEAK, unit, base, exponent) STATS_DESC(SCOPE, name, KVM_STATS_TYPE_PEAK, \
unit, base, exponent, 1, 0)
#define STATS_DESC_LINEAR_HIST(SCOPE, name, unit, base, exponent, sz, bsz) \
STATS_DESC(SCOPE, name, KVM_STATS_TYPE_LINEAR_HIST, \
unit, base, exponent, sz, bsz)
#define STATS_DESC_LOG_HIST(SCOPE, name, unit, base, exponent, sz) \
STATS_DESC(SCOPE, name, KVM_STATS_TYPE_LOG_HIST, \
unit, base, exponent, sz, 0)
/* Cumulative counter, read/write */ /* Cumulative counter, read/write */
#define STATS_DESC_COUNTER(SCOPE, name) \ #define STATS_DESC_COUNTER(SCOPE, name) \
...@@ -1424,6 +1434,14 @@ struct _kvm_stats_desc { ...@@ -1424,6 +1434,14 @@ struct _kvm_stats_desc {
#define STATS_DESC_TIME_NSEC(SCOPE, name) \ #define STATS_DESC_TIME_NSEC(SCOPE, name) \
STATS_DESC_CUMULATIVE(SCOPE, name, KVM_STATS_UNIT_SECONDS, \ STATS_DESC_CUMULATIVE(SCOPE, name, KVM_STATS_UNIT_SECONDS, \
KVM_STATS_BASE_POW10, -9) KVM_STATS_BASE_POW10, -9)
/* Linear histogram for time in nanosecond */
#define STATS_DESC_LINHIST_TIME_NSEC(SCOPE, name, sz, bsz) \
STATS_DESC_LINEAR_HIST(SCOPE, name, KVM_STATS_UNIT_SECONDS, \
KVM_STATS_BASE_POW10, -9, sz, bsz)
/* Logarithmic histogram for time in nanosecond */
#define STATS_DESC_LOGHIST_TIME_NSEC(SCOPE, name, sz) \
STATS_DESC_LOG_HIST(SCOPE, name, KVM_STATS_UNIT_SECONDS, \
KVM_STATS_BASE_POW10, -9, sz)
#define KVM_GENERIC_VM_STATS() \ #define KVM_GENERIC_VM_STATS() \
STATS_DESC_COUNTER(VM_GENERIC, remote_tlb_flush) STATS_DESC_COUNTER(VM_GENERIC, remote_tlb_flush)
...@@ -1437,10 +1455,52 @@ struct _kvm_stats_desc { ...@@ -1437,10 +1455,52 @@ struct _kvm_stats_desc {
STATS_DESC_TIME_NSEC(VCPU_GENERIC, halt_poll_fail_ns) STATS_DESC_TIME_NSEC(VCPU_GENERIC, halt_poll_fail_ns)
extern struct dentry *kvm_debugfs_dir; extern struct dentry *kvm_debugfs_dir;
ssize_t kvm_stats_read(char *id, const struct kvm_stats_header *header, ssize_t kvm_stats_read(char *id, const struct kvm_stats_header *header,
const struct _kvm_stats_desc *desc, const struct _kvm_stats_desc *desc,
void *stats, size_t size_stats, void *stats, size_t size_stats,
char __user *user_buffer, size_t size, loff_t *offset); char __user *user_buffer, size_t size, loff_t *offset);
/**
* kvm_stats_linear_hist_update() - Update bucket value for linear histogram
* statistics data.
*
* @data: start address of the stats data
* @size: the number of bucket of the stats data
* @value: the new value used to update the linear histogram's bucket
* @bucket_size: the size (width) of a bucket
*/
static inline void kvm_stats_linear_hist_update(u64 *data, size_t size,
u64 value, size_t bucket_size)
{
size_t index = div64_u64(value, bucket_size);
index = min(index, size - 1);
++data[index];
}
/**
* kvm_stats_log_hist_update() - Update bucket value for logarithmic histogram
* statistics data.
*
* @data: start address of the stats data
* @size: the number of bucket of the stats data
* @value: the new value used to update the logarithmic histogram's bucket
*/
static inline void kvm_stats_log_hist_update(u64 *data, size_t size, u64 value)
{
size_t index = fls64(value);
index = min(index, size - 1);
++data[index];
}
#define KVM_STATS_LINEAR_HIST_UPDATE(array, value, bsize) \
kvm_stats_linear_hist_update(array, ARRAY_SIZE(array), value, bsize)
#define KVM_STATS_LOG_HIST_UPDATE(array, value) \
kvm_stats_log_hist_update(array, ARRAY_SIZE(array), value)
extern const struct kvm_stats_header kvm_vm_stats_header; extern const struct kvm_stats_header kvm_vm_stats_header;
extern const struct _kvm_stats_desc kvm_vm_stats_desc[]; extern const struct _kvm_stats_desc kvm_vm_stats_desc[];
extern const struct kvm_stats_header kvm_vcpu_stats_header; extern const struct kvm_stats_header kvm_vcpu_stats_header;
......
...@@ -1965,7 +1965,9 @@ struct kvm_stats_header { ...@@ -1965,7 +1965,9 @@ struct kvm_stats_header {
#define KVM_STATS_TYPE_CUMULATIVE (0x0 << 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_INSTANT (0x1 << KVM_STATS_TYPE_SHIFT)
#define KVM_STATS_TYPE_PEAK (0x2 << KVM_STATS_TYPE_SHIFT) #define KVM_STATS_TYPE_PEAK (0x2 << KVM_STATS_TYPE_SHIFT)
#define KVM_STATS_TYPE_MAX KVM_STATS_TYPE_PEAK #define KVM_STATS_TYPE_LINEAR_HIST (0x3 << KVM_STATS_TYPE_SHIFT)
#define KVM_STATS_TYPE_LOG_HIST (0x4 << KVM_STATS_TYPE_SHIFT)
#define KVM_STATS_TYPE_MAX KVM_STATS_TYPE_LOG_HIST
#define KVM_STATS_UNIT_SHIFT 4 #define KVM_STATS_UNIT_SHIFT 4
#define KVM_STATS_UNIT_MASK (0xF << KVM_STATS_UNIT_SHIFT) #define KVM_STATS_UNIT_MASK (0xF << KVM_STATS_UNIT_SHIFT)
...@@ -1988,8 +1990,9 @@ struct kvm_stats_header { ...@@ -1988,8 +1990,9 @@ struct kvm_stats_header {
* @size: The number of data items for this stats. * @size: The number of data items for this stats.
* Every data item is of type __u64. * Every data item is of type __u64.
* @offset: The offset of the stats to the start of stat structure in * @offset: The offset of the stats to the start of stat structure in
* struture kvm or kvm_vcpu. * structure kvm or kvm_vcpu.
* @unused: Unused field for future usage. Always 0 for now. * @bucket_size: A parameter value used for histogram stats. It is only used
* for linear histogram stats, specifying the size of the bucket;
* @name: The name string for the stats. Its size is indicated by the * @name: The name string for the stats. Its size is indicated by the
* &kvm_stats_header->name_size. * &kvm_stats_header->name_size.
*/ */
...@@ -1998,7 +2001,7 @@ struct kvm_stats_desc { ...@@ -1998,7 +2001,7 @@ struct kvm_stats_desc {
__s16 exponent; __s16 exponent;
__u16 size; __u16 size;
__u32 offset; __u32 offset;
__u32 unused; __u32 bucket_size;
char name[]; char name[];
}; };
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment