From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from eggs.gnu.org ([2001:4830:134:3::10]:59391) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1X1wEE-0007fp-Bd for qemu-devel@nongnu.org; Tue, 01 Jul 2014 07:28:09 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1X1wE5-0002Ti-Le for qemu-devel@nongnu.org; Tue, 01 Jul 2014 07:28:02 -0400 Received: from mail.ispras.ru ([83.149.199.45]:33216) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1X1wE5-0002Rh-AJ for qemu-devel@nongnu.org; Tue, 01 Jul 2014 07:27:53 -0400 Received: from PASHAISP (unknown [80.250.189.177]) by mail.ispras.ru (Postfix) with ESMTPSA id 8DE20540159 for ; Tue, 1 Jul 2014 15:27:52 +0400 (MSK) From: "Pavel Dovgaluk" Date: Tue, 1 Jul 2014 15:27:53 +0400 Message-ID: <008201cf951f$8024e4a0$806eade0$@Dovgaluk@ispras.ru> MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Content-Language: ru Subject: [Qemu-devel] [RFC PATCH 14/22] Command-line options for record/replay List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: 'QEMU Developers' This patch introduces command-line options for record and replay. Signed-off-by: Pavel Dovgalyuk --- 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=[,period=,suffix=,snapshot=,debug=,rtc=,icou nt=]\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=[,suffix=,snapshot=,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 \n"