diff mbox

[RFC,15/22] Clock values record/replay

Message ID 008301cf951f$a5448650$efcd92f0$@Dovgaluk@ispras.ru
State New
Headers show

Commit Message

Pavel Dovgalyuk July 1, 2014, 11:28 a.m. UTC
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 <pavel.dovgaluk@gmail.com>
---

     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 mbox

Patch

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;