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

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: Jing Zhang <jingzhangos@google.com>
Message-Id: <20210802165633.1866976-2-jingzhangos@google.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>

authored by

Jing Zhang and committed by
Paolo Bonzini
f95937cc 73143035

+82 -43
-4
arch/arm64/kvm/guest.c
··· 31 31 const struct _kvm_stats_desc kvm_vm_stats_desc[] = { 32 32 KVM_GENERIC_VM_STATS() 33 33 }; 34 - static_assert(ARRAY_SIZE(kvm_vm_stats_desc) == 35 - sizeof(struct kvm_vm_stat) / sizeof(u64)); 36 34 37 35 const struct kvm_stats_header kvm_vm_stats_header = { 38 36 .name_size = KVM_STATS_NAME_SIZE, ··· 50 52 STATS_DESC_COUNTER(VCPU, mmio_exit_kernel), 51 53 STATS_DESC_COUNTER(VCPU, exits) 52 54 }; 53 - static_assert(ARRAY_SIZE(kvm_vcpu_stats_desc) == 54 - sizeof(struct kvm_vcpu_stat) / sizeof(u64)); 55 55 56 56 const struct kvm_stats_header kvm_vcpu_stats_header = { 57 57 .name_size = KVM_STATS_NAME_SIZE,
-4
arch/mips/kvm/mips.c
··· 41 41 const struct _kvm_stats_desc kvm_vm_stats_desc[] = { 42 42 KVM_GENERIC_VM_STATS() 43 43 }; 44 - static_assert(ARRAY_SIZE(kvm_vm_stats_desc) == 45 - sizeof(struct kvm_vm_stat) / sizeof(u64)); 46 44 47 45 const struct kvm_stats_header kvm_vm_stats_header = { 48 46 .name_size = KVM_STATS_NAME_SIZE, ··· 83 85 STATS_DESC_COUNTER(VCPU, vz_cpucfg_exits), 84 86 #endif 85 87 }; 86 - static_assert(ARRAY_SIZE(kvm_vcpu_stats_desc) == 87 - sizeof(struct kvm_vcpu_stat) / sizeof(u64)); 88 88 89 89 const struct kvm_stats_header kvm_vcpu_stats_header = { 90 90 .name_size = KVM_STATS_NAME_SIZE,
-4
arch/powerpc/kvm/book3s.c
··· 43 43 STATS_DESC_ICOUNTER(VM, num_2M_pages), 44 44 STATS_DESC_ICOUNTER(VM, num_1G_pages) 45 45 }; 46 - static_assert(ARRAY_SIZE(kvm_vm_stats_desc) == 47 - sizeof(struct kvm_vm_stat) / sizeof(u64)); 48 46 49 47 const struct kvm_stats_header kvm_vm_stats_header = { 50 48 .name_size = KVM_STATS_NAME_SIZE, ··· 86 88 STATS_DESC_COUNTER(VCPU, pthru_host), 87 89 STATS_DESC_COUNTER(VCPU, pthru_bad_aff) 88 90 }; 89 - static_assert(ARRAY_SIZE(kvm_vcpu_stats_desc) == 90 - sizeof(struct kvm_vcpu_stat) / sizeof(u64)); 91 91 92 92 const struct kvm_stats_header kvm_vcpu_stats_header = { 93 93 .name_size = KVM_STATS_NAME_SIZE,
-4
arch/powerpc/kvm/booke.c
··· 41 41 STATS_DESC_ICOUNTER(VM, num_2M_pages), 42 42 STATS_DESC_ICOUNTER(VM, num_1G_pages) 43 43 }; 44 - static_assert(ARRAY_SIZE(kvm_vm_stats_desc) == 45 - sizeof(struct kvm_vm_stat) / sizeof(u64)); 46 44 47 45 const struct kvm_stats_header kvm_vm_stats_header = { 48 46 .name_size = KVM_STATS_NAME_SIZE, ··· 77 79 STATS_DESC_COUNTER(VCPU, pthru_host), 78 80 STATS_DESC_COUNTER(VCPU, pthru_bad_aff) 79 81 }; 80 - static_assert(ARRAY_SIZE(kvm_vcpu_stats_desc) == 81 - sizeof(struct kvm_vcpu_stat) / sizeof(u64)); 82 82 83 83 const struct kvm_stats_header kvm_vcpu_stats_header = { 84 84 .name_size = KVM_STATS_NAME_SIZE,
-4
arch/s390/kvm/kvm-s390.c
··· 66 66 STATS_DESC_COUNTER(VM, inject_service_signal), 67 67 STATS_DESC_COUNTER(VM, inject_virtio) 68 68 }; 69 - static_assert(ARRAY_SIZE(kvm_vm_stats_desc) == 70 - sizeof(struct kvm_vm_stat) / sizeof(u64)); 71 69 72 70 const struct kvm_stats_header kvm_vm_stats_header = { 73 71 .name_size = KVM_STATS_NAME_SIZE, ··· 172 174 STATS_DESC_COUNTER(VCPU, instruction_diagnose_other), 173 175 STATS_DESC_COUNTER(VCPU, pfault_sync) 174 176 }; 175 - static_assert(ARRAY_SIZE(kvm_vcpu_stats_desc) == 176 - sizeof(struct kvm_vcpu_stat) / sizeof(u64)); 177 177 178 178 const struct kvm_stats_header kvm_vcpu_stats_header = { 179 179 .name_size = KVM_STATS_NAME_SIZE,
-4
arch/x86/kvm/x86.c
··· 238 238 STATS_DESC_PCOUNTER(VM, max_mmu_rmap_size), 239 239 STATS_DESC_PCOUNTER(VM, max_mmu_page_hash_collisions) 240 240 }; 241 - static_assert(ARRAY_SIZE(kvm_vm_stats_desc) == 242 - sizeof(struct kvm_vm_stat) / sizeof(u64)); 243 241 244 242 const struct kvm_stats_header kvm_vm_stats_header = { 245 243 .name_size = KVM_STATS_NAME_SIZE, ··· 277 279 STATS_DESC_COUNTER(VCPU, directed_yield_successful), 278 280 STATS_DESC_ICOUNTER(VCPU, guest_mode) 279 281 }; 280 - static_assert(ARRAY_SIZE(kvm_vcpu_stats_desc) == 281 - sizeof(struct kvm_vcpu_stat) / sizeof(u64)); 282 282 283 283 const struct kvm_stats_header kvm_vcpu_stats_header = { 284 284 .name_size = KVM_STATS_NAME_SIZE,
+75 -15
include/linux/kvm_host.h
··· 1356 1356 char name[KVM_STATS_NAME_SIZE]; 1357 1357 }; 1358 1358 1359 - #define STATS_DESC_COMMON(type, unit, base, exp) \ 1359 + #define STATS_DESC_COMMON(type, unit, base, exp, sz, bsz) \ 1360 1360 .flags = type | unit | base | \ 1361 1361 BUILD_BUG_ON_ZERO(type & ~KVM_STATS_TYPE_MASK) | \ 1362 1362 BUILD_BUG_ON_ZERO(unit & ~KVM_STATS_UNIT_MASK) | \ 1363 1363 BUILD_BUG_ON_ZERO(base & ~KVM_STATS_BASE_MASK), \ 1364 1364 .exponent = exp, \ 1365 - .size = 1 1365 + .size = sz, \ 1366 + .bucket_size = bsz 1366 1367 1367 - #define VM_GENERIC_STATS_DESC(stat, type, unit, base, exp) \ 1368 + #define VM_GENERIC_STATS_DESC(stat, type, unit, base, exp, sz, bsz) \ 1368 1369 { \ 1369 1370 { \ 1370 - STATS_DESC_COMMON(type, unit, base, exp), \ 1371 + STATS_DESC_COMMON(type, unit, base, exp, sz, bsz), \ 1371 1372 .offset = offsetof(struct kvm_vm_stat, generic.stat) \ 1372 1373 }, \ 1373 1374 .name = #stat, \ 1374 1375 } 1375 - #define VCPU_GENERIC_STATS_DESC(stat, type, unit, base, exp) \ 1376 + #define VCPU_GENERIC_STATS_DESC(stat, type, unit, base, exp, sz, bsz) \ 1376 1377 { \ 1377 1378 { \ 1378 - STATS_DESC_COMMON(type, unit, base, exp), \ 1379 + STATS_DESC_COMMON(type, unit, base, exp, sz, bsz), \ 1379 1380 .offset = offsetof(struct kvm_vcpu_stat, generic.stat) \ 1380 1381 }, \ 1381 1382 .name = #stat, \ 1382 1383 } 1383 - #define VM_STATS_DESC(stat, type, unit, base, exp) \ 1384 + #define VM_STATS_DESC(stat, type, unit, base, exp, sz, bsz) \ 1384 1385 { \ 1385 1386 { \ 1386 - STATS_DESC_COMMON(type, unit, base, exp), \ 1387 + STATS_DESC_COMMON(type, unit, base, exp, sz, bsz), \ 1387 1388 .offset = offsetof(struct kvm_vm_stat, stat) \ 1388 1389 }, \ 1389 1390 .name = #stat, \ 1390 1391 } 1391 - #define VCPU_STATS_DESC(stat, type, unit, base, exp) \ 1392 + #define VCPU_STATS_DESC(stat, type, unit, base, exp, sz, bsz) \ 1392 1393 { \ 1393 1394 { \ 1394 - STATS_DESC_COMMON(type, unit, base, exp), \ 1395 + STATS_DESC_COMMON(type, unit, base, exp, sz, bsz), \ 1395 1396 .offset = offsetof(struct kvm_vcpu_stat, stat) \ 1396 1397 }, \ 1397 1398 .name = #stat, \ 1398 1399 } 1399 1400 /* SCOPE: VM, VM_GENERIC, VCPU, VCPU_GENERIC */ 1400 - #define STATS_DESC(SCOPE, stat, type, unit, base, exp) \ 1401 - SCOPE##_STATS_DESC(stat, type, unit, base, exp) 1401 + #define STATS_DESC(SCOPE, stat, type, unit, base, exp, sz, bsz) \ 1402 + SCOPE##_STATS_DESC(stat, type, unit, base, exp, sz, bsz) 1402 1403 1403 1404 #define STATS_DESC_CUMULATIVE(SCOPE, name, unit, base, exponent) \ 1404 - STATS_DESC(SCOPE, name, KVM_STATS_TYPE_CUMULATIVE, unit, base, exponent) 1405 + STATS_DESC(SCOPE, name, KVM_STATS_TYPE_CUMULATIVE, \ 1406 + unit, base, exponent, 1, 0) 1405 1407 #define STATS_DESC_INSTANT(SCOPE, name, unit, base, exponent) \ 1406 - STATS_DESC(SCOPE, name, KVM_STATS_TYPE_INSTANT, unit, base, exponent) 1408 + STATS_DESC(SCOPE, name, KVM_STATS_TYPE_INSTANT, \ 1409 + unit, base, exponent, 1, 0) 1407 1410 #define STATS_DESC_PEAK(SCOPE, name, unit, base, exponent) \ 1408 - STATS_DESC(SCOPE, name, KVM_STATS_TYPE_PEAK, unit, base, exponent) 1411 + STATS_DESC(SCOPE, name, KVM_STATS_TYPE_PEAK, \ 1412 + unit, base, exponent, 1, 0) 1413 + #define STATS_DESC_LINEAR_HIST(SCOPE, name, unit, base, exponent, sz, bsz) \ 1414 + STATS_DESC(SCOPE, name, KVM_STATS_TYPE_LINEAR_HIST, \ 1415 + unit, base, exponent, sz, bsz) 1416 + #define STATS_DESC_LOG_HIST(SCOPE, name, unit, base, exponent, sz) \ 1417 + STATS_DESC(SCOPE, name, KVM_STATS_TYPE_LOG_HIST, \ 1418 + unit, base, exponent, sz, 0) 1409 1419 1410 1420 /* Cumulative counter, read/write */ 1411 1421 #define STATS_DESC_COUNTER(SCOPE, name) \ ··· 1434 1424 #define STATS_DESC_TIME_NSEC(SCOPE, name) \ 1435 1425 STATS_DESC_CUMULATIVE(SCOPE, name, KVM_STATS_UNIT_SECONDS, \ 1436 1426 KVM_STATS_BASE_POW10, -9) 1427 + /* Linear histogram for time in nanosecond */ 1428 + #define STATS_DESC_LINHIST_TIME_NSEC(SCOPE, name, sz, bsz) \ 1429 + STATS_DESC_LINEAR_HIST(SCOPE, name, KVM_STATS_UNIT_SECONDS, \ 1430 + KVM_STATS_BASE_POW10, -9, sz, bsz) 1431 + /* Logarithmic histogram for time in nanosecond */ 1432 + #define STATS_DESC_LOGHIST_TIME_NSEC(SCOPE, name, sz) \ 1433 + STATS_DESC_LOG_HIST(SCOPE, name, KVM_STATS_UNIT_SECONDS, \ 1434 + KVM_STATS_BASE_POW10, -9, sz) 1437 1435 1438 1436 #define KVM_GENERIC_VM_STATS() \ 1439 1437 STATS_DESC_COUNTER(VM_GENERIC, remote_tlb_flush) ··· 1455 1437 STATS_DESC_TIME_NSEC(VCPU_GENERIC, halt_poll_fail_ns) 1456 1438 1457 1439 extern struct dentry *kvm_debugfs_dir; 1440 + 1458 1441 ssize_t kvm_stats_read(char *id, const struct kvm_stats_header *header, 1459 1442 const struct _kvm_stats_desc *desc, 1460 1443 void *stats, size_t size_stats, 1461 1444 char __user *user_buffer, size_t size, loff_t *offset); 1445 + 1446 + /** 1447 + * kvm_stats_linear_hist_update() - Update bucket value for linear histogram 1448 + * statistics data. 1449 + * 1450 + * @data: start address of the stats data 1451 + * @size: the number of bucket of the stats data 1452 + * @value: the new value used to update the linear histogram's bucket 1453 + * @bucket_size: the size (width) of a bucket 1454 + */ 1455 + static inline void kvm_stats_linear_hist_update(u64 *data, size_t size, 1456 + u64 value, size_t bucket_size) 1457 + { 1458 + size_t index = div64_u64(value, bucket_size); 1459 + 1460 + index = min(index, size - 1); 1461 + ++data[index]; 1462 + } 1463 + 1464 + /** 1465 + * kvm_stats_log_hist_update() - Update bucket value for logarithmic histogram 1466 + * statistics data. 1467 + * 1468 + * @data: start address of the stats data 1469 + * @size: the number of bucket of the stats data 1470 + * @value: the new value used to update the logarithmic histogram's bucket 1471 + */ 1472 + static inline void kvm_stats_log_hist_update(u64 *data, size_t size, u64 value) 1473 + { 1474 + size_t index = fls64(value); 1475 + 1476 + index = min(index, size - 1); 1477 + ++data[index]; 1478 + } 1479 + 1480 + #define KVM_STATS_LINEAR_HIST_UPDATE(array, value, bsize) \ 1481 + kvm_stats_linear_hist_update(array, ARRAY_SIZE(array), value, bsize) 1482 + #define KVM_STATS_LOG_HIST_UPDATE(array, value) \ 1483 + kvm_stats_log_hist_update(array, ARRAY_SIZE(array), value) 1484 + 1485 + 1462 1486 extern const struct kvm_stats_header kvm_vm_stats_header; 1463 1487 extern const struct _kvm_stats_desc kvm_vm_stats_desc[]; 1464 1488 extern const struct kvm_stats_header kvm_vcpu_stats_header;
+7 -4
include/uapi/linux/kvm.h
··· 1965 1965 #define KVM_STATS_TYPE_CUMULATIVE (0x0 << KVM_STATS_TYPE_SHIFT) 1966 1966 #define KVM_STATS_TYPE_INSTANT (0x1 << KVM_STATS_TYPE_SHIFT) 1967 1967 #define KVM_STATS_TYPE_PEAK (0x2 << KVM_STATS_TYPE_SHIFT) 1968 - #define KVM_STATS_TYPE_MAX KVM_STATS_TYPE_PEAK 1968 + #define KVM_STATS_TYPE_LINEAR_HIST (0x3 << KVM_STATS_TYPE_SHIFT) 1969 + #define KVM_STATS_TYPE_LOG_HIST (0x4 << KVM_STATS_TYPE_SHIFT) 1970 + #define KVM_STATS_TYPE_MAX KVM_STATS_TYPE_LOG_HIST 1969 1971 1970 1972 #define KVM_STATS_UNIT_SHIFT 4 1971 1973 #define KVM_STATS_UNIT_MASK (0xF << KVM_STATS_UNIT_SHIFT) ··· 1990 1988 * @size: The number of data items for this stats. 1991 1989 * Every data item is of type __u64. 1992 1990 * @offset: The offset of the stats to the start of stat structure in 1993 - * struture kvm or kvm_vcpu. 1994 - * @unused: Unused field for future usage. Always 0 for now. 1991 + * structure kvm or kvm_vcpu. 1992 + * @bucket_size: A parameter value used for histogram stats. It is only used 1993 + * for linear histogram stats, specifying the size of the bucket; 1995 1994 * @name: The name string for the stats. Its size is indicated by the 1996 1995 * &kvm_stats_header->name_size. 1997 1996 */ ··· 2001 1998 __s16 exponent; 2002 1999 __u16 size; 2003 2000 __u32 offset; 2004 - __u32 unused; 2001 + __u32 bucket_size; 2005 2002 char name[]; 2006 2003 }; 2007 2004