replay: initialization and deinitialization
This patch introduces the functions for enabling the record/replay and for freeing the resources when simulator closes. Reviewed-by: Paolo Bonzini <pbonzini@redhat.com> Signed-off-by: Pavel Dovgalyuk <pavel.dovgaluk@ispras.ru> Message-Id: <20150917162507.8676.90232.stgit@PASHA-ISP.def.inno> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> Signed-off-by: Pavel Dovgalyuk <Pavel.Dovgaluk@ispras.ru>
This commit is contained in:
parent
8a354bd935
commit
7615936ebf
2
exec.c
2
exec.c
@ -50,6 +50,7 @@
|
||||
#include "qemu/rcu_queue.h"
|
||||
#include "qemu/main-loop.h"
|
||||
#include "translate-all.h"
|
||||
#include "sysemu/replay.h"
|
||||
|
||||
#include "exec/memory-internal.h"
|
||||
#include "exec/ram_addr.h"
|
||||
@ -882,6 +883,7 @@ void cpu_abort(CPUState *cpu, const char *fmt, ...)
|
||||
}
|
||||
va_end(ap2);
|
||||
va_end(ap);
|
||||
replay_finish();
|
||||
#if defined(CONFIG_USER_ONLY)
|
||||
{
|
||||
struct sigaction act;
|
||||
|
@ -43,6 +43,15 @@ typedef enum ReplayCheckpoint ReplayCheckpoint;
|
||||
|
||||
extern ReplayMode replay_mode;
|
||||
|
||||
/* Replay process control functions */
|
||||
|
||||
/*! Enables recording or saving event log with specified parameters */
|
||||
void replay_configure(struct QemuOpts *opts);
|
||||
/*! Initializes timers used for snapshotting and enables events recording */
|
||||
void replay_start(void);
|
||||
/*! Closes replay log file and frees other resources. */
|
||||
void replay_finish(void);
|
||||
|
||||
/* Processing the instructions */
|
||||
|
||||
/*! Returns number of executed instructions. */
|
||||
|
@ -33,6 +33,8 @@ enum ReplayEvents {
|
||||
/* some of greater codes are reserved for checkpoints */
|
||||
EVENT_CHECKPOINT,
|
||||
EVENT_CHECKPOINT_LAST = EVENT_CHECKPOINT + CHECKPOINT_COUNT - 1,
|
||||
/* end of log event */
|
||||
EVENT_END,
|
||||
EVENT_COUNT
|
||||
};
|
||||
|
||||
|
130
replay/replay.c
130
replay/replay.c
@ -15,9 +15,18 @@
|
||||
#include "qemu/timer.h"
|
||||
#include "qemu/main-loop.h"
|
||||
#include "sysemu/sysemu.h"
|
||||
#include "qemu/error-report.h"
|
||||
|
||||
/* Current version of the replay mechanism.
|
||||
Increase it when file format changes. */
|
||||
#define REPLAY_VERSION 0xe02002
|
||||
/* Size of replay log header */
|
||||
#define HEADER_SIZE (sizeof(uint32_t) + sizeof(uint64_t))
|
||||
|
||||
ReplayMode replay_mode = REPLAY_MODE_NONE;
|
||||
|
||||
/* Name of replay file */
|
||||
static char *replay_filename;
|
||||
ReplayState replay_state;
|
||||
|
||||
bool replay_next_event_is(int event)
|
||||
@ -194,3 +203,124 @@ out:
|
||||
replay_mutex_unlock();
|
||||
return res;
|
||||
}
|
||||
|
||||
static void replay_enable(const char *fname, int mode)
|
||||
{
|
||||
const char *fmode = NULL;
|
||||
assert(!replay_file);
|
||||
|
||||
switch (mode) {
|
||||
case REPLAY_MODE_RECORD:
|
||||
fmode = "wb";
|
||||
break;
|
||||
case REPLAY_MODE_PLAY:
|
||||
fmode = "rb";
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "Replay: internal error: invalid replay mode\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
atexit(replay_finish);
|
||||
|
||||
replay_mutex_init();
|
||||
|
||||
replay_file = fopen(fname, fmode);
|
||||
if (replay_file == NULL) {
|
||||
fprintf(stderr, "Replay: open %s: %s\n", fname, strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
replay_filename = g_strdup(fname);
|
||||
|
||||
replay_mode = mode;
|
||||
replay_data_kind = -1;
|
||||
replay_state.instructions_count = 0;
|
||||
replay_state.current_step = 0;
|
||||
|
||||
/* skip file header for RECORD and check it for PLAY */
|
||||
if (replay_mode == REPLAY_MODE_RECORD) {
|
||||
fseek(replay_file, HEADER_SIZE, SEEK_SET);
|
||||
} else if (replay_mode == REPLAY_MODE_PLAY) {
|
||||
unsigned int version = replay_get_dword();
|
||||
if (version != REPLAY_VERSION) {
|
||||
fprintf(stderr, "Replay: invalid input log file version\n");
|
||||
exit(1);
|
||||
}
|
||||
/* go to the beginning */
|
||||
fseek(replay_file, HEADER_SIZE, SEEK_SET);
|
||||
replay_fetch_data_kind();
|
||||
}
|
||||
|
||||
replay_init_events();
|
||||
}
|
||||
|
||||
void replay_configure(QemuOpts *opts)
|
||||
{
|
||||
const char *fname;
|
||||
const char *rr;
|
||||
ReplayMode mode = REPLAY_MODE_NONE;
|
||||
|
||||
rr = qemu_opt_get(opts, "rr");
|
||||
if (!rr) {
|
||||
/* Just enabling icount */
|
||||
return;
|
||||
} else if (!strcmp(rr, "record")) {
|
||||
mode = REPLAY_MODE_RECORD;
|
||||
} else if (!strcmp(rr, "replay")) {
|
||||
mode = REPLAY_MODE_PLAY;
|
||||
} else {
|
||||
error_report("Invalid icount rr option: %s", rr);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
fname = qemu_opt_get(opts, "rrfile");
|
||||
if (!fname) {
|
||||
error_report("File name not specified for replay");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
replay_enable(fname, mode);
|
||||
}
|
||||
|
||||
void replay_start(void)
|
||||
{
|
||||
if (replay_mode == REPLAY_MODE_NONE) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Timer for snapshotting will be set up here. */
|
||||
|
||||
replay_enable_events();
|
||||
}
|
||||
|
||||
void replay_finish(void)
|
||||
{
|
||||
if (replay_mode == REPLAY_MODE_NONE) {
|
||||
return;
|
||||
}
|
||||
|
||||
replay_save_instructions();
|
||||
|
||||
/* finalize the file */
|
||||
if (replay_file) {
|
||||
if (replay_mode == REPLAY_MODE_RECORD) {
|
||||
/* write end event */
|
||||
replay_put_event(EVENT_END);
|
||||
|
||||
/* write header */
|
||||
fseek(replay_file, 0, SEEK_SET);
|
||||
replay_put_dword(REPLAY_VERSION);
|
||||
}
|
||||
|
||||
fclose(replay_file);
|
||||
replay_file = NULL;
|
||||
}
|
||||
if (replay_filename) {
|
||||
g_free(replay_filename);
|
||||
replay_filename = NULL;
|
||||
}
|
||||
|
||||
replay_finish_events();
|
||||
replay_mutex_destroy();
|
||||
}
|
||||
|
@ -20,3 +20,12 @@ bool replay_checkpoint(ReplayCheckpoint checkpoint)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool replay_events_enabled(void)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
void replay_finish(void)
|
||||
{
|
||||
}
|
||||
|
4
vl.c
4
vl.c
@ -4616,6 +4616,8 @@ int main(int argc, char **argv, char **envp)
|
||||
exit(1);
|
||||
}
|
||||
|
||||
replay_start();
|
||||
|
||||
/* This checkpoint is required by replay to separate prior clock
|
||||
reading from the other reads, because timer polling functions query
|
||||
clock values from the log. */
|
||||
@ -4657,6 +4659,8 @@ int main(int argc, char **argv, char **envp)
|
||||
}
|
||||
|
||||
main_loop();
|
||||
replay_disable_events();
|
||||
|
||||
bdrv_close_all();
|
||||
pause_all_vcpus();
|
||||
res_free();
|
||||
|
Loading…
Reference in New Issue
Block a user