1 // SPDX-License-Identifier: GPL-2.0-only
3 * kvm_binary_stats_test
5 * Copyright (C) 2021, Google LLC.
7 * Test the fd-based interface for KVM statistics.
10 #define _GNU_SOURCE /* for program_invocation_short_name */
17 #include "test_util.h"
21 #include "linux/kvm.h"
23 static void stats_test(int stats_fd)
29 struct kvm_stats_header header;
31 struct kvm_stats_desc *stats_desc;
33 struct kvm_stats_desc *pdesc;
36 /* Read kvm stats header */
37 read_stats_header(stats_fd, &header);
39 size_desc = get_stats_descriptor_size(&header);
41 /* Read kvm stats id string */
42 id = malloc(header.name_size);
43 TEST_ASSERT(id, "Allocate memory for id string");
45 ret = read(stats_fd, id, header.name_size);
46 TEST_ASSERT(ret == header.name_size, "Read id string");
48 /* Check id string, that should start with "kvm" */
49 TEST_ASSERT(!strncmp(id, "kvm", 3) && strlen(id) < header.name_size,
50 "Invalid KVM stats type, id: %s", id);
52 /* Sanity check for other fields in header */
53 if (header.num_desc == 0) {
54 printf("No KVM stats defined!");
58 * The descriptor and data offsets must be valid, they must not overlap
59 * the header, and the descriptor and data blocks must not overlap each
60 * other. Note, the data block is rechecked after its size is known.
62 TEST_ASSERT(header.desc_offset && header.desc_offset >= sizeof(header) &&
63 header.data_offset && header.data_offset >= sizeof(header),
64 "Invalid offset fields in header");
66 TEST_ASSERT(header.desc_offset > header.data_offset ||
67 (header.desc_offset + size_desc * header.num_desc <= header.data_offset),
68 "Descriptor block is overlapped with data block");
70 /* Read kvm stats descriptors */
71 stats_desc = read_stats_descriptors(stats_fd, &header);
73 /* Sanity check for fields in descriptors */
74 for (i = 0; i < header.num_desc; ++i) {
75 pdesc = get_stats_descriptor(stats_desc, i, &header);
76 type = pdesc->flags & KVM_STATS_TYPE_MASK;
77 unit = pdesc->flags & KVM_STATS_UNIT_MASK;
78 base = pdesc->flags & KVM_STATS_BASE_MASK;
80 /* Check name string */
81 TEST_ASSERT(strlen(pdesc->name) < header.name_size,
82 "KVM stats name (index: %d) too long", i);
84 /* Check type,unit,base boundaries */
85 TEST_ASSERT(type <= KVM_STATS_TYPE_MAX,
86 "Unknown KVM stats (%s) type: %u", pdesc->name, type);
87 TEST_ASSERT(unit <= KVM_STATS_UNIT_MAX,
88 "Unknown KVM stats (%s) unit: %u", pdesc->name, unit);
89 TEST_ASSERT(base <= KVM_STATS_BASE_MAX,
90 "Unknown KVM stats (%s) base: %u", pdesc->name, base);
93 * Check exponent for stats unit
94 * Exponent for counter should be greater than or equal to 0
95 * Exponent for unit bytes should be greater than or equal to 0
96 * Exponent for unit seconds should be less than or equal to 0
97 * Exponent for unit clock cycles should be greater than or
99 * Exponent for unit boolean should be 0
101 switch (pdesc->flags & KVM_STATS_UNIT_MASK) {
102 case KVM_STATS_UNIT_NONE:
103 case KVM_STATS_UNIT_BYTES:
104 case KVM_STATS_UNIT_CYCLES:
105 TEST_ASSERT(pdesc->exponent >= 0,
106 "Unsupported KVM stats (%s) exponent: %i",
107 pdesc->name, pdesc->exponent);
109 case KVM_STATS_UNIT_SECONDS:
110 TEST_ASSERT(pdesc->exponent <= 0,
111 "Unsupported KVM stats (%s) exponent: %i",
112 pdesc->name, pdesc->exponent);
114 case KVM_STATS_UNIT_BOOLEAN:
115 TEST_ASSERT(pdesc->exponent == 0,
116 "Unsupported KVM stats (%s) exponent: %d",
117 pdesc->name, pdesc->exponent);
121 /* Check size field, which should not be zero */
122 TEST_ASSERT(pdesc->size,
123 "KVM descriptor(%s) with size of 0", pdesc->name);
124 /* Check bucket_size field */
125 switch (pdesc->flags & KVM_STATS_TYPE_MASK) {
126 case KVM_STATS_TYPE_LINEAR_HIST:
127 TEST_ASSERT(pdesc->bucket_size,
128 "Bucket size of Linear Histogram stats (%s) is zero",
132 TEST_ASSERT(!pdesc->bucket_size,
133 "Bucket size of stats (%s) is not zero",
136 size_data += pdesc->size * sizeof(*stats_data);
140 * Now that the size of the data block is known, verify the data block
141 * doesn't overlap the descriptor block.
143 TEST_ASSERT(header.data_offset >= header.desc_offset ||
144 header.data_offset + size_data <= header.desc_offset,
145 "Data block is overlapped with Descriptor block");
147 /* Check validity of all stats data size */
148 TEST_ASSERT(size_data >= header.num_desc * sizeof(*stats_data),
149 "Data size is not correct");
151 /* Check stats offset */
152 for (i = 0; i < header.num_desc; ++i) {
153 pdesc = get_stats_descriptor(stats_desc, i, &header);
154 TEST_ASSERT(pdesc->offset < size_data,
155 "Invalid offset (%u) for stats: %s",
156 pdesc->offset, pdesc->name);
159 /* Allocate memory for stats data */
160 stats_data = malloc(size_data);
161 TEST_ASSERT(stats_data, "Allocate memory for stats data");
162 /* Read kvm stats data as a bulk */
163 ret = pread(stats_fd, stats_data, size_data, header.data_offset);
164 TEST_ASSERT(ret == size_data, "Read KVM stats data");
165 /* Read kvm stats data one by one */
166 for (i = 0; i < header.num_desc; ++i) {
167 pdesc = get_stats_descriptor(stats_desc, i, &header);
168 read_stat_data(stats_fd, &header, pdesc, stats_data,
178 static void vm_stats_test(struct kvm_vm *vm)
180 int stats_fd = vm_get_stats_fd(vm);
182 stats_test(stats_fd);
184 TEST_ASSERT(fcntl(stats_fd, F_GETFD) == -1, "Stats fd not freed");
187 static void vcpu_stats_test(struct kvm_vcpu *vcpu)
189 int stats_fd = vcpu_get_stats_fd(vcpu);
191 stats_test(stats_fd);
193 TEST_ASSERT(fcntl(stats_fd, F_GETFD) == -1, "Stats fd not freed");
196 #define DEFAULT_NUM_VM 4
197 #define DEFAULT_NUM_VCPU 4
200 * Usage: kvm_bin_form_stats [#vm] [#vcpu]
201 * The first parameter #vm set the number of VMs being created.
202 * The second parameter #vcpu set the number of VCPUs being created.
203 * By default, DEFAULT_NUM_VM VM and DEFAULT_NUM_VCPU VCPU for the VM would be
204 * created for testing.
207 int main(int argc, char *argv[])
210 struct kvm_vcpu **vcpus;
212 int max_vm = DEFAULT_NUM_VM;
213 int max_vcpu = DEFAULT_NUM_VCPU;
215 /* Get the number of VMs and VCPUs that would be created for testing. */
217 max_vm = strtol(argv[1], NULL, 0);
219 max_vm = DEFAULT_NUM_VM;
222 max_vcpu = strtol(argv[2], NULL, 0);
224 max_vcpu = DEFAULT_NUM_VCPU;
227 /* Check the extension for binary stats */
228 TEST_REQUIRE(kvm_has_cap(KVM_CAP_BINARY_STATS_FD));
230 /* Create VMs and VCPUs */
231 vms = malloc(sizeof(vms[0]) * max_vm);
232 TEST_ASSERT(vms, "Allocate memory for storing VM pointers");
234 vcpus = malloc(sizeof(struct kvm_vcpu *) * max_vm * max_vcpu);
235 TEST_ASSERT(vcpus, "Allocate memory for storing vCPU pointers");
237 for (i = 0; i < max_vm; ++i) {
238 vms[i] = vm_create_barebones();
239 for (j = 0; j < max_vcpu; ++j)
240 vcpus[i * max_vcpu + j] = __vm_vcpu_add(vms[i], j);
243 /* Check stats read for every VM and VCPU */
244 for (i = 0; i < max_vm; ++i) {
245 vm_stats_test(vms[i]);
246 for (j = 0; j < max_vcpu; ++j)
247 vcpu_stats_test(vcpus[i * max_vcpu + j]);
250 for (i = 0; i < max_vm; ++i)