dirty-log-perf.cc 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146
  1. #include "kvmxx.hh"
  2. #include "exception.hh"
  3. #include "memmap.hh"
  4. #include "identity.hh"
  5. #include <stdlib.h>
  6. #include <stdio.h>
  7. #include <sys/time.h>
  8. namespace {
  9. const int page_size = 4096;
  10. int64_t nr_total_pages = 256 * 1024;
  11. int64_t nr_slot_pages = 256 * 1024;
  12. // Return the current time in nanoseconds.
  13. uint64_t time_ns()
  14. {
  15. struct timespec ts;
  16. clock_gettime(CLOCK_MONOTONIC, &ts);
  17. return ts.tv_sec * (uint64_t)1000000000 + ts.tv_nsec;
  18. }
  19. // Update nr_to_write pages selected from nr_pages pages.
  20. void write_mem(void* slot_head, int64_t nr_to_write, int64_t nr_pages)
  21. {
  22. char* var = static_cast<char*>(slot_head);
  23. int64_t interval = nr_pages / nr_to_write;
  24. for (int64_t i = 0; i < nr_to_write; ++i) {
  25. ++(*var);
  26. var += interval * page_size;
  27. }
  28. }
  29. // Let the guest update nr_to_write pages selected from nr_pages pages.
  30. void do_guest_write(kvm::vcpu& vcpu, void* slot_head,
  31. int64_t nr_to_write, int64_t nr_pages)
  32. {
  33. identity::vcpu guest_write_thread(vcpu, std::bind(write_mem, slot_head,
  34. nr_to_write, nr_pages));
  35. vcpu.run();
  36. }
  37. // Check how long it takes to update dirty log.
  38. void check_dirty_log(kvm::vcpu& vcpu, mem_slot& slot, void* slot_head)
  39. {
  40. slot.set_dirty_logging(true);
  41. slot.update_dirty_log();
  42. for (int64_t i = 1; i <= nr_slot_pages; i *= 2) {
  43. do_guest_write(vcpu, slot_head, i, nr_slot_pages);
  44. uint64_t start_ns = time_ns();
  45. int n = slot.update_dirty_log();
  46. uint64_t end_ns = time_ns();
  47. printf("get dirty log: %10lld ns for %10d dirty pages (expected %lld)\n",
  48. end_ns - start_ns, n, i);
  49. }
  50. slot.set_dirty_logging(false);
  51. }
  52. }
  53. void parse_options(int ac, char **av)
  54. {
  55. int opt;
  56. char *endptr;
  57. while ((opt = getopt(ac, av, "n:m:")) != -1) {
  58. switch (opt) {
  59. case 'n':
  60. errno = 0;
  61. nr_slot_pages = strtol(optarg, &endptr, 10);
  62. if (errno || endptr == optarg) {
  63. printf("dirty-log-perf: Invalid number: -n %s\n", optarg);
  64. exit(1);
  65. }
  66. if (*endptr == 'k' || *endptr == 'K') {
  67. nr_slot_pages *= 1024;
  68. }
  69. break;
  70. case 'm':
  71. errno = 0;
  72. nr_total_pages = strtol(optarg, &endptr, 10);
  73. if (errno || endptr == optarg) {
  74. printf("dirty-log-perf: Invalid number: -m %s\n", optarg);
  75. exit(1);
  76. }
  77. if (*endptr == 'k' || *endptr == 'K') {
  78. nr_total_pages *= 1024;
  79. }
  80. break;
  81. default:
  82. printf("dirty-log-perf: Invalid option\n");
  83. exit(1);
  84. }
  85. }
  86. if (nr_slot_pages > nr_total_pages) {
  87. printf("dirty-log-perf: Invalid setting: slot %lld > mem %lld\n",
  88. nr_slot_pages, nr_total_pages);
  89. exit(1);
  90. }
  91. printf("dirty-log-perf: %lld slot pages / %lld mem pages\n",
  92. nr_slot_pages, nr_total_pages);
  93. }
  94. int test_main(int ac, char **av)
  95. {
  96. kvm::system sys;
  97. kvm::vm vm(sys);
  98. mem_map memmap(vm);
  99. parse_options(ac, av);
  100. void* mem_head;
  101. int64_t mem_size = nr_total_pages * page_size;
  102. if (posix_memalign(&mem_head, page_size, mem_size)) {
  103. printf("dirty-log-perf: Could not allocate guest memory.\n");
  104. exit(1);
  105. }
  106. uint64_t mem_addr = reinterpret_cast<uintptr_t>(mem_head);
  107. identity::hole hole(mem_head, mem_size);
  108. identity::vm ident_vm(vm, memmap, hole);
  109. kvm::vcpu vcpu(vm, 0);
  110. uint64_t slot_size = nr_slot_pages * page_size;
  111. uint64_t next_size = mem_size - slot_size;
  112. uint64_t next_addr = mem_addr + slot_size;
  113. mem_slot slot(memmap, mem_addr, slot_size, mem_head);
  114. mem_slot other_slot(memmap, next_addr, next_size, (void *)next_addr);
  115. // pre-allocate shadow pages
  116. do_guest_write(vcpu, mem_head, nr_total_pages, nr_total_pages);
  117. check_dirty_log(vcpu, slot, mem_head);
  118. return 0;
  119. }
  120. int main(int ac, char** av)
  121. {
  122. return try_main(test_main, ac, av);
  123. }