kvm_binary_stats_test.c 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * kvm_binary_stats_test
  4. *
  5. * Copyright (C) 2021, Google LLC.
  6. *
  7. * Test the fd-based interface for KVM statistics.
  8. */
  9. #include <fcntl.h>
  10. #include <stdio.h>
  11. #include <stdlib.h>
  12. #include <string.h>
  13. #include <errno.h>
  14. #include "test_util.h"
  15. #include "kvm_util.h"
  16. #include "asm/kvm.h"
  17. #include "linux/kvm.h"
  18. #include "kselftest.h"
  19. static void stats_test(int stats_fd)
  20. {
  21. ssize_t ret;
  22. int i;
  23. size_t size_desc;
  24. size_t size_data = 0;
  25. struct kvm_stats_header header;
  26. char *id;
  27. struct kvm_stats_desc *stats_desc;
  28. u64 *stats_data;
  29. struct kvm_stats_desc *pdesc;
  30. u32 type, unit, base;
  31. /* Read kvm stats header */
  32. read_stats_header(stats_fd, &header);
  33. size_desc = get_stats_descriptor_size(&header);
  34. /* Read kvm stats id string */
  35. id = malloc(header.name_size);
  36. TEST_ASSERT(id, "Allocate memory for id string");
  37. ret = pread(stats_fd, id, header.name_size, sizeof(header));
  38. TEST_ASSERT(ret == header.name_size,
  39. "Expected header size '%u', read '%lu' bytes",
  40. header.name_size, ret);
  41. /* Check id string, that should start with "kvm" */
  42. TEST_ASSERT(!strncmp(id, "kvm", 3) && strlen(id) < header.name_size,
  43. "Invalid KVM stats type, id: %s", id);
  44. /* Sanity check for other fields in header */
  45. if (header.num_desc == 0) {
  46. ksft_print_msg("No KVM stats defined!\n");
  47. return;
  48. }
  49. /*
  50. * The descriptor and data offsets must be valid, they must not overlap
  51. * the header, and the descriptor and data blocks must not overlap each
  52. * other. Note, the data block is rechecked after its size is known.
  53. */
  54. TEST_ASSERT(header.desc_offset && header.desc_offset >= sizeof(header) &&
  55. header.data_offset && header.data_offset >= sizeof(header),
  56. "Invalid offset fields in header");
  57. TEST_ASSERT(header.desc_offset > header.data_offset ||
  58. (header.desc_offset + size_desc * header.num_desc <= header.data_offset),
  59. "Descriptor block is overlapped with data block");
  60. /* Read kvm stats descriptors */
  61. stats_desc = read_stats_descriptors(stats_fd, &header);
  62. /* Sanity check for fields in descriptors */
  63. for (i = 0; i < header.num_desc; ++i) {
  64. pdesc = get_stats_descriptor(stats_desc, i, &header);
  65. type = pdesc->flags & KVM_STATS_TYPE_MASK;
  66. unit = pdesc->flags & KVM_STATS_UNIT_MASK;
  67. base = pdesc->flags & KVM_STATS_BASE_MASK;
  68. /* Check name string */
  69. TEST_ASSERT(strlen(pdesc->name) < header.name_size,
  70. "KVM stats name (index: %d) too long", i);
  71. /* Check type,unit,base boundaries */
  72. TEST_ASSERT(type <= KVM_STATS_TYPE_MAX,
  73. "Unknown KVM stats (%s) type: %u", pdesc->name, type);
  74. TEST_ASSERT(unit <= KVM_STATS_UNIT_MAX,
  75. "Unknown KVM stats (%s) unit: %u", pdesc->name, unit);
  76. TEST_ASSERT(base <= KVM_STATS_BASE_MAX,
  77. "Unknown KVM stats (%s) base: %u", pdesc->name, base);
  78. /*
  79. * Check exponent for stats unit
  80. * Exponent for counter should be greater than or equal to 0
  81. * Exponent for unit bytes should be greater than or equal to 0
  82. * Exponent for unit seconds should be less than or equal to 0
  83. * Exponent for unit clock cycles should be greater than or
  84. * equal to 0
  85. * Exponent for unit boolean should be 0
  86. */
  87. switch (pdesc->flags & KVM_STATS_UNIT_MASK) {
  88. case KVM_STATS_UNIT_NONE:
  89. case KVM_STATS_UNIT_BYTES:
  90. case KVM_STATS_UNIT_CYCLES:
  91. TEST_ASSERT(pdesc->exponent >= 0,
  92. "Unsupported KVM stats (%s) exponent: %i",
  93. pdesc->name, pdesc->exponent);
  94. break;
  95. case KVM_STATS_UNIT_SECONDS:
  96. TEST_ASSERT(pdesc->exponent <= 0,
  97. "Unsupported KVM stats (%s) exponent: %i",
  98. pdesc->name, pdesc->exponent);
  99. break;
  100. case KVM_STATS_UNIT_BOOLEAN:
  101. TEST_ASSERT(pdesc->exponent == 0,
  102. "Unsupported KVM stats (%s) exponent: %d",
  103. pdesc->name, pdesc->exponent);
  104. break;
  105. }
  106. /* Check size field, which should not be zero */
  107. TEST_ASSERT(pdesc->size,
  108. "KVM descriptor(%s) with size of 0", pdesc->name);
  109. /* Check bucket_size field */
  110. switch (pdesc->flags & KVM_STATS_TYPE_MASK) {
  111. case KVM_STATS_TYPE_LINEAR_HIST:
  112. TEST_ASSERT(pdesc->bucket_size,
  113. "Bucket size of Linear Histogram stats (%s) is zero",
  114. pdesc->name);
  115. break;
  116. default:
  117. TEST_ASSERT(!pdesc->bucket_size,
  118. "Bucket size of stats (%s) is not zero",
  119. pdesc->name);
  120. }
  121. size_data = max(size_data, pdesc->offset + pdesc->size * sizeof(*stats_data));
  122. }
  123. /*
  124. * Now that the size of the data block is known, verify the data block
  125. * doesn't overlap the descriptor block.
  126. */
  127. TEST_ASSERT(header.data_offset >= header.desc_offset ||
  128. header.data_offset + size_data <= header.desc_offset,
  129. "Data block is overlapped with Descriptor block");
  130. /* Check validity of all stats data size */
  131. TEST_ASSERT(size_data >= header.num_desc * sizeof(*stats_data),
  132. "Data size is not correct");
  133. /* Allocate memory for stats data */
  134. stats_data = malloc(size_data);
  135. TEST_ASSERT(stats_data, "Allocate memory for stats data");
  136. /* Read kvm stats data as a bulk */
  137. ret = pread(stats_fd, stats_data, size_data, header.data_offset);
  138. TEST_ASSERT(ret == size_data, "Read KVM stats data");
  139. /* Read kvm stats data one by one */
  140. for (i = 0; i < header.num_desc; ++i) {
  141. pdesc = get_stats_descriptor(stats_desc, i, &header);
  142. read_stat_data(stats_fd, &header, pdesc, stats_data,
  143. pdesc->size);
  144. }
  145. free(stats_data);
  146. free(stats_desc);
  147. free(id);
  148. close(stats_fd);
  149. TEST_ASSERT(fcntl(stats_fd, F_GETFD) == -1, "Stats fd not freed");
  150. }
  151. #define DEFAULT_NUM_VM 4
  152. #define DEFAULT_NUM_VCPU 4
  153. /*
  154. * Usage: kvm_bin_form_stats [#vm] [#vcpu]
  155. * The first parameter #vm set the number of VMs being created.
  156. * The second parameter #vcpu set the number of VCPUs being created.
  157. * By default, DEFAULT_NUM_VM VM and DEFAULT_NUM_VCPU VCPU for the VM would be
  158. * created for testing.
  159. */
  160. int main(int argc, char *argv[])
  161. {
  162. int vm_stats_fds, *vcpu_stats_fds;
  163. int i, j;
  164. struct kvm_vcpu **vcpus;
  165. struct kvm_vm **vms;
  166. int max_vm = DEFAULT_NUM_VM;
  167. int max_vcpu = DEFAULT_NUM_VCPU;
  168. /* Get the number of VMs and VCPUs that would be created for testing. */
  169. if (argc > 1) {
  170. max_vm = strtol(argv[1], NULL, 0);
  171. if (max_vm <= 0)
  172. max_vm = DEFAULT_NUM_VM;
  173. }
  174. if (argc > 2) {
  175. max_vcpu = strtol(argv[2], NULL, 0);
  176. if (max_vcpu <= 0)
  177. max_vcpu = DEFAULT_NUM_VCPU;
  178. }
  179. ksft_print_header();
  180. /* Check the extension for binary stats */
  181. TEST_REQUIRE(kvm_has_cap(KVM_CAP_BINARY_STATS_FD));
  182. ksft_set_plan(max_vm);
  183. /* Create VMs and VCPUs */
  184. vms = malloc(sizeof(vms[0]) * max_vm);
  185. TEST_ASSERT(vms, "Allocate memory for storing VM pointers");
  186. vcpus = malloc(sizeof(struct kvm_vcpu *) * max_vm * max_vcpu);
  187. TEST_ASSERT(vcpus, "Allocate memory for storing vCPU pointers");
  188. /*
  189. * Not per-VM as the array is populated, used, and invalidated within a
  190. * single for-loop iteration.
  191. */
  192. vcpu_stats_fds = calloc(max_vm, sizeof(*vcpu_stats_fds));
  193. TEST_ASSERT(vcpu_stats_fds, "Allocate memory for VM stats fds");
  194. for (i = 0; i < max_vm; ++i) {
  195. vms[i] = vm_create_barebones();
  196. for (j = 0; j < max_vcpu; ++j)
  197. vcpus[i * max_vcpu + j] = __vm_vcpu_add(vms[i], j);
  198. }
  199. /*
  200. * Check stats read for every VM and vCPU, with a variety of flavors.
  201. * Note, stats_test() closes the passed in stats fd.
  202. */
  203. for (i = 0; i < max_vm; ++i) {
  204. /*
  205. * Verify that creating multiple userspace references to a
  206. * single stats file works and doesn't cause explosions.
  207. */
  208. vm_stats_fds = vm_get_stats_fd(vms[i]);
  209. stats_test(kvm_dup(vm_stats_fds));
  210. /* Verify userspace can instantiate multiple stats files. */
  211. stats_test(vm_get_stats_fd(vms[i]));
  212. for (j = 0; j < max_vcpu; ++j) {
  213. vcpu_stats_fds[j] = vcpu_get_stats_fd(vcpus[i * max_vcpu + j]);
  214. stats_test(kvm_dup(vcpu_stats_fds[j]));
  215. stats_test(vcpu_get_stats_fd(vcpus[i * max_vcpu + j]));
  216. }
  217. /*
  218. * Close the VM fd and redo the stats tests. KVM should gift a
  219. * reference (to the VM) to each stats fd, i.e. stats should
  220. * still be accessible even after userspace has put its last
  221. * _direct_ reference to the VM.
  222. */
  223. kvm_vm_free(vms[i]);
  224. stats_test(vm_stats_fds);
  225. for (j = 0; j < max_vcpu; ++j)
  226. stats_test(vcpu_stats_fds[j]);
  227. ksft_test_result_pass("vm%i\n", i);
  228. }
  229. free(vms);
  230. free(vcpus);
  231. free(vcpu_stats_fds);
  232. ksft_finished(); /* Print results and exit() accordingly */
  233. }