0001
0002
0003
0004
0005
0006
0007
0008
0009
0010 #define _GNU_SOURCE
0011 #include <fcntl.h>
0012 #include <stdio.h>
0013 #include <stdlib.h>
0014 #include <string.h>
0015 #include <errno.h>
0016
0017 #include "test_util.h"
0018
0019 #include "kvm_util.h"
0020 #include "asm/kvm.h"
0021 #include "linux/kvm.h"
0022
0023 static void stats_test(int stats_fd)
0024 {
0025 ssize_t ret;
0026 int i;
0027 size_t size_desc;
0028 size_t size_data = 0;
0029 struct kvm_stats_header header;
0030 char *id;
0031 struct kvm_stats_desc *stats_desc;
0032 u64 *stats_data;
0033 struct kvm_stats_desc *pdesc;
0034 u32 type, unit, base;
0035
0036
0037 read_stats_header(stats_fd, &header);
0038
0039 size_desc = get_stats_descriptor_size(&header);
0040
0041
0042 id = malloc(header.name_size);
0043 TEST_ASSERT(id, "Allocate memory for id string");
0044
0045 ret = read(stats_fd, id, header.name_size);
0046 TEST_ASSERT(ret == header.name_size, "Read id string");
0047
0048
0049 TEST_ASSERT(!strncmp(id, "kvm", 3) && strlen(id) < header.name_size,
0050 "Invalid KVM stats type, id: %s", id);
0051
0052
0053 if (header.num_desc == 0) {
0054 printf("No KVM stats defined!");
0055 return;
0056 }
0057
0058
0059
0060
0061
0062 TEST_ASSERT(header.desc_offset && header.desc_offset >= sizeof(header) &&
0063 header.data_offset && header.data_offset >= sizeof(header),
0064 "Invalid offset fields in header");
0065
0066 TEST_ASSERT(header.desc_offset > header.data_offset ||
0067 (header.desc_offset + size_desc * header.num_desc <= header.data_offset),
0068 "Descriptor block is overlapped with data block");
0069
0070
0071 stats_desc = read_stats_descriptors(stats_fd, &header);
0072
0073
0074 for (i = 0; i < header.num_desc; ++i) {
0075 pdesc = get_stats_descriptor(stats_desc, i, &header);
0076 type = pdesc->flags & KVM_STATS_TYPE_MASK;
0077 unit = pdesc->flags & KVM_STATS_UNIT_MASK;
0078 base = pdesc->flags & KVM_STATS_BASE_MASK;
0079
0080
0081 TEST_ASSERT(strlen(pdesc->name) < header.name_size,
0082 "KVM stats name (index: %d) too long", i);
0083
0084
0085 TEST_ASSERT(type <= KVM_STATS_TYPE_MAX,
0086 "Unknown KVM stats (%s) type: %u", pdesc->name, type);
0087 TEST_ASSERT(unit <= KVM_STATS_UNIT_MAX,
0088 "Unknown KVM stats (%s) unit: %u", pdesc->name, unit);
0089 TEST_ASSERT(base <= KVM_STATS_BASE_MAX,
0090 "Unknown KVM stats (%s) base: %u", pdesc->name, base);
0091
0092
0093
0094
0095
0096
0097
0098
0099
0100
0101 switch (pdesc->flags & KVM_STATS_UNIT_MASK) {
0102 case KVM_STATS_UNIT_NONE:
0103 case KVM_STATS_UNIT_BYTES:
0104 case KVM_STATS_UNIT_CYCLES:
0105 TEST_ASSERT(pdesc->exponent >= 0,
0106 "Unsupported KVM stats (%s) exponent: %i",
0107 pdesc->name, pdesc->exponent);
0108 break;
0109 case KVM_STATS_UNIT_SECONDS:
0110 TEST_ASSERT(pdesc->exponent <= 0,
0111 "Unsupported KVM stats (%s) exponent: %i",
0112 pdesc->name, pdesc->exponent);
0113 break;
0114 case KVM_STATS_UNIT_BOOLEAN:
0115 TEST_ASSERT(pdesc->exponent == 0,
0116 "Unsupported KVM stats (%s) exponent: %d",
0117 pdesc->name, pdesc->exponent);
0118 break;
0119 }
0120
0121
0122 TEST_ASSERT(pdesc->size,
0123 "KVM descriptor(%s) with size of 0", pdesc->name);
0124
0125 switch (pdesc->flags & KVM_STATS_TYPE_MASK) {
0126 case KVM_STATS_TYPE_LINEAR_HIST:
0127 TEST_ASSERT(pdesc->bucket_size,
0128 "Bucket size of Linear Histogram stats (%s) is zero",
0129 pdesc->name);
0130 break;
0131 default:
0132 TEST_ASSERT(!pdesc->bucket_size,
0133 "Bucket size of stats (%s) is not zero",
0134 pdesc->name);
0135 }
0136 size_data += pdesc->size * sizeof(*stats_data);
0137 }
0138
0139
0140
0141
0142
0143 TEST_ASSERT(header.data_offset >= header.desc_offset ||
0144 header.data_offset + size_data <= header.desc_offset,
0145 "Data block is overlapped with Descriptor block");
0146
0147
0148 TEST_ASSERT(size_data >= header.num_desc * sizeof(*stats_data),
0149 "Data size is not correct");
0150
0151
0152 for (i = 0; i < header.num_desc; ++i) {
0153 pdesc = get_stats_descriptor(stats_desc, i, &header);
0154 TEST_ASSERT(pdesc->offset < size_data,
0155 "Invalid offset (%u) for stats: %s",
0156 pdesc->offset, pdesc->name);
0157 }
0158
0159
0160 stats_data = malloc(size_data);
0161 TEST_ASSERT(stats_data, "Allocate memory for stats data");
0162
0163 ret = pread(stats_fd, stats_data, size_data, header.data_offset);
0164 TEST_ASSERT(ret == size_data, "Read KVM stats data");
0165
0166 for (i = 0; i < header.num_desc; ++i) {
0167 pdesc = get_stats_descriptor(stats_desc, i, &header);
0168 read_stat_data(stats_fd, &header, pdesc, stats_data,
0169 pdesc->size);
0170 }
0171
0172 free(stats_data);
0173 free(stats_desc);
0174 free(id);
0175 }
0176
0177
0178 static void vm_stats_test(struct kvm_vm *vm)
0179 {
0180 int stats_fd = vm_get_stats_fd(vm);
0181
0182 stats_test(stats_fd);
0183 close(stats_fd);
0184 TEST_ASSERT(fcntl(stats_fd, F_GETFD) == -1, "Stats fd not freed");
0185 }
0186
0187 static void vcpu_stats_test(struct kvm_vcpu *vcpu)
0188 {
0189 int stats_fd = vcpu_get_stats_fd(vcpu);
0190
0191 stats_test(stats_fd);
0192 close(stats_fd);
0193 TEST_ASSERT(fcntl(stats_fd, F_GETFD) == -1, "Stats fd not freed");
0194 }
0195
0196 #define DEFAULT_NUM_VM 4
0197 #define DEFAULT_NUM_VCPU 4
0198
0199
0200
0201
0202
0203
0204
0205
0206
0207 int main(int argc, char *argv[])
0208 {
0209 int i, j;
0210 struct kvm_vcpu **vcpus;
0211 struct kvm_vm **vms;
0212 int max_vm = DEFAULT_NUM_VM;
0213 int max_vcpu = DEFAULT_NUM_VCPU;
0214
0215
0216 if (argc > 1) {
0217 max_vm = strtol(argv[1], NULL, 0);
0218 if (max_vm <= 0)
0219 max_vm = DEFAULT_NUM_VM;
0220 }
0221 if (argc > 2) {
0222 max_vcpu = strtol(argv[2], NULL, 0);
0223 if (max_vcpu <= 0)
0224 max_vcpu = DEFAULT_NUM_VCPU;
0225 }
0226
0227
0228 TEST_REQUIRE(kvm_has_cap(KVM_CAP_BINARY_STATS_FD));
0229
0230
0231 vms = malloc(sizeof(vms[0]) * max_vm);
0232 TEST_ASSERT(vms, "Allocate memory for storing VM pointers");
0233
0234 vcpus = malloc(sizeof(struct kvm_vcpu *) * max_vm * max_vcpu);
0235 TEST_ASSERT(vcpus, "Allocate memory for storing vCPU pointers");
0236
0237 for (i = 0; i < max_vm; ++i) {
0238 vms[i] = vm_create_barebones();
0239 for (j = 0; j < max_vcpu; ++j)
0240 vcpus[i * max_vcpu + j] = __vm_vcpu_add(vms[i], j);
0241 }
0242
0243
0244 for (i = 0; i < max_vm; ++i) {
0245 vm_stats_test(vms[i]);
0246 for (j = 0; j < max_vcpu; ++j)
0247 vcpu_stats_test(vcpus[i * max_vcpu + j]);
0248 }
0249
0250 for (i = 0; i < max_vm; ++i)
0251 kvm_vm_free(vms[i]);
0252 free(vms);
0253 return 0;
0254 }