From: "Pavel Dovgaluk" <Pavel.Dovgaluk@ispras.ru>
To: 'QEMU Developers' <qemu-devel@nongnu.org>
Subject: [Qemu-devel] [RFC PATCH 14/22] Command-line options for record/replay
Date: Tue, 1 Jul 2014 15:27:53 +0400 [thread overview]
Message-ID: <008201cf951f$8024e4a0$806eade0$@Dovgaluk@ispras.ru> (raw)
This patch introduces command-line options for record and replay.
Signed-off-by: Pavel Dovgalyuk <pavel.dovgaluk@gmail.com>
---
diff --git a/vl.c b/vl.c
index 41ddcd2..adab76d
--- a/vl.c
+++ b/vl.c
@@ -118,6 +118,7 @@ int main(int argc, char **argv)
#include "qapi/opts-visitor.h"
#include "qom/object_interfaces.h"
#include "qapi-event.h"
+#include "replay/replay.h"
#define DEFAULT_RAM_SIZE 128
@@ -488,6 +489,63 @@ static QemuOptsList qemu_msg_opts = {
},
};
+static QemuOptsList qemu_record_opts = {
+ .name = "record",
+ .head = QTAILQ_HEAD_INITIALIZER(qemu_record_opts.head),
+ .desc = {
+ {
+ .name = "fname",
+ .type = QEMU_OPT_STRING,
+ },{
+ .name = "period",
+ .type = QEMU_OPT_NUMBER,
+ },{
+ .name = "suffix",
+ .type = QEMU_OPT_STRING,
+ },{
+ .name = "snapshot",
+ .type = QEMU_OPT_BOOL,
+ },{
+ .name = "debug",
+ .type = QEMU_OPT_BOOL,
+ },{
+ .name = "rtc",
+ .type = QEMU_OPT_NUMBER,
+ },{
+ .name = "icount",
+ .type = QEMU_OPT_NUMBER,
+ },
+ { /* end of list */ }
+ },
+};
+
+
+static QemuOptsList qemu_replay_opts = {
+ .name = "replay",
+ .head = QTAILQ_HEAD_INITIALIZER(qemu_replay_opts.head),
+ .desc = {
+ {
+ .name = "fname",
+ .type = QEMU_OPT_STRING,
+ },{
+ .name = "suffix",
+ .type = QEMU_OPT_STRING,
+ },{
+ .name = "snapshot",
+ .type = QEMU_OPT_BOOL,
+ },{
+ .name = "debug",
+ .type = QEMU_OPT_BOOL,
+ },{
+ .name = "icount",
+ .type = QEMU_OPT_NUMBER,
+ },
+ { /* end of list */ }
+ },
+};
+
+
+
static QemuOptsList qemu_name_opts = {
.name = "name",
.implied_opt_name = "guest",
@@ -547,6 +605,7 @@ QemuOpts *qemu_get_machine_opts(void)
return qemu_find_opts_singleton("machine");
}
+
const char *qemu_get_vm_name(void)
{
return qemu_name;
@@ -757,7 +816,7 @@ void vm_start(void)
/***********************************************************/
/* host time/date access */
-void qemu_get_timedate(struct tm *tm, int offset)
+void qemu_get_timedate_no_warning(struct tm *tm, int offset)
{
time_t ti;
@@ -774,9 +833,25 @@ void qemu_get_timedate(struct tm *tm, int offset)
}
}
+/* host time/date access */
+void qemu_get_timedate(struct tm *tm, int offset)
+{
+ if (replay_mode == REPLAY_SAVE)
+ fprintf(stderr, "REPLAY WARNING! qemu_get_timedate function may cause some troubles\n");
+ qemu_get_timedate_no_warning(tm,offset);
+}
+
int qemu_timedate_diff(struct tm *tm)
{
time_t seconds;
+ time_t systime = time(NULL);
+
+ if (replay_mode == REPLAY_SAVE) {
+ replay_save_time_t(systime);
+ } else if (replay_mode == REPLAY_PLAY
+ && replay_get_play_submode() != REPLAY_PLAY_CHANGED) {
+ systime = replay_read_time_t();
+ }
if (rtc_date_offset == -1)
if (rtc_utc)
@@ -789,13 +864,23 @@ int qemu_timedate_diff(struct tm *tm)
else
seconds = mktimegm(tm) + rtc_date_offset;
- return seconds - time(NULL);
+ return seconds - systime;
}
static void configure_rtc_date_offset(const char *startdate, int legacy)
{
time_t rtc_start_date;
struct tm tm;
+ time_t systime = time(NULL);
+
+ if (replay_mode == REPLAY_SAVE)
+ {
+ replay_save_time_t(systime);
+ }
+ else if (replay_mode == REPLAY_PLAY)
+ {
+ systime = replay_read_time_t();
+ }
if (!strcmp(startdate, "now") && legacy) {
rtc_date_offset = -1;
@@ -827,7 +912,7 @@ static void configure_rtc_date_offset(const char *startdate, int legacy)
"'2006-06-17T16:01:21' or '2006-06-17'\n");
exit(1);
}
- rtc_date_offset = time(NULL) - rtc_start_date;
+ rtc_date_offset = systime - rtc_start_date;
}
}
@@ -1130,7 +1215,7 @@ static int cleanup_add_fd(QemuOpts *opts, void *opaque)
static int drive_init_func(QemuOpts *opts, void *opaque)
{
BlockInterfaceType *block_default_type = opaque;
-
+
return drive_new(opts, *block_default_type) == NULL;
}
@@ -1852,10 +1937,11 @@ void qemu_system_reset_request(void)
{
if (no_reboot) {
shutdown_requested = 1;
+ cpu_stop_current();
} else {
reset_requested = 1;
+ cpu_exit_current();
}
- cpu_stop_current();
qemu_notify_event();
}
@@ -1919,12 +2005,18 @@ void qemu_system_killed(int signal, pid_t pid)
qemu_system_shutdown_request();
}
-void qemu_system_shutdown_request(void)
+void qemu_system_shutdown_request_impl(void)
{
shutdown_requested = 1;
qemu_notify_event();
}
+void qemu_system_shutdown_request(void)
+{
+ replay_shutdown_request();
+ qemu_system_shutdown_request_impl();
+}
+
static void qemu_system_powerdown(void)
{
qapi_event_send_powerdown(&error_abort);
@@ -1966,7 +2058,8 @@ static bool main_loop_should_exit(void)
return true;
}
}
- if (qemu_reset_requested()) {
+ if (qemu_reset_requested_get() && replay_checkpoint(7)) {
+ qemu_reset_requested();
pause_all_vcpus();
cpu_synchronize_all_states();
qemu_system_reset(VMRESET_REPORT);
@@ -2504,7 +2597,8 @@ static int serial_parse(const char *devname)
exit(1);
}
snprintf(label, sizeof(label), "serial%d", index);
- serial_hds[index] = qemu_chr_new(label, devname, NULL);
+ serial_hds[index] = (replay_mode == REPLAY_NONE ? qemu_chr_new : qemu_chr_new_replay)
+ (label, devname, NULL);
if (!serial_hds[index]) {
fprintf(stderr, "qemu: could not connect serial device"
" to character backend '%s'\n", devname);
@@ -2895,7 +2989,7 @@ out:
int main(int argc, char **argv, char **envp)
{
int i;
- int snapshot, linux_boot;
+ int snapshot, linux_boot, replay_snapshot;
const char *icount_option = NULL;
const char *initrd_filename;
const char *kernel_filename, *kernel_cmdline;
@@ -2928,6 +3022,7 @@ int main(int argc, char **argv, char **envp)
};
const char *trace_events = NULL;
const char *trace_file = NULL;
+
const ram_addr_t default_ram_size = (ram_addr_t)DEFAULT_RAM_SIZE *
1024 * 1024;
ram_addr_t maxram_size = default_ram_size;
@@ -2967,6 +3062,8 @@ int main(int argc, char **argv, char **envp)
qemu_add_opts(&qemu_msg_opts);
qemu_add_opts(&qemu_name_opts);
qemu_add_opts(&qemu_numa_opts);
+ qemu_add_opts(&qemu_replay_opts);
+ qemu_add_opts(&qemu_record_opts);
runstate_init();
@@ -2980,6 +3077,7 @@ int main(int argc, char **argv, char **envp)
cpu_model = NULL;
ram_size = default_ram_size;
snapshot = 0;
+ replay_snapshot = 1;
cyls = heads = secs = 0;
translation = BIOS_ATA_TRANSLATION_AUTO;
@@ -3097,6 +3195,7 @@ int main(int argc, char **argv, char **envp)
break;
case QEMU_OPTION_pflash:
drive_add(IF_PFLASH, -1, optarg, PFLASH_OPTS);
+ not_compatible_replay_param++;
break;
case QEMU_OPTION_snapshot:
snapshot = 1;
@@ -3253,6 +3352,7 @@ int main(int argc, char **argv, char **envp)
#endif
case QEMU_OPTION_bt:
add_device_config(DEV_BT, optarg);
+ not_compatible_replay_param++;
break;
case QEMU_OPTION_audio_help:
AUD_help ();
@@ -3466,6 +3566,7 @@ int main(int argc, char **argv, char **envp)
if (!opts) {
exit(1);
}
+ not_compatible_replay_param++;
break;
case QEMU_OPTION_fsdev:
olist = qemu_find_opts("fsdev");
@@ -3594,6 +3695,7 @@ int main(int argc, char **argv, char **envp)
if (strncmp(optarg, "mon:", 4) == 0) {
default_monitor = 0;
}
+ not_compatible_replay_param++;
break;
case QEMU_OPTION_debugcon:
add_device_config(DEV_DEBUGCON, optarg);
@@ -3714,6 +3816,7 @@ int main(int argc, char **argv, char **envp)
if (!qemu_opts_parse(qemu_find_opts("smp-opts"), optarg, 1)) {
exit(1);
}
+ not_compatible_replay_param++;
break;
case QEMU_OPTION_vnc:
#ifdef CONFIG_VNC
@@ -3948,6 +4051,28 @@ int main(int argc, char **argv, char **envp)
exit(1);
}
break;
+ case QEMU_OPTION_record:
+ {
+ opts = qemu_opts_parse(qemu_find_opts("record"), optarg, 0);
+ if (!opts) {
+ fprintf(stderr, "Invalid record options: %s\n", optarg);
+ exit(1);
+ }
+ replay_configure(opts, REPLAY_SAVE);
+ replay_snapshot = qemu_opt_get_bool(opts, "snapshot", 1);
+ break;
+ }
+ case QEMU_OPTION_replay:
+ {
+ opts = qemu_opts_parse(qemu_find_opts("replay"), optarg, 0);
+ if (!opts) {
+ fprintf(stderr, "Invalid replay options: %s\n", optarg);
+ exit(1);
+ }
+ replay_configure(opts, REPLAY_PLAY);
+ replay_snapshot = qemu_opt_get_bool(opts, "snapshot", 1);
+ break;
+ }
default:
os_parse_cmd_args(popt->index, optarg);
}
@@ -3961,7 +4086,13 @@ int main(int argc, char **argv, char **envp)
fprintf(stderr, "qemu_init_main_loop failed\n");
exit(1);
}
-
+
+ if (not_compatible_replay_param && (replay_mode != REPLAY_NONE))
+ {
+ fprintf(stderr, "options -smp, -pflash, -chardev, -bt, -parallel not compatible with
replay\n");
+ exit(1);
+ }
+
if (qemu_opts_foreach(qemu_find_opts("sandbox"), parse_sandbox, NULL, 0)) {
exit(1);
}
@@ -4329,7 +4460,7 @@ int main(int argc, char **argv, char **envp)
ram_mig_init();
/* open the virtual block devices */
- if (snapshot)
+ if (snapshot || (replay_mode != REPLAY_NONE && replay_snapshot))
qemu_opts_foreach(qemu_find_opts("drive"), drive_enable_snapshot, NULL, 0);
if (qemu_opts_foreach(qemu_find_opts("drive"), drive_init_func,
&machine_class->block_default_type, 1) != 0) {
@@ -4497,7 +4628,6 @@ int main(int argc, char **argv, char **envp)
autostart = 0;
}
}
-
qdev_prop_check_global();
if (vmstate_dump_file) {
/* dump and exit */
@@ -4525,8 +4655,13 @@ int main(int argc, char **argv, char **envp)
exit(1);
}
}
+
+ replay_init_timer();
main_loop();
+ if (replay_mode != REPLAY_NONE) {
+ replay_disable_events();
+ }
bdrv_close_all();
pause_all_vcpus();
res_free();
diff --git a/qemu-options.hx b/qemu-options.hx
index 9e54686..c51d196
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -3228,6 +3228,7 @@ Write device configuration to @var{file}. The @var{file} can be either
filename
command line and device configuration into file or dash @code{-}) character to print the
output to stdout. This can be later used as input file for @code{-readconfig} option.
ETEXI
+
DEF("nodefconfig", 0, QEMU_OPTION_nodefconfig,
"-nodefconfig\n"
" do not load default config files at startup\n",
@@ -3333,6 +3334,37 @@ STEXI
@findex -msg
prepend a timestamp to each log message.(default:on)
ETEXI
+DEF("record", HAS_ARG, QEMU_OPTION_record,
+ "-record
fname=<filename>[,period=<period>,suffix=<suffix>,snapshot=<on/off>,debug=<on/off>,rtc=<period>,icou
nt=<icount>]\n"
+ " writes replay file for latter replaying\n",
+ QEMU_ARCH_ALL)
+STEXI
+@item -record
fname=@var{file}[,period=@var{period},suffix=@var{suffix},snapshot=@var{snapshot},debug=@var{debug},
rtc=@var{rtc},icount=@var{icount}]
+Writes compact execution trace into @var{file}.
+VM state is auto saved every @var{period} second,
+if this parameter is specified. Changes for disk images are written
+into separate files with @var{suffix} added. If no @var{suffix} is
+specified, "replay_qcow" is used as suffix.
+If @var{snapshot} parameter is set as off, then original disk image will be
+modified. Default value is on.
+@var{rtc} parameter enables periodic saving of RTC into the log.
+These RTC values can be used for log file navigation later.
+@var{icount} parameter is used for vm clock emulation.
+ETEXI
+
+DEF("replay", HAS_ARG, QEMU_OPTION_replay,
+ "-replay fname=<filename>[,suffix=<suffix>,snapshot=<on/off>,icount=<icount>]\n"
+ " plays saved replay file\n", QEMU_ARCH_ALL)
+STEXI
+@item -replay
fname=@var{filename}[,suffix=@var{suffix},snapshot=@var{snapshot},icount=@var{icount}]
+Plays compact execution trace from @var{filename}.
+Changes for disk images and VM states are read
+from separate files with @var{suffix} added. If no @var{suffix} is
+specified, "replay_qcow" is used as suffix.
+If @var{snapshot} parameter is set as off, then original disk image will be
+modified. Default value is on.
+@var{icount} parameter is used for vm clock emulation.
+ETEXI
DEF("dump-vmstate", HAS_ARG, QEMU_OPTION_dump_vmstate,
"-dump-vmstate <file>\n"
reply other threads:[~2014-07-01 11:28 UTC|newest]
Thread overview: [no followups] expand[flat|nested] mbox.gz Atom feed
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='008201cf951f$8024e4a0$806eade0$@Dovgaluk@ispras.ru' \
--to=pavel.dovgaluk@ispras.ru \
--cc=qemu-devel@nongnu.org \
/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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.