qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Qemu-devel] [RFC PATCH v1 2/5] VMState test: basic vmstate testing mech


From: Sanidhya Kashyap
Subject: [Qemu-devel] [RFC PATCH v1 2/5] VMState test: basic vmstate testing mechanism
Date: Mon, 7 Jul 2014 22:48:01 +0530

This patch introduces the mechanism to test the devices state by storing
and dumping in in the QEMUFile pointer.

The testing is done as follows:
1) The VM is halted.
2) guest state is synchronized.
3) Then the device state is dumped to a temporary memory.
4) The guest state is reset.
5) Then the device state is loaded from the temporary memory.
6) The guest is resumed.

If the guest resumes, then there is no issue with the vmstates.

Currently, in this patch, I am directly using the qemu_system_reset()
function to reset all the states of the guest. But, what I have found
is that there is a difference in the registration of devices' reset
function in QEMUResetEntry and in SaveStateEntry. Since, we dump and
load all the devices information using the SaveStateEntry, but the reseting
of the devices takes place with the help of QEMUResetEntry. Thus, in
future, I will try to use the qdevified device tree to reset the functions.


As of now, I am providing DPRINTF to know about the amount of time spend in
saving and loading the data from the buffer. If there is any other way that
should be used to print the stats, then please do let me know.

Signed-off-by: Sanidhya Kashyap <address@hidden>
---
 qapi-schema.json |  12 +++++
 qmp-commands.hx  |  28 +++++++++++
 savevm.c         | 148 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 188 insertions(+)

diff --git a/qapi-schema.json b/qapi-schema.json
index b11aad2..92acf91 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -3480,3 +3480,15 @@
 # Since: 2.1
 ##
 { 'command': 'rtc-reset-reinjection' }
+
+## @test-vmstates
+#
+# tests the vmstates' value by dumping and loading in memory
+# @times: total iterations
+# @sinterval: sleep interval between iteration
+#
+# Since 2.1
+##
+{ 'command': 'test-vmstates',
+  'data': {'*times'     : 'int',
+           '*sinterval' : 'int' } }
diff --git a/qmp-commands.hx b/qmp-commands.hx
index 4be4765..ccddabb 100644
--- a/qmp-commands.hx
+++ b/qmp-commands.hx
@@ -3755,3 +3755,31 @@ Example:
 <- { "return": {} }
 
 EQMP
+
+    {
+        .name       = "test-vmstates",
+        .args_type  = "times:i?,sinterval:i?",
+        .mhandler.cmd_new = qmp_marshal_input_test_vmstates,
+    },
+
+SQMP
+test-vmstates
+--------------------
+
+Tests the vmstates' entry by dumping and loading in/from memory
+
+Arguments:
+
+- "times" :    the total iterations for vmstates testing. The default
+               value is 10.
+- "sinterval": the sleep interval between the iterations. The default
+               value is 100 milliseconds.
+
+Example:
+
+-> { "execute": "test-vmstates",
+     "arguments": {
+        "times": 10
+        "sinterval": 100 } }
+<- { "return": {} }
+EQMP
diff --git a/savevm.c b/savevm.c
index e19ae0a..3713a56 100644
--- a/savevm.c
+++ b/savevm.c
@@ -1137,6 +1137,154 @@ void do_savevm(Monitor *mon, const QDict *qdict)
     }
 }
 
+#ifdef DEBUG_TEST_VMSTATES
+#define DPRINTF(fmt, ...) \
+    do { printf("vmstate_test: " fmt, ## __VA_ARGS__); } while (0)
+#else
+#define DPRINTF(fmt, ...) \
+    do { } while (0)
+#endif
+
+#define TEST_VMSTATE_MIN_TIMES 10
+#define TEST_VMSTATE_MAX_TIMES 1000
+
+#define TEST_VMSTATE_MIN_INTERVAL_MS 1
+#define TEST_VMSTATE_DEFAULT_INTERVAL_MS 100
+#define TEST_VMSTATE_MAX_INTERVAL_MS 10000
+
+typedef struct VMStateLogState VMStateLogState;
+
+struct VMStateLogState {
+    int64_t times;
+    int64_t sleep_interval;
+    int64_t save_vmstates_duration;
+    int64_t load_vmstates_duration;
+    bool active_state;
+    QEMUTimer *timer;
+};
+
+static VMStateLogState *vmstate_current_state(void)
+{
+    static VMStateLogState current_state = {
+        .active_state = false,
+    };
+
+    return &current_state;
+}
+
+static void vmstate_test_cb(void *opaque)
+{
+    VMStateLogState *v = opaque;
+    int saved_vm_running = runstate_is_running();
+    const QEMUSizedBuffer *qsb;
+    QEMUFile *f;
+    int ret;
+    int64_t start_time = qemu_clock_get_ms(QEMU_CLOCK_REALTIME);
+
+    /* executing the steps for a single time with the help of timer */
+    if (--(v->times) > 0) {
+        saved_vm_running = runstate_is_running();
+
+        /* stopping the VM before dumping the vmstates */
+        vm_stop(RUN_STATE_SAVE_VM);
+
+        f = qemu_bufopen("w", NULL);
+        if (!f) {
+            goto testing_end;
+        }
+
+        cpu_synchronize_all_states();
+
+        /* saving the vmsates to memory buffer */
+        ret = qemu_save_device_state(f);
+        if (ret < 0) {
+            goto testing_end;
+        }
+        v->save_vmstates_duration = qemu_clock_get_ms(QEMU_CLOCK_REALTIME) -
+                                    start_time;
+        DPRINTF("iteration: %ld, save time: %ld(ms)\n",
+                v->times, v->save_vmstates_duration);
+
+        /* clearing the states of the guest */
+        qemu_system_reset(VMRESET_SILENT);
+
+        start_time = qemu_clock_get_ms(QEMU_CLOCK_REALTIME);
+        qsb = qemu_buf_get(f);
+        f = qemu_bufopen("r", (QEMUSizedBuffer *)qsb);
+        if (!f) {
+            goto testing_end;
+        }
+
+        /* loading the device states from the saved buffer */
+        ret = qemu_loadvm_state(f);
+        qemu_fclose(f);
+        if (ret < 0) {
+            goto testing_end;
+        }
+        v->load_vmstates_duration = qemu_clock_get_ms(QEMU_CLOCK_REALTIME) -
+                                    start_time;
+        DPRINTF("iteration: %ld, load time: %ld(ms)\n",
+                v->times, v->load_vmstates_duration);
+
+        if (saved_vm_running) {
+            vm_start();
+        }
+        timer_mod(v->timer, qemu_clock_get_ms(QEMU_CLOCK_REALTIME) +
+                                              v->sleep_interval);
+        return;
+    }
+
+ testing_end:
+    if (saved_vm_running) {
+        vm_start();
+    }
+    timer_del(v->timer);
+    timer_free(v->timer);
+    v->active_state = false;
+    return;
+}
+
+void qmp_test_vmstates(bool has_times, int64_t times,
+                       bool has_sinterval, int64_t sinterval,
+                       Error **errp)
+{
+    VMStateLogState *v = vmstate_current_state();
+
+    if (v->active_state) {
+        error_setg(errp, "VMState testing already in progress\n");
+        return;
+    }
+
+    /* checking the value of times to be in the defined range */
+    if (!has_times) {
+        v->times = TEST_VMSTATE_MIN_TIMES;
+    } else if (times >= TEST_VMSTATE_MIN_TIMES &&
+               times <= TEST_VMSTATE_MAX_TIMES) {
+        v->times = times;
+    } else {
+        error_setg(errp, "epoch value must be in the range [%d, %d]\n",
+                   TEST_VMSTATE_MIN_TIMES, TEST_VMSTATE_MAX_TIMES);
+        return;
+    }
+
+    /* checking for the value of sleep_interval to be in the defined range */
+    if (!has_sinterval) {
+        v->sleep_interval = TEST_VMSTATE_DEFAULT_INTERVAL_MS;
+    } else if (sinterval >= TEST_VMSTATE_MIN_INTERVAL_MS &&
+               sinterval <= TEST_VMSTATE_MAX_INTERVAL_MS) {
+        v->sleep_interval = sinterval;
+    } else {
+        error_setg(errp, "sleep interval value must be "
+                   "in the defined range [%d, %d](ms)\n",
+                   TEST_VMSTATE_MIN_INTERVAL_MS, TEST_VMSTATE_MAX_INTERVAL_MS);
+        return;
+    }
+
+    v->active_state = true;
+    v->timer = timer_new_ms(QEMU_CLOCK_REALTIME, vmstate_test_cb, v);
+    timer_mod(v->timer, qemu_clock_get_ms(QEMU_CLOCK_REALTIME));
+}
+
 void qmp_xen_save_devices_state(const char *filename, Error **errp)
 {
     QEMUFile *f;
-- 
1.9.3




reply via email to

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