From: Sanidhya Kashyap <sanidhya.iiith@gmail.com>
To: qemu list <qemu-devel@nongnu.org>
Cc: Sanidhya Kashyap <sanidhya.iiith@gmail.com>,
"Dr. David Alan Gilbert" <dgilbert@redhat.com>,
Juan Quintela <quintela@redhat.com>
Subject: [Qemu-devel] [PATCH RFC v2 05/12] VMstate test: basic VMState testing mechanism
Date: Fri, 25 Jul 2014 21:09:29 +0530 [thread overview]
Message-ID: <1406302776-2306-6-git-send-email-sanidhya.iiith@gmail.com> (raw)
In-Reply-To: <1406302776-2306-1-git-send-email-sanidhya.iiith@gmail.com>
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 <sanidhya.iiith@gmail.com>
---
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
next prev parent reply other threads:[~2014-07-25 15:41 UTC|newest]
Thread overview: 32+ messages / expand[flat|nested] mbox.gz Atom feed top
2014-07-25 15:39 [Qemu-devel] [PATCH RFC v2 00/12] VMState testing Sanidhya Kashyap
2014-07-25 15:39 ` [Qemu-devel] [PATCH RFC v2 01/12] QEMUSizedBuffer/QEMUFile Sanidhya Kashyap
2014-07-28 21:32 ` Eric Blake
2014-08-06 11:11 ` Dr. David Alan Gilbert
2014-07-25 15:39 ` [Qemu-devel] [PATCH RFC v2 02/12] reset handler for qdevified devices Sanidhya Kashyap
2014-07-29 12:43 ` Juan Quintela
2014-07-25 15:39 ` [Qemu-devel] [PATCH RFC v2 03/12] VMState test: query command to extract the qdevified device names Sanidhya Kashyap
2014-07-28 21:47 ` Eric Blake
2014-07-29 12:45 ` Juan Quintela
2014-07-29 15:14 ` Eric Blake
2014-07-29 17:37 ` Sanidhya Kashyap
2014-07-25 15:39 ` [Qemu-devel] [PATCH RFC v2 04/12] VMState test: hmp interface for showing qdevified devices Sanidhya Kashyap
2014-07-25 15:39 ` Sanidhya Kashyap [this message]
2014-07-28 21:52 ` [Qemu-devel] [PATCH RFC v2 05/12] VMstate test: basic VMState testing mechanism Eric Blake
2014-07-29 13:40 ` Juan Quintela
2014-07-29 17:59 ` Sanidhya Kashyap
2014-07-25 15:39 ` [Qemu-devel] [PATCH RFC v2 06/12] VMState test: hmp interface for vmstate testing Sanidhya Kashyap
2014-07-25 15:39 ` [Qemu-devel] [PATCH RFC v2 07/12] VMState test: qmp interface for querying the vmstate testing process Sanidhya Kashyap
2014-07-29 15:17 ` Eric Blake
2014-07-29 16:40 ` Eric Blake
2014-07-25 15:39 ` [Qemu-devel] [PATCH RFC v2 08/12] VMState test: hmp " Sanidhya Kashyap
2014-07-25 15:39 ` [Qemu-devel] [PATCH RFC v2 09/12] VMState test: update period of " Sanidhya Kashyap
2014-07-29 16:48 ` Eric Blake
2014-07-29 18:04 ` Sanidhya Kashyap
2014-07-29 19:42 ` Eric Blake
2014-07-25 15:39 ` [Qemu-devel] [PATCH RFC v2 10/12] VMState test: hmp interface for period update Sanidhya Kashyap
2014-07-25 15:39 ` [Qemu-devel] [PATCH RFC v2 11/12] VMState test: cancel mechanism for an already running vmstate testing process Sanidhya Kashyap
2014-07-29 16:50 ` Eric Blake
2014-07-25 15:39 ` [Qemu-devel] [PATCH RFC v2 12/12] VMState test: hmp interface for cancel mechanism Sanidhya Kashyap
2014-07-29 16:52 ` Eric Blake
2014-07-29 18:06 ` Sanidhya Kashyap
2014-07-30 5:48 ` Markus Armbruster
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1406302776-2306-6-git-send-email-sanidhya.iiith@gmail.com \
--to=sanidhya.iiith@gmail.com \
--cc=dgilbert@redhat.com \
--cc=qemu-devel@nongnu.org \
--cc=quintela@redhat.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).