From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from eggs.gnu.org ([2001:4830:134:3::10]:52008) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1Xta2P-0007Ls-Mz for qemu-devel@nongnu.org; Wed, 26 Nov 2014 05:41:39 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1Xta2J-0000nW-DS for qemu-devel@nongnu.org; Wed, 26 Nov 2014 05:41:33 -0500 Received: from mail.ispras.ru ([83.149.199.45]:35075) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1Xta2J-0000nP-1e for qemu-devel@nongnu.org; Wed, 26 Nov 2014 05:41:27 -0500 From: Pavel Dovgalyuk Date: Wed, 26 Nov 2014 13:41:29 +0300 Message-ID: <20141126104129.7772.11110.stgit@PASHA-ISP> In-Reply-To: <20141126103841.7772.11864.stgit@PASHA-ISP> References: <20141126103841.7772.11864.stgit@PASHA-ISP> MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: 7bit Subject: [Qemu-devel] [RFC PATCH v5 29/31] replay: initialization and deinitialization List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: qemu-devel@nongnu.org Cc: peter.maydell@linaro.org, peter.crosthwaite@xilinx.com, alex.bennee@linaro.org, mark.burton@greensocs.com, real@ispras.ru, batuzovk@ispras.ru, maria.klimushenkova@ispras.ru, pavel.dovgaluk@ispras.ru, pbonzini@redhat.com, afaerber@suse.de, fred.konrad@greensocs.com This patch introduces the functions for enabling the record/replay and for freeing the resources when simulator closes. Signed-off-by: Pavel Dovgalyuk --- block.c | 2 - exec.c | 1 replay/replay-internal.h | 2 + replay/replay.c | 134 ++++++++++++++++++++++++++++++++++++++++++++++ replay/replay.h | 13 ++++ stubs/replay.c | 1 vl.c | 5 ++ 7 files changed, 157 insertions(+), 1 deletions(-) diff --git a/block.c b/block.c index 02c6a78..08b6b3f 100644 --- a/block.c +++ b/block.c @@ -1941,7 +1941,7 @@ void bdrv_drain_all(void) busy |= bs_busy; } } - if (replay_mode == REPLAY_MODE_PLAY) { + if (replay_mode == REPLAY_MODE_PLAY && replay_checkpoints) { /* Skip checkpoints from the log */ while (replay_checkpoint(8)) { /* Nothing */ diff --git a/exec.c b/exec.c index 759055d..2215984 100644 --- a/exec.c +++ b/exec.c @@ -794,6 +794,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; diff --git a/replay/replay-internal.h b/replay/replay-internal.h index c32bd9c..142e09a 100755 --- a/replay/replay-internal.h +++ b/replay/replay-internal.h @@ -34,6 +34,8 @@ /* for checkpoint event */ #define EVENT_CHECKPOINT 96 +/* end of log event */ +#define EVENT_END 127 /* Asynchronous events IDs */ diff --git a/replay/replay.c b/replay/replay.c index 07ede73..14e650c 100755 --- a/replay/replay.c +++ b/replay/replay.c @@ -14,14 +14,23 @@ #include "replay-internal.h" #include "qemu/timer.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; /*! Stores current submode for PLAY mode */ ReplaySubmode play_submode = REPLAY_SUBMODE_UNKNOWN; +/* Name of replay file */ +static char *replay_filename; /* Suffix for the disk images filenames */ char *replay_image_suffix; ReplayState replay_state; +bool replay_checkpoints; ReplaySubmode replay_get_play_submode(void) { @@ -154,6 +163,10 @@ void replay_shutdown_request(void) /* Used checkpoints: 2 3 4 5 6 7 8 9 10 11 */ int replay_checkpoint(unsigned int checkpoint) { + if (!replay_checkpoints) { + return 1; + } + replay_save_instructions(); if (replay_file) { @@ -178,3 +191,124 @@ int replay_checkpoint(unsigned int checkpoint) return 1; } + +static void replay_enable(const char *fname, int mode) +{ + const char *fmode = NULL; + if (replay_file) { + fprintf(stderr, + "Replay: some record/replay operation is already started\n"); + return; + } + + switch (mode) { + case REPLAY_MODE_RECORD: + fmode = "wb"; + break; + case REPLAY_MODE_PLAY: + fmode = "rb"; + play_submode = REPLAY_SUBMODE_NORMAL; + break; + default: + fprintf(stderr, "Replay: internal error: invalid replay mode\n"); + exit(1); + } + + atexit(replay_finish); + + 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_has_unread_data = 0; + 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(); + uint64_t offset = replay_get_qword(); + if (version != REPLAY_VERSION) { + fprintf(stderr, "Replay: invalid input log file version\n"); + exit(1); + } + /* go to the beginning */ + fseek(replay_file, 12, SEEK_SET); + } + + replay_init_events(); +} + +void replay_configure(QemuOpts *opts, int mode) +{ + const char *fname; + + fname = qemu_opt_get(opts, "fname"); + if (!fname) { + fprintf(stderr, "File name not specified for replay\n"); + exit(1); + } + + const char *suffix = qemu_opt_get(opts, "suffix"); + if (suffix) { + replay_image_suffix = g_strdup(suffix); + } else { + replay_image_suffix = g_strdup("replay_qcow"); + } + + replay_enable(fname, mode); +} + +void replay_init_timer(void) +{ + if (replay_mode == REPLAY_MODE_NONE) { + return; + } + + replay_checkpoints = true; + 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) { + uint64_t offset = 0; + /* write end event */ + replay_put_event(EVENT_END); + + /* write header */ + fseek(replay_file, 0, SEEK_SET); + replay_put_dword(REPLAY_VERSION); + replay_put_qword(offset); + } + + fclose(replay_file); + replay_file = NULL; + } + if (replay_filename) { + g_free(replay_filename); + replay_filename = NULL; + } + if (replay_image_suffix) { + g_free(replay_image_suffix); + replay_image_suffix = NULL; + } + + replay_finish_events(); +} diff --git a/replay/replay.h b/replay/replay.h index c72a3fd..9c40648 100755 --- a/replay/replay.h +++ b/replay/replay.h @@ -17,6 +17,8 @@ #include #include "qapi-types.h" +struct QemuOpts; + /* replay clock kinds */ /* rdtsc */ #define REPLAY_CLOCK_REAL_TICKS 0 @@ -29,10 +31,21 @@ extern ReplayMode replay_mode; extern char *replay_image_suffix; +/*! Is set to true after finishing initialization */ +extern bool replay_checkpoints; /*! Returns replay play submode */ ReplaySubmode replay_get_play_submode(void); +/* Replay process control functions */ + +/*! Enables recording or saving event log with specified parameters */ +void replay_configure(struct QemuOpts *opts, int mode); +/*! Initializes timers used for snapshotting and enables events recording */ +void replay_init_timer(void); +/*! Closes replay log file and frees other resources. */ +void replay_finish(void); + /* Processing the instructions */ /*! Returns number of executed instructions. */ diff --git a/stubs/replay.c b/stubs/replay.c index f2d4ed6..4827ef1 100755 --- a/stubs/replay.c +++ b/stubs/replay.c @@ -2,6 +2,7 @@ #include "sysemu/sysemu.h" ReplayMode replay_mode; +bool replay_checkpoints; ReplaySubmode replay_get_play_submode(void) { diff --git a/vl.c b/vl.c index 717d67e..877a77c 100644 --- a/vl.c +++ b/vl.c @@ -4363,7 +4363,12 @@ int main(int argc, char **argv, char **envp) } } + replay_init_timer(); + main_loop(); + if (replay_mode != REPLAY_MODE_NONE) { + replay_disable_events(); + } bdrv_close_all(); pause_all_vcpus(); res_free();