Commit 89d9a43c authored by David Matlack's avatar David Matlack Committed by Paolo Bonzini

KVM: selftests: Wait for all vCPU to be created before entering guest mode

Thread creation requires taking the mmap_sem in write mode, which causes
vCPU threads running in guest mode to block while they are populating
memory. Fix this by waiting for all vCPU threads to be created and start
running before entering guest mode on any one vCPU thread.

This substantially improves the "Populate memory time" when using 1GiB
pages since it allows all vCPUs to zero pages in parallel rather than
blocking because a writer is waiting (which is waiting for another vCPU
that is busy zeroing a 1GiB page).

Before:

  $ ./dirty_log_perf_test -v256 -s anonymous_hugetlb_1gb
  ...
  Populate memory time: 52.811184013s

After:

  $ ./dirty_log_perf_test -v256 -s anonymous_hugetlb_1gb
  ...
  Populate memory time: 10.204573342s
Signed-off-by: default avatarDavid Matlack <dmatlack@google.com>
Message-Id: <20211111001257.1446428-4-dmatlack@google.com>
Signed-off-by: default avatarPaolo Bonzini <pbonzini@redhat.com>
parent 81bcb261
...@@ -22,6 +22,9 @@ struct vcpu_thread { ...@@ -22,6 +22,9 @@ struct vcpu_thread {
/* The pthread backing the vCPU. */ /* The pthread backing the vCPU. */
pthread_t thread; pthread_t thread;
/* Set to true once the vCPU thread is up and running. */
bool running;
}; };
/* The vCPU threads involved in this test. */ /* The vCPU threads involved in this test. */
...@@ -30,6 +33,9 @@ static struct vcpu_thread vcpu_threads[KVM_MAX_VCPUS]; ...@@ -30,6 +33,9 @@ static struct vcpu_thread vcpu_threads[KVM_MAX_VCPUS];
/* The function run by each vCPU thread, as provided by the test. */ /* The function run by each vCPU thread, as provided by the test. */
static void (*vcpu_thread_fn)(struct perf_test_vcpu_args *); static void (*vcpu_thread_fn)(struct perf_test_vcpu_args *);
/* Set to true once all vCPU threads are up and running. */
static bool all_vcpu_threads_running;
/* /*
* Continuously write to the first 8 bytes of each page in the * Continuously write to the first 8 bytes of each page in the
* specified region. * specified region.
...@@ -196,6 +202,17 @@ static void *vcpu_thread_main(void *data) ...@@ -196,6 +202,17 @@ static void *vcpu_thread_main(void *data)
{ {
struct vcpu_thread *vcpu = data; struct vcpu_thread *vcpu = data;
WRITE_ONCE(vcpu->running, true);
/*
* Wait for all vCPU threads to be up and running before calling the test-
* provided vCPU thread function. This prevents thread creation (which
* requires taking the mmap_sem in write mode) from interfering with the
* guest faulting in its memory.
*/
while (!READ_ONCE(all_vcpu_threads_running))
;
vcpu_thread_fn(&perf_test_args.vcpu_args[vcpu->vcpu_id]); vcpu_thread_fn(&perf_test_args.vcpu_args[vcpu->vcpu_id]);
return NULL; return NULL;
...@@ -206,14 +223,23 @@ void perf_test_start_vcpu_threads(int vcpus, void (*vcpu_fn)(struct perf_test_vc ...@@ -206,14 +223,23 @@ void perf_test_start_vcpu_threads(int vcpus, void (*vcpu_fn)(struct perf_test_vc
int vcpu_id; int vcpu_id;
vcpu_thread_fn = vcpu_fn; vcpu_thread_fn = vcpu_fn;
WRITE_ONCE(all_vcpu_threads_running, false);
for (vcpu_id = 0; vcpu_id < vcpus; vcpu_id++) { for (vcpu_id = 0; vcpu_id < vcpus; vcpu_id++) {
struct vcpu_thread *vcpu = &vcpu_threads[vcpu_id]; struct vcpu_thread *vcpu = &vcpu_threads[vcpu_id];
vcpu->vcpu_id = vcpu_id; vcpu->vcpu_id = vcpu_id;
WRITE_ONCE(vcpu->running, false);
pthread_create(&vcpu->thread, NULL, vcpu_thread_main, vcpu); pthread_create(&vcpu->thread, NULL, vcpu_thread_main, vcpu);
} }
for (vcpu_id = 0; vcpu_id < vcpus; vcpu_id++) {
while (!READ_ONCE(vcpu_threads[vcpu_id].running))
;
}
WRITE_ONCE(all_vcpu_threads_running, true);
} }
void perf_test_join_vcpu_threads(int vcpus) void perf_test_join_vcpu_threads(int vcpus)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment