public inbox for kvm@vger.kernel.org
 help / color / mirror / Atom feed
From: James Houghton <jthoughton@google.com>
To: Paolo Bonzini <pbonzini@redhat.com>,
	Sean Christopherson <seanjc@google.com>
Cc: James Houghton <jthoughton@google.com>,
	kvm@vger.kernel.org,  linux-kernel@vger.kernel.org
Subject: [PATCH 2/2] KVM: selftests: Add parallel KVM_GET_DIRTY_LOG to dirty_log_perf_test
Date: Tue, 30 Sep 2025 17:28:50 +0000	[thread overview]
Message-ID: <20250930172850.598938-2-jthoughton@google.com> (raw)
In-Reply-To: <20250930172850.598938-1-jthoughton@google.com>

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@google.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


  reply	other threads:[~2025-09-30 17:29 UTC|newest]

Thread overview: 5+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2025-09-30 17:28 [PATCH 1/2] KVM: For manual-protect GET_DIRTY_LOG, do not hold slots lock James Houghton
2025-09-30 17:28 ` James Houghton [this message]
2025-10-01 11:50 ` kernel test robot
2025-10-06  7:33 ` Dan Carpenter
2025-10-08 22:31   ` James Houghton

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20250930172850.598938-2-jthoughton@google.com \
    --to=jthoughton@google.com \
    --cc=kvm@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=pbonzini@redhat.com \
    --cc=seanjc@google.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox