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:
Pavel Dovgalyuk 2015-09-17 19:25:07 +03:00 committed by Paolo Bonzini
parent 8a354bd935
commit 7615936ebf
6 changed files with 156 additions and 0 deletions

2
exec.c
View File

@ -50,6 +50,7 @@
#include "qemu/rcu_queue.h" #include "qemu/rcu_queue.h"
#include "qemu/main-loop.h" #include "qemu/main-loop.h"
#include "translate-all.h" #include "translate-all.h"
#include "sysemu/replay.h"
#include "exec/memory-internal.h" #include "exec/memory-internal.h"
#include "exec/ram_addr.h" #include "exec/ram_addr.h"
@ -882,6 +883,7 @@ void cpu_abort(CPUState *cpu, const char *fmt, ...)
} }
va_end(ap2); va_end(ap2);
va_end(ap); va_end(ap);
replay_finish();
#if defined(CONFIG_USER_ONLY) #if defined(CONFIG_USER_ONLY)
{ {
struct sigaction act; struct sigaction act;

View File

@ -43,6 +43,15 @@ typedef enum ReplayCheckpoint ReplayCheckpoint;
extern ReplayMode replay_mode; 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 */ /* Processing the instructions */
/*! Returns number of executed instructions. */ /*! Returns number of executed instructions. */

View File

@ -33,6 +33,8 @@ enum ReplayEvents {
/* some of greater codes are reserved for checkpoints */ /* some of greater codes are reserved for checkpoints */
EVENT_CHECKPOINT, EVENT_CHECKPOINT,
EVENT_CHECKPOINT_LAST = EVENT_CHECKPOINT + CHECKPOINT_COUNT - 1, EVENT_CHECKPOINT_LAST = EVENT_CHECKPOINT + CHECKPOINT_COUNT - 1,
/* end of log event */
EVENT_END,
EVENT_COUNT EVENT_COUNT
}; };

View File

@ -15,9 +15,18 @@
#include "qemu/timer.h" #include "qemu/timer.h"
#include "qemu/main-loop.h" #include "qemu/main-loop.h"
#include "sysemu/sysemu.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; ReplayMode replay_mode = REPLAY_MODE_NONE;
/* Name of replay file */
static char *replay_filename;
ReplayState replay_state; ReplayState replay_state;
bool replay_next_event_is(int event) bool replay_next_event_is(int event)
@ -194,3 +203,124 @@ out:
replay_mutex_unlock(); replay_mutex_unlock();
return res; 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();
}

View File

@ -20,3 +20,12 @@ bool replay_checkpoint(ReplayCheckpoint checkpoint)
{ {
return true; return true;
} }
bool replay_events_enabled(void)
{
return false;
}
void replay_finish(void)
{
}

4
vl.c
View File

@ -4616,6 +4616,8 @@ int main(int argc, char **argv, char **envp)
exit(1); exit(1);
} }
replay_start();
/* This checkpoint is required by replay to separate prior clock /* This checkpoint is required by replay to separate prior clock
reading from the other reads, because timer polling functions query reading from the other reads, because timer polling functions query
clock values from the log. */ clock values from the log. */
@ -4657,6 +4659,8 @@ int main(int argc, char **argv, char **envp)
} }
main_loop(); main_loop();
replay_disable_events();
bdrv_close_all(); bdrv_close_all();
pause_all_vcpus(); pause_all_vcpus();
res_free(); res_free();