qemu-devel
[Top][All Lists]
Advanced

[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




reply via email to

[Prev in Thread] Current Thread [Next in Thread]