From patchwork Tue Jul 1 11:28:56 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Pavel Dovgalyuk X-Patchwork-Id: 366058 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [IPv6:2001:4830:134:3::11]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 076D11400CF for ; Tue, 1 Jul 2014 21:29:35 +1000 (EST) Received: from localhost ([::1]:46292 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1X1wFh-0001N3-7O for incoming@patchwork.ozlabs.org; Tue, 01 Jul 2014 07:29:33 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:59867) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1X1wFC-0000iE-QV for qemu-devel@nongnu.org; Tue, 01 Jul 2014 07:29:09 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1X1wF6-00037p-2F for qemu-devel@nongnu.org; Tue, 01 Jul 2014 07:29:02 -0400 Received: from mail.ispras.ru ([83.149.199.45]:33227) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1X1wF5-00037e-Lj for qemu-devel@nongnu.org; Tue, 01 Jul 2014 07:28:55 -0400 Received: from PASHAISP (unknown [80.250.189.177]) by mail.ispras.ru (Postfix) with ESMTPSA id D3D21540159 for ; Tue, 1 Jul 2014 15:28:54 +0400 (MSK) From: "Pavel Dovgaluk" To: "'QEMU Developers'" Date: Tue, 1 Jul 2014 15:28:56 +0400 Message-ID: <008301cf951f$a5448650$efcd92f0$@Dovgaluk@ispras.ru> MIME-Version: 1.0 X-Mailer: Microsoft Office Outlook 12.0 Thread-Index: Ac+VH6T5hILyh0nRQrSMNct5KP677g== Content-Language: ru X-detected-operating-system: by eggs.gnu.org: GNU/Linux 3.x X-Received-From: 83.149.199.45 Subject: [Qemu-devel] [RFC PATCH 15/22] Clock values record/replay X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org These patches contain modifications for recording and replaying host and virtual clock to the execution log. RDTSC output is also recorded. Signed-off-by: Pavel Dovgalyuk --- timer_list->notify_opaque = opaque; @@ -457,7 +461,7 @@ bool timer_expired(QEMUTimer *timer_head, int64_t current_time) return timer_expired_ns(timer_head, current_time * timer_head->scale); } -bool timerlist_run_timers(QEMUTimerList *timer_list) +bool timerlist_run_timers(QEMUTimerList *timer_list, bool run_all) { QEMUTimer *ts; int64_t current_time; @@ -465,6 +469,20 @@ bool timerlist_run_timers(QEMUTimerList *timer_list) QEMUTimerCB *cb; void *opaque; + switch (timer_list->clock->type) { + case QEMU_CLOCK_REALTIME: + break; + default: + case QEMU_CLOCK_VIRTUAL: + if ((replay_mode != REPLAY_NONE && !runstate_is_running()) || !replay_checkpoint(run_all ? 2 : 3)) + return false; + break; + case QEMU_CLOCK_HOST: + if ((replay_mode != REPLAY_NONE && !runstate_is_running()) || !replay_checkpoint(run_all ? 5 : 6)) + return false; + break; + } + qemu_event_reset(&timer_list->timers_done_ev); if (!timer_list->clock->enabled) { goto out; @@ -497,9 +515,9 @@ out: return progress; } -bool qemu_clock_run_timers(QEMUClockType type) +bool qemu_clock_run_timers(QEMUClockType type, bool run_all) { - return timerlist_run_timers(main_loop_tlg.tl[type]); + return timerlist_run_timers(main_loop_tlg.tl[type], run_all); } void timerlistgroup_init(QEMUTimerListGroup *tlg, @@ -524,7 +542,7 @@ bool timerlistgroup_run_timers(QEMUTimerListGroup *tlg) QEMUClockType type; bool progress = false; for (type = 0; type < QEMU_CLOCK_MAX; type++) { - progress |= timerlist_run_timers(tlg->tl[type]); + progress |= timerlist_run_timers(tlg->tl[type], false); } return progress; } @@ -533,11 +551,17 @@ int64_t timerlistgroup_deadline_ns(QEMUTimerListGroup *tlg) { int64_t deadline = -1; QEMUClockType type; + bool play = replay_mode == REPLAY_PLAY && replay_get_play_submode() != REPLAY_PLAY_CHANGED; 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( + if (!play || tlg->tl[type]->clock->type == QEMU_CLOCK_REALTIME) { + deadline = qemu_soonest_timeout(deadline, + timerlist_deadline_ns( tlg->tl[type])); + } else { + // read clock from the replay file + qemu_clock_get_ns(tlg->tl[type]->clock->type); + } } } return deadline; @@ -553,11 +577,14 @@ int64_t qemu_clock_get_ns(QEMUClockType type) return get_clock(); default: case QEMU_CLOCK_VIRTUAL: - if (use_icount) { - return cpu_get_icount(); + if (replay_icount) { + now = replay_get_icount(); + } else if (use_icount) { + now = cpu_get_icount(); } else { - return cpu_get_clock(); + now = cpu_get_clock(); } + return now; case QEMU_CLOCK_HOST: now = get_clock_realtime(); last = clock->last; @@ -605,7 +632,7 @@ bool qemu_clock_run_all_timers(void) QEMUClockType type; for (type = 0; type < QEMU_CLOCK_MAX; type++) { - progress |= qemu_clock_run_timers(type); + progress |= qemu_clock_run_timers(type, true); } return progress; diff --git a/include/qemu/timer.h b/include/qemu/timer.h index 7f9a074..ef754a2 --- a/include/qemu/timer.h +++ b/include/qemu/timer.h @@ -4,6 +4,7 @@ #include "qemu/typedefs.h" #include "qemu-common.h" #include "qemu/notify.h" +#include "replay/replay.h" /* timers */ @@ -64,6 +65,10 @@ struct QEMUTimer { }; extern QEMUTimerListGroup main_loop_tlg; +/* Offset for realtime clock for replay changed mode. */ +extern int64_t realtime_clock_replay_offset; +/* Offset for real ticks clock for replay changed mode. */ +extern int64_t real_ticks_replay_offset; /* * QEMUClockType @@ -237,7 +242,7 @@ void qemu_clock_unregister_reset_notifier(QEMUClockType type, * * Returns: true if any timer ran. */ -bool qemu_clock_run_timers(QEMUClockType type); +bool qemu_clock_run_timers(QEMUClockType type, bool run_all); /** * qemu_clock_run_all_timers: @@ -333,7 +338,7 @@ QEMUClockType timerlist_get_clock(QEMUTimerList *timer_list); * * Returns: true if any timer expired */ -bool timerlist_run_timers(QEMUTimerList *timer_list); +bool timerlist_run_timers(QEMUTimerList *timer_list, bool run_all); /** * timerlist_notify: @@ -689,6 +694,7 @@ int64_t cpu_get_ticks(void); void cpu_enable_ticks(void); /* Caller must hold BQL */ void cpu_disable_ticks(void); +void cpu_do_enable_ticks(void); static inline int64_t get_ticks_per_sec(void) { @@ -699,8 +705,7 @@ static inline int64_t get_ticks_per_sec(void) * Low level clock functions */ -/* real time host monotonic timer */ -static inline int64_t get_clock_realtime(void) +static inline int64_t get_clock_realtime_impl(void) { struct timeval tv; @@ -708,6 +713,24 @@ static inline int64_t get_clock_realtime(void) return tv.tv_sec * 1000000000LL + (tv.tv_usec * 1000); } +/* real time host monotonic timer */ +static inline int64_t get_clock_realtime(void) +{ + int64_t result = get_clock_realtime_impl(); + + if (replay_mode == REPLAY_SAVE) { + replay_save_clock(REPLAY_CLOCK_REALTIME, result); + } else if (replay_mode == REPLAY_PLAY) { + if (replay_get_play_submode() == REPLAY_PLAY_CHANGED) { + result += realtime_clock_replay_offset; + } else { + result = replay_read_clock(REPLAY_CLOCK_REALTIME); + } + } + + return result; +} + /* Warning: don't insert tracepoints into these functions, they are also used by simpletrace backend and tracepoints would cause an infinite recursion! */ @@ -749,6 +772,8 @@ int64_t cpu_get_clock(void); /*******************************************/ /* host CPU ticks (if available) */ +#define cpu_get_real_ticks cpu_get_real_ticks_impl + #if defined(_ARCH_PPC) static inline int64_t cpu_get_real_ticks(void) @@ -902,6 +927,27 @@ static inline int64_t cpu_get_real_ticks (void) } #endif +#undef cpu_get_real_ticks + +static inline int64_t cpu_get_real_ticks(void) +{ + int64_t val = cpu_get_real_ticks_impl(); + + if (replay_mode == REPLAY_SAVE) { + replay_save_clock(REPLAY_CLOCK_REAL_TICKS, val); + } else if (replay_mode == REPLAY_PLAY) { + if (replay_get_play_submode() == REPLAY_PLAY_CHANGED) { + // not used in replay_icount mode + // remove it later? + val += real_ticks_replay_offset; + } else { + val = replay_read_clock(REPLAY_CLOCK_REAL_TICKS); + } + } + + return val; +} + #ifdef CONFIG_PROFILER static inline int64_t profile_getclock(void) { diff --git a/qemu-timer.c b/qemu-timer.c index 00a5d35..987d999 --- a/qemu-timer.c +++ b/qemu-timer.c @@ -41,6 +41,9 @@ #include #endif +#include "replay/replay.h" +#include "qemu/log.h" + /***********************************************************/ /* timers */ @@ -103,7 +106,8 @@ QEMUTimerList *timerlist_new(QEMUClockType type, QEMUClock *clock = qemu_clock_ptr(type); timer_list = g_malloc0(sizeof(QEMUTimerList)); - qemu_event_init(&timer_list->timers_done_ev, false); + // create signaled event, because they should be signaled outside the timerlist_run_timers function + qemu_event_init(&timer_list->timers_done_ev, true); timer_list->clock = clock; timer_list->notify_cb = cb;