[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20250930172850.598938-2-jthoughton@google.com>
Date: Tue, 30 Sep 2025 17:28:50 +0000
From: James Houghton <jthoughton@...gle.com>
To: Paolo Bonzini <pbonzini@...hat.com>, Sean Christopherson <seanjc@...gle.com>
Cc: James Houghton <jthoughton@...gle.com>, kvm@...r.kernel.org,
linux-kernel@...r.kernel.org
Subject: [PATCH 2/2] KVM: selftests: Add parallel KVM_GET_DIRTY_LOG to dirty_log_perf_test
The parallelism is by memslot. This is useful because KVM no longer
serializes KVM_GET_DIRTY_LOG if KVM_CAP_MANUAL_DIRTY_LOG_PROTECT2 is
enabled.
Signed-off-by: James Houghton <jthoughton@...gle.com>
---
.../selftests/kvm/dirty_log_perf_test.c | 20 ++++++++--
.../testing/selftests/kvm/include/memstress.h | 2 +
tools/testing/selftests/kvm/lib/kvm_util.c | 2 +
tools/testing/selftests/kvm/lib/memstress.c | 40 +++++++++++++++++++
4 files changed, 61 insertions(+), 3 deletions(-)
diff --git a/tools/testing/selftests/kvm/dirty_log_perf_test.c b/tools/testing/selftests/kvm/dirty_log_perf_test.c
index e79817bd0e29..8a5f289c4966 100644
--- a/tools/testing/selftests/kvm/dirty_log_perf_test.c
+++ b/tools/testing/selftests/kvm/dirty_log_perf_test.c
@@ -131,8 +131,18 @@ struct test_params {
int slots;
uint32_t write_percent;
bool random_access;
+ bool parallel_get_dirty_log;
};
+static void get_dirty_log(struct kvm_vm *vm, unsigned long *bitmaps[],
+ struct test_params *p)
+{
+ if (p->parallel_get_dirty_log)
+ memstress_get_dirty_log_parallel(vm, bitmaps, p->slots);
+ else
+ memstress_get_dirty_log(vm, bitmaps, p->slots);
+}
+
static void run_test(enum vm_guest_mode mode, void *arg)
{
struct test_params *p = arg;
@@ -230,7 +240,7 @@ static void run_test(enum vm_guest_mode mode, void *arg)
iteration, ts_diff.tv_sec, ts_diff.tv_nsec);
clock_gettime(CLOCK_MONOTONIC, &start);
- memstress_get_dirty_log(vm, bitmaps, p->slots);
+ get_dirty_log(vm, bitmaps, p);
ts_diff = timespec_elapsed(start);
get_dirty_log_total = timespec_add(get_dirty_log_total,
ts_diff);
@@ -292,7 +302,7 @@ static void run_test(enum vm_guest_mode mode, void *arg)
static void help(char *name)
{
puts("");
- printf("usage: %s [-h] [-a] [-i iterations] [-p offset] [-g] "
+ printf("usage: %s [-h] [-a] [-i iterations] [-p offset] [-g] [-l] "
"[-m mode] [-n] [-b vcpu bytes] [-v vcpus] [-o] [-r random seed ] [-s mem type]"
"[-x memslots] [-w percentage] [-c physical cpus to run test on]\n", name);
puts("");
@@ -305,6 +315,7 @@ static void help(char *name)
" and writes will be tracked as soon as dirty logging is\n"
" enabled on the memslot (i.e. KVM_DIRTY_LOG_INITIALLY_SET\n"
" is not enabled).\n");
+ printf(" -l: Do KVM_GET_DIRTY_LOG calls for each memslot in parallel.\n");
printf(" -p: specify guest physical test memory offset\n"
" Warning: a low offset can conflict with the loaded test code.\n");
guest_modes_help();
@@ -355,7 +366,7 @@ int main(int argc, char *argv[])
guest_modes_append_default();
- while ((opt = getopt(argc, argv, "ab:c:eghi:m:nop:r:s:v:x:w:")) != -1) {
+ while ((opt = getopt(argc, argv, "ab:c:eghi:lm:nop:r:s:v:x:w:")) != -1) {
switch (opt) {
case 'a':
p.random_access = true;
@@ -379,6 +390,9 @@ int main(int argc, char *argv[])
case 'i':
p.iterations = atoi_positive("Number of iterations", optarg);
break;
+ case 'l':
+ p.parallel_get_dirty_log = true;
+ break;
case 'm':
guest_modes_cmdline(optarg);
break;
diff --git a/tools/testing/selftests/kvm/include/memstress.h b/tools/testing/selftests/kvm/include/memstress.h
index 9071eb6dea60..3e6ad2cdec80 100644
--- a/tools/testing/selftests/kvm/include/memstress.h
+++ b/tools/testing/selftests/kvm/include/memstress.h
@@ -74,6 +74,8 @@ void memstress_setup_nested(struct kvm_vm *vm, int nr_vcpus, struct kvm_vcpu *vc
void memstress_enable_dirty_logging(struct kvm_vm *vm, int slots);
void memstress_disable_dirty_logging(struct kvm_vm *vm, int slots);
void memstress_get_dirty_log(struct kvm_vm *vm, unsigned long *bitmaps[], int slots);
+void memstress_get_dirty_log_parallel(struct kvm_vm *vm, unsigned long *bitmaps[],
+ int slots);
void memstress_clear_dirty_log(struct kvm_vm *vm, unsigned long *bitmaps[],
int slots, uint64_t pages_per_slot);
unsigned long **memstress_alloc_bitmaps(int slots, uint64_t pages_per_slot);
diff --git a/tools/testing/selftests/kvm/lib/memstress.c b/tools/testing/selftests/kvm/lib/memstress.c
index 557c0a0a5658..abbd96a1c3ba 100644
--- a/tools/testing/selftests/kvm/lib/memstress.c
+++ b/tools/testing/selftests/kvm/lib/memstress.c
@@ -40,6 +40,12 @@ static bool all_vcpu_threads_running;
static struct kvm_vcpu *vcpus[KVM_MAX_VCPUS];
+struct get_dirty_log_args {
+ struct kvm_vm *vm;
+ unsigned long *bitmap;
+ int slot;
+};
+
/*
* Continuously write to the first 8 bytes of each page in the
* specified region.
@@ -341,6 +347,15 @@ void memstress_disable_dirty_logging(struct kvm_vm *vm, int slots)
toggle_dirty_logging(vm, slots, false);
}
+static void *get_dirty_log_worker(void *arg)
+{
+ struct get_dirty_log_args *args = arg;
+
+ kvm_vm_get_dirty_log(args->vm, args->slot, args->bitmap);
+
+ return NULL;
+}
+
void memstress_get_dirty_log(struct kvm_vm *vm, unsigned long *bitmaps[], int slots)
{
int i;
@@ -352,6 +367,31 @@ void memstress_get_dirty_log(struct kvm_vm *vm, unsigned long *bitmaps[], int sl
}
}
+void memstress_get_dirty_log_parallel(struct kvm_vm *vm, unsigned long *bitmaps[],
+ int slots)
+{
+ struct {
+ pthread_t thd;
+ struct get_dirty_log_args args;
+ } *threads;
+ int i;
+
+ threads = malloc(slots * sizeof(*threads));
+
+ for (i = 0; i < slots; i++) {
+ threads[i].args.vm = vm;
+ threads[i].args.slot = MEMSTRESS_MEM_SLOT_INDEX + i;
+ threads[i].args.bitmap = bitmaps[i];
+ pthread_create(&threads[i].thd, NULL, get_dirty_log_worker,
+ &threads[i].args);
+ }
+
+ for (i = 0; i < slots; i++)
+ pthread_join(threads[i].thd, NULL);
+
+ free(threads);
+}
+
void memstress_clear_dirty_log(struct kvm_vm *vm, unsigned long *bitmaps[],
int slots, uint64_t pages_per_slot)
{
--
2.51.0.618.g983fd99d29-goog
Powered by blists - more mailing lists