[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-devel] [PATCH RFC v2 05/12] VMstate test: basic VMState testing me
From: |
Sanidhya Kashyap |
Subject: |
[Qemu-devel] [PATCH RFC v2 05/12] VMstate test: basic VMState testing mechanism |
Date: |
Fri, 25 Jul 2014 21:09:29 +0530 |
In this patch, I have made the following changes:
* changed the DPRINT statement.
* renamed the variables.
* added noqdev variable which decides which option to use for resetting.
* added devices option which can help in resetting one or many devices
(only qdevified ones).
* updated the documentation.
Signed-off-by: Sanidhya Kashyap <address@hidden>
---
qapi-schema.json | 26 ++++++
qmp-commands.hx | 37 ++++++++
savevm.c | 251 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 314 insertions(+)
diff --git a/qapi-schema.json b/qapi-schema.json
index 996e6b5..ec48977 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -3502,3 +3502,29 @@
##
{ 'command': 'query-qdev-devices',
'returns': 'VMStatesQdevDevices' }
+
+##
+# @test-vmstates
+#
+# tests the vmstates' value by dumping and loading in memory
+#
+# @iterations: (optional) The total iterations for vmstate testing.
+# The min and max defind value is 10 and 100 respectively.
+#
+# @period: (optional) sleep interval between iteration (in milliseconds).
+# The default interval is 100 milliseconds with min and max being
+# 1 and 10000 respectively.
+#
+# @noqdev: boolean variable which decides whether to use qdevified devices
+# or not. Will be removed when all the devices have been qdevified.
+#
+# @devices: (optional) helps in resetting particular qdevified decices
+# that have been registered with SaveStateEntry
+#
+# Since 2.2
+##
+{ 'command': 'test-vmstates',
+ 'data': {'*iterations': 'int',
+ '*period': 'int',
+ 'noqdev': 'bool',
+ '*qdevices': 'VMStatesQdevDevices' } }
diff --git a/qmp-commands.hx b/qmp-commands.hx
index 2e20032..6210f56 100644
--- a/qmp-commands.hx
+++ b/qmp-commands.hx
@@ -3778,5 +3778,42 @@ Example (1):
}
]
}
+EQMP
+
+ {
+ .name = "test-vmstates",
+ .args_type = "iterations:i?,period:i?,noqdev:b,qdevices:O?",
+ .mhandler.cmd_new = qmp_marshal_input_test_vmstates,
+ },
+
+SQMP
+test-vmstates
+-------------
+
+Tests the vmstates' entry by dumping and loading in/from memory
+
+Arguments:
+- "iterations": (optional) The total iterations for vmstate testing.
+ The min and max defined value is 10 and 100 respectively.
+
+- "period": (optional) sleep interval between iteration (in milliseconds).
+ The default interval is 100 milliseconds with min and max being
+ 1 and 10000 respectively.
+
+- "noqdev": boolean variable which decides whether to use qdev or not.
+ Will be removed when all the devices have been qdevified.
+
+- "devices": (optional) helps in resetting particular qdevified decices
+ that have been registered with SaveStateEntry
+
+
+Example:
+
+-> { "execute": "test-vmstates",
+ "arguments": {
+ "iterations": 10,
+ "period": 100,
+ "noqdev": false } }
+<- { "return": {} }
EQMP
diff --git a/savevm.c b/savevm.c
index 7c1600a..304d8fc 100644
--- a/savevm.c
+++ b/savevm.c
@@ -1201,6 +1201,257 @@ VMStatesQdevDevices *qmp_query_qdev_devices(Error
**errp)
return qdev_devices;
}
+#define DEBUG_TEST_VMSTATES 1
+
+#ifndef DEBUG_TEST_VMSTATES
+#define DEBUG_TEST_VMSTATES 0
+#endif
+
+#define DPRINTF(fmt, ...) \
+ do { \
+ if (DEBUG_TEST_VMSTATES) { \
+ printf("vmstate_test: " fmt, ## __VA_ARGS__); \
+ } \
+ } while (0)
+
+#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 current_iteration;
+ int64_t iterations;
+ int64_t period;
+ bool active_state;
+ bool noqdev;
+ VMStatesQdevDevices *qdevices;
+ QEMUTimer *timer;
+
+ QTAILQ_HEAD(qdev_list, VMStatesQdevResetEntry) qdev_list;
+};
+
+static VMStateLogState *vmstate_current_state(void)
+{
+ static VMStateLogState current_state = {
+ .active_state = false,
+ };
+
+ return ¤t_state;
+}
+
+static inline void test_vmstates_clear_qdev_entries(VMStateLogState *v)
+{
+ VMStatesQdevResetEntry *qre, *new_qre;
+ QTAILQ_FOREACH_SAFE(qre, &v->qdev_list, entry, new_qre) {
+ QTAILQ_REMOVE(&v->qdev_list, qre, entry);
+ }
+}
+
+static inline bool check_device_name(VMStateLogState *v,
+ VMStatesQdevDevices *qdevices,
+ Error **errp)
+{
+ VMStatesQdevResetEntry *qre;
+ strList *devices_name = qdevices->device;
+ QTAILQ_INIT(&v->qdev_list);
+ bool device_present;
+
+ /* now, checking against each one */
+ for (; devices_name; devices_name = devices_name->next) {
+ device_present = false;
+ VMStatesQdevResetEntry *new_qre;
+ QTAILQ_FOREACH(qre, &vmstate_reset_handlers, entry) {
+ if (!strcmp(qre->device_name, devices_name->value)) {
+
+ device_present = true;
+
+ new_qre = g_malloc0(sizeof(VMStatesQdevResetEntry));
+ new_qre->dev = qre->dev;
+ strcpy(new_qre->device_name, qre->device_name);
+ QTAILQ_INSERT_TAIL(&v->qdev_list, new_qre, entry);
+
+ break;
+ }
+ }
+ if (!device_present) {
+ test_vmstates_clear_qdev_entries(v);
+ error_setg(errp, "Incorrect device name - %s\n",
+ devices_name->value);
+ return false;
+ }
+ }
+ return true;
+}
+
+static inline void test_vmstates_reset_devices(VMStateLogState *v)
+{
+ VMStatesQdevResetEntry *qre;
+
+ if (v->noqdev) {
+ DPRINTF("resetting all devices\n");
+ qemu_system_reset(VMRESET_SILENT);
+ } else if (!v->qdevices) {
+ QTAILQ_FOREACH(qre, &vmstate_reset_handlers, entry) {
+ DPRINTF("resetting device: %s\n", qre->device_name);
+ device_reset(qre->dev);
+ }
+ } else {
+ QTAILQ_FOREACH(qre, &v->qdev_list, entry) {
+ DPRINTF("resetting device: %s\n", qre->device_name);
+ device_reset(qre->dev);
+ }
+ }
+}
+
+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 save_vmstates_duration, load_vmstates_duration;
+ 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->current_iteration) <= v->iterations) {
+ 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;
+ }
+ save_vmstates_duration = qemu_clock_get_ms(QEMU_CLOCK_REALTIME) -
+ start_time;
+ DPRINTF("iteration: %ld, save time (ms): %ld\n",
+ v->current_iteration, save_vmstates_duration);
+
+ /* clearing the states of the guest */
+ test_vmstates_reset_devices(v);
+
+ 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;
+ }
+ load_vmstates_duration = qemu_clock_get_ms(QEMU_CLOCK_REALTIME) -
+ start_time;
+ DPRINTF("iteration: %ld, load time (ms): %ld\n",
+ v->current_iteration, load_vmstates_duration);
+
+ if (saved_vm_running) {
+ vm_start();
+ }
+ timer_mod(v->timer, qemu_clock_get_ms(QEMU_CLOCK_REALTIME) +
+ v->period);
+ return;
+ }
+
+ testing_end:
+ if (saved_vm_running) {
+ vm_start();
+ }
+ timer_del(v->timer);
+ timer_free(v->timer);
+ test_vmstates_clear_qdev_entries(v);
+ v->active_state = false;
+ return;
+}
+
+void qmp_test_vmstates(bool has_iterations, int64_t iterations,
+ bool has_period, int64_t period, bool noqdev,
+ bool has_qdevices, VMStatesQdevDevices *qdevices,
+ Error **errp)
+{
+ VMStateLogState *v = vmstate_current_state();
+ Error *local_err;
+
+ if (v->active_state) {
+ error_setg(errp, "VMState testing already in progress\n");
+ return;
+ }
+
+ v->active_state = true;
+
+ /* checking the value of total iterations to be in the defined range */
+ if (!has_iterations) {
+ v->iterations = TEST_VMSTATE_MIN_TIMES;
+ } else if (iterations >= TEST_VMSTATE_MIN_TIMES &&
+ iterations <= TEST_VMSTATE_MAX_TIMES) {
+ v->iterations = iterations;
+ } else {
+ error_setg(errp, "iterations value must be in the range [%d, %d]\n",
+ TEST_VMSTATE_MIN_TIMES, TEST_VMSTATE_MAX_TIMES);
+ v->active_state = false;
+ return;
+ }
+
+ /* checking for the value of period to be in the defined range */
+ if (!has_period) {
+ v->period = TEST_VMSTATE_DEFAULT_INTERVAL_MS;
+ } else if (period >= TEST_VMSTATE_MIN_INTERVAL_MS &&
+ period <= TEST_VMSTATE_MAX_INTERVAL_MS) {
+ v->period = period;
+ } else {
+ error_setg(errp, "sleep interval (period) value must be "
+ "in the defined range [%d, %d](ms)\n",
+ TEST_VMSTATE_MIN_INTERVAL_MS, TEST_VMSTATE_MAX_INTERVAL_MS);
+ v->active_state = false;
+ return;
+ }
+
+ /*
+ * checking the devices information
+ * if no devices have been selected, then all the devices will be tested
+ * noqdev -> if true -- then use qemu_system_reset
+ * -> if false -- then use qdevified devices
+ */
+ if (noqdev && has_qdevices) {
+ error_setg(errp, "either qdev or non-qdev devices allowed, not
both\n");
+ return;
+ } else if (!noqdev && !has_qdevices) {
+ v->qdevices = NULL;
+ } else if (has_qdevices) {
+ if (check_device_name(v, qdevices, &local_err)) {
+ v->qdevices = qdevices;
+ } else {
+ if (local_err) {
+ error_propagate(errp, local_err);
+ }
+ return;
+ }
+ }
+
+ v->noqdev = noqdev;
+ v->current_iteration = 0;
+ 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
- [Qemu-devel] [PATCH RFC v2 01/12] QEMUSizedBuffer/QEMUFile, (continued)
- [Qemu-devel] [PATCH RFC v2 01/12] QEMUSizedBuffer/QEMUFile, Sanidhya Kashyap, 2014/07/25
- [Qemu-devel] [PATCH RFC v2 02/12] reset handler for qdevified devices, Sanidhya Kashyap, 2014/07/25
- [Qemu-devel] [PATCH RFC v2 03/12] VMState test: query command to extract the qdevified device names, Sanidhya Kashyap, 2014/07/25
- [Qemu-devel] [PATCH RFC v2 04/12] VMState test: hmp interface for showing qdevified devices, Sanidhya Kashyap, 2014/07/25
- [Qemu-devel] [PATCH RFC v2 05/12] VMstate test: basic VMState testing mechanism,
Sanidhya Kashyap <=
- [Qemu-devel] [PATCH RFC v2 06/12] VMState test: hmp interface for vmstate testing, Sanidhya Kashyap, 2014/07/25
- [Qemu-devel] [PATCH RFC v2 07/12] VMState test: qmp interface for querying the vmstate testing process, Sanidhya Kashyap, 2014/07/25
- [Qemu-devel] [PATCH RFC v2 08/12] VMState test: hmp interface for querying the vmstate testing process, Sanidhya Kashyap, 2014/07/25
- [Qemu-devel] [PATCH RFC v2 09/12] VMState test: update period of vmstate testing process, Sanidhya Kashyap, 2014/07/25