[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-devel] [RFC PATCH 15/22] Clock values record/replay
From: |
Pavel Dovgaluk |
Subject: |
[Qemu-devel] [RFC PATCH 15/22] Clock values record/replay |
Date: |
Tue, 1 Jul 2014 15:28:56 +0400 |
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 <address@hidden>
---
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 <sys/prctl.h>
#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;
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;
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- [Qemu-devel] [RFC PATCH 15/22] Clock values record/replay,
Pavel Dovgaluk <=