[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[PATCH 42/42] migration-test: Split vcpu-dirty-limit-test
From: |
Juan Quintela |
Subject: |
[PATCH 42/42] migration-test: Split vcpu-dirty-limit-test |
Date: |
Fri, 9 Jun 2023 00:49:43 +0200 |
It is not really a migration test, it just happens that migration
infrastructure is useful to it.
Once there, put migration-helpers.* as maintained.
Signed-off-by: Juan Quintela <quintela@redhat.com>
---
MAINTAINERS | 3 +-
tests/qtest/migration-test.c | 246 ----------------------
tests/qtest/vcpu-dirty-limit-test.c | 310 ++++++++++++++++++++++++++++
tests/qtest/meson.build | 5 +-
4 files changed, 316 insertions(+), 248 deletions(-)
create mode 100644 tests/qtest/vcpu-dirty-limit-test.c
diff --git a/MAINTAINERS b/MAINTAINERS
index 436b3f0afe..20de5ae8b5 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -3176,7 +3176,8 @@ F: include/qemu/userfaultfd.h
F: migration/
F: scripts/vmstate-static-checker.py
F: tests/vmstate-static-checker-data/
-F: tests/qtest/migration-test.c
+F: tests/qtest/migration-*
+F: tests/qtest/vcpu-dirty-limit-test.c
F: docs/devel/migration.rst
F: qapi/migration.json
F: tests/migration/
diff --git a/tests/qtest/migration-test.c b/tests/qtest/migration-test.c
index 4d3321b7b3..58bb829dcf 100644
--- a/tests/qtest/migration-test.c
+++ b/tests/qtest/migration-test.c
@@ -14,17 +14,11 @@
#include "libqtest.h"
#include "qapi/error.h"
-#include "qapi/qmp/qdict.h"
-#include "qemu/module.h"
#include "qemu/option.h"
-#include "qemu/range.h"
#include "qemu/sockets.h"
-#include "chardev/char.h"
#include "qapi/qapi-visit-sockets.h"
#include "qapi/qobject-input-visitor.h"
-#include "qapi/qobject-output-visitor.h"
#include "crypto/tlscredspsk.h"
-#include "qapi/qmp/qlist.h"
#include "migration-helpers.h"
#include "tests/migration/migration-test.h"
@@ -37,12 +31,6 @@
static bool uffd_feature_thread_id;
-/*
- * Dirtylimit stop working if dirty page rate error
- * value less than DIRTYLIMIT_TOLERANCE_RANGE
- */
-#define DIRTYLIMIT_TOLERANCE_RANGE 25 /* MB/s */
-
#if defined(__linux__)
#include <sys/syscall.h>
#include <sys/vfs.h>
@@ -2146,238 +2134,6 @@ static void test_multifd_tcp_cancel(void)
guest_destroy(to2);
}
-static void calc_dirty_rate(QTestState *who, uint64_t calc_time)
-{
- qtest_qmp_assert_success(who,
- "{ 'execute': 'calc-dirty-rate',"
- "'arguments': { "
- "'calc-time': %" PRIu64 ","
- "'mode': 'dirty-ring' }}",
- calc_time);
-}
-
-static QDict *query_dirty_rate(QTestState *who)
-{
- return qtest_qmp_assert_success_ref(who,
- "{ 'execute': 'query-dirty-rate' }");
-}
-
-static void dirtylimit_set_all(QTestState *who, uint64_t dirtyrate)
-{
- qtest_qmp_assert_success(who,
- "{ 'execute': 'set-vcpu-dirty-limit',"
- "'arguments': { "
- "'dirty-rate': %" PRIu64 " } }",
- dirtyrate);
-}
-
-static void cancel_vcpu_dirty_limit(QTestState *who)
-{
- qtest_qmp_assert_success(who,
- "{ 'execute': 'cancel-vcpu-dirty-limit' }");
-}
-
-static QDict *query_vcpu_dirty_limit(QTestState *who)
-{
- QDict *rsp;
-
- rsp = qtest_qmp(who, "{ 'execute': 'query-vcpu-dirty-limit' }");
- g_assert(!qdict_haskey(rsp, "error"));
- g_assert(qdict_haskey(rsp, "return"));
-
- return rsp;
-}
-
-static bool calc_dirtyrate_ready(QTestState *who)
-{
- QDict *rsp_return;
- gchar *status;
-
- rsp_return = query_dirty_rate(who);
- g_assert(rsp_return);
-
- status = g_strdup(qdict_get_str(rsp_return, "status"));
- g_assert(status);
-
- return g_strcmp0(status, "measuring");
-}
-
-static void wait_for_calc_dirtyrate_complete(QTestState *who,
- int64_t time_s)
-{
- int max_try_count = 10000;
- usleep(time_s * 1000000);
-
- while (!calc_dirtyrate_ready(who) && max_try_count--) {
- usleep(1000);
- }
-
- /*
- * Set the timeout with 10 s(max_try_count * 1000us),
- * if dirtyrate measurement not complete, fail test.
- */
- g_assert_cmpint(max_try_count, !=, 0);
-}
-
-static int64_t get_dirty_rate(QTestState *who)
-{
- QDict *rsp_return;
- gchar *status;
- QList *rates;
- const QListEntry *entry;
- QDict *rate;
- int64_t dirtyrate;
-
- rsp_return = query_dirty_rate(who);
- g_assert(rsp_return);
-
- status = g_strdup(qdict_get_str(rsp_return, "status"));
- g_assert(status);
- g_assert_cmpstr(status, ==, "measured");
-
- rates = qdict_get_qlist(rsp_return, "vcpu-dirty-rate");
- g_assert(rates && !qlist_empty(rates));
-
- entry = qlist_first(rates);
- g_assert(entry);
-
- rate = qobject_to(QDict, qlist_entry_obj(entry));
- g_assert(rate);
-
- dirtyrate = qdict_get_try_int(rate, "dirty-rate", -1);
-
- qobject_unref(rsp_return);
- return dirtyrate;
-}
-
-static int64_t get_limit_rate(QTestState *who)
-{
- QDict *rsp_return;
- QList *rates;
- const QListEntry *entry;
- QDict *rate;
- int64_t dirtyrate;
-
- rsp_return = query_vcpu_dirty_limit(who);
- g_assert(rsp_return);
-
- rates = qdict_get_qlist(rsp_return, "return");
- g_assert(rates && !qlist_empty(rates));
-
- entry = qlist_first(rates);
- g_assert(entry);
-
- rate = qobject_to(QDict, qlist_entry_obj(entry));
- g_assert(rate);
-
- dirtyrate = qdict_get_try_int(rate, "limit-rate", -1);
-
- qobject_unref(rsp_return);
- return dirtyrate;
-}
-
-static GuestState *dirtylimit_start_vm(void)
-{
- GuestState *vm = guest_create("dirtylimit-test");
-
- guest_use_dirty_ring(vm);
- guest_realize(vm);
-
- return vm;
-}
-
-static void dirtylimit_stop_vm(GuestState *vm)
-{
- guest_destroy(vm);
-}
-
-static void test_vcpu_dirty_limit(void)
-{
- int64_t origin_rate;
- int64_t quota_rate;
- int64_t rate ;
- int max_try_count = 20;
- int hit = 0;
-
- /* Start vm for vcpu dirtylimit test */
- GuestState *vm = dirtylimit_start_vm();
-
- /* Wait for the first serial output from the vm*/
- wait_for_serial(vm);
-
- /* Do dirtyrate measurement with calc time equals 1s */
- calc_dirty_rate(vm->qs, 1);
-
- /* Sleep calc time and wait for calc dirtyrate complete */
- wait_for_calc_dirtyrate_complete(vm->qs, 1);
-
- /* Query original dirty page rate */
- origin_rate = get_dirty_rate(vm->qs);
-
- /* VM booted from bootsect should dirty memory steadily */
- assert(origin_rate != 0);
-
- /* Setup quota dirty page rate at half of origin */
- quota_rate = origin_rate / 2;
-
- /* Set dirtylimit */
- dirtylimit_set_all(vm->qs, quota_rate);
-
- /*
- * Check if set-vcpu-dirty-limit and query-vcpu-dirty-limit
- * works literally
- */
- g_assert_cmpint(quota_rate, ==, get_limit_rate(vm->qs));
-
- /* Sleep a bit to check if it take effect */
- usleep(2000000);
-
- /*
- * Check if dirtylimit take effect realistically, set the
- * timeout with 20 s(max_try_count * 1s), if dirtylimit
- * doesn't take effect, fail test.
- */
- while (--max_try_count) {
- calc_dirty_rate(vm->qs, 1);
- wait_for_calc_dirtyrate_complete(vm->qs, 1);
- rate = get_dirty_rate(vm->qs);
-
- /*
- * Assume hitting if current rate is less
- * than quota rate (within accepting error)
- */
- if (rate < (quota_rate + DIRTYLIMIT_TOLERANCE_RANGE)) {
- hit = 1;
- break;
- }
- }
-
- g_assert_cmpint(hit, ==, 1);
-
- hit = 0;
- max_try_count = 20;
-
- /* Check if dirtylimit cancellation take effect */
- cancel_vcpu_dirty_limit(vm->qs);
- while (--max_try_count) {
- calc_dirty_rate(vm->qs, 1);
- wait_for_calc_dirtyrate_complete(vm->qs, 1);
- rate = get_dirty_rate(vm->qs);
-
- /*
- * Assume dirtylimit be canceled if current rate is
- * greater than quota rate (within accepting error)
- */
- if (rate > (quota_rate + DIRTYLIMIT_TOLERANCE_RANGE)) {
- hit = 1;
- break;
- }
- }
-
- g_assert_cmpint(hit, ==, 1);
- dirtylimit_stop_vm(vm);
-}
-
static bool shm_supported(void)
{
if (g_file_test("/dev/shm", G_FILE_TEST_IS_DIR)) {
@@ -2566,8 +2322,6 @@ int main(int argc, char **argv)
if (g_str_equal(arch, "x86_64") && has_kvm && kvm_dirty_ring_supported()) {
qtest_add_func("/migration/dirty_ring",
test_precopy_unix_dirty_ring);
- qtest_add_func("/migration/vcpu_dirty_limit",
- test_vcpu_dirty_limit);
}
ret = g_test_run();
diff --git a/tests/qtest/vcpu-dirty-limit-test.c
b/tests/qtest/vcpu-dirty-limit-test.c
new file mode 100644
index 0000000000..eebcf04509
--- /dev/null
+++ b/tests/qtest/vcpu-dirty-limit-test.c
@@ -0,0 +1,310 @@
+/*
+ * QTest testcase for vcpu-dirty-limit
+ *
+ * Copyright (c) 2016-2018 Red Hat, Inc. and/or its affiliates
+ * based on the vhost-user-test.c that is:
+ * Copyright (c) 2014 Virtual Open Systems Sarl.
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ *
+ */
+
+#include "qemu/osdep.h"
+
+#include "qemu/module.h"
+#include "qapi/qmp/qlist.h"
+
+#include "migration-helpers.h"
+
+/* For dirty ring test */
+#if defined(__linux__) && defined(HOST_X86_64)
+#include "linux/kvm.h"
+#include <sys/ioctl.h>
+#endif
+
+/*
+ * Dirtylimit stop working if dirty page rate error
+ * value less than DIRTYLIMIT_TOLERANCE_RANGE
+ */
+#define DIRTYLIMIT_TOLERANCE_RANGE 25 /* MB/s */
+
+static void calc_dirty_rate(QTestState *who, uint64_t calc_time)
+{
+ qtest_qmp_assert_success(who,
+ "{ 'execute': 'calc-dirty-rate',"
+ "'arguments': { "
+ "'calc-time': %" PRIu64 ","
+ "'mode': 'dirty-ring' }}",
+ calc_time);
+}
+
+static QDict *query_dirty_rate(QTestState *who)
+{
+ return qtest_qmp_assert_success_ref(who,
+ "{ 'execute': 'query-dirty-rate' }");
+}
+
+static void dirtylimit_set_all(QTestState *who, uint64_t dirtyrate)
+{
+ qtest_qmp_assert_success(who,
+ "{ 'execute': 'set-vcpu-dirty-limit',"
+ "'arguments': { "
+ "'dirty-rate': %" PRIu64 " } }",
+ dirtyrate);
+}
+
+static void cancel_vcpu_dirty_limit(QTestState *who)
+{
+ qtest_qmp_assert_success(who,
+ "{ 'execute': 'cancel-vcpu-dirty-limit' }");
+}
+
+static QDict *query_vcpu_dirty_limit(QTestState *who)
+{
+ QDict *rsp;
+
+ rsp = qtest_qmp(who, "{ 'execute': 'query-vcpu-dirty-limit' }");
+ g_assert(!qdict_haskey(rsp, "error"));
+ g_assert(qdict_haskey(rsp, "return"));
+
+ return rsp;
+}
+
+static bool calc_dirtyrate_ready(QTestState *who)
+{
+ QDict *rsp_return;
+ gchar *status;
+
+ rsp_return = query_dirty_rate(who);
+ g_assert(rsp_return);
+
+ status = g_strdup(qdict_get_str(rsp_return, "status"));
+ g_assert(status);
+
+ return g_strcmp0(status, "measuring");
+}
+
+static void wait_for_calc_dirtyrate_complete(QTestState *who,
+ int64_t time_s)
+{
+ int max_try_count = 10000;
+ usleep(time_s * 1000000);
+
+ while (!calc_dirtyrate_ready(who) && max_try_count--) {
+ usleep(1000);
+ }
+
+ /*
+ * Set the timeout with 10 s(max_try_count * 1000us),
+ * if dirtyrate measurement not complete, fail test.
+ */
+ g_assert_cmpint(max_try_count, !=, 0);
+}
+
+static int64_t get_dirty_rate(QTestState *who)
+{
+ QDict *rsp_return;
+ gchar *status;
+ QList *rates;
+ const QListEntry *entry;
+ QDict *rate;
+ int64_t dirtyrate;
+
+ rsp_return = query_dirty_rate(who);
+ g_assert(rsp_return);
+
+ status = g_strdup(qdict_get_str(rsp_return, "status"));
+ g_assert(status);
+ g_assert_cmpstr(status, ==, "measured");
+
+ rates = qdict_get_qlist(rsp_return, "vcpu-dirty-rate");
+ g_assert(rates && !qlist_empty(rates));
+
+ entry = qlist_first(rates);
+ g_assert(entry);
+
+ rate = qobject_to(QDict, qlist_entry_obj(entry));
+ g_assert(rate);
+
+ dirtyrate = qdict_get_try_int(rate, "dirty-rate", -1);
+
+ qobject_unref(rsp_return);
+ return dirtyrate;
+}
+
+static int64_t get_limit_rate(QTestState *who)
+{
+ QDict *rsp_return;
+ QList *rates;
+ const QListEntry *entry;
+ QDict *rate;
+ int64_t dirtyrate;
+
+ rsp_return = query_vcpu_dirty_limit(who);
+ g_assert(rsp_return);
+
+ rates = qdict_get_qlist(rsp_return, "return");
+ g_assert(rates && !qlist_empty(rates));
+
+ entry = qlist_first(rates);
+ g_assert(entry);
+
+ rate = qobject_to(QDict, qlist_entry_obj(entry));
+ g_assert(rate);
+
+ dirtyrate = qdict_get_try_int(rate, "limit-rate", -1);
+
+ qobject_unref(rsp_return);
+ return dirtyrate;
+}
+
+static GuestState *dirtylimit_start_vm(void)
+{
+ GuestState *vm = guest_create("dirtylimit-test");
+
+ guest_use_dirty_ring(vm);
+ guest_realize(vm);
+
+ return vm;
+}
+
+static void dirtylimit_stop_vm(GuestState *vm)
+{
+ guest_destroy(vm);
+}
+
+static void test_vcpu_dirty_limit(void)
+{
+ int64_t origin_rate;
+ int64_t quota_rate;
+ int64_t rate ;
+ int max_try_count = 20;
+ int hit = 0;
+
+ /* Start vm for vcpu dirtylimit test */
+ GuestState *vm = dirtylimit_start_vm();
+
+ /* Wait for the first serial output from the vm*/
+ wait_for_serial(vm);
+
+ /* Do dirtyrate measurement with calc time equals 1s */
+ calc_dirty_rate(vm->qs, 1);
+
+ /* Sleep calc time and wait for calc dirtyrate complete */
+ wait_for_calc_dirtyrate_complete(vm->qs, 1);
+
+ /* Query original dirty page rate */
+ origin_rate = get_dirty_rate(vm->qs);
+
+ /* VM booted from bootsect should dirty memory steadily */
+ assert(origin_rate != 0);
+
+ /* Setup quota dirty page rate at half of origin */
+ quota_rate = origin_rate / 2;
+
+ /* Set dirtylimit */
+ dirtylimit_set_all(vm->qs, quota_rate);
+
+ /*
+ * Check if set-vcpu-dirty-limit and query-vcpu-dirty-limit
+ * works literally
+ */
+ g_assert_cmpint(quota_rate, ==, get_limit_rate(vm->qs));
+
+ /* Sleep a bit to check if it take effect */
+ usleep(2000000);
+
+ /*
+ * Check if dirtylimit take effect realistically, set the
+ * timeout with 20 s(max_try_count * 1s), if dirtylimit
+ * doesn't take effect, fail test.
+ */
+ while (--max_try_count) {
+ calc_dirty_rate(vm->qs, 1);
+ wait_for_calc_dirtyrate_complete(vm->qs, 1);
+ rate = get_dirty_rate(vm->qs);
+
+ /*
+ * Assume hitting if current rate is less
+ * than quota rate (within accepting error)
+ */
+ if (rate < (quota_rate + DIRTYLIMIT_TOLERANCE_RANGE)) {
+ hit = 1;
+ break;
+ }
+ }
+
+ g_assert_cmpint(hit, ==, 1);
+
+ hit = 0;
+ max_try_count = 20;
+
+ /* Check if dirtylimit cancellation take effect */
+ cancel_vcpu_dirty_limit(vm->qs);
+ while (--max_try_count) {
+ calc_dirty_rate(vm->qs, 1);
+ wait_for_calc_dirtyrate_complete(vm->qs, 1);
+ rate = get_dirty_rate(vm->qs);
+
+ /*
+ * Assume dirtylimit be canceled if current rate is
+ * greater than quota rate (within accepting error)
+ */
+ if (rate > (quota_rate + DIRTYLIMIT_TOLERANCE_RANGE)) {
+ hit = 1;
+ break;
+ }
+ }
+
+ g_assert_cmpint(hit, ==, 1);
+ dirtylimit_stop_vm(vm);
+}
+
+int main(int argc, char **argv)
+{
+ g_autoptr(GError) err = NULL;
+
+ g_test_init(&argc, &argv, NULL);
+
+ if (!qtest_has_accel("kvm")) {
+ g_test_skip("No KVM or TCG accelerator available");
+ return 0;
+ }
+
+ if (!g_str_equal(qtest_get_arch(), "x86_64")) {
+ g_test_skip("Only x86_64 support available");
+ return 0;
+ }
+
+ if (!kvm_dirty_ring_supported()) {
+ g_test_skip("KVM dirty ring is not supported");
+ return 0;
+ }
+
+ tmpfs = g_dir_make_tmp("vcpu-dirty-limit-test-XXXXXX", &err);
+ if (!tmpfs) {
+ g_test_message("Can't create temporary directory in %s: %s",
+ g_get_tmp_dir(), err->message);
+ }
+ g_assert(tmpfs);
+ bootfile_create(tmpfs);
+
+ module_call_init(MODULE_INIT_QOM);
+
+ qtest_add_func("/vcpu_dirty_limit/basic", test_vcpu_dirty_limit);
+
+ int ret = g_test_run();
+
+ g_assert_cmpint(ret, ==, 0);
+
+ bootfile_delete();
+ ret = rmdir(tmpfs);
+ if (ret != 0) {
+ g_test_message("unable to rmdir: path (%s): %s",
+ tmpfs, strerror(errno));
+ }
+ g_free(tmpfs);
+
+ return ret;
+}
diff --git a/tests/qtest/meson.build b/tests/qtest/meson.build
index 5fa6833ad7..ed0d03e3d3 100644
--- a/tests/qtest/meson.build
+++ b/tests/qtest/meson.build
@@ -9,6 +9,7 @@ slow_qtests = {
'qos-test' : 60,
'qom-test' : 300,
'test-hmp' : 120,
+ 'vcpu-dirty-limit' : 150,
}
qtests_generic = [
@@ -101,7 +102,8 @@ qtests_i386 = \
'vmgenid-test',
'migration-test',
'test-x86-cpuid-compat',
- 'numa-test'
+ 'numa-test',
+ 'vcpu-dirty-limit-test',
]
if dbus_display and targetos != 'windows'
@@ -315,6 +317,7 @@ qtests = {
'tpm-tis-device-test': [io, tpmemu_files, 'tpm-tis-util.c'],
'vmgenid-test': files('boot-sector.c', 'acpi-utils.c'),
'netdev-socket': files('netdev-socket.c', '../unit/socket-helpers.c'),
+ 'vcpu-dirty-limit-test': migration_files,
}
if vnc.found()
--
2.40.1
- [PATCH 33/42] migration-test: Remove connect_uri, (continued)
- [PATCH 33/42] migration-test: Remove connect_uri, Juan Quintela, 2023/06/08
- [PATCH 31/42] migration-test: Preffer to->uri to uri parameter for migration, Juan Quintela, 2023/06/08
- [PATCH 36/42] migration-test: Remove unused listen_uri, Juan Quintela, 2023/06/08
- [PATCH 34/42] migration-test: Use new schema for all tests that use unix sockets, Juan Quintela, 2023/06/08
- [PATCH 35/42] migration-test: Set uri for tcp tests with guest_set_uri(), Juan Quintela, 2023/06/08
- [PATCH 37/42] migration-test: Create get_event GuestState variable, Juan Quintela, 2023/06/08
- [PATCH 38/42] migration-test: Create guest_realize(), Juan Quintela, 2023/06/08
- [PATCH 39/42] migration-test: Unfold test_migrate_end() into three functions, Juan Quintela, 2023/06/08
- [PATCH 40/42] migration-test: Create migrate_incoming() function, Juan Quintela, 2023/06/08
- [PATCH 41/42] migration-test: Move functions to migration-helpers.c, Juan Quintela, 2023/06/08
- [PATCH 42/42] migration-test: Split vcpu-dirty-limit-test,
Juan Quintela <=