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