Commit 8bd7f71d authored by Pavel Dovgalyuk's avatar Pavel Dovgalyuk Committed by Paolo Bonzini
Browse files

replay: checkpoints



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: default avatarPavel Dovgalyuk <pavel.dovgaluk@ispras.ru>
Message-Id: <20150917162444.8676.52916.stgit@PASHA-ISP.def.inno>
Signed-off-by: default avatarPaolo Bonzini <pbonzini@redhat.com>
Signed-off-by: default avatarPavel Dovgalyuk <Pavel.Dovgaluk@ispras.ru>
parent efab87cf
Loading
Loading
Loading
Loading
+12 −0
Original line number Diff line number Diff line
@@ -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.
+20 −0
Original line number Diff line number Diff line
@@ -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 */
@@ -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 */

+34 −7
Original line number Diff line number Diff line
@@ -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>
@@ -478,9 +479,30 @@ 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(;;) {
@@ -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)) {
        if (qemu_clock_use_for_deadline(type)) {
            if (!play || type == QEMU_CLOCK_REALTIME) {
                deadline = qemu_soonest_timeout(deadline,
                                            timerlist_deadline_ns(
                                                tlg->tl[type]));
                                                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;
@@ -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;
+4 −0
Original line number Diff line number Diff line
@@ -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
};

+34 −0
Original line number Diff line number Diff line
@@ -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;
}
Loading