Skip to content

Commit

Permalink
replay: checkpoints
Browse files Browse the repository at this point in the history
This patch introduces checkpoints that synchronize cpu thread and iothread.
When checkpoint is met in the code all asynchronous events from the queue
are executed.

Signed-off-by: Pavel Dovgalyuk <[email protected]>
Message-Id: <[email protected]>
Signed-off-by: Paolo Bonzini <[email protected]>
Signed-off-by: Pavel Dovgalyuk <[email protected]>
  • Loading branch information
Dovgalyuk authored and bonzini committed Nov 6, 2015
1 parent efab87c commit 8bd7f71
Show file tree
Hide file tree
Showing 7 changed files with 134 additions and 12 deletions.
12 changes: 12 additions & 0 deletions cpus.c
Original file line number Diff line number Diff line change
Expand Up @@ -410,6 +410,18 @@ void qemu_clock_warp(QEMUClockType type)
return;
}

/* Nothing to do if the VM is stopped: QEMU_CLOCK_VIRTUAL timers
* do not fire, so computing the deadline does not make sense.
*/
if (!runstate_is_running()) {
return;
}

/* warp clock deterministically in record/replay mode */
if (!replay_checkpoint(CHECKPOINT_CLOCK_WARP)) {
return;
}

if (icount_sleep) {
/*
* If the CPUs have been sleeping, advance QEMU_CLOCK_VIRTUAL timer now.
Expand Down
20 changes: 20 additions & 0 deletions include/sysemu/replay.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,20 @@ enum ReplayClockKind {
};
typedef enum ReplayClockKind ReplayClockKind;

/* IDs of the checkpoints */
enum ReplayCheckpoint {
CHECKPOINT_CLOCK_WARP,
CHECKPOINT_RESET_REQUESTED,
CHECKPOINT_SUSPEND_REQUESTED,
CHECKPOINT_CLOCK_VIRTUAL,
CHECKPOINT_CLOCK_HOST,
CHECKPOINT_CLOCK_VIRTUAL_RT,
CHECKPOINT_INIT,
CHECKPOINT_RESET,
CHECKPOINT_COUNT
};
typedef enum ReplayCheckpoint ReplayCheckpoint;

extern ReplayMode replay_mode;

/* Processing the instructions */
Expand Down Expand Up @@ -70,6 +84,12 @@ int64_t replay_read_clock(ReplayClockKind kind);

/*! Called when qemu shutdown is requested. */
void replay_shutdown_request(void);
/*! Should be called at check points in the execution.
These check points are skipped, if they were not met.
Saves checkpoint in the SAVE mode and validates in the PLAY mode.
Returns 0 in PLAY mode if checkpoint was not found.
Returns 1 in all other cases. */
bool replay_checkpoint(ReplayCheckpoint checkpoint);

/* Asynchronous events queue */

Expand Down
41 changes: 34 additions & 7 deletions qemu-timer.c
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
#include "qemu/main-loop.h"
#include "qemu/timer.h"
#include "sysemu/replay.h"
#include "sysemu/sysemu.h"

#ifdef CONFIG_POSIX
#include <pthread.h>
Expand Down Expand Up @@ -478,10 +479,31 @@ bool timerlist_run_timers(QEMUTimerList *timer_list)
void *opaque;

qemu_event_reset(&timer_list->timers_done_ev);
if (!timer_list->clock->enabled) {
if (!timer_list->clock->enabled || !timer_list->active_timers) {
goto out;
}

switch (timer_list->clock->type) {
case QEMU_CLOCK_REALTIME:
break;
default:
case QEMU_CLOCK_VIRTUAL:
if (!replay_checkpoint(CHECKPOINT_CLOCK_VIRTUAL)) {
goto out;
}
break;
case QEMU_CLOCK_HOST:
if (!replay_checkpoint(CHECKPOINT_CLOCK_HOST)) {
goto out;
}
break;
case QEMU_CLOCK_VIRTUAL_RT:
if (!replay_checkpoint(CHECKPOINT_CLOCK_VIRTUAL_RT)) {
goto out;
}
break;
}

current_time = qemu_clock_get_ns(timer_list->clock->type);
for(;;) {
qemu_mutex_lock(&timer_list->active_timers_lock);
Expand Down Expand Up @@ -545,11 +567,17 @@ int64_t timerlistgroup_deadline_ns(QEMUTimerListGroup *tlg)
{
int64_t deadline = -1;
QEMUClockType type;
bool play = replay_mode == REPLAY_MODE_PLAY;
for (type = 0; type < QEMU_CLOCK_MAX; type++) {
if (qemu_clock_use_for_deadline(tlg->tl[type]->clock->type)) {
deadline = qemu_soonest_timeout(deadline,
timerlist_deadline_ns(
tlg->tl[type]));
if (qemu_clock_use_for_deadline(type)) {
if (!play || type == QEMU_CLOCK_REALTIME) {
deadline = qemu_soonest_timeout(deadline,
timerlist_deadline_ns(tlg->tl[type]));
} else {
/* Read clock from the replay file and
do not calculate the deadline, based on virtual clock. */
qemu_clock_get_ns(type);
}
}
}
return deadline;
Expand All @@ -574,8 +602,7 @@ int64_t qemu_clock_get_ns(QEMUClockType type)
now = REPLAY_CLOCK(REPLAY_CLOCK_HOST, get_clock_realtime());
last = clock->last;
clock->last = now;
if ((now < last || now > (last + get_max_clock_jump()))
&& replay_mode == REPLAY_MODE_NONE) {
if (now < last || now > (last + get_max_clock_jump())) {
notifier_list_notify(&clock->reset_notifiers, &now);
}
return now;
Expand Down
4 changes: 4 additions & 0 deletions replay/replay-internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,10 @@ enum ReplayEvents {
/* some of greater codes are reserved for clocks */
EVENT_CLOCK,
EVENT_CLOCK_LAST = EVENT_CLOCK + REPLAY_CLOCK_COUNT - 1,
/* for checkpoint event */
/* some of greater codes are reserved for checkpoints */
EVENT_CHECKPOINT,
EVENT_CHECKPOINT_LAST = EVENT_CHECKPOINT + CHECKPOINT_COUNT - 1,
EVENT_COUNT
};

Expand Down
34 changes: 34 additions & 0 deletions replay/replay.c
Original file line number Diff line number Diff line change
Expand Up @@ -160,3 +160,37 @@ void replay_shutdown_request(void)
replay_mutex_unlock();
}
}

bool replay_checkpoint(ReplayCheckpoint checkpoint)
{
bool res = false;
assert(EVENT_CHECKPOINT + checkpoint <= EVENT_CHECKPOINT_LAST);
replay_save_instructions();

if (!replay_file) {
return true;
}

replay_mutex_lock();

if (replay_mode == REPLAY_MODE_PLAY) {
if (replay_next_event_is(EVENT_CHECKPOINT + checkpoint)) {
replay_finish_event();
} else if (replay_data_kind != EVENT_ASYNC) {
res = false;
goto out;
}
replay_read_events(checkpoint);
/* replay_read_events may leave some unread events.
Return false if not all of the events associated with
checkpoint were processed */
res = replay_data_kind != EVENT_ASYNC;
} else if (replay_mode == REPLAY_MODE_RECORD) {
replay_put_event(EVENT_CHECKPOINT + checkpoint);
replay_save_events(checkpoint);
res = true;
}
out:
replay_mutex_unlock();
return res;
}
6 changes: 6 additions & 0 deletions stubs/replay.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#include "sysemu/replay.h"
#include <stdlib.h>
#include "sysemu/sysemu.h"

ReplayMode replay_mode;

Expand All @@ -14,3 +15,8 @@ int64_t replay_read_clock(unsigned int kind)
abort();
return 0;
}

bool replay_checkpoint(ReplayCheckpoint checkpoint)
{
return true;
}
29 changes: 24 additions & 5 deletions vl.c
Original file line number Diff line number Diff line change
Expand Up @@ -1642,15 +1642,21 @@ static void qemu_kill_report(void)
static int qemu_reset_requested(void)
{
int r = reset_requested;
reset_requested = 0;
return r;
if (r && replay_checkpoint(CHECKPOINT_RESET_REQUESTED)) {
reset_requested = 0;
return r;
}
return false;
}

static int qemu_suspend_requested(void)
{
int r = suspend_requested;
suspend_requested = 0;
return r;
if (r && replay_checkpoint(CHECKPOINT_SUSPEND_REQUESTED)) {
suspend_requested = 0;
return r;
}
return false;
}

static WakeupReason qemu_wakeup_requested(void)
Expand Down Expand Up @@ -1798,7 +1804,12 @@ void qemu_system_killed(int signal, pid_t pid)
shutdown_signal = signal;
shutdown_pid = pid;
no_shutdown = 0;
qemu_system_shutdown_request();

/* Cannot call qemu_system_shutdown_request directly because
* we are in a signal handler.
*/
shutdown_requested = 1;
qemu_notify_event();
}

void qemu_system_shutdown_request(void)
Expand Down Expand Up @@ -4483,6 +4494,10 @@ int main(int argc, char **argv, char **envp)
}
qemu_add_globals();

/* 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. */
replay_checkpoint(CHECKPOINT_INIT);
qdev_machine_init();

current_machine->ram_size = ram_size;
Expand Down Expand Up @@ -4601,6 +4616,10 @@ int main(int argc, char **argv, char **envp)
exit(1);
}

/* 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. */
replay_checkpoint(CHECKPOINT_RESET);
qemu_system_reset(VMRESET_SILENT);
register_global_state();
if (loadvm) {
Expand Down

0 comments on commit 8bd7f71

Please sign in to comment.