mirror of https://github.com/xemu-project/xemu.git
replay: save/load initial state
This patch implements initial vmstate creation or loading at the start of record/replay. It is needed for rewinding the execution in the replay mode. v4 changes: - snapshots are not created by default anymore v3 changes: - added rrsnapshot option Signed-off-by: Pavel Dovgalyuk <pavel.dovgaluk@ispras.ru> Message-Id: <20170124071746.4572.61449.stgit@PASHA-ISP> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
This commit is contained in:
parent
ac8c19ba74
commit
9c2037d0a4
|
@ -196,6 +196,22 @@ is recorded to the log. In replay phase the queue is matched with
|
||||||
events read from the log. Therefore block devices requests are processed
|
events read from the log. Therefore block devices requests are processed
|
||||||
deterministically.
|
deterministically.
|
||||||
|
|
||||||
|
Snapshotting
|
||||||
|
------------
|
||||||
|
|
||||||
|
New VM snapshots may be created in replay mode. They can be used later
|
||||||
|
to recover the desired VM state. All VM states created in replay mode
|
||||||
|
are associated with the moment of time in the replay scenario.
|
||||||
|
After recovering the VM state replay will start from that position.
|
||||||
|
|
||||||
|
Default starting snapshot name may be specified with icount field
|
||||||
|
rrsnapshot as follows:
|
||||||
|
-icount shift=7,rr=record,rrfile=replay.bin,rrsnapshot=snapshot_name
|
||||||
|
|
||||||
|
This snapshot is created at start of recording and restored at start
|
||||||
|
of replaying. It also can be loaded while replaying to roll back
|
||||||
|
the execution.
|
||||||
|
|
||||||
Network devices
|
Network devices
|
||||||
---------------
|
---------------
|
||||||
|
|
||||||
|
|
|
@ -43,6 +43,9 @@ typedef struct ReplayNetState ReplayNetState;
|
||||||
|
|
||||||
extern ReplayMode replay_mode;
|
extern ReplayMode replay_mode;
|
||||||
|
|
||||||
|
/* Name of the initial VM snapshot */
|
||||||
|
extern char *replay_snapshot;
|
||||||
|
|
||||||
/* Replay process control functions */
|
/* Replay process control functions */
|
||||||
|
|
||||||
/*! Enables recording or saving event log with specified parameters */
|
/*! Enables recording or saving event log with specified parameters */
|
||||||
|
@ -149,4 +152,10 @@ void replay_unregister_net(ReplayNetState *rns);
|
||||||
void replay_net_packet_event(ReplayNetState *rns, unsigned flags,
|
void replay_net_packet_event(ReplayNetState *rns, unsigned flags,
|
||||||
const struct iovec *iov, int iovcnt);
|
const struct iovec *iov, int iovcnt);
|
||||||
|
|
||||||
|
/* VM state operations */
|
||||||
|
|
||||||
|
/*! Called at the start of execution.
|
||||||
|
Loads or saves initial vmstate depending on execution mode. */
|
||||||
|
void replay_vmstate_init(void);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -3400,12 +3400,12 @@ re-inject them.
|
||||||
ETEXI
|
ETEXI
|
||||||
|
|
||||||
DEF("icount", HAS_ARG, QEMU_OPTION_icount, \
|
DEF("icount", HAS_ARG, QEMU_OPTION_icount, \
|
||||||
"-icount [shift=N|auto][,align=on|off][,sleep=on|off,rr=record|replay,rrfile=<filename>]\n" \
|
"-icount [shift=N|auto][,align=on|off][,sleep=on|off,rr=record|replay,rrfile=<filename>,rrsnapshot=<snapshot>]\n" \
|
||||||
" enable virtual instruction counter with 2^N clock ticks per\n" \
|
" enable virtual instruction counter with 2^N clock ticks per\n" \
|
||||||
" instruction, enable aligning the host and virtual clocks\n" \
|
" instruction, enable aligning the host and virtual clocks\n" \
|
||||||
" or disable real time cpu sleeping\n", QEMU_ARCH_ALL)
|
" or disable real time cpu sleeping\n", QEMU_ARCH_ALL)
|
||||||
STEXI
|
STEXI
|
||||||
@item -icount [shift=@var{N}|auto][,rr=record|replay,rrfile=@var{filename}]
|
@item -icount [shift=@var{N}|auto][,rr=record|replay,rrfile=@var{filename},rrsnapshot=@var{snapshot}]
|
||||||
@findex -icount
|
@findex -icount
|
||||||
Enable virtual instruction counter. The virtual cpu will execute one
|
Enable virtual instruction counter. The virtual cpu will execute one
|
||||||
instruction every 2^@var{N} ns of virtual time. If @code{auto} is specified
|
instruction every 2^@var{N} ns of virtual time. If @code{auto} is specified
|
||||||
|
@ -3438,6 +3438,10 @@ when the shift value is high (how high depends on the host machine).
|
||||||
When @option{rr} option is specified deterministic record/replay is enabled.
|
When @option{rr} option is specified deterministic record/replay is enabled.
|
||||||
Replay log is written into @var{filename} file in record mode and
|
Replay log is written into @var{filename} file in record mode and
|
||||||
read from this file in replay mode.
|
read from this file in replay mode.
|
||||||
|
|
||||||
|
Option rrsnapshot is used to create new vm snapshot named @var{snapshot}
|
||||||
|
at the start of execution recording. In replay mode this option is used
|
||||||
|
to load the initial VM state.
|
||||||
ETEXI
|
ETEXI
|
||||||
|
|
||||||
DEF("watchdog", HAS_ARG, QEMU_OPTION_watchdog, \
|
DEF("watchdog", HAS_ARG, QEMU_OPTION_watchdog, \
|
||||||
|
|
|
@ -59,3 +59,20 @@ void replay_vmstate_register(void)
|
||||||
{
|
{
|
||||||
vmstate_register(NULL, 0, &vmstate_replay, &replay_state);
|
vmstate_register(NULL, 0, &vmstate_replay, &replay_state);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void replay_vmstate_init(void)
|
||||||
|
{
|
||||||
|
if (replay_snapshot) {
|
||||||
|
if (replay_mode == REPLAY_MODE_RECORD) {
|
||||||
|
if (save_vmstate(cur_mon, replay_snapshot) != 0) {
|
||||||
|
error_report("Could not create snapshot for icount record");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
} else if (replay_mode == REPLAY_MODE_PLAY) {
|
||||||
|
if (load_vmstate(replay_snapshot) != 0) {
|
||||||
|
error_report("Could not load snapshot for icount replay");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -26,6 +26,7 @@
|
||||||
#define HEADER_SIZE (sizeof(uint32_t) + sizeof(uint64_t))
|
#define HEADER_SIZE (sizeof(uint32_t) + sizeof(uint64_t))
|
||||||
|
|
||||||
ReplayMode replay_mode = REPLAY_MODE_NONE;
|
ReplayMode replay_mode = REPLAY_MODE_NONE;
|
||||||
|
char *replay_snapshot;
|
||||||
|
|
||||||
/* Name of replay file */
|
/* Name of replay file */
|
||||||
static char *replay_filename;
|
static char *replay_filename;
|
||||||
|
@ -292,6 +293,7 @@ void replay_configure(QemuOpts *opts)
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
replay_snapshot = g_strdup(qemu_opt_get(opts, "rrsnapshot"));
|
||||||
replay_vmstate_register();
|
replay_vmstate_register();
|
||||||
replay_enable(fname, mode);
|
replay_enable(fname, mode);
|
||||||
|
|
||||||
|
@ -346,6 +348,9 @@ void replay_finish(void)
|
||||||
replay_filename = NULL;
|
replay_filename = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
g_free(replay_snapshot);
|
||||||
|
replay_snapshot = NULL;
|
||||||
|
|
||||||
replay_finish_events();
|
replay_finish_events();
|
||||||
replay_mutex_destroy();
|
replay_mutex_destroy();
|
||||||
}
|
}
|
||||||
|
|
7
vl.c
7
vl.c
|
@ -465,6 +465,9 @@ static QemuOptsList qemu_icount_opts = {
|
||||||
}, {
|
}, {
|
||||||
.name = "rrfile",
|
.name = "rrfile",
|
||||||
.type = QEMU_OPT_STRING,
|
.type = QEMU_OPT_STRING,
|
||||||
|
}, {
|
||||||
|
.name = "rrsnapshot",
|
||||||
|
.type = QEMU_OPT_STRING,
|
||||||
},
|
},
|
||||||
{ /* end of list */ }
|
{ /* end of list */ }
|
||||||
},
|
},
|
||||||
|
@ -4634,7 +4637,9 @@ int main(int argc, char **argv, char **envp)
|
||||||
replay_checkpoint(CHECKPOINT_RESET);
|
replay_checkpoint(CHECKPOINT_RESET);
|
||||||
qemu_system_reset(VMRESET_SILENT);
|
qemu_system_reset(VMRESET_SILENT);
|
||||||
register_global_state();
|
register_global_state();
|
||||||
if (loadvm) {
|
if (replay_mode != REPLAY_MODE_NONE) {
|
||||||
|
replay_vmstate_init();
|
||||||
|
} else if (loadvm) {
|
||||||
if (load_vmstate(loadvm) < 0) {
|
if (load_vmstate(loadvm) < 0) {
|
||||||
autostart = 0;
|
autostart = 0;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue