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.
15 #include "test_util.h"
19 #include "linux/kvm.h"
20 #include "kselftest.h"
22 static void stats_test(int stats_fd
)
28 struct kvm_stats_header header
;
30 struct kvm_stats_desc
*stats_desc
;
32 struct kvm_stats_desc
*pdesc
;
35 /* Read kvm stats header */
36 read_stats_header(stats_fd
, &header
);
38 size_desc
= get_stats_descriptor_size(&header
);
40 /* Read kvm stats id string */
41 id
= malloc(header
.name_size
);
42 TEST_ASSERT(id
, "Allocate memory for id string");
44 ret
= pread(stats_fd
, id
, header
.name_size
, sizeof(header
));
45 TEST_ASSERT(ret
== header
.name_size
,
46 "Expected header size '%u', read '%lu' bytes",
47 header
.name_size
, ret
);
49 /* Check id string, that should start with "kvm" */
50 TEST_ASSERT(!strncmp(id
, "kvm", 3) && strlen(id
) < header
.name_size
,
51 "Invalid KVM stats type, id: %s", id
);
53 /* Sanity check for other fields in header */
54 if (header
.num_desc
== 0) {
55 ksft_print_msg("No KVM stats defined!\n");
59 * The descriptor and data offsets must be valid, they must not overlap
60 * the header, and the descriptor and data blocks must not overlap each
61 * other. Note, the data block is rechecked after its size is known.
63 TEST_ASSERT(header
.desc_offset
&& header
.desc_offset
>= sizeof(header
) &&
64 header
.data_offset
&& header
.data_offset
>= sizeof(header
),
65 "Invalid offset fields in header");
67 TEST_ASSERT(header
.desc_offset
> header
.data_offset
||
68 (header
.desc_offset
+ size_desc
* header
.num_desc
<= header
.data_offset
),
69 "Descriptor block is overlapped with data block");
71 /* Read kvm stats descriptors */
72 stats_desc
= read_stats_descriptors(stats_fd
, &header
);
74 /* Sanity check for fields in descriptors */
75 for (i
= 0; i
< header
.num_desc
; ++i
) {
76 pdesc
= get_stats_descriptor(stats_desc
, i
, &header
);
77 type
= pdesc
->flags
& KVM_STATS_TYPE_MASK
;
78 unit
= pdesc
->flags
& KVM_STATS_UNIT_MASK
;
79 base
= pdesc
->flags
& KVM_STATS_BASE_MASK
;
81 /* Check name string */
82 TEST_ASSERT(strlen(pdesc
->name
) < header
.name_size
,
83 "KVM stats name (index: %d) too long", i
);
85 /* Check type,unit,base boundaries */
86 TEST_ASSERT(type
<= KVM_STATS_TYPE_MAX
,
87 "Unknown KVM stats (%s) type: %u", pdesc
->name
, type
);
88 TEST_ASSERT(unit
<= KVM_STATS_UNIT_MAX
,
89 "Unknown KVM stats (%s) unit: %u", pdesc
->name
, unit
);
90 TEST_ASSERT(base
<= KVM_STATS_BASE_MAX
,
91 "Unknown KVM stats (%s) base: %u", pdesc
->name
, base
);
94 * Check exponent for stats unit
95 * Exponent for counter should be greater than or equal to 0
96 * Exponent for unit bytes should be greater than or equal to 0
97 * Exponent for unit seconds should be less than or equal to 0
98 * Exponent for unit clock cycles should be greater than or
100 * Exponent for unit boolean should be 0
102 switch (pdesc
->flags
& KVM_STATS_UNIT_MASK
) {
103 case KVM_STATS_UNIT_NONE
:
104 case KVM_STATS_UNIT_BYTES
:
105 case KVM_STATS_UNIT_CYCLES
:
106 TEST_ASSERT(pdesc
->exponent
>= 0,
107 "Unsupported KVM stats (%s) exponent: %i",
108 pdesc
->name
, pdesc
->exponent
);
110 case KVM_STATS_UNIT_SECONDS
:
111 TEST_ASSERT(pdesc
->exponent
<= 0,
112 "Unsupported KVM stats (%s) exponent: %i",
113 pdesc
->name
, pdesc
->exponent
);
115 case KVM_STATS_UNIT_BOOLEAN
:
116 TEST_ASSERT(pdesc
->exponent
== 0,
117 "Unsupported KVM stats (%s) exponent: %d",
118 pdesc
->name
, pdesc
->exponent
);
122 /* Check size field, which should not be zero */
123 TEST_ASSERT(pdesc
->size
,
124 "KVM descriptor(%s) with size of 0", pdesc
->name
);
125 /* Check bucket_size field */
126 switch (pdesc
->flags
& KVM_STATS_TYPE_MASK
) {
127 case KVM_STATS_TYPE_LINEAR_HIST
:
128 TEST_ASSERT(pdesc
->bucket_size
,
129 "Bucket size of Linear Histogram stats (%s) is zero",
133 TEST_ASSERT(!pdesc
->bucket_size
,
134 "Bucket size of stats (%s) is not zero",
137 size_data
= max(size_data
, pdesc
->offset
+ pdesc
->size
* sizeof(*stats_data
));
141 * Now that the size of the data block is known, verify the data block
142 * doesn't overlap the descriptor block.
144 TEST_ASSERT(header
.data_offset
>= header
.desc_offset
||
145 header
.data_offset
+ size_data
<= header
.desc_offset
,
146 "Data block is overlapped with Descriptor block");
148 /* Check validity of all stats data size */
149 TEST_ASSERT(size_data
>= header
.num_desc
* sizeof(*stats_data
),
150 "Data size is not correct");
152 /* Allocate memory for stats data */
153 stats_data
= malloc(size_data
);
154 TEST_ASSERT(stats_data
, "Allocate memory for stats data");
155 /* Read kvm stats data as a bulk */
156 ret
= pread(stats_fd
, stats_data
, size_data
, header
.data_offset
);
157 TEST_ASSERT(ret
== size_data
, "Read KVM stats data");
158 /* Read kvm stats data one by one */
159 for (i
= 0; i
< header
.num_desc
; ++i
) {
160 pdesc
= get_stats_descriptor(stats_desc
, i
, &header
);
161 read_stat_data(stats_fd
, &header
, pdesc
, stats_data
,
170 TEST_ASSERT(fcntl(stats_fd
, F_GETFD
) == -1, "Stats fd not freed");
173 #define DEFAULT_NUM_VM 4
174 #define DEFAULT_NUM_VCPU 4
177 * Usage: kvm_bin_form_stats [#vm] [#vcpu]
178 * The first parameter #vm set the number of VMs being created.
179 * The second parameter #vcpu set the number of VCPUs being created.
180 * By default, DEFAULT_NUM_VM VM and DEFAULT_NUM_VCPU VCPU for the VM would be
181 * created for testing.
184 int main(int argc
, char *argv
[])
186 int vm_stats_fds
, *vcpu_stats_fds
;
188 struct kvm_vcpu
**vcpus
;
190 int max_vm
= DEFAULT_NUM_VM
;
191 int max_vcpu
= DEFAULT_NUM_VCPU
;
193 /* Get the number of VMs and VCPUs that would be created for testing. */
195 max_vm
= strtol(argv
[1], NULL
, 0);
197 max_vm
= DEFAULT_NUM_VM
;
200 max_vcpu
= strtol(argv
[2], NULL
, 0);
202 max_vcpu
= DEFAULT_NUM_VCPU
;
207 /* Check the extension for binary stats */
208 TEST_REQUIRE(kvm_has_cap(KVM_CAP_BINARY_STATS_FD
));
210 ksft_set_plan(max_vm
);
212 /* Create VMs and VCPUs */
213 vms
= malloc(sizeof(vms
[0]) * max_vm
);
214 TEST_ASSERT(vms
, "Allocate memory for storing VM pointers");
216 vcpus
= malloc(sizeof(struct kvm_vcpu
*) * max_vm
* max_vcpu
);
217 TEST_ASSERT(vcpus
, "Allocate memory for storing vCPU pointers");
220 * Not per-VM as the array is populated, used, and invalidated within a
221 * single for-loop iteration.
223 vcpu_stats_fds
= calloc(max_vm
, sizeof(*vcpu_stats_fds
));
224 TEST_ASSERT(vcpu_stats_fds
, "Allocate memory for VM stats fds");
226 for (i
= 0; i
< max_vm
; ++i
) {
227 vms
[i
] = vm_create_barebones();
228 for (j
= 0; j
< max_vcpu
; ++j
)
229 vcpus
[i
* max_vcpu
+ j
] = __vm_vcpu_add(vms
[i
], j
);
233 * Check stats read for every VM and vCPU, with a variety of flavors.
234 * Note, stats_test() closes the passed in stats fd.
236 for (i
= 0; i
< max_vm
; ++i
) {
238 * Verify that creating multiple userspace references to a
239 * single stats file works and doesn't cause explosions.
241 vm_stats_fds
= vm_get_stats_fd(vms
[i
]);
242 stats_test(dup(vm_stats_fds
));
244 /* Verify userspace can instantiate multiple stats files. */
245 stats_test(vm_get_stats_fd(vms
[i
]));
247 for (j
= 0; j
< max_vcpu
; ++j
) {
248 vcpu_stats_fds
[j
] = vcpu_get_stats_fd(vcpus
[i
* max_vcpu
+ j
]);
249 stats_test(dup(vcpu_stats_fds
[j
]));
250 stats_test(vcpu_get_stats_fd(vcpus
[i
* max_vcpu
+ j
]));
254 * Close the VM fd and redo the stats tests. KVM should gift a
255 * reference (to the VM) to each stats fd, i.e. stats should
256 * still be accessible even after userspace has put its last
257 * _direct_ reference to the VM.
261 stats_test(vm_stats_fds
);
262 for (j
= 0; j
< max_vcpu
; ++j
)
263 stats_test(vcpu_stats_fds
[j
]);
265 ksft_test_result_pass("vm%i\n", i
);
270 free(vcpu_stats_fds
);
272 ksft_finished(); /* Print results and exit() accordingly */