All of lore.kernel.org
 help / color / mirror / Atom feed
* [Qemu-devel] [PULL 00/18] Record/replay core for 2.5-rc1
@ 2015-11-05 12:13 Paolo Bonzini
  2015-11-05 12:13 ` [Qemu-devel] [PULL 01/18] replay: global variables and function stubs Paolo Bonzini
                   ` (18 more replies)
  0 siblings, 19 replies; 26+ messages in thread
From: Paolo Bonzini @ 2015-11-05 12:13 UTC (permalink / raw)
  To: qemu-devel

The following changes since commit 6c5f30cad290c745f910481d0e890b3f4fad1f00:

  Merge remote-tracking branch 'remotes/juanquintela/tags/migration/20151104' into staging (2015-11-05 10:10:57 +0000)

are available in the git repository at:


  git://github.com/bonzini/qemu.git tags/for-upstream-replay

for you to fetch changes up to 88dcb341cd6163a47346de83d4206591da6a9959:

  replay: recording of the user input (2015-11-05 12:40:48 +0100)

----------------------------------------------------------------
So here it is, let's see what happens.

----------------------------------------------------------------
Pavel Dovgalyuk (18):
      replay: global variables and function stubs
      replay: internal functions for replay log
      replay: introduce mutex to protect the replay log
      replay: introduce icount event
      cpu-exec: allow temporary disabling icount
      cpu: replay instructions sequence
      replay: interrupts and exceptions
      replay: asynchronous events infrastructure
      replay: recording and replaying clock ticks
      replay: shutdown event
      icount: improve counting for record/replay
      replay: checkpoints
      bottom halves: introduce bh call function
      replay: ptimer
      replay: initialization and deinitialization
      replay: replay blockers for devices
      replay: command line options
      replay: recording of the user input

 Makefile.objs             |   2 +
 async.c                   |   7 +-
 cpu-exec.c                |  55 ++++++--
 cpus.c                    |  64 ++++++---
 docs/replay.txt           | 168 +++++++++++++++++++++++
 exec.c                    |   2 +
 hw/bt/hci.c               |   7 +
 hw/core/ptimer.c          |   3 +-
 include/block/aio.h       |   5 +
 include/exec/exec-all.h   |   1 +
 include/qapi/qmp/qerror.h |   3 +
 include/sysemu/replay.h   | 120 ++++++++++++++++
 include/ui/input.h        |   2 +
 main-loop.c               |   3 +
 qapi-schema.json          |  18 +++
 qemu-options.hx           |   8 +-
 qemu-timer.c              |  43 +++++-
 replay/Makefile.objs      |   5 +
 replay/replay-events.c    | 279 +++++++++++++++++++++++++++++++++++++
 replay/replay-input.c     | 160 ++++++++++++++++++++++
 replay/replay-internal.c  | 206 ++++++++++++++++++++++++++++
 replay/replay-internal.h  | 140 +++++++++++++++++++
 replay/replay-time.c      |  64 +++++++++
 replay/replay.c           | 342 ++++++++++++++++++++++++++++++++++++++++++++++
 stubs/Makefile.objs       |   2 +
 stubs/replay-user.c       |  32 +++++
 stubs/replay.c            |  31 +++++
 translate-all.c           |   2 +-
 ui/input.c                |  27 ++--
 vl.c                      |  60 ++++++--
 30 files changed, 1803 insertions(+), 58 deletions(-)
 create mode 100644 docs/replay.txt
 create mode 100644 include/sysemu/replay.h
 create mode 100644 replay/Makefile.objs
 create mode 100644 replay/replay-events.c
 create mode 100644 replay/replay-input.c
 create mode 100644 replay/replay-internal.c
 create mode 100644 replay/replay-internal.h
 create mode 100644 replay/replay-time.c
 create mode 100644 replay/replay.c
 create mode 100644 stubs/replay-user.c
 create mode 100644 stubs/replay.c
-- 
1.8.3.1

^ permalink raw reply	[flat|nested] 26+ messages in thread

* [Qemu-devel] [PULL 01/18] replay: global variables and function stubs
  2015-11-05 12:13 [Qemu-devel] [PULL 00/18] Record/replay core for 2.5-rc1 Paolo Bonzini
@ 2015-11-05 12:13 ` Paolo Bonzini
  2015-11-05 12:13 ` [Qemu-devel] [PULL 02/18] replay: internal functions for replay log Paolo Bonzini
                   ` (17 subsequent siblings)
  18 siblings, 0 replies; 26+ messages in thread
From: Paolo Bonzini @ 2015-11-05 12:13 UTC (permalink / raw)
  To: qemu-devel; +Cc: Pavel Dovgalyuk

From: Pavel Dovgalyuk <Pavel.Dovgaluk@ispras.ru>

This patch adds global variables, defines, function declarations,
and function stubs for deterministic VM replay used by external modules.

Reviewed-by: Paolo Bonzini <pbonzini@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>

Signed-off-by: Pavel Dovgalyuk <pavel.dovgaluk@ispras.ru>
Message-Id: <20150917162337.8676.41538.stgit@PASHA-ISP.def.inno>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 Makefile.objs           |   2 +
 docs/replay.txt         | 168 ++++++++++++++++++++++++++++++++++++++++++++++++
 include/sysemu/replay.h |  19 ++++++
 qapi-schema.json        |  18 ++++++
 replay/Makefile.objs    |   1 +
 replay/replay.c         |  14 ++++
 stubs/Makefile.objs     |   2 +
 stubs/replay-user.c     |  12 ++++
 stubs/replay.c          |   3 +
 9 files changed, 239 insertions(+)
 create mode 100644 docs/replay.txt
 create mode 100644 include/sysemu/replay.h
 create mode 100644 replay/Makefile.objs
 create mode 100644 replay/replay.c
 create mode 100644 stubs/replay-user.c
 create mode 100644 stubs/replay.c

diff --git a/Makefile.objs b/Makefile.objs
index fe02ee2..77be052 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -54,6 +54,8 @@ common-obj-y += audio/
 common-obj-y += hw/
 common-obj-y += accel.o
 
+common-obj-y += replay/
+
 common-obj-y += ui/
 common-obj-y += bt-host.o bt-vhci.o
 bt-host.o-cflags := $(BLUEZ_CFLAGS)
diff --git a/docs/replay.txt b/docs/replay.txt
new file mode 100644
index 0000000..149727e
--- /dev/null
+++ b/docs/replay.txt
@@ -0,0 +1,168 @@
+Copyright (c) 2010-2015 Institute for System Programming
+                        of the Russian Academy of Sciences.
+
+This work is licensed under the terms of the GNU GPL, version 2 or later.
+See the COPYING file in the top-level directory.
+
+Record/replay
+-------------
+
+Record/replay functions are used for the reverse execution and deterministic
+replay of qemu execution. This implementation of deterministic replay can
+be used for deterministic debugging of guest code through a gdb remote
+interface.
+
+Execution recording writes a non-deterministic events log, which can be later
+used for replaying the execution anywhere and for unlimited number of times.
+It also supports checkpointing for faster rewinding during reverse debugging.
+Execution replaying reads the log and replays all non-deterministic events
+including external input, hardware clocks, and interrupts.
+
+Deterministic replay has the following features:
+ * Deterministically replays whole system execution and all contents of
+   the memory, state of the hardware devices, clocks, and screen of the VM.
+ * Writes execution log into the file for later replaying for multiple times
+   on different machines.
+ * Supports i386, x86_64, and ARM hardware platforms.
+ * Performs deterministic replay of all operations with keyboard and mouse
+   input devices.
+
+Usage of the record/replay:
+ * First, record the execution, by adding the following arguments to the command line:
+   '-icount shift=7,rr=record,rrfile=replay.bin -net none'.
+   Block devices' images are not actually changed in the recording mode,
+   because all of the changes are written to the temporary overlay file.
+ * Then you can replay it by using another command
+   line option: '-icount shift=7,rr=replay,rrfile=replay.bin -net none'
+ * '-net none' option should also be specified if network replay patches
+   are not applied.
+
+Papers with description of deterministic replay implementation:
+http://www.computer.org/csdl/proceedings/csmr/2012/4666/00/4666a553-abs.html
+http://dl.acm.org/citation.cfm?id=2786805.2803179
+
+Modifications of qemu include:
+ * wrappers for clock and time functions to save their return values in the log
+ * saving different asynchronous events (e.g. system shutdown) into the log
+ * synchronization of the bottom halves execution
+ * synchronization of the threads from thread pool
+ * recording/replaying user input (mouse and keyboard)
+ * adding internal checkpoints for cpu and io synchronization
+
+Non-deterministic events
+------------------------
+
+Our record/replay system is based on saving and replaying non-deterministic
+events (e.g. keyboard input) and simulating deterministic ones (e.g. reading
+from HDD or memory of the VM). Saving only non-deterministic events makes
+log file smaller, simulation faster, and allows using reverse debugging even
+for realtime applications.
+
+The following non-deterministic data from peripheral devices is saved into
+the log: mouse and keyboard input, network packets, audio controller input,
+USB packets, serial port input, and hardware clocks (they are non-deterministic
+too, because their values are taken from the host machine). Inputs from
+simulated hardware, memory of VM, software interrupts, and execution of
+instructions are not saved into the log, because they are deterministic and
+can be replayed by simulating the behavior of virtual machine starting from
+initial state.
+
+We had to solve three tasks to implement deterministic replay: recording
+non-deterministic events, replaying non-deterministic events, and checking
+that there is no divergence between record and replay modes.
+
+We changed several parts of QEMU to make event log recording and replaying.
+Devices' models that have non-deterministic input from external devices were
+changed to write every external event into the execution log immediately.
+E.g. network packets are written into the log when they arrive into the virtual
+network adapter.
+
+All non-deterministic events are coming from these devices. But to
+replay them we need to know at which moments they occur. We specify
+these moments by counting the number of instructions executed between
+every pair of consecutive events.
+
+Instruction counting
+--------------------
+
+QEMU should work in icount mode to use record/replay feature. icount was
+designed to allow deterministic execution in absence of external inputs
+of the virtual machine. We also use icount to control the occurrence of the
+non-deterministic events. The number of instructions elapsed from the last event
+is written to the log while recording the execution. In replay mode we
+can predict when to inject that event using the instruction counter.
+
+Timers
+------
+
+Timers are used to execute callbacks from different subsystems of QEMU
+at the specified moments of time. There are several kinds of timers:
+ * Real time clock. Based on host time and used only for callbacks that
+   do not change the virtual machine state. For this reason real time
+   clock and timers does not affect deterministic replay at all.
+ * Virtual clock. These timers run only during the emulation. In icount
+   mode virtual clock value is calculated using executed instructions counter.
+   That is why it is completely deterministic and does not have to be recorded.
+ * Host clock. This clock is used by device models that simulate real time
+   sources (e.g. real time clock chip). Host clock is the one of the sources
+   of non-determinism. Host clock read operations should be logged to
+   make the execution deterministic.
+ * Real time clock for icount. This clock is similar to real time clock but
+   it is used only for increasing virtual clock while virtual machine is
+   sleeping. Due to its nature it is also non-deterministic as the host clock
+   and has to be logged too.
+
+Checkpoints
+-----------
+
+Replaying of the execution of virtual machine is bound by sources of
+non-determinism. These are inputs from clock and peripheral devices,
+and QEMU thread scheduling. Thread scheduling affect on processing events
+from timers, asynchronous input-output, and bottom halves.
+
+Invocations of timers are coupled with clock reads and changing the state
+of the virtual machine. Reads produce non-deterministic data taken from
+host clock. And VM state changes should preserve their order. Their relative
+order in replay mode must replicate the order of callbacks in record mode.
+To preserve this order we use checkpoints. When a specific clock is processed
+in record mode we save to the log special "checkpoint" event.
+Checkpoints here do not refer to virtual machine snapshots. They are just
+record/replay events used for synchronization.
+
+QEMU in replay mode will try to invoke timers processing in random moment
+of time. That's why we do not process a group of timers until the checkpoint
+event will be read from the log. Such an event allows synchronizing CPU
+execution and timer events.
+
+Another checkpoints application in record/replay is instruction counting
+while the virtual machine is idle. This function (qemu_clock_warp) is called
+from the wait loop. It changes virtual machine state and must be deterministic
+then. That is why we added checkpoint to this function to prevent its
+operation in replay mode when it does not correspond to record mode.
+
+Bottom halves
+-------------
+
+Disk I/O events are completely deterministic in our model, because
+in both record and replay modes we start virtual machine from the same
+disk state. But callbacks that virtual disk controller uses for reading and
+writing the disk may occur at different moments of time in record and replay
+modes.
+
+Reading and writing requests are created by CPU thread of QEMU. Later these
+requests proceed to block layer which creates "bottom halves". Bottom
+halves consist of callback and its parameters. They are processed when
+main loop locks the global mutex. These locks are not synchronized with
+replaying process because main loop also processes the events that do not
+affect the virtual machine state (like user interaction with monitor).
+
+That is why we had to implement saving and replaying bottom halves callbacks
+synchronously to the CPU execution. When the callback is about to execute
+it is added to the queue in the replay module. This queue is written to the
+log when its callbacks are executed. In replay mode callbacks are not processed
+until the corresponding event is read from the events log file.
+
+Sometimes the block layer uses asynchronous callbacks for its internal purposes
+(like reading or writing VM snapshots or disk image cluster tables). In this
+case bottom halves are not marked as "replayable" and do not saved
+into the log.
diff --git a/include/sysemu/replay.h b/include/sysemu/replay.h
new file mode 100644
index 0000000..d6b73c3
--- /dev/null
+++ b/include/sysemu/replay.h
@@ -0,0 +1,19 @@
+#ifndef REPLAY_H
+#define REPLAY_H
+
+/*
+ * replay.h
+ *
+ * Copyright (c) 2010-2015 Institute for System Programming
+ *                         of the Russian Academy of Sciences.
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ *
+ */
+
+#include "qapi-types.h"
+
+extern ReplayMode replay_mode;
+
+#endif
diff --git a/qapi-schema.json b/qapi-schema.json
index 702b7b5..e18f14c 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -3876,3 +3876,21 @@
 
 # Rocker ethernet network switch
 { 'include': 'qapi/rocker.json' }
+
+##
+# ReplayMode:
+#
+# Mode of the replay subsystem.
+#
+# @none: normal execution mode. Replay or record are not enabled.
+#
+# @record: record mode. All non-deterministic data is written into the
+#          replay log.
+#
+# @play: replay mode. Non-deterministic data required for system execution
+#        is read from the log.
+#
+# Since: 2.5
+##
+{ 'enum': 'ReplayMode',
+  'data': [ 'none', 'record', 'play' ] }
diff --git a/replay/Makefile.objs b/replay/Makefile.objs
new file mode 100644
index 0000000..d3f22c8
--- /dev/null
+++ b/replay/Makefile.objs
@@ -0,0 +1 @@
+common-obj-y += replay.o
diff --git a/replay/replay.c b/replay/replay.c
new file mode 100644
index 0000000..a0ef04f
--- /dev/null
+++ b/replay/replay.c
@@ -0,0 +1,14 @@
+/*
+ * replay.c
+ *
+ * Copyright (c) 2010-2015 Institute for System Programming
+ *                         of the Russian Academy of Sciences.
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ *
+ */
+
+#include "sysemu/replay.h"
+
+ReplayMode replay_mode = REPLAY_MODE_NONE;
diff --git a/stubs/Makefile.objs b/stubs/Makefile.objs
index 251443b..330e1a4 100644
--- a/stubs/Makefile.objs
+++ b/stubs/Makefile.objs
@@ -21,6 +21,8 @@ stub-obj-y += mon-printf.o
 stub-obj-y += monitor-init.o
 stub-obj-y += notify-event.o
 stub-obj-y += qtest.o
+stub-obj-y += replay.o
+stub-obj-y += replay-user.o
 stub-obj-y += reset.o
 stub-obj-y += runstate-check.o
 stub-obj-y += set-fd-handler.o
diff --git a/stubs/replay-user.c b/stubs/replay-user.c
new file mode 100644
index 0000000..0c90bfc
--- /dev/null
+++ b/stubs/replay-user.c
@@ -0,0 +1,12 @@
+/*
+ * replay.c
+ *
+ * Copyright (c) 2010-2015 Institute for System Programming
+ *                         of the Russian Academy of Sciences.
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ *
+ */
+
+#include "sysemu/replay.h"
diff --git a/stubs/replay.c b/stubs/replay.c
new file mode 100644
index 0000000..12c1a75
--- /dev/null
+++ b/stubs/replay.c
@@ -0,0 +1,3 @@
+#include "sysemu/replay.h"
+
+ReplayMode replay_mode;
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [Qemu-devel] [PULL 02/18] replay: internal functions for replay log
  2015-11-05 12:13 [Qemu-devel] [PULL 00/18] Record/replay core for 2.5-rc1 Paolo Bonzini
  2015-11-05 12:13 ` [Qemu-devel] [PULL 01/18] replay: global variables and function stubs Paolo Bonzini
@ 2015-11-05 12:13 ` Paolo Bonzini
  2018-05-11  9:27   ` Peter Maydell
  2015-11-05 12:13 ` [Qemu-devel] [PULL 03/18] replay: introduce mutex to protect the " Paolo Bonzini
                   ` (16 subsequent siblings)
  18 siblings, 1 reply; 26+ messages in thread
From: Paolo Bonzini @ 2015-11-05 12:13 UTC (permalink / raw)
  To: qemu-devel; +Cc: Pavel Dovgalyuk

From: Pavel Dovgalyuk <Pavel.Dovgaluk@ispras.ru>

This patch adds functions to perform read and write operations
with replay log.

Reviewed-by: Paolo Bonzini <pbonzini@redhat.com>

Signed-off-by: Pavel Dovgalyuk <pavel.dovgaluk@ispras.ru>
Message-Id: <20150917162342.8676.29445.stgit@PASHA-ISP.def.inno>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 replay/Makefile.objs     |   1 +
 replay/replay-internal.c | 155 +++++++++++++++++++++++++++++++++++++++++++++++
 replay/replay-internal.h |  46 ++++++++++++++
 3 files changed, 202 insertions(+)
 create mode 100644 replay/replay-internal.c
 create mode 100644 replay/replay-internal.h

diff --git a/replay/Makefile.objs b/replay/Makefile.objs
index d3f22c8..e67a932 100644
--- a/replay/Makefile.objs
+++ b/replay/Makefile.objs
@@ -1 +1,2 @@
 common-obj-y += replay.o
+common-obj-y += replay-internal.o
diff --git a/replay/replay-internal.c b/replay/replay-internal.c
new file mode 100644
index 0000000..04efeee
--- /dev/null
+++ b/replay/replay-internal.c
@@ -0,0 +1,155 @@
+/*
+ * replay-internal.c
+ *
+ * Copyright (c) 2010-2015 Institute for System Programming
+ *                         of the Russian Academy of Sciences.
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ *
+ */
+
+#include "qemu-common.h"
+#include "replay-internal.h"
+#include "qemu/error-report.h"
+#include "sysemu/sysemu.h"
+
+unsigned int replay_data_kind = -1;
+static unsigned int replay_has_unread_data;
+
+/* File for replay writing */
+FILE *replay_file;
+
+void replay_put_byte(uint8_t byte)
+{
+    if (replay_file) {
+        putc(byte, replay_file);
+    }
+}
+
+void replay_put_event(uint8_t event)
+{
+    replay_put_byte(event);
+}
+
+
+void replay_put_word(uint16_t word)
+{
+    replay_put_byte(word >> 8);
+    replay_put_byte(word);
+}
+
+void replay_put_dword(uint32_t dword)
+{
+    replay_put_word(dword >> 16);
+    replay_put_word(dword);
+}
+
+void replay_put_qword(int64_t qword)
+{
+    replay_put_dword(qword >> 32);
+    replay_put_dword(qword);
+}
+
+void replay_put_array(const uint8_t *buf, size_t size)
+{
+    if (replay_file) {
+        replay_put_dword(size);
+        fwrite(buf, 1, size, replay_file);
+    }
+}
+
+uint8_t replay_get_byte(void)
+{
+    uint8_t byte = 0;
+    if (replay_file) {
+        byte = getc(replay_file);
+    }
+    return byte;
+}
+
+uint16_t replay_get_word(void)
+{
+    uint16_t word = 0;
+    if (replay_file) {
+        word = replay_get_byte();
+        word = (word << 8) + replay_get_byte();
+    }
+
+    return word;
+}
+
+uint32_t replay_get_dword(void)
+{
+    uint32_t dword = 0;
+    if (replay_file) {
+        dword = replay_get_word();
+        dword = (dword << 16) + replay_get_word();
+    }
+
+    return dword;
+}
+
+int64_t replay_get_qword(void)
+{
+    int64_t qword = 0;
+    if (replay_file) {
+        qword = replay_get_dword();
+        qword = (qword << 32) + replay_get_dword();
+    }
+
+    return qword;
+}
+
+void replay_get_array(uint8_t *buf, size_t *size)
+{
+    if (replay_file) {
+        *size = replay_get_dword();
+        if (fread(buf, 1, *size, replay_file) != *size) {
+            error_report("replay read error");
+        }
+    }
+}
+
+void replay_get_array_alloc(uint8_t **buf, size_t *size)
+{
+    if (replay_file) {
+        *size = replay_get_dword();
+        *buf = g_malloc(*size);
+        if (fread(*buf, 1, *size, replay_file) != *size) {
+            error_report("replay read error");
+        }
+    }
+}
+
+void replay_check_error(void)
+{
+    if (replay_file) {
+        if (feof(replay_file)) {
+            error_report("replay file is over");
+            qemu_system_vmstop_request_prepare();
+            qemu_system_vmstop_request(RUN_STATE_PAUSED);
+        } else if (ferror(replay_file)) {
+            error_report("replay file is over or something goes wrong");
+            qemu_system_vmstop_request_prepare();
+            qemu_system_vmstop_request(RUN_STATE_INTERNAL_ERROR);
+        }
+    }
+}
+
+void replay_fetch_data_kind(void)
+{
+    if (replay_file) {
+        if (!replay_has_unread_data) {
+            replay_data_kind = replay_get_byte();
+            replay_check_error();
+            replay_has_unread_data = 1;
+        }
+    }
+}
+
+void replay_finish_event(void)
+{
+    replay_has_unread_data = 0;
+    replay_fetch_data_kind();
+}
diff --git a/replay/replay-internal.h b/replay/replay-internal.h
new file mode 100644
index 0000000..17600de
--- /dev/null
+++ b/replay/replay-internal.h
@@ -0,0 +1,46 @@
+#ifndef REPLAY_INTERNAL_H
+#define REPLAY_INTERNAL_H
+
+/*
+ * replay-internal.h
+ *
+ * Copyright (c) 2010-2015 Institute for System Programming
+ *                         of the Russian Academy of Sciences.
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ *
+ */
+
+#include <stdio.h>
+
+extern unsigned int replay_data_kind;
+
+/* File for replay writing */
+extern FILE *replay_file;
+
+void replay_put_byte(uint8_t byte);
+void replay_put_event(uint8_t event);
+void replay_put_word(uint16_t word);
+void replay_put_dword(uint32_t dword);
+void replay_put_qword(int64_t qword);
+void replay_put_array(const uint8_t *buf, size_t size);
+
+uint8_t replay_get_byte(void);
+uint16_t replay_get_word(void);
+uint32_t replay_get_dword(void);
+int64_t replay_get_qword(void);
+void replay_get_array(uint8_t *buf, size_t *size);
+void replay_get_array_alloc(uint8_t **buf, size_t *size);
+
+/*! Checks error status of the file. */
+void replay_check_error(void);
+
+/*! Finishes processing of the replayed event and fetches
+    the next event from the log. */
+void replay_finish_event(void);
+/*! Reads data type from the file and stores it in the
+    replay_data_kind variable. */
+void replay_fetch_data_kind(void);
+
+#endif
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [Qemu-devel] [PULL 03/18] replay: introduce mutex to protect the replay log
  2015-11-05 12:13 [Qemu-devel] [PULL 00/18] Record/replay core for 2.5-rc1 Paolo Bonzini
  2015-11-05 12:13 ` [Qemu-devel] [PULL 01/18] replay: global variables and function stubs Paolo Bonzini
  2015-11-05 12:13 ` [Qemu-devel] [PULL 02/18] replay: internal functions for replay log Paolo Bonzini
@ 2015-11-05 12:13 ` Paolo Bonzini
  2015-11-05 12:13 ` [Qemu-devel] [PULL 04/18] replay: introduce icount event Paolo Bonzini
                   ` (15 subsequent siblings)
  18 siblings, 0 replies; 26+ messages in thread
From: Paolo Bonzini @ 2015-11-05 12:13 UTC (permalink / raw)
  To: qemu-devel; +Cc: Pavel Dovgalyuk

From: Pavel Dovgalyuk <Pavel.Dovgaluk@ispras.ru>

This mutex will protect read/write operations for replay log.
Using mutex is necessary because most of the events consist of
several fields stored in the log. The mutex will help to avoid races.

Reviewed-by: Paolo Bonzini <pbonzini@redhat.com>

Signed-off-by: Pavel Dovgalyuk <pavel.dovgaluk@ispras.ru>
Message-Id: <20150917162348.8676.8628.stgit@PASHA-ISP.def.inno>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 replay/replay-internal.c | 27 +++++++++++++++++++++++++++
 replay/replay-internal.h |  7 +++++++
 2 files changed, 34 insertions(+)

diff --git a/replay/replay-internal.c b/replay/replay-internal.c
index 04efeee..efae672 100644
--- a/replay/replay-internal.c
+++ b/replay/replay-internal.c
@@ -17,6 +17,13 @@
 unsigned int replay_data_kind = -1;
 static unsigned int replay_has_unread_data;
 
+/* Mutex to protect reading and writing events to the log.
+   replay_data_kind and replay_has_unread_data are also protected
+   by this mutex.
+   It also protects replay events queue which stores events to be
+   written or read to the log. */
+static QemuMutex lock;
+
 /* File for replay writing */
 FILE *replay_file;
 
@@ -153,3 +160,23 @@ void replay_finish_event(void)
     replay_has_unread_data = 0;
     replay_fetch_data_kind();
 }
+
+void replay_mutex_init(void)
+{
+    qemu_mutex_init(&lock);
+}
+
+void replay_mutex_destroy(void)
+{
+    qemu_mutex_destroy(&lock);
+}
+
+void replay_mutex_lock(void)
+{
+    qemu_mutex_lock(&lock);
+}
+
+void replay_mutex_unlock(void)
+{
+    qemu_mutex_unlock(&lock);
+}
diff --git a/replay/replay-internal.h b/replay/replay-internal.h
index 17600de..8a0de0d 100644
--- a/replay/replay-internal.h
+++ b/replay/replay-internal.h
@@ -33,6 +33,13 @@ int64_t replay_get_qword(void);
 void replay_get_array(uint8_t *buf, size_t *size);
 void replay_get_array_alloc(uint8_t **buf, size_t *size);
 
+/* Mutex functions for protecting replay log file */
+
+void replay_mutex_init(void);
+void replay_mutex_destroy(void);
+void replay_mutex_lock(void);
+void replay_mutex_unlock(void);
+
 /*! Checks error status of the file. */
 void replay_check_error(void);
 
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [Qemu-devel] [PULL 04/18] replay: introduce icount event
  2015-11-05 12:13 [Qemu-devel] [PULL 00/18] Record/replay core for 2.5-rc1 Paolo Bonzini
                   ` (2 preceding siblings ...)
  2015-11-05 12:13 ` [Qemu-devel] [PULL 03/18] replay: introduce mutex to protect the " Paolo Bonzini
@ 2015-11-05 12:13 ` Paolo Bonzini
  2015-11-05 12:13 ` [Qemu-devel] [PULL 05/18] cpu-exec: allow temporary disabling icount Paolo Bonzini
                   ` (14 subsequent siblings)
  18 siblings, 0 replies; 26+ messages in thread
From: Paolo Bonzini @ 2015-11-05 12:13 UTC (permalink / raw)
  To: qemu-devel; +Cc: Pavel Dovgalyuk

From: Pavel Dovgalyuk <Pavel.Dovgaluk@ispras.ru>

This patch adds icount event to the replay subsystem. This event corresponds
to execution of several instructions and used to synchronize input events
in the replay phase.

Reviewed-by: Paolo Bonzini <pbonzini@redhat.com>

Signed-off-by: Pavel Dovgalyuk <pavel.dovgaluk@ispras.ru>
Message-Id: <20150917162354.8676.31351.stgit@PASHA-ISP.def.inno>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 include/sysemu/replay.h  |  7 +++++++
 replay/replay-internal.c | 24 ++++++++++++++++++++++++
 replay/replay-internal.h | 21 +++++++++++++++++++++
 replay/replay.c          | 33 +++++++++++++++++++++++++++++++++
 4 files changed, 85 insertions(+)

diff --git a/include/sysemu/replay.h b/include/sysemu/replay.h
index d6b73c3..a03c748 100644
--- a/include/sysemu/replay.h
+++ b/include/sysemu/replay.h
@@ -12,8 +12,15 @@
  *
  */
 
+#include <stdbool.h>
+#include <stdint.h>
 #include "qapi-types.h"
 
 extern ReplayMode replay_mode;
 
+/* Processing the instructions */
+
+/*! Returns number of executed instructions. */
+uint64_t replay_get_current_step(void);
+
 #endif
diff --git a/replay/replay-internal.c b/replay/replay-internal.c
index efae672..35cff44 100644
--- a/replay/replay-internal.c
+++ b/replay/replay-internal.c
@@ -10,6 +10,7 @@
  */
 
 #include "qemu-common.h"
+#include "sysemu/replay.h"
 #include "replay-internal.h"
 #include "qemu/error-report.h"
 #include "sysemu/sysemu.h"
@@ -36,6 +37,7 @@ void replay_put_byte(uint8_t byte)
 
 void replay_put_event(uint8_t event)
 {
+    assert(event < EVENT_COUNT);
     replay_put_byte(event);
 }
 
@@ -149,8 +151,15 @@ void replay_fetch_data_kind(void)
     if (replay_file) {
         if (!replay_has_unread_data) {
             replay_data_kind = replay_get_byte();
+            if (replay_data_kind == EVENT_INSTRUCTION) {
+                replay_state.instructions_count = replay_get_dword();
+            }
             replay_check_error();
             replay_has_unread_data = 1;
+            if (replay_data_kind >= EVENT_COUNT) {
+                error_report("Replay: unknown event kind %d", replay_data_kind);
+                exit(1);
+            }
         }
     }
 }
@@ -180,3 +189,18 @@ void replay_mutex_unlock(void)
 {
     qemu_mutex_unlock(&lock);
 }
+
+/*! Saves cached instructions. */
+void replay_save_instructions(void)
+{
+    if (replay_file && replay_mode == REPLAY_MODE_RECORD) {
+        replay_mutex_lock();
+        int diff = (int)(replay_get_current_step() - replay_state.current_step);
+        if (diff > 0) {
+            replay_put_event(EVENT_INSTRUCTION);
+            replay_put_dword(diff);
+            replay_state.current_step += diff;
+        }
+        replay_mutex_unlock();
+    }
+}
diff --git a/replay/replay-internal.h b/replay/replay-internal.h
index 8a0de0d..ff4fabc 100644
--- a/replay/replay-internal.h
+++ b/replay/replay-internal.h
@@ -14,6 +14,20 @@
 
 #include <stdio.h>
 
+enum ReplayEvents {
+    /* for instruction event */
+    EVENT_INSTRUCTION,
+    EVENT_COUNT
+};
+
+typedef struct ReplayState {
+    /*! Current step - number of processed instructions and timer events. */
+    uint64_t current_step;
+    /*! Number of instructions to be executed before other events happen. */
+    int instructions_count;
+} ReplayState;
+extern ReplayState replay_state;
+
 extern unsigned int replay_data_kind;
 
 /* File for replay writing */
@@ -50,4 +64,11 @@ void replay_finish_event(void);
     replay_data_kind variable. */
 void replay_fetch_data_kind(void);
 
+/*! Saves queued events (like instructions and sound). */
+void replay_save_instructions(void);
+
+/*! Skips async events until some sync event will be found.
+    \return true, if event was found */
+bool replay_next_event_is(int event);
+
 #endif
diff --git a/replay/replay.c b/replay/replay.c
index a0ef04f..62e8aba 100644
--- a/replay/replay.c
+++ b/replay/replay.c
@@ -9,6 +9,39 @@
  *
  */
 
+#include "qemu-common.h"
 #include "sysemu/replay.h"
+#include "replay-internal.h"
+#include "qemu/timer.h"
 
 ReplayMode replay_mode = REPLAY_MODE_NONE;
+
+ReplayState replay_state;
+
+bool replay_next_event_is(int event)
+{
+    bool res = false;
+
+    /* nothing to skip - not all instructions used */
+    if (replay_state.instructions_count != 0) {
+        assert(replay_data_kind == EVENT_INSTRUCTION);
+        return event == EVENT_INSTRUCTION;
+    }
+
+    while (true) {
+        if (event == replay_data_kind) {
+            res = true;
+        }
+        switch (replay_data_kind) {
+        default:
+            /* clock, time_t, checkpoint and other events */
+            return res;
+        }
+    }
+    return res;
+}
+
+uint64_t replay_get_current_step(void)
+{
+    return cpu_get_icount_raw();
+}
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [Qemu-devel] [PULL 05/18] cpu-exec: allow temporary disabling icount
  2015-11-05 12:13 [Qemu-devel] [PULL 00/18] Record/replay core for 2.5-rc1 Paolo Bonzini
                   ` (3 preceding siblings ...)
  2015-11-05 12:13 ` [Qemu-devel] [PULL 04/18] replay: introduce icount event Paolo Bonzini
@ 2015-11-05 12:13 ` Paolo Bonzini
  2015-11-05 12:13 ` [Qemu-devel] [PULL 06/18] cpu: replay instructions sequence Paolo Bonzini
                   ` (13 subsequent siblings)
  18 siblings, 0 replies; 26+ messages in thread
From: Paolo Bonzini @ 2015-11-05 12:13 UTC (permalink / raw)
  To: qemu-devel; +Cc: Pavel Dovgalyuk

From: Pavel Dovgalyuk <Pavel.Dovgaluk@ispras.ru>

This patch is required for deterministic replay to generate an exception
by trying executing an instruction without changing icount.
It adds new flag to TB for disabling icount while translating it.

Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>

Signed-off-by: Pavel Dovgalyuk <pavel.dovgaluk@ispras.ru>
Message-Id: <20150917162359.8676.77011.stgit@PASHA-ISP.def.inno>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 cpu-exec.c              | 7 ++++---
 include/exec/exec-all.h | 1 +
 translate-all.c         | 2 +-
 3 files changed, 6 insertions(+), 4 deletions(-)

diff --git a/cpu-exec.c b/cpu-exec.c
index 7eef083..a1e3d58 100644
--- a/cpu-exec.c
+++ b/cpu-exec.c
@@ -184,7 +184,7 @@ static inline tcg_target_ulong cpu_tb_exec(CPUState *cpu, uint8_t *tb_ptr)
 /* Execute the code without caching the generated code. An interpreter
    could be used if available. */
 static void cpu_exec_nocache(CPUState *cpu, int max_cycles,
-                             TranslationBlock *orig_tb)
+                             TranslationBlock *orig_tb, bool ignore_icount)
 {
     TranslationBlock *tb;
 
@@ -194,7 +194,8 @@ static void cpu_exec_nocache(CPUState *cpu, int max_cycles,
         max_cycles = CF_COUNT_MASK;
 
     tb = tb_gen_code(cpu, orig_tb->pc, orig_tb->cs_base, orig_tb->flags,
-                     max_cycles | CF_NOCACHE);
+                     max_cycles | CF_NOCACHE
+                         | (ignore_icount ? CF_IGNORE_ICOUNT : 0));
     tb->orig_tb = tcg_ctx.tb_ctx.tb_invalidated_flag ? NULL : orig_tb;
     cpu->current_tb = tb;
     /* execute the generated code */
@@ -519,7 +520,7 @@ int cpu_exec(CPUState *cpu)
                             if (insns_left > 0) {
                                 /* Execute remaining instructions.  */
                                 tb = (TranslationBlock *)(next_tb & ~TB_EXIT_MASK);
-                                cpu_exec_nocache(cpu, insns_left, tb);
+                                cpu_exec_nocache(cpu, insns_left, tb, false);
                                 align_clocks(&sc, cpu);
                             }
                             cpu->exception_index = EXCP_INTERRUPT;
diff --git a/include/exec/exec-all.h b/include/exec/exec-all.h
index 9b93b9b..b07de10 100644
--- a/include/exec/exec-all.h
+++ b/include/exec/exec-all.h
@@ -190,6 +190,7 @@ struct TranslationBlock {
 #define CF_LAST_IO     0x8000 /* Last insn may be an IO access.  */
 #define CF_NOCACHE     0x10000 /* To be freed after execution */
 #define CF_USE_ICOUNT  0x20000
+#define CF_IGNORE_ICOUNT 0x40000 /* Do not generate icount code */
 
     void *tc_ptr;    /* pointer to the translated code */
     uint8_t *tc_search;  /* pointer to search data */
diff --git a/translate-all.c b/translate-all.c
index 20ce40e..a940bd2 100644
--- a/translate-all.c
+++ b/translate-all.c
@@ -1069,7 +1069,7 @@ TranslationBlock *tb_gen_code(CPUState *cpu,
 #endif
 
     phys_pc = get_page_addr_code(env, pc);
-    if (use_icount) {
+    if (use_icount && !(cflags & CF_IGNORE_ICOUNT)) {
         cflags |= CF_USE_ICOUNT;
     }
 
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [Qemu-devel] [PULL 06/18] cpu: replay instructions sequence
  2015-11-05 12:13 [Qemu-devel] [PULL 00/18] Record/replay core for 2.5-rc1 Paolo Bonzini
                   ` (4 preceding siblings ...)
  2015-11-05 12:13 ` [Qemu-devel] [PULL 05/18] cpu-exec: allow temporary disabling icount Paolo Bonzini
@ 2015-11-05 12:13 ` Paolo Bonzini
  2015-11-05 12:13 ` [Qemu-devel] [PULL 07/18] replay: interrupts and exceptions Paolo Bonzini
                   ` (12 subsequent siblings)
  18 siblings, 0 replies; 26+ messages in thread
From: Paolo Bonzini @ 2015-11-05 12:13 UTC (permalink / raw)
  To: qemu-devel; +Cc: Pavel Dovgalyuk

From: Pavel Dovgalyuk <Pavel.Dovgaluk@ispras.ru>

This patch adds calls to replay functions into the icount setup block.
In record mode number of executed instructions is written to the log.
In replay mode number of istructions to execute is taken from the replay log.
When replayed instructions counter is expired qemu_notify_event()
function is called to wake up the iothread.

Reviewed-by: Paolo Bonzini <pbonzini@redhat.com>

Signed-off-by: Pavel Dovgalyuk <pavel.dovgaluk@ispras.ru>
Message-Id: <20150917162405.8676.31890.stgit@PASHA-ISP.def.inno>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 cpus.c                  | 38 +++++++++++++++++++++++++-------------
 include/sysemu/replay.h |  4 ++++
 replay/replay.c         | 34 ++++++++++++++++++++++++++++++++++
 3 files changed, 63 insertions(+), 13 deletions(-)

diff --git a/cpus.c b/cpus.c
index d2e9e4f..f07cac2 100644
--- a/cpus.c
+++ b/cpus.c
@@ -42,6 +42,7 @@
 #include "qemu/seqlock.h"
 #include "qapi-event.h"
 #include "hw/nmi.h"
+#include "sysemu/replay.h"
 
 #ifndef _WIN32
 #include "qemu/compatfd.h"
@@ -1411,6 +1412,28 @@ int vm_stop_force_state(RunState state)
     }
 }
 
+static int64_t tcg_get_icount_limit(void)
+{
+    int64_t deadline;
+
+    if (replay_mode != REPLAY_MODE_PLAY) {
+        deadline = qemu_clock_deadline_ns_all(QEMU_CLOCK_VIRTUAL);
+
+        /* Maintain prior (possibly buggy) behaviour where if no deadline
+         * was set (as there is no QEMU_CLOCK_VIRTUAL timer) or it is more than
+         * INT32_MAX nanoseconds ahead, we still use INT32_MAX
+         * nanoseconds.
+         */
+        if ((deadline < 0) || (deadline > INT32_MAX)) {
+            deadline = INT32_MAX;
+        }
+
+        return qemu_icount_round(deadline);
+    } else {
+        return replay_get_instructions();
+    }
+}
+
 static int tcg_cpu_exec(CPUState *cpu)
 {
     int ret;
@@ -1423,24 +1446,12 @@ static int tcg_cpu_exec(CPUState *cpu)
 #endif
     if (use_icount) {
         int64_t count;
-        int64_t deadline;
         int decr;
         timers_state.qemu_icount -= (cpu->icount_decr.u16.low
                                     + cpu->icount_extra);
         cpu->icount_decr.u16.low = 0;
         cpu->icount_extra = 0;
-        deadline = qemu_clock_deadline_ns_all(QEMU_CLOCK_VIRTUAL);
-
-        /* Maintain prior (possibly buggy) behaviour where if no deadline
-         * was set (as there is no QEMU_CLOCK_VIRTUAL timer) or it is more than
-         * INT32_MAX nanoseconds ahead, we still use INT32_MAX
-         * nanoseconds.
-         */
-        if ((deadline < 0) || (deadline > INT32_MAX)) {
-            deadline = INT32_MAX;
-        }
-
-        count = qemu_icount_round(deadline);
+        count = tcg_get_icount_limit();
         timers_state.qemu_icount += count;
         decr = (count > 0xffff) ? 0xffff : count;
         count -= decr;
@@ -1458,6 +1469,7 @@ static int tcg_cpu_exec(CPUState *cpu)
                         + cpu->icount_extra);
         cpu->icount_decr.u32 = 0;
         cpu->icount_extra = 0;
+        replay_account_executed_instructions();
     }
     return ret;
 }
diff --git a/include/sysemu/replay.h b/include/sysemu/replay.h
index a03c748..d19715f 100644
--- a/include/sysemu/replay.h
+++ b/include/sysemu/replay.h
@@ -22,5 +22,9 @@ extern ReplayMode replay_mode;
 
 /*! Returns number of executed instructions. */
 uint64_t replay_get_current_step(void);
+/*! Returns number of instructions to execute in replay mode. */
+int replay_get_instructions(void);
+/*! Updates instructions counter in replay mode. */
+void replay_account_executed_instructions(void);
 
 #endif
diff --git a/replay/replay.c b/replay/replay.c
index 62e8aba..b2c6750 100644
--- a/replay/replay.c
+++ b/replay/replay.c
@@ -13,6 +13,7 @@
 #include "sysemu/replay.h"
 #include "replay-internal.h"
 #include "qemu/timer.h"
+#include "qemu/main-loop.h"
 
 ReplayMode replay_mode = REPLAY_MODE_NONE;
 
@@ -45,3 +46,36 @@ uint64_t replay_get_current_step(void)
 {
     return cpu_get_icount_raw();
 }
+
+int replay_get_instructions(void)
+{
+    int res = 0;
+    replay_mutex_lock();
+    if (replay_next_event_is(EVENT_INSTRUCTION)) {
+        res = replay_state.instructions_count;
+    }
+    replay_mutex_unlock();
+    return res;
+}
+
+void replay_account_executed_instructions(void)
+{
+    if (replay_mode == REPLAY_MODE_PLAY) {
+        replay_mutex_lock();
+        if (replay_state.instructions_count > 0) {
+            int count = (int)(replay_get_current_step()
+                              - replay_state.current_step);
+            replay_state.instructions_count -= count;
+            replay_state.current_step += count;
+            if (replay_state.instructions_count == 0) {
+                assert(replay_data_kind == EVENT_INSTRUCTION);
+                replay_finish_event();
+                /* Wake up iothread. This is required because
+                   timers will not expire until clock counters
+                   will be read from the log. */
+                qemu_notify_event();
+            }
+        }
+        replay_mutex_unlock();
+    }
+}
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [Qemu-devel] [PULL 07/18] replay: interrupts and exceptions
  2015-11-05 12:13 [Qemu-devel] [PULL 00/18] Record/replay core for 2.5-rc1 Paolo Bonzini
                   ` (5 preceding siblings ...)
  2015-11-05 12:13 ` [Qemu-devel] [PULL 06/18] cpu: replay instructions sequence Paolo Bonzini
@ 2015-11-05 12:13 ` Paolo Bonzini
  2015-11-05 12:13 ` [Qemu-devel] [PULL 08/18] replay: asynchronous events infrastructure Paolo Bonzini
                   ` (11 subsequent siblings)
  18 siblings, 0 replies; 26+ messages in thread
From: Paolo Bonzini @ 2015-11-05 12:13 UTC (permalink / raw)
  To: qemu-devel; +Cc: Pavel Dovgalyuk

From: Pavel Dovgalyuk <Pavel.Dovgaluk@ispras.ru>

This patch includes modifications of common cpu files. All interrupts and
exceptions occured during recording are written into the replay log.
These events allow correct replaying the execution by kicking cpu thread
when one of these events is found in the log.

Signed-off-by: Pavel Dovgalyuk <pavel.dovgaluk@ispras.ru>
Message-Id: <20150917162416.8676.57647.stgit@PASHA-ISP.def.inno>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 cpu-exec.c               | 48 ++++++++++++++++++++++++++--------
 include/sysemu/replay.h  | 17 ++++++++++++
 replay/replay-internal.h |  4 +++
 replay/replay.c          | 67 ++++++++++++++++++++++++++++++++++++++++++++++++
 stubs/replay-user.c      | 20 +++++++++++++++
 5 files changed, 146 insertions(+), 10 deletions(-)

diff --git a/cpu-exec.c b/cpu-exec.c
index a1e3d58..a57b388 100644
--- a/cpu-exec.c
+++ b/cpu-exec.c
@@ -30,6 +30,7 @@
 #if defined(TARGET_I386) && !defined(CONFIG_USER_ONLY)
 #include "hw/i386/apic.h"
 #endif
+#include "sysemu/replay.h"
 
 /* -icount align implementation. */
 
@@ -346,21 +347,25 @@ int cpu_exec(CPUState *cpu)
     uintptr_t next_tb;
     SyncClocks sc;
 
+    /* replay_interrupt may need current_cpu */
+    current_cpu = cpu;
+
     if (cpu->halted) {
 #if defined(TARGET_I386) && !defined(CONFIG_USER_ONLY)
-        if (cpu->interrupt_request & CPU_INTERRUPT_POLL) {
+        if ((cpu->interrupt_request & CPU_INTERRUPT_POLL)
+            && replay_interrupt()) {
             apic_poll_irq(x86_cpu->apic_state);
             cpu_reset_interrupt(cpu, CPU_INTERRUPT_POLL);
         }
 #endif
         if (!cpu_has_work(cpu)) {
+            current_cpu = NULL;
             return EXCP_HALTED;
         }
 
         cpu->halted = 0;
     }
 
-    current_cpu = cpu;
     atomic_mb_set(&tcg_current_cpu, cpu);
     rcu_read_lock();
 
@@ -402,10 +407,22 @@ int cpu_exec(CPUState *cpu)
                     cpu->exception_index = -1;
                     break;
 #else
-                    cc->do_interrupt(cpu);
-                    cpu->exception_index = -1;
+                    if (replay_exception()) {
+                        cc->do_interrupt(cpu);
+                        cpu->exception_index = -1;
+                    } else if (!replay_has_interrupt()) {
+                        /* give a chance to iothread in replay mode */
+                        ret = EXCP_INTERRUPT;
+                        break;
+                    }
 #endif
                 }
+            } else if (replay_has_exception()
+                       && cpu->icount_decr.u16.low + cpu->icount_extra == 0) {
+                /* try to cause an exception pending in the log */
+                cpu_exec_nocache(cpu, 1, tb_find_fast(cpu), true);
+                ret = -1;
+                break;
             }
 
             next_tb = 0; /* force lookup of first TB */
@@ -421,30 +438,40 @@ int cpu_exec(CPUState *cpu)
                         cpu->exception_index = EXCP_DEBUG;
                         cpu_loop_exit(cpu);
                     }
-                    if (interrupt_request & CPU_INTERRUPT_HALT) {
+                    if (replay_mode == REPLAY_MODE_PLAY
+                        && !replay_has_interrupt()) {
+                        /* Do nothing */
+                    } else if (interrupt_request & CPU_INTERRUPT_HALT) {
+                        replay_interrupt();
                         cpu->interrupt_request &= ~CPU_INTERRUPT_HALT;
                         cpu->halted = 1;
                         cpu->exception_index = EXCP_HLT;
                         cpu_loop_exit(cpu);
                     }
 #if defined(TARGET_I386)
-                    if (interrupt_request & CPU_INTERRUPT_INIT) {
+                    else if (interrupt_request & CPU_INTERRUPT_INIT) {
+                        replay_interrupt();
                         cpu_svm_check_intercept_param(env, SVM_EXIT_INIT, 0);
                         do_cpu_init(x86_cpu);
                         cpu->exception_index = EXCP_HALTED;
                         cpu_loop_exit(cpu);
                     }
 #else
-                    if (interrupt_request & CPU_INTERRUPT_RESET) {
+                    else if (interrupt_request & CPU_INTERRUPT_RESET) {
+                        replay_interrupt();
                         cpu_reset(cpu);
+                        cpu_loop_exit(cpu);
                     }
 #endif
                     /* The target hook has 3 exit conditions:
                        False when the interrupt isn't processed,
                        True when it is, and we should restart on a new TB,
                        and via longjmp via cpu_loop_exit.  */
-                    if (cc->cpu_exec_interrupt(cpu, interrupt_request)) {
-                        next_tb = 0;
+                    else {
+                        replay_interrupt();
+                        if (cc->cpu_exec_interrupt(cpu, interrupt_request)) {
+                            next_tb = 0;
+                        }
                     }
                     /* Don't use the cached interrupt_request value,
                        do_interrupt may have updated the EXITTB flag. */
@@ -455,7 +482,8 @@ int cpu_exec(CPUState *cpu)
                         next_tb = 0;
                     }
                 }
-                if (unlikely(cpu->exit_request)) {
+                if (unlikely(cpu->exit_request
+                             || replay_has_interrupt())) {
                     cpu->exit_request = 0;
                     cpu->exception_index = EXCP_INTERRUPT;
                     cpu_loop_exit(cpu);
diff --git a/include/sysemu/replay.h b/include/sysemu/replay.h
index d19715f..8915523 100644
--- a/include/sysemu/replay.h
+++ b/include/sysemu/replay.h
@@ -27,4 +27,21 @@ int replay_get_instructions(void);
 /*! Updates instructions counter in replay mode. */
 void replay_account_executed_instructions(void);
 
+/* Interrupts and exceptions */
+
+/*! Called by exception handler to write or read
+    exception processing events. */
+bool replay_exception(void);
+/*! Used to determine that exception is pending.
+    Does not proceed to the next event in the log. */
+bool replay_has_exception(void);
+/*! Called by interrupt handlers to write or read
+    interrupt processing events.
+    \return true if interrupt should be processed */
+bool replay_interrupt(void);
+/*! Tries to read interrupt event from the file.
+    Returns true, when interrupt request is pending */
+bool replay_has_interrupt(void);
+
+
 #endif
diff --git a/replay/replay-internal.h b/replay/replay-internal.h
index ff4fabc..5ff1c14 100644
--- a/replay/replay-internal.h
+++ b/replay/replay-internal.h
@@ -17,6 +17,10 @@
 enum ReplayEvents {
     /* for instruction event */
     EVENT_INSTRUCTION,
+    /* for software interrupt */
+    EVENT_INTERRUPT,
+    /* for emulated exceptions */
+    EVENT_EXCEPTION,
     EVENT_COUNT
 };
 
diff --git a/replay/replay.c b/replay/replay.c
index b2c6750..b4fc64a 100644
--- a/replay/replay.c
+++ b/replay/replay.c
@@ -79,3 +79,70 @@ void replay_account_executed_instructions(void)
         replay_mutex_unlock();
     }
 }
+
+bool replay_exception(void)
+{
+    if (replay_mode == REPLAY_MODE_RECORD) {
+        replay_save_instructions();
+        replay_mutex_lock();
+        replay_put_event(EVENT_EXCEPTION);
+        replay_mutex_unlock();
+        return true;
+    } else if (replay_mode == REPLAY_MODE_PLAY) {
+        bool res = replay_has_exception();
+        if (res) {
+            replay_mutex_lock();
+            replay_finish_event();
+            replay_mutex_unlock();
+        }
+        return res;
+    }
+
+    return true;
+}
+
+bool replay_has_exception(void)
+{
+    bool res = false;
+    if (replay_mode == REPLAY_MODE_PLAY) {
+        replay_account_executed_instructions();
+        replay_mutex_lock();
+        res = replay_next_event_is(EVENT_EXCEPTION);
+        replay_mutex_unlock();
+    }
+
+    return res;
+}
+
+bool replay_interrupt(void)
+{
+    if (replay_mode == REPLAY_MODE_RECORD) {
+        replay_save_instructions();
+        replay_mutex_lock();
+        replay_put_event(EVENT_INTERRUPT);
+        replay_mutex_unlock();
+        return true;
+    } else if (replay_mode == REPLAY_MODE_PLAY) {
+        bool res = replay_has_interrupt();
+        if (res) {
+            replay_mutex_lock();
+            replay_finish_event();
+            replay_mutex_unlock();
+        }
+        return res;
+    }
+
+    return true;
+}
+
+bool replay_has_interrupt(void)
+{
+    bool res = false;
+    if (replay_mode == REPLAY_MODE_PLAY) {
+        replay_account_executed_instructions();
+        replay_mutex_lock();
+        res = replay_next_event_is(EVENT_INTERRUPT);
+        replay_mutex_unlock();
+    }
+    return res;
+}
diff --git a/stubs/replay-user.c b/stubs/replay-user.c
index 0c90bfc..ab8cff7 100644
--- a/stubs/replay-user.c
+++ b/stubs/replay-user.c
@@ -10,3 +10,23 @@
  */
 
 #include "sysemu/replay.h"
+
+bool replay_exception(void)
+{
+    return true;
+}
+
+bool replay_has_exception(void)
+{
+    return true;
+}
+
+bool replay_interrupt(void)
+{
+    return true;
+}
+
+bool replay_has_interrupt(void)
+{
+    return true;
+}
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [Qemu-devel] [PULL 08/18] replay: asynchronous events infrastructure
  2015-11-05 12:13 [Qemu-devel] [PULL 00/18] Record/replay core for 2.5-rc1 Paolo Bonzini
                   ` (6 preceding siblings ...)
  2015-11-05 12:13 ` [Qemu-devel] [PULL 07/18] replay: interrupts and exceptions Paolo Bonzini
@ 2015-11-05 12:13 ` Paolo Bonzini
  2015-11-05 12:13 ` [Qemu-devel] [PULL 09/18] replay: recording and replaying clock ticks Paolo Bonzini
                   ` (10 subsequent siblings)
  18 siblings, 0 replies; 26+ messages in thread
From: Paolo Bonzini @ 2015-11-05 12:13 UTC (permalink / raw)
  To: qemu-devel; +Cc: Pavel Dovgalyuk

From: Pavel Dovgalyuk <Pavel.Dovgaluk@ispras.ru>

This patch adds module for saving and replaying asynchronous events.
These events include network packets, keyboard and mouse input,
USB packets, thread pool and bottom halves callbacks.
All events are stored in the queue to be processed at synchronization points
such as beginning of TB execution, or checkpoint in the iothread.

Signed-off-by: Pavel Dovgalyuk <pavel.dovgaluk@ispras.ru>
Message-Id: <20150917162422.8676.88696.stgit@PASHA-ISP.def.inno>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>

Signed-off-by: Pavel Dovgalyuk <Pavel.Dovgaluk@ispras.ru>
---
 include/sysemu/replay.h  |   6 ++
 replay/Makefile.objs     |   1 +
 replay/replay-events.c   | 227 +++++++++++++++++++++++++++++++++++++++++++++++
 replay/replay-internal.h |  29 ++++++
 4 files changed, 263 insertions(+)
 create mode 100644 replay/replay-events.c

diff --git a/include/sysemu/replay.h b/include/sysemu/replay.h
index 8915523..c2a7651 100644
--- a/include/sysemu/replay.h
+++ b/include/sysemu/replay.h
@@ -43,5 +43,11 @@ bool replay_interrupt(void);
     Returns true, when interrupt request is pending */
 bool replay_has_interrupt(void);
 
+/* Asynchronous events queue */
+
+/*! Disables storing events in the queue */
+void replay_disable_events(void);
+/*! Returns true when saving events is enabled */
+bool replay_events_enabled(void);
 
 #endif
diff --git a/replay/Makefile.objs b/replay/Makefile.objs
index e67a932..6b439c2 100644
--- a/replay/Makefile.objs
+++ b/replay/Makefile.objs
@@ -1,2 +1,3 @@
 common-obj-y += replay.o
 common-obj-y += replay-internal.o
+common-obj-y += replay-events.o
diff --git a/replay/replay-events.c b/replay/replay-events.c
new file mode 100644
index 0000000..8dcc96d
--- /dev/null
+++ b/replay/replay-events.c
@@ -0,0 +1,227 @@
+/*
+ * replay-events.c
+ *
+ * Copyright (c) 2010-2015 Institute for System Programming
+ *                         of the Russian Academy of Sciences.
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ *
+ */
+
+#include "qemu-common.h"
+#include "qemu/error-report.h"
+#include "sysemu/replay.h"
+#include "replay-internal.h"
+
+typedef struct Event {
+    ReplayAsyncEventKind event_kind;
+    void *opaque;
+    void *opaque2;
+    uint64_t id;
+
+    QTAILQ_ENTRY(Event) events;
+} Event;
+
+static QTAILQ_HEAD(, Event) events_list = QTAILQ_HEAD_INITIALIZER(events_list);
+static unsigned int read_event_kind = -1;
+static uint64_t read_id = -1;
+static int read_checkpoint = -1;
+
+static bool events_enabled;
+
+/* Functions */
+
+static void replay_run_event(Event *event)
+{
+    switch (event->event_kind) {
+    default:
+        error_report("Replay: invalid async event ID (%d) in the queue",
+                    event->event_kind);
+        exit(1);
+        break;
+    }
+}
+
+void replay_enable_events(void)
+{
+    events_enabled = true;
+}
+
+bool replay_has_events(void)
+{
+    return !QTAILQ_EMPTY(&events_list);
+}
+
+void replay_flush_events(void)
+{
+    replay_mutex_lock();
+    while (!QTAILQ_EMPTY(&events_list)) {
+        Event *event = QTAILQ_FIRST(&events_list);
+        replay_mutex_unlock();
+        replay_run_event(event);
+        replay_mutex_lock();
+        QTAILQ_REMOVE(&events_list, event, events);
+        g_free(event);
+    }
+    replay_mutex_unlock();
+}
+
+void replay_disable_events(void)
+{
+    if (replay_mode != REPLAY_MODE_NONE) {
+        events_enabled = false;
+        /* Flush events queue before waiting of completion */
+        replay_flush_events();
+    }
+}
+
+void replay_clear_events(void)
+{
+    replay_mutex_lock();
+    while (!QTAILQ_EMPTY(&events_list)) {
+        Event *event = QTAILQ_FIRST(&events_list);
+        QTAILQ_REMOVE(&events_list, event, events);
+
+        g_free(event);
+    }
+    replay_mutex_unlock();
+}
+
+/*! Adds specified async event to the queue */
+#if 0
+static void replay_add_event(ReplayAsyncEventKind event_kind,
+                             void *opaque,
+                             void *opaque2, uint64_t id)
+{
+    assert(event_kind < REPLAY_ASYNC_COUNT);
+
+    if (!replay_file || replay_mode == REPLAY_MODE_NONE
+        || !events_enabled) {
+        Event e;
+        e.event_kind = event_kind;
+        e.opaque = opaque;
+        e.opaque2 = opaque2;
+        e.id = id;
+        replay_run_event(&e);
+        return;
+    }
+
+    Event *event = g_malloc0(sizeof(Event));
+    event->event_kind = event_kind;
+    event->opaque = opaque;
+    event->opaque2 = opaque2;
+    event->id = id;
+
+    replay_mutex_lock();
+    QTAILQ_INSERT_TAIL(&events_list, event, events);
+    replay_mutex_unlock();
+}
+#endif
+
+static void replay_save_event(Event *event, int checkpoint)
+{
+    if (replay_mode != REPLAY_MODE_PLAY) {
+        /* put the event into the file */
+        replay_put_event(EVENT_ASYNC);
+        replay_put_byte(checkpoint);
+        replay_put_byte(event->event_kind);
+
+        /* save event-specific data */
+        switch (event->event_kind) {
+        default:
+            error_report("Unknown ID %d of replay event", read_event_kind);
+            exit(1);
+            break;
+        }
+    }
+}
+
+/* Called with replay mutex locked */
+void replay_save_events(int checkpoint)
+{
+    while (!QTAILQ_EMPTY(&events_list)) {
+        Event *event = QTAILQ_FIRST(&events_list);
+        replay_save_event(event, checkpoint);
+
+        replay_mutex_unlock();
+        replay_run_event(event);
+        replay_mutex_lock();
+        QTAILQ_REMOVE(&events_list, event, events);
+        g_free(event);
+    }
+}
+
+static Event *replay_read_event(int checkpoint)
+{
+    Event *event;
+    if (read_event_kind == -1) {
+        read_checkpoint = replay_get_byte();
+        read_event_kind = replay_get_byte();
+        read_id = -1;
+        replay_check_error();
+    }
+
+    if (checkpoint != read_checkpoint) {
+        return NULL;
+    }
+
+    /* Events that has not to be in the queue */
+    switch (read_event_kind) {
+    default:
+        error_report("Unknown ID %d of replay event", read_event_kind);
+        exit(1);
+        break;
+    }
+
+    QTAILQ_FOREACH(event, &events_list, events) {
+        if (event->event_kind == read_event_kind
+            && (read_id == -1 || read_id == event->id)) {
+            break;
+        }
+    }
+
+    if (event) {
+        QTAILQ_REMOVE(&events_list, event, events);
+    } else {
+        return NULL;
+    }
+
+    /* Read event-specific data */
+
+    return event;
+}
+
+/* Called with replay mutex locked */
+void replay_read_events(int checkpoint)
+{
+    while (replay_data_kind == EVENT_ASYNC) {
+        Event *event = replay_read_event(checkpoint);
+        if (!event) {
+            break;
+        }
+        replay_mutex_unlock();
+        replay_run_event(event);
+        replay_mutex_lock();
+
+        g_free(event);
+        replay_finish_event();
+        read_event_kind = -1;
+    }
+}
+
+void replay_init_events(void)
+{
+    read_event_kind = -1;
+}
+
+void replay_finish_events(void)
+{
+    events_enabled = false;
+    replay_clear_events();
+}
+
+bool replay_events_enabled(void)
+{
+    return events_enabled;
+}
diff --git a/replay/replay-internal.h b/replay/replay-internal.h
index 5ff1c14..23807ca 100644
--- a/replay/replay-internal.h
+++ b/replay/replay-internal.h
@@ -21,9 +21,19 @@ enum ReplayEvents {
     EVENT_INTERRUPT,
     /* for emulated exceptions */
     EVENT_EXCEPTION,
+    /* for async events */
+    EVENT_ASYNC,
     EVENT_COUNT
 };
 
+/* Asynchronous events IDs */
+
+enum ReplayAsyncEventKind {
+    REPLAY_ASYNC_COUNT
+};
+
+typedef enum ReplayAsyncEventKind ReplayAsyncEventKind;
+
 typedef struct ReplayState {
     /*! Current step - number of processed instructions and timer events. */
     uint64_t current_step;
@@ -75,4 +85,23 @@ void replay_save_instructions(void);
     \return true, if event was found */
 bool replay_next_event_is(int event);
 
+/* Asynchronous events queue */
+
+/*! Initializes events' processing internals */
+void replay_init_events(void);
+/*! Clears internal data structures for events handling */
+void replay_finish_events(void);
+/*! Enables storing events in the queue */
+void replay_enable_events(void);
+/*! Flushes events queue */
+void replay_flush_events(void);
+/*! Clears events list before loading new VM state */
+void replay_clear_events(void);
+/*! Returns true if there are any unsaved events in the queue */
+bool replay_has_events(void);
+/*! Saves events from queue into the file */
+void replay_save_events(int checkpoint);
+/*! Read events from the file into the input queue */
+void replay_read_events(int checkpoint);
+
 #endif
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [Qemu-devel] [PULL 09/18] replay: recording and replaying clock ticks
  2015-11-05 12:13 [Qemu-devel] [PULL 00/18] Record/replay core for 2.5-rc1 Paolo Bonzini
                   ` (7 preceding siblings ...)
  2015-11-05 12:13 ` [Qemu-devel] [PULL 08/18] replay: asynchronous events infrastructure Paolo Bonzini
@ 2015-11-05 12:13 ` Paolo Bonzini
  2015-11-05 12:13 ` [Qemu-devel] [PULL 10/18] replay: shutdown event Paolo Bonzini
                   ` (9 subsequent siblings)
  18 siblings, 0 replies; 26+ messages in thread
From: Paolo Bonzini @ 2015-11-05 12:13 UTC (permalink / raw)
  To: qemu-devel; +Cc: Pavel Dovgalyuk

From: Pavel Dovgalyuk <Pavel.Dovgaluk@ispras.ru>

Clock ticks are considered as the sources of non-deterministic data for
virtual machine. This patch implements saving the clock values when they
are acquired (virtual, host clock).
When replaying the execution corresponding values are read from log and
transfered to the module, which wants to read the values.
Such a design required the clock polling to be synchronized. Sometimes
it is not true - e.g. when timeouts for timer lists are checked. In this case
we use a cached value of the clock, passing it to the client code.

Signed-off-by: Pavel Dovgalyuk <pavel.dovgaluk@ispras.ru>
Message-Id: <20150917162427.8676.36558.stgit@PASHA-ISP.def.inno>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Signed-off-by: Pavel Dovgalyuk <Pavel.Dovgaluk@ispras.ru>
---
 cpus.c                   |  3 ++-
 include/sysemu/replay.h  | 23 +++++++++++++++++
 qemu-timer.c             |  8 +++---
 replay/Makefile.objs     |  1 +
 replay/replay-internal.h | 11 +++++++++
 replay/replay-time.c     | 64 ++++++++++++++++++++++++++++++++++++++++++++++++
 stubs/replay.c           | 13 ++++++++++
 7 files changed, 119 insertions(+), 4 deletions(-)
 create mode 100644 replay/replay-time.c

diff --git a/cpus.c b/cpus.c
index f07cac2..2385caa 100644
--- a/cpus.c
+++ b/cpus.c
@@ -346,7 +346,8 @@ static void icount_warp_rt(void *opaque)
 
     seqlock_write_lock(&timers_state.vm_clock_seqlock);
     if (runstate_is_running()) {
-        int64_t clock = cpu_get_clock_locked();
+        int64_t clock = REPLAY_CLOCK(REPLAY_CLOCK_VIRTUAL_RT,
+                                     cpu_get_clock_locked());
         int64_t warp_delta;
 
         warp_delta = clock - vm_clock_warp_start;
diff --git a/include/sysemu/replay.h b/include/sysemu/replay.h
index c2a7651..2398509 100644
--- a/include/sysemu/replay.h
+++ b/include/sysemu/replay.h
@@ -16,6 +16,16 @@
 #include <stdint.h>
 #include "qapi-types.h"
 
+/* replay clock kinds */
+enum ReplayClockKind {
+    /* host_clock */
+    REPLAY_CLOCK_HOST,
+    /* virtual_rt_clock */
+    REPLAY_CLOCK_VIRTUAL_RT,
+    REPLAY_CLOCK_COUNT
+};
+typedef enum ReplayClockKind ReplayClockKind;
+
 extern ReplayMode replay_mode;
 
 /* Processing the instructions */
@@ -43,6 +53,19 @@ bool replay_interrupt(void);
     Returns true, when interrupt request is pending */
 bool replay_has_interrupt(void);
 
+/* Processing clocks and other time sources */
+
+/*! Save the specified clock */
+int64_t replay_save_clock(ReplayClockKind kind, int64_t clock);
+/*! Read the specified clock from the log or return cached data */
+int64_t replay_read_clock(ReplayClockKind kind);
+/*! Saves or reads the clock depending on the current replay mode. */
+#define REPLAY_CLOCK(clock, value)                                      \
+    (replay_mode == REPLAY_MODE_PLAY ? replay_read_clock((clock))       \
+        : replay_mode == REPLAY_MODE_RECORD                             \
+            ? replay_save_clock((clock), (value))                       \
+        : (value))
+
 /* Asynchronous events queue */
 
 /*! Disables storing events in the queue */
diff --git a/qemu-timer.c b/qemu-timer.c
index 2463fe6..3dc847b 100644
--- a/qemu-timer.c
+++ b/qemu-timer.c
@@ -24,6 +24,7 @@
 
 #include "qemu/main-loop.h"
 #include "qemu/timer.h"
+#include "sysemu/replay.h"
 
 #ifdef CONFIG_POSIX
 #include <pthread.h>
@@ -570,15 +571,16 @@ int64_t qemu_clock_get_ns(QEMUClockType type)
             return cpu_get_clock();
         }
     case QEMU_CLOCK_HOST:
-        now = get_clock_realtime();
+        now = REPLAY_CLOCK(REPLAY_CLOCK_HOST, get_clock_realtime());
         last = clock->last;
         clock->last = now;
-        if (now < last || now > (last + get_max_clock_jump())) {
+        if ((now < last || now > (last + get_max_clock_jump()))
+            && replay_mode == REPLAY_MODE_NONE) {
             notifier_list_notify(&clock->reset_notifiers, &now);
         }
         return now;
     case QEMU_CLOCK_VIRTUAL_RT:
-        return cpu_get_clock();
+        return REPLAY_CLOCK(REPLAY_CLOCK_VIRTUAL_RT, cpu_get_clock());
     }
 }
 
diff --git a/replay/Makefile.objs b/replay/Makefile.objs
index 6b439c2..56328ac 100644
--- a/replay/Makefile.objs
+++ b/replay/Makefile.objs
@@ -1,3 +1,4 @@
 common-obj-y += replay.o
 common-obj-y += replay-internal.o
 common-obj-y += replay-events.o
+common-obj-y += replay-time.o
diff --git a/replay/replay-internal.h b/replay/replay-internal.h
index 23807ca..f042c46 100644
--- a/replay/replay-internal.h
+++ b/replay/replay-internal.h
@@ -23,6 +23,10 @@ enum ReplayEvents {
     EVENT_EXCEPTION,
     /* for async events */
     EVENT_ASYNC,
+    /* for clock read/writes */
+    /* some of greater codes are reserved for clocks */
+    EVENT_CLOCK,
+    EVENT_CLOCK_LAST = EVENT_CLOCK + REPLAY_CLOCK_COUNT - 1,
     EVENT_COUNT
 };
 
@@ -35,6 +39,8 @@ enum ReplayAsyncEventKind {
 typedef enum ReplayAsyncEventKind ReplayAsyncEventKind;
 
 typedef struct ReplayState {
+    /*! Cached clock values. */
+    int64_t cached_clock[REPLAY_CLOCK_COUNT];
     /*! Current step - number of processed instructions and timer events. */
     uint64_t current_step;
     /*! Number of instructions to be executed before other events happen. */
@@ -85,6 +91,11 @@ void replay_save_instructions(void);
     \return true, if event was found */
 bool replay_next_event_is(int event);
 
+/*! Reads next clock value from the file.
+    If clock kind read from the file is different from the parameter,
+    the value is not used. */
+void replay_read_next_clock(unsigned int kind);
+
 /* Asynchronous events queue */
 
 /*! Initializes events' processing internals */
diff --git a/replay/replay-time.c b/replay/replay-time.c
new file mode 100644
index 0000000..6d06951
--- /dev/null
+++ b/replay/replay-time.c
@@ -0,0 +1,64 @@
+/*
+ * replay-time.c
+ *
+ * Copyright (c) 2010-2015 Institute for System Programming
+ *                         of the Russian Academy of Sciences.
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ *
+ */
+
+#include "qemu-common.h"
+#include "sysemu/replay.h"
+#include "replay-internal.h"
+#include "qemu/error-report.h"
+
+int64_t replay_save_clock(ReplayClockKind kind, int64_t clock)
+{
+    replay_save_instructions();
+
+    if (replay_file) {
+        replay_mutex_lock();
+        replay_put_event(EVENT_CLOCK + kind);
+        replay_put_qword(clock);
+        replay_mutex_unlock();
+    }
+
+    return clock;
+}
+
+void replay_read_next_clock(ReplayClockKind kind)
+{
+    unsigned int read_kind = replay_data_kind - EVENT_CLOCK;
+
+    assert(read_kind == kind);
+
+    int64_t clock = replay_get_qword();
+
+    replay_check_error();
+    replay_finish_event();
+
+    replay_state.cached_clock[read_kind] = clock;
+}
+
+/*! Reads next clock event from the input. */
+int64_t replay_read_clock(ReplayClockKind kind)
+{
+    replay_account_executed_instructions();
+
+    if (replay_file) {
+        int64_t ret;
+        replay_mutex_lock();
+        if (replay_next_event_is(EVENT_CLOCK + kind)) {
+            replay_read_next_clock(kind);
+        }
+        ret = replay_state.cached_clock[kind];
+        replay_mutex_unlock();
+
+        return ret;
+    }
+
+    error_report("REPLAY INTERNAL ERROR %d", __LINE__);
+    exit(1);
+}
diff --git a/stubs/replay.c b/stubs/replay.c
index 12c1a75..f0d95b0 100644
--- a/stubs/replay.c
+++ b/stubs/replay.c
@@ -1,3 +1,16 @@
 #include "sysemu/replay.h"
+#include <stdlib.h>
 
 ReplayMode replay_mode;
+
+int64_t replay_save_clock(unsigned int kind, int64_t clock)
+{
+    abort();
+    return 0;
+}
+
+int64_t replay_read_clock(unsigned int kind)
+{
+    abort();
+    return 0;
+}
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [Qemu-devel] [PULL 10/18] replay: shutdown event
  2015-11-05 12:13 [Qemu-devel] [PULL 00/18] Record/replay core for 2.5-rc1 Paolo Bonzini
                   ` (8 preceding siblings ...)
  2015-11-05 12:13 ` [Qemu-devel] [PULL 09/18] replay: recording and replaying clock ticks Paolo Bonzini
@ 2015-11-05 12:13 ` Paolo Bonzini
  2015-11-05 12:13 ` [Qemu-devel] [PULL 11/18] icount: improve counting for record/replay Paolo Bonzini
                   ` (8 subsequent siblings)
  18 siblings, 0 replies; 26+ messages in thread
From: Paolo Bonzini @ 2015-11-05 12:13 UTC (permalink / raw)
  To: qemu-devel; +Cc: Pavel Dovgalyuk

From: Pavel Dovgalyuk <Pavel.Dovgaluk@ispras.ru>

This patch records and replays simulator shutdown event.

Reviewed-by: Paolo Bonzini <pbonzini@redhat.com>

Signed-off-by: Pavel Dovgalyuk <pavel.dovgaluk@ispras.ru>
Message-Id: <20150917162433.8676.32262.stgit@PASHA-ISP.def.inno>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Signed-off-by: Pavel Dovgalyuk <Pavel.Dovgaluk@ispras.ru>
---
 include/sysemu/replay.h  |  5 +++++
 replay/replay-internal.h |  2 ++
 replay/replay.c          | 14 ++++++++++++++
 vl.c                     |  2 ++
 4 files changed, 23 insertions(+)

diff --git a/include/sysemu/replay.h b/include/sysemu/replay.h
index 2398509..fcc93d1 100644
--- a/include/sysemu/replay.h
+++ b/include/sysemu/replay.h
@@ -66,6 +66,11 @@ int64_t replay_read_clock(ReplayClockKind kind);
             ? replay_save_clock((clock), (value))                       \
         : (value))
 
+/* Events */
+
+/*! Called when qemu shutdown is requested. */
+void replay_shutdown_request(void);
+
 /* Asynchronous events queue */
 
 /*! Disables storing events in the queue */
diff --git a/replay/replay-internal.h b/replay/replay-internal.h
index f042c46..4414695 100644
--- a/replay/replay-internal.h
+++ b/replay/replay-internal.h
@@ -23,6 +23,8 @@ enum ReplayEvents {
     EVENT_EXCEPTION,
     /* for async events */
     EVENT_ASYNC,
+    /* for shutdown request */
+    EVENT_SHUTDOWN,
     /* for clock read/writes */
     /* some of greater codes are reserved for clocks */
     EVENT_CLOCK,
diff --git a/replay/replay.c b/replay/replay.c
index b4fc64a..65dca7f 100644
--- a/replay/replay.c
+++ b/replay/replay.c
@@ -14,6 +14,7 @@
 #include "replay-internal.h"
 #include "qemu/timer.h"
 #include "qemu/main-loop.h"
+#include "sysemu/sysemu.h"
 
 ReplayMode replay_mode = REPLAY_MODE_NONE;
 
@@ -34,6 +35,10 @@ bool replay_next_event_is(int event)
             res = true;
         }
         switch (replay_data_kind) {
+        case EVENT_SHUTDOWN:
+            replay_finish_event();
+            qemu_system_shutdown_request();
+            break;
         default:
             /* clock, time_t, checkpoint and other events */
             return res;
@@ -146,3 +151,12 @@ bool replay_has_interrupt(void)
     }
     return res;
 }
+
+void replay_shutdown_request(void)
+{
+    if (replay_mode == REPLAY_MODE_RECORD) {
+        replay_mutex_lock();
+        replay_put_event(EVENT_SHUTDOWN);
+        replay_mutex_unlock();
+    }
+}
diff --git a/vl.c b/vl.c
index 601ace2..f481a1e 100644
--- a/vl.c
+++ b/vl.c
@@ -122,6 +122,7 @@ int main(int argc, char **argv)
 #include "qapi-event.h"
 #include "exec/semihost.h"
 #include "crypto/init.h"
+#include "sysemu/replay.h"
 
 #define MAX_VIRTIO_CONSOLES 1
 #define MAX_SCLP_CONSOLES 1
@@ -1803,6 +1804,7 @@ void qemu_system_killed(int signal, pid_t pid)
 void qemu_system_shutdown_request(void)
 {
     trace_qemu_system_shutdown_request();
+    replay_shutdown_request();
     shutdown_requested = 1;
     qemu_notify_event();
 }
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [Qemu-devel] [PULL 11/18] icount: improve counting for record/replay
  2015-11-05 12:13 [Qemu-devel] [PULL 00/18] Record/replay core for 2.5-rc1 Paolo Bonzini
                   ` (9 preceding siblings ...)
  2015-11-05 12:13 ` [Qemu-devel] [PULL 10/18] replay: shutdown event Paolo Bonzini
@ 2015-11-05 12:13 ` Paolo Bonzini
  2015-11-05 12:13 ` [Qemu-devel] [PULL 12/18] replay: checkpoints Paolo Bonzini
                   ` (7 subsequent siblings)
  18 siblings, 0 replies; 26+ messages in thread
From: Paolo Bonzini @ 2015-11-05 12:13 UTC (permalink / raw)
  To: qemu-devel; +Cc: Pavel Dovgalyuk

From: Pavel Dovgalyuk <Pavel.Dovgaluk@ispras.ru>

icount_warp_rt function is called by qemu_clock_warp and as
callback of icount_warp timer. This patch adds call to qemu_clock_warp
into main_loop_wait function, because icount warp may be missed
in record/replay mode, when CPU is sleeping.
This patch also disables of calling this function by timer, because
it is not needed after making modifications of main_loop_wait.

Signed-off-by: Pavel Dovgalyuk <pavel.dovgaluk@ispras.ru>
Message-Id: <20150917162439.8676.38290.stgit@PASHA-ISP.def.inno>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Signed-off-by: Pavel Dovgalyuk <Pavel.Dovgaluk@ispras.ru>
---
 cpus.c      | 11 ++++++++---
 main-loop.c |  3 +++
 2 files changed, 11 insertions(+), 3 deletions(-)

diff --git a/cpus.c b/cpus.c
index 2385caa..1a7318f 100644
--- a/cpus.c
+++ b/cpus.c
@@ -335,7 +335,7 @@ static int64_t qemu_icount_round(int64_t count)
     return (count + (1 << icount_time_shift) - 1) >> icount_time_shift;
 }
 
-static void icount_warp_rt(void *opaque)
+static void icount_warp_rt(void)
 {
     /* The icount_warp_timer is rescheduled soon after vm_clock_warp_start
      * changes from -1 to another value, so the race here is okay.
@@ -370,6 +370,11 @@ static void icount_warp_rt(void *opaque)
     }
 }
 
+static void icount_dummy_timer(void *opaque)
+{
+    (void)opaque;
+}
+
 void qtest_clock_warp(int64_t dest)
 {
     int64_t clock = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
@@ -414,7 +419,7 @@ void qemu_clock_warp(QEMUClockType type)
          * the CPU starts running, in case the CPU is woken by an event other
          * than the earliest QEMU_CLOCK_VIRTUAL timer.
          */
-        icount_warp_rt(NULL);
+        icount_warp_rt();
         timer_del(icount_warp_timer);
     }
     if (!all_cpu_threads_idle()) {
@@ -607,7 +612,7 @@ void configure_icount(QemuOpts *opts, Error **errp)
     icount_sleep = qemu_opt_get_bool(opts, "sleep", true);
     if (icount_sleep) {
         icount_warp_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL_RT,
-                                         icount_warp_rt, NULL);
+                                         icount_dummy_timer, NULL);
     }
 
     icount_align_option = qemu_opt_get_bool(opts, "align", false);
diff --git a/main-loop.c b/main-loop.c
index db600a3..df28670 100644
--- a/main-loop.c
+++ b/main-loop.c
@@ -506,6 +506,9 @@ int main_loop_wait(int nonblocking)
     slirp_pollfds_poll(gpollfds, (ret < 0));
 #endif
 
+    /* CPU thread can infinitely wait for event after
+       missing the warp */
+    qemu_clock_warp(QEMU_CLOCK_VIRTUAL);
     qemu_clock_run_all_timers();
 
     return ret;
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [Qemu-devel] [PULL 12/18] replay: checkpoints
  2015-11-05 12:13 [Qemu-devel] [PULL 00/18] Record/replay core for 2.5-rc1 Paolo Bonzini
                   ` (10 preceding siblings ...)
  2015-11-05 12:13 ` [Qemu-devel] [PULL 11/18] icount: improve counting for record/replay Paolo Bonzini
@ 2015-11-05 12:13 ` Paolo Bonzini
  2015-11-05 12:13 ` [Qemu-devel] [PULL 13/18] bottom halves: introduce bh call function Paolo Bonzini
                   ` (6 subsequent siblings)
  18 siblings, 0 replies; 26+ messages in thread
From: Paolo Bonzini @ 2015-11-05 12:13 UTC (permalink / raw)
  To: qemu-devel; +Cc: Pavel Dovgalyuk

From: Pavel Dovgalyuk <Pavel.Dovgaluk@ispras.ru>

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 <pavel.dovgaluk@ispras.ru>
Message-Id: <20150917162444.8676.52916.stgit@PASHA-ISP.def.inno>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Signed-off-by: Pavel Dovgalyuk <Pavel.Dovgaluk@ispras.ru>
---
 cpus.c                   | 12 ++++++++++++
 include/sysemu/replay.h  | 20 ++++++++++++++++++++
 qemu-timer.c             | 41 ++++++++++++++++++++++++++++++++++-------
 replay/replay-internal.h |  4 ++++
 replay/replay.c          | 34 ++++++++++++++++++++++++++++++++++
 stubs/replay.c           |  6 ++++++
 vl.c                     | 29 ++++++++++++++++++++++++-----
 7 files changed, 134 insertions(+), 12 deletions(-)

diff --git a/cpus.c b/cpus.c
index 1a7318f..2619fd0 100644
--- a/cpus.c
+++ b/cpus.c
@@ -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.
diff --git a/include/sysemu/replay.h b/include/sysemu/replay.h
index fcc93d1..e2696fe 100644
--- a/include/sysemu/replay.h
+++ b/include/sysemu/replay.h
@@ -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 */
 
diff --git a/qemu-timer.c b/qemu-timer.c
index 3dc847b..f16e422 100644
--- a/qemu-timer.c
+++ b/qemu-timer.c
@@ -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,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);
@@ -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;
@@ -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;
diff --git a/replay/replay-internal.h b/replay/replay-internal.h
index 4414695..bf64be5 100644
--- a/replay/replay-internal.h
+++ b/replay/replay-internal.h
@@ -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
 };
 
diff --git a/replay/replay.c b/replay/replay.c
index 65dca7f..44fbed9 100644
--- a/replay/replay.c
+++ b/replay/replay.c
@@ -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;
+}
diff --git a/stubs/replay.c b/stubs/replay.c
index f0d95b0..3354fcf 100644
--- a/stubs/replay.c
+++ b/stubs/replay.c
@@ -1,5 +1,6 @@
 #include "sysemu/replay.h"
 #include <stdlib.h>
+#include "sysemu/sysemu.h"
 
 ReplayMode replay_mode;
 
@@ -14,3 +15,8 @@ int64_t replay_read_clock(unsigned int kind)
     abort();
     return 0;
 }
+
+bool replay_checkpoint(ReplayCheckpoint checkpoint)
+{
+    return true;
+}
diff --git a/vl.c b/vl.c
index f481a1e..8806092 100644
--- a/vl.c
+++ b/vl.c
@@ -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)
@@ -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)
@@ -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;
@@ -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) {
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [Qemu-devel] [PULL 13/18] bottom halves: introduce bh call function
  2015-11-05 12:13 [Qemu-devel] [PULL 00/18] Record/replay core for 2.5-rc1 Paolo Bonzini
                   ` (11 preceding siblings ...)
  2015-11-05 12:13 ` [Qemu-devel] [PULL 12/18] replay: checkpoints Paolo Bonzini
@ 2015-11-05 12:13 ` Paolo Bonzini
  2015-11-05 12:13 ` [Qemu-devel] [PULL 14/18] replay: ptimer Paolo Bonzini
                   ` (5 subsequent siblings)
  18 siblings, 0 replies; 26+ messages in thread
From: Paolo Bonzini @ 2015-11-05 12:13 UTC (permalink / raw)
  To: qemu-devel; +Cc: Pavel Dovgalyuk

From: Pavel Dovgalyuk <Pavel.Dovgaluk@ispras.ru>

This patch introduces aio_bh_call function. It is used to execute
bottom halves as callbacks without adding them to the queue.

Signed-off-by: Pavel Dovgalyuk <pavel.dovgaluk@ispras.ru>
Message-Id: <20150917162450.8676.56980.stgit@PASHA-ISP.def.inno>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Signed-off-by: Pavel Dovgalyuk <Pavel.Dovgaluk@ispras.ru>
---
 async.c             | 7 ++++++-
 include/block/aio.h | 5 +++++
 2 files changed, 11 insertions(+), 1 deletion(-)

diff --git a/async.c b/async.c
index bdc64a3..9589e4b 100644
--- a/async.c
+++ b/async.c
@@ -59,6 +59,11 @@ QEMUBH *aio_bh_new(AioContext *ctx, QEMUBHFunc *cb, void *opaque)
     return bh;
 }
 
+void aio_bh_call(QEMUBH *bh)
+{
+    bh->cb(bh->opaque);
+}
+
 /* Multiple occurrences of aio_bh_poll cannot be called concurrently */
 int aio_bh_poll(AioContext *ctx)
 {
@@ -84,7 +89,7 @@ int aio_bh_poll(AioContext *ctx)
                 ret = 1;
             }
             bh->idle = 0;
-            bh->cb(bh->opaque);
+            aio_bh_call(bh);
         }
     }
 
diff --git a/include/block/aio.h b/include/block/aio.h
index bcc7d43..92efc5e 100644
--- a/include/block/aio.h
+++ b/include/block/aio.h
@@ -209,6 +209,11 @@ void aio_notify(AioContext *ctx);
 void aio_notify_accept(AioContext *ctx);
 
 /**
+ * aio_bh_call: Executes callback function of the specified BH.
+ */
+void aio_bh_call(QEMUBH *bh);
+
+/**
  * aio_bh_poll: Poll bottom halves for an AioContext.
  *
  * These are internal functions used by the QEMU main loop.
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [Qemu-devel] [PULL 14/18] replay: ptimer
  2015-11-05 12:13 [Qemu-devel] [PULL 00/18] Record/replay core for 2.5-rc1 Paolo Bonzini
                   ` (12 preceding siblings ...)
  2015-11-05 12:13 ` [Qemu-devel] [PULL 13/18] bottom halves: introduce bh call function Paolo Bonzini
@ 2015-11-05 12:13 ` Paolo Bonzini
  2015-11-05 12:14 ` [Qemu-devel] [PULL 15/18] replay: initialization and deinitialization Paolo Bonzini
                   ` (4 subsequent siblings)
  18 siblings, 0 replies; 26+ messages in thread
From: Paolo Bonzini @ 2015-11-05 12:13 UTC (permalink / raw)
  To: qemu-devel; +Cc: Pavel Dovgalyuk

From: Pavel Dovgalyuk <Pavel.Dovgaluk@ispras.ru>

This patch adds deterministic replay for hardware periodic countdown timers.
ptimer uses bottom halves layer to execute such an asynchronous callback.
We put this callback into the replay queue instead of bottom halves one.
When checkpoint is met by main loop thread, the replay queue is processed
and callback is executed. Binding callback moment to one of the checkpoints
makes it deterministic.

Signed-off-by: Pavel Dovgalyuk <pavel.dovgaluk@ispras.ru>
Message-Id: <20150917162456.8676.83366.stgit@PASHA-ISP.def.inno>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Signed-off-by: Pavel Dovgalyuk <Pavel.Dovgaluk@ispras.ru>
---
 hw/core/ptimer.c         |  3 ++-
 include/sysemu/replay.h  |  3 +++
 replay/replay-events.c   | 25 ++++++++++++++++++++++---
 replay/replay-internal.h |  1 +
 4 files changed, 28 insertions(+), 4 deletions(-)

diff --git a/hw/core/ptimer.c b/hw/core/ptimer.c
index 8437bd6..edf077c 100644
--- a/hw/core/ptimer.c
+++ b/hw/core/ptimer.c
@@ -9,6 +9,7 @@
 #include "qemu/timer.h"
 #include "hw/ptimer.h"
 #include "qemu/host-utils.h"
+#include "sysemu/replay.h"
 
 struct ptimer_state
 {
@@ -27,7 +28,7 @@ struct ptimer_state
 static void ptimer_trigger(ptimer_state *s)
 {
     if (s->bh) {
-        qemu_bh_schedule(s->bh);
+        replay_bh_schedule_event(s->bh);
     }
 }
 
diff --git a/include/sysemu/replay.h b/include/sysemu/replay.h
index e2696fe..fdf46f8 100644
--- a/include/sysemu/replay.h
+++ b/include/sysemu/replay.h
@@ -15,6 +15,7 @@
 #include <stdbool.h>
 #include <stdint.h>
 #include "qapi-types.h"
+#include "qemu/typedefs.h"
 
 /* replay clock kinds */
 enum ReplayClockKind {
@@ -97,5 +98,7 @@ bool replay_checkpoint(ReplayCheckpoint checkpoint);
 void replay_disable_events(void);
 /*! Returns true when saving events is enabled */
 bool replay_events_enabled(void);
+/*! Adds bottom half event to the queue */
+void replay_bh_schedule_event(QEMUBH *bh);
 
 #endif
diff --git a/replay/replay-events.c b/replay/replay-events.c
index 8dcc96d..8db2c7a 100644
--- a/replay/replay-events.c
+++ b/replay/replay-events.c
@@ -13,6 +13,7 @@
 #include "qemu/error-report.h"
 #include "sysemu/replay.h"
 #include "replay-internal.h"
+#include "block/aio.h"
 
 typedef struct Event {
     ReplayAsyncEventKind event_kind;
@@ -35,6 +36,9 @@ static bool events_enabled;
 static void replay_run_event(Event *event)
 {
     switch (event->event_kind) {
+    case REPLAY_ASYNC_EVENT_BH:
+        aio_bh_call(event->opaque);
+        break;
     default:
         error_report("Replay: invalid async event ID (%d) in the queue",
                     event->event_kind);
@@ -89,7 +93,6 @@ void replay_clear_events(void)
 }
 
 /*! Adds specified async event to the queue */
-#if 0
 static void replay_add_event(ReplayAsyncEventKind event_kind,
                              void *opaque,
                              void *opaque2, uint64_t id)
@@ -117,7 +120,16 @@ static void replay_add_event(ReplayAsyncEventKind event_kind,
     QTAILQ_INSERT_TAIL(&events_list, event, events);
     replay_mutex_unlock();
 }
-#endif
+
+void replay_bh_schedule_event(QEMUBH *bh)
+{
+    if (replay_mode != REPLAY_MODE_NONE) {
+        uint64_t id = replay_get_current_step();
+        replay_add_event(REPLAY_ASYNC_EVENT_BH, bh, NULL, id);
+    } else {
+        qemu_bh_schedule(bh);
+    }
+}
 
 static void replay_save_event(Event *event, int checkpoint)
 {
@@ -129,10 +141,12 @@ static void replay_save_event(Event *event, int checkpoint)
 
         /* save event-specific data */
         switch (event->event_kind) {
+        case REPLAY_ASYNC_EVENT_BH:
+            replay_put_qword(event->id);
+            break;
         default:
             error_report("Unknown ID %d of replay event", read_event_kind);
             exit(1);
-            break;
         }
     }
 }
@@ -168,6 +182,11 @@ static Event *replay_read_event(int checkpoint)
 
     /* Events that has not to be in the queue */
     switch (read_event_kind) {
+    case REPLAY_ASYNC_EVENT_BH:
+        if (read_id == -1) {
+            read_id = replay_get_qword();
+        }
+        break;
     default:
         error_report("Unknown ID %d of replay event", read_event_kind);
         exit(1);
diff --git a/replay/replay-internal.h b/replay/replay-internal.h
index bf64be5..7ba6064 100644
--- a/replay/replay-internal.h
+++ b/replay/replay-internal.h
@@ -39,6 +39,7 @@ enum ReplayEvents {
 /* Asynchronous events IDs */
 
 enum ReplayAsyncEventKind {
+    REPLAY_ASYNC_EVENT_BH,
     REPLAY_ASYNC_COUNT
 };
 
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [Qemu-devel] [PULL 15/18] replay: initialization and deinitialization
  2015-11-05 12:13 [Qemu-devel] [PULL 00/18] Record/replay core for 2.5-rc1 Paolo Bonzini
                   ` (13 preceding siblings ...)
  2015-11-05 12:13 ` [Qemu-devel] [PULL 14/18] replay: ptimer Paolo Bonzini
@ 2015-11-05 12:14 ` Paolo Bonzini
  2015-11-05 12:14 ` [Qemu-devel] [PULL 16/18] replay: replay blockers for devices Paolo Bonzini
                   ` (3 subsequent siblings)
  18 siblings, 0 replies; 26+ messages in thread
From: Paolo Bonzini @ 2015-11-05 12:14 UTC (permalink / raw)
  To: qemu-devel; +Cc: Pavel Dovgalyuk

From: Pavel Dovgalyuk <Pavel.Dovgaluk@ispras.ru>

This patch introduces the functions for enabling the record/replay and for
freeing the resources when simulator closes.

Reviewed-by: Paolo Bonzini <pbonzini@redhat.com>

Signed-off-by: Pavel Dovgalyuk <pavel.dovgaluk@ispras.ru>
Message-Id: <20150917162507.8676.90232.stgit@PASHA-ISP.def.inno>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Signed-off-by: Pavel Dovgalyuk <Pavel.Dovgaluk@ispras.ru>
---
 exec.c                   |   2 +
 include/sysemu/replay.h  |   9 ++++
 replay/replay-internal.h |   2 +
 replay/replay.c          | 130 +++++++++++++++++++++++++++++++++++++++++++++++
 stubs/replay.c           |   9 ++++
 vl.c                     |   4 ++
 6 files changed, 156 insertions(+)

diff --git a/exec.c b/exec.c
index 8af2570..b60e2de 100644
--- a/exec.c
+++ b/exec.c
@@ -50,6 +50,7 @@
 #include "qemu/rcu_queue.h"
 #include "qemu/main-loop.h"
 #include "translate-all.h"
+#include "sysemu/replay.h"
 
 #include "exec/memory-internal.h"
 #include "exec/ram_addr.h"
@@ -882,6 +883,7 @@ void cpu_abort(CPUState *cpu, const char *fmt, ...)
     }
     va_end(ap2);
     va_end(ap);
+    replay_finish();
 #if defined(CONFIG_USER_ONLY)
     {
         struct sigaction act;
diff --git a/include/sysemu/replay.h b/include/sysemu/replay.h
index fdf46f8..ad5234c 100644
--- a/include/sysemu/replay.h
+++ b/include/sysemu/replay.h
@@ -43,6 +43,15 @@ typedef enum ReplayCheckpoint ReplayCheckpoint;
 
 extern ReplayMode replay_mode;
 
+/* Replay process control functions */
+
+/*! Enables recording or saving event log with specified parameters */
+void replay_configure(struct QemuOpts *opts);
+/*! Initializes timers used for snapshotting and enables events recording */
+void replay_start(void);
+/*! Closes replay log file and frees other resources. */
+void replay_finish(void);
+
 /* Processing the instructions */
 
 /*! Returns number of executed instructions. */
diff --git a/replay/replay-internal.h b/replay/replay-internal.h
index 7ba6064..d40de2b 100644
--- a/replay/replay-internal.h
+++ b/replay/replay-internal.h
@@ -33,6 +33,8 @@ enum ReplayEvents {
     /* some of greater codes are reserved for checkpoints */
     EVENT_CHECKPOINT,
     EVENT_CHECKPOINT_LAST = EVENT_CHECKPOINT + CHECKPOINT_COUNT - 1,
+    /* end of log event */
+    EVENT_END,
     EVENT_COUNT
 };
 
diff --git a/replay/replay.c b/replay/replay.c
index 44fbed9..7edeffc 100644
--- a/replay/replay.c
+++ b/replay/replay.c
@@ -15,9 +15,18 @@
 #include "qemu/timer.h"
 #include "qemu/main-loop.h"
 #include "sysemu/sysemu.h"
+#include "qemu/error-report.h"
+
+/* Current version of the replay mechanism.
+   Increase it when file format changes. */
+#define REPLAY_VERSION              0xe02002
+/* Size of replay log header */
+#define HEADER_SIZE                 (sizeof(uint32_t) + sizeof(uint64_t))
 
 ReplayMode replay_mode = REPLAY_MODE_NONE;
 
+/* Name of replay file  */
+static char *replay_filename;
 ReplayState replay_state;
 
 bool replay_next_event_is(int event)
@@ -194,3 +203,124 @@ out:
     replay_mutex_unlock();
     return res;
 }
+
+static void replay_enable(const char *fname, int mode)
+{
+    const char *fmode = NULL;
+    assert(!replay_file);
+
+    switch (mode) {
+    case REPLAY_MODE_RECORD:
+        fmode = "wb";
+        break;
+    case REPLAY_MODE_PLAY:
+        fmode = "rb";
+        break;
+    default:
+        fprintf(stderr, "Replay: internal error: invalid replay mode\n");
+        exit(1);
+    }
+
+    atexit(replay_finish);
+
+    replay_mutex_init();
+
+    replay_file = fopen(fname, fmode);
+    if (replay_file == NULL) {
+        fprintf(stderr, "Replay: open %s: %s\n", fname, strerror(errno));
+        exit(1);
+    }
+
+    replay_filename = g_strdup(fname);
+
+    replay_mode = mode;
+    replay_data_kind = -1;
+    replay_state.instructions_count = 0;
+    replay_state.current_step = 0;
+
+    /* skip file header for RECORD and check it for PLAY */
+    if (replay_mode == REPLAY_MODE_RECORD) {
+        fseek(replay_file, HEADER_SIZE, SEEK_SET);
+    } else if (replay_mode == REPLAY_MODE_PLAY) {
+        unsigned int version = replay_get_dword();
+        if (version != REPLAY_VERSION) {
+            fprintf(stderr, "Replay: invalid input log file version\n");
+            exit(1);
+        }
+        /* go to the beginning */
+        fseek(replay_file, HEADER_SIZE, SEEK_SET);
+        replay_fetch_data_kind();
+    }
+
+    replay_init_events();
+}
+
+void replay_configure(QemuOpts *opts)
+{
+    const char *fname;
+    const char *rr;
+    ReplayMode mode = REPLAY_MODE_NONE;
+
+    rr = qemu_opt_get(opts, "rr");
+    if (!rr) {
+        /* Just enabling icount */
+        return;
+    } else if (!strcmp(rr, "record")) {
+        mode = REPLAY_MODE_RECORD;
+    } else if (!strcmp(rr, "replay")) {
+        mode = REPLAY_MODE_PLAY;
+    } else {
+        error_report("Invalid icount rr option: %s", rr);
+        exit(1);
+    }
+
+    fname = qemu_opt_get(opts, "rrfile");
+    if (!fname) {
+        error_report("File name not specified for replay");
+        exit(1);
+    }
+
+    replay_enable(fname, mode);
+}
+
+void replay_start(void)
+{
+    if (replay_mode == REPLAY_MODE_NONE) {
+        return;
+    }
+
+    /* Timer for snapshotting will be set up here. */
+
+    replay_enable_events();
+}
+
+void replay_finish(void)
+{
+    if (replay_mode == REPLAY_MODE_NONE) {
+        return;
+    }
+
+    replay_save_instructions();
+
+    /* finalize the file */
+    if (replay_file) {
+        if (replay_mode == REPLAY_MODE_RECORD) {
+            /* write end event */
+            replay_put_event(EVENT_END);
+
+            /* write header */
+            fseek(replay_file, 0, SEEK_SET);
+            replay_put_dword(REPLAY_VERSION);
+        }
+
+        fclose(replay_file);
+        replay_file = NULL;
+    }
+    if (replay_filename) {
+        g_free(replay_filename);
+        replay_filename = NULL;
+    }
+
+    replay_finish_events();
+    replay_mutex_destroy();
+}
diff --git a/stubs/replay.c b/stubs/replay.c
index 3354fcf..8f98790 100644
--- a/stubs/replay.c
+++ b/stubs/replay.c
@@ -20,3 +20,12 @@ bool replay_checkpoint(ReplayCheckpoint checkpoint)
 {
     return true;
 }
+
+bool replay_events_enabled(void)
+{
+    return false;
+}
+
+void replay_finish(void)
+{
+}
diff --git a/vl.c b/vl.c
index 8806092..b3ff137 100644
--- a/vl.c
+++ b/vl.c
@@ -4616,6 +4616,8 @@ int main(int argc, char **argv, char **envp)
         exit(1);
     }
 
+    replay_start();
+
     /* 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. */
@@ -4657,6 +4659,8 @@ int main(int argc, char **argv, char **envp)
     }
 
     main_loop();
+    replay_disable_events();
+
     bdrv_close_all();
     pause_all_vcpus();
     res_free();
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [Qemu-devel] [PULL 16/18] replay: replay blockers for devices
  2015-11-05 12:13 [Qemu-devel] [PULL 00/18] Record/replay core for 2.5-rc1 Paolo Bonzini
                   ` (14 preceding siblings ...)
  2015-11-05 12:14 ` [Qemu-devel] [PULL 15/18] replay: initialization and deinitialization Paolo Bonzini
@ 2015-11-05 12:14 ` Paolo Bonzini
  2015-11-05 12:14 ` [Qemu-devel] [PULL 17/18] replay: command line options Paolo Bonzini
                   ` (2 subsequent siblings)
  18 siblings, 0 replies; 26+ messages in thread
From: Paolo Bonzini @ 2015-11-05 12:14 UTC (permalink / raw)
  To: qemu-devel; +Cc: Pavel Dovgalyuk

From: Pavel Dovgalyuk <Pavel.Dovgaluk@ispras.ru>

Some devices are not supported by record/replay subsystem.
This patch introduces replay blocker which denies starting record/replay
if such devices are included into the configuration.

Signed-off-by: Pavel Dovgalyuk <pavel.dovgaluk@ispras.ru>
Message-Id: <20150917162512.8676.11367.stgit@PASHA-ISP.def.inno>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Signed-off-by: Pavel Dovgalyuk <Pavel.Dovgaluk@ispras.ru>
---
 hw/bt/hci.c               |  7 +++++++
 include/qapi/qmp/qerror.h |  3 +++
 include/sysemu/replay.h   |  3 +++
 replay/replay.c           | 12 ++++++++++++
 vl.c                      | 10 ++++++++++
 5 files changed, 35 insertions(+)

diff --git a/hw/bt/hci.c b/hw/bt/hci.c
index 6a88d49..2151d01 100644
--- a/hw/bt/hci.c
+++ b/hw/bt/hci.c
@@ -23,6 +23,8 @@
 #include "hw/usb.h"
 #include "sysemu/bt.h"
 #include "hw/bt.h"
+#include "qapi/qmp/qerror.h"
+#include "sysemu/replay.h"
 
 struct bt_hci_s {
     uint8_t *(*evt_packet)(void *opaque);
@@ -72,6 +74,8 @@ struct bt_hci_s {
 
     struct HCIInfo info;
     struct bt_device_s device;
+
+    Error *replay_blocker;
 };
 
 #define DEFAULT_RSSI_DBM	20
@@ -2189,6 +2193,9 @@ struct HCIInfo *bt_new_hci(struct bt_scatternet_s *net)
 
     s->device.handle_destroy = bt_hci_destroy;
 
+    error_setg(&s->replay_blocker, QERR_REPLAY_NOT_SUPPORTED, "-bt hci");
+    replay_add_blocker(s->replay_blocker);
+
     return &s->info;
 }
 
diff --git a/include/qapi/qmp/qerror.h b/include/qapi/qmp/qerror.h
index 842b27a..f601499 100644
--- a/include/qapi/qmp/qerror.h
+++ b/include/qapi/qmp/qerror.h
@@ -106,4 +106,7 @@
 #define QERR_UNSUPPORTED \
     "this feature or command is not currently supported"
 
+#define QERR_REPLAY_NOT_SUPPORTED \
+    "Record/replay feature is not supported for '%s'"
+
 #endif /* QERROR_H */
diff --git a/include/sysemu/replay.h b/include/sysemu/replay.h
index ad5234c..3b27f12 100644
--- a/include/sysemu/replay.h
+++ b/include/sysemu/replay.h
@@ -15,6 +15,7 @@
 #include <stdbool.h>
 #include <stdint.h>
 #include "qapi-types.h"
+#include "qapi/error.h"
 #include "qemu/typedefs.h"
 
 /* replay clock kinds */
@@ -51,6 +52,8 @@ void replay_configure(struct QemuOpts *opts);
 void replay_start(void);
 /*! Closes replay log file and frees other resources. */
 void replay_finish(void);
+/*! Adds replay blocker with the specified error description */
+void replay_add_blocker(Error *reason);
 
 /* Processing the instructions */
 
diff --git a/replay/replay.c b/replay/replay.c
index 7edeffc..1373346 100644
--- a/replay/replay.c
+++ b/replay/replay.c
@@ -28,6 +28,7 @@ ReplayMode replay_mode = REPLAY_MODE_NONE;
 /* Name of replay file  */
 static char *replay_filename;
 ReplayState replay_state;
+static GSList *replay_blockers;
 
 bool replay_next_event_is(int event)
 {
@@ -289,6 +290,12 @@ void replay_start(void)
         return;
     }
 
+    if (replay_blockers) {
+        error_report("Record/replay: %s",
+                     error_get_pretty(replay_blockers->data));
+        exit(1);
+    }
+
     /* Timer for snapshotting will be set up here. */
 
     replay_enable_events();
@@ -324,3 +331,8 @@ void replay_finish(void)
     replay_finish_events();
     replay_mutex_destroy();
 }
+
+void replay_add_blocker(Error *reason)
+{
+    replay_blockers = g_slist_prepend(replay_blockers, reason);
+}
diff --git a/vl.c b/vl.c
index b3ff137..c1e54f4 100644
--- a/vl.c
+++ b/vl.c
@@ -123,6 +123,7 @@ int main(int argc, char **argv)
 #include "exec/semihost.h"
 #include "crypto/init.h"
 #include "sysemu/replay.h"
+#include "qapi/qmp/qerror.h"
 
 #define MAX_VIRTIO_CONSOLES 1
 #define MAX_SCLP_CONSOLES 1
@@ -847,7 +848,11 @@ static void configure_rtc(QemuOpts *opts)
         if (!strcmp(value, "utc")) {
             rtc_utc = 1;
         } else if (!strcmp(value, "localtime")) {
+            Error *blocker = NULL;
             rtc_utc = 0;
+            error_setg(&blocker, QERR_REPLAY_NOT_SUPPORTED,
+                      "-rtc base=localtime");
+            replay_add_blocker(blocker);
         } else {
             configure_rtc_date_offset(value, 0);
         }
@@ -1256,6 +1261,11 @@ static void smp_parse(QemuOpts *opts)
         exit(1);
     }
 
+    if (smp_cpus > 1 || smp_cores > 1 || smp_threads > 1) {
+        Error *blocker = NULL;
+        error_setg(&blocker, QERR_REPLAY_NOT_SUPPORTED, "smp");
+        replay_add_blocker(blocker);
+    }
 }
 
 static void realtime_init(void)
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [Qemu-devel] [PULL 17/18] replay: command line options
  2015-11-05 12:13 [Qemu-devel] [PULL 00/18] Record/replay core for 2.5-rc1 Paolo Bonzini
                   ` (15 preceding siblings ...)
  2015-11-05 12:14 ` [Qemu-devel] [PULL 16/18] replay: replay blockers for devices Paolo Bonzini
@ 2015-11-05 12:14 ` Paolo Bonzini
  2015-11-05 12:14 ` [Qemu-devel] [PULL 18/18] replay: recording of the user input Paolo Bonzini
  2015-11-05 14:00 ` [Qemu-devel] [PULL 00/18] Record/replay core for 2.5-rc1 Peter Maydell
  18 siblings, 0 replies; 26+ messages in thread
From: Paolo Bonzini @ 2015-11-05 12:14 UTC (permalink / raw)
  To: qemu-devel; +Cc: Pavel Dovgalyuk

From: Pavel Dovgalyuk <Pavel.Dovgaluk@ispras.ru>

This patch introduces command line options for enabling recording or replaying
virtual machine behavior. These options are added to icount command line
parameter. They include 'rr' which switches between record and replay
and 'rrfile' for specifying the filename for replay log.

Signed-off-by: Pavel Dovgalyuk <pavel.dovgaluk@ispras.ru>
Message-Id: <20150917162518.8676.70792.stgit@PASHA-ISP.def.inno>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Signed-off-by: Pavel Dovgalyuk <Pavel.Dovgaluk@ispras.ru>
---
 qemu-options.hx |  8 ++++++--
 replay/replay.c |  4 ++++
 vl.c            | 15 ++++++++++++---
 3 files changed, 22 insertions(+), 5 deletions(-)

diff --git a/qemu-options.hx b/qemu-options.hx
index 949db7f..0eea4ee 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -3157,12 +3157,12 @@ re-inject them.
 ETEXI
 
 DEF("icount", HAS_ARG, QEMU_OPTION_icount, \
-    "-icount [shift=N|auto][,align=on|off][,sleep=no]\n" \
+    "-icount [shift=N|auto][,align=on|off][,sleep=no,rr=record|replay,rrfile=<filename>]\n" \
     "                enable virtual instruction counter with 2^N clock ticks per\n" \
     "                instruction, enable aligning the host and virtual clocks\n" \
     "                or disable real time cpu sleeping\n", QEMU_ARCH_ALL)
 STEXI
-@item -icount [shift=@var{N}|auto]
+@item -icount [shift=@var{N}|auto][,rr=record|replay,rrfile=@var{filename}]
 @findex -icount
 Enable virtual instruction counter.  The virtual cpu will execute one
 instruction every 2^@var{N} ns of virtual time.  If @code{auto} is specified
@@ -3191,6 +3191,10 @@ Currently this option does not work when @option{shift} is @code{auto}.
 Note: The sync algorithm will work for those shift values for which
 the guest clock runs ahead of the host clock. Typically this happens
 when the shift value is high (how high depends on the host machine).
+
+When @option{rr} option is specified deterministic record/replay is enabled.
+Replay log is written into @var{filename} file in record mode and
+read from this file in replay mode.
 ETEXI
 
 DEF("watchdog", HAS_ARG, QEMU_OPTION_watchdog, \
diff --git a/replay/replay.c b/replay/replay.c
index 1373346..0d33e82 100644
--- a/replay/replay.c
+++ b/replay/replay.c
@@ -295,6 +295,10 @@ void replay_start(void)
                      error_get_pretty(replay_blockers->data));
         exit(1);
     }
+    if (!use_icount) {
+        error_report("Please enable icount to use record/replay");
+        exit(1);
+    }
 
     /* Timer for snapshotting will be set up here. */
 
diff --git a/vl.c b/vl.c
index c1e54f4..bc4890b 100644
--- a/vl.c
+++ b/vl.c
@@ -476,6 +476,12 @@ static QemuOptsList qemu_icount_opts = {
         }, {
             .name = "sleep",
             .type = QEMU_OPT_BOOL,
+        }, {
+            .name = "rr",
+            .type = QEMU_OPT_STRING,
+        }, {
+            .name = "rrfile",
+            .type = QEMU_OPT_STRING,
         },
         { /* end of list */ }
     },
@@ -4014,6 +4020,8 @@ int main(int argc, char **argv, char **envp)
         }
     }
 
+    replay_configure(icount_opts);
+
     opts = qemu_get_machine_opts();
     optarg = qemu_opt_get(opts, "type");
     if (optarg) {
@@ -4447,9 +4455,10 @@ int main(int argc, char **argv, char **envp)
     }
 
     /* open the virtual block devices */
-    if (snapshot)
-        qemu_opts_foreach(qemu_find_opts("drive"),
-                          drive_enable_snapshot, NULL, NULL);
+    if (snapshot || replay_mode != REPLAY_MODE_NONE) {
+        qemu_opts_foreach(qemu_find_opts("drive"), drive_enable_snapshot,
+                          NULL, NULL);
+    }
     if (qemu_opts_foreach(qemu_find_opts("drive"), drive_init_func,
                           &machine_class->block_default_type, NULL)) {
         exit(1);
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [Qemu-devel] [PULL 18/18] replay: recording of the user input
  2015-11-05 12:13 [Qemu-devel] [PULL 00/18] Record/replay core for 2.5-rc1 Paolo Bonzini
                   ` (16 preceding siblings ...)
  2015-11-05 12:14 ` [Qemu-devel] [PULL 17/18] replay: command line options Paolo Bonzini
@ 2015-11-05 12:14 ` Paolo Bonzini
  2015-11-05 14:00 ` [Qemu-devel] [PULL 00/18] Record/replay core for 2.5-rc1 Peter Maydell
  18 siblings, 0 replies; 26+ messages in thread
From: Paolo Bonzini @ 2015-11-05 12:14 UTC (permalink / raw)
  To: qemu-devel; +Cc: Pavel Dovgalyuk

From: Pavel Dovgalyuk <Pavel.Dovgaluk@ispras.ru>

This records user input (keyboard and mouse events) in record mode and replays
these input events in replay mode.

Signed-off-by: Pavel Dovgalyuk <pavel.dovgaluk@ispras.ru>
Message-Id: <20150917162524.8676.11696.stgit@PASHA-ISP.def.inno>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Signed-off-by: Pavel Dovgalyuk <Pavel.Dovgaluk@ispras.ru>
---
 include/sysemu/replay.h  |   4 ++
 include/ui/input.h       |   2 +
 replay/Makefile.objs     |   1 +
 replay/replay-events.c   |  33 ++++++++++
 replay/replay-input.c    | 160 +++++++++++++++++++++++++++++++++++++++++++++++
 replay/replay-internal.h |  13 ++++
 ui/input.c               |  27 +++++---
 7 files changed, 232 insertions(+), 8 deletions(-)
 create mode 100644 replay/replay-input.c

diff --git a/include/sysemu/replay.h b/include/sysemu/replay.h
index 3b27f12..abb4688 100644
--- a/include/sysemu/replay.h
+++ b/include/sysemu/replay.h
@@ -112,5 +112,9 @@ void replay_disable_events(void);
 bool replay_events_enabled(void);
 /*! Adds bottom half event to the queue */
 void replay_bh_schedule_event(QEMUBH *bh);
+/*! Adds input event to the queue */
+void replay_input_event(QemuConsole *src, InputEvent *evt);
+/*! Adds input sync event to the queue */
+void replay_input_sync_event(void);
 
 #endif
diff --git a/include/ui/input.h b/include/ui/input.h
index 5d5ac00..d06a12d 100644
--- a/include/ui/input.h
+++ b/include/ui/input.h
@@ -33,7 +33,9 @@ void qemu_input_handler_bind(QemuInputHandlerState *s,
                              const char *device_id, int head,
                              Error **errp);
 void qemu_input_event_send(QemuConsole *src, InputEvent *evt);
+void qemu_input_event_send_impl(QemuConsole *src, InputEvent *evt);
 void qemu_input_event_sync(void);
+void qemu_input_event_sync_impl(void);
 
 InputEvent *qemu_input_event_new_key(KeyValue *key, bool down);
 void qemu_input_event_send_key(QemuConsole *src, KeyValue *key, bool down);
diff --git a/replay/Makefile.objs b/replay/Makefile.objs
index 56328ac..232193a 100644
--- a/replay/Makefile.objs
+++ b/replay/Makefile.objs
@@ -2,3 +2,4 @@ common-obj-y += replay.o
 common-obj-y += replay-internal.o
 common-obj-y += replay-events.o
 common-obj-y += replay-time.o
+common-obj-y += replay-input.o
diff --git a/replay/replay-events.c b/replay/replay-events.c
index 8db2c7a..402f644 100644
--- a/replay/replay-events.c
+++ b/replay/replay-events.c
@@ -14,6 +14,7 @@
 #include "sysemu/replay.h"
 #include "replay-internal.h"
 #include "block/aio.h"
+#include "ui/input.h"
 
 typedef struct Event {
     ReplayAsyncEventKind event_kind;
@@ -39,6 +40,13 @@ static void replay_run_event(Event *event)
     case REPLAY_ASYNC_EVENT_BH:
         aio_bh_call(event->opaque);
         break;
+    case REPLAY_ASYNC_EVENT_INPUT:
+        qemu_input_event_send_impl(NULL, (InputEvent *)event->opaque);
+        qapi_free_InputEvent((InputEvent *)event->opaque);
+        break;
+    case REPLAY_ASYNC_EVENT_INPUT_SYNC:
+        qemu_input_event_sync_impl();
+        break;
     default:
         error_report("Replay: invalid async event ID (%d) in the queue",
                     event->event_kind);
@@ -131,6 +139,16 @@ void replay_bh_schedule_event(QEMUBH *bh)
     }
 }
 
+void replay_add_input_event(struct InputEvent *event)
+{
+    replay_add_event(REPLAY_ASYNC_EVENT_INPUT, event, NULL, 0);
+}
+
+void replay_add_input_sync_event(void)
+{
+    replay_add_event(REPLAY_ASYNC_EVENT_INPUT_SYNC, NULL, NULL, 0);
+}
+
 static void replay_save_event(Event *event, int checkpoint)
 {
     if (replay_mode != REPLAY_MODE_PLAY) {
@@ -144,6 +162,11 @@ static void replay_save_event(Event *event, int checkpoint)
         case REPLAY_ASYNC_EVENT_BH:
             replay_put_qword(event->id);
             break;
+        case REPLAY_ASYNC_EVENT_INPUT:
+            replay_save_input_event(event->opaque);
+            break;
+        case REPLAY_ASYNC_EVENT_INPUT_SYNC:
+            break;
         default:
             error_report("Unknown ID %d of replay event", read_event_kind);
             exit(1);
@@ -187,6 +210,16 @@ static Event *replay_read_event(int checkpoint)
             read_id = replay_get_qword();
         }
         break;
+    case REPLAY_ASYNC_EVENT_INPUT:
+        event = g_malloc0(sizeof(Event));
+        event->event_kind = read_event_kind;
+        event->opaque = replay_read_input_event();
+        return event;
+    case REPLAY_ASYNC_EVENT_INPUT_SYNC:
+        event = g_malloc0(sizeof(Event));
+        event->event_kind = read_event_kind;
+        event->opaque = 0;
+        return event;
     default:
         error_report("Unknown ID %d of replay event", read_event_kind);
         exit(1);
diff --git a/replay/replay-input.c b/replay/replay-input.c
new file mode 100644
index 0000000..9879895
--- /dev/null
+++ b/replay/replay-input.c
@@ -0,0 +1,160 @@
+/*
+ * replay-input.c
+ *
+ * Copyright (c) 2010-2015 Institute for System Programming
+ *                         of the Russian Academy of Sciences.
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ *
+ */
+
+#include "qemu-common.h"
+#include "sysemu/replay.h"
+#include "replay-internal.h"
+#include "qemu/notify.h"
+#include "ui/input.h"
+#include "qapi/qmp-output-visitor.h"
+#include "qapi/qmp-input-visitor.h"
+#include "qapi-visit.h"
+
+static InputEvent *qapi_clone_InputEvent(InputEvent *src)
+{
+    QmpOutputVisitor *qov;
+    QmpInputVisitor *qiv;
+    Visitor *ov, *iv;
+    QObject *obj;
+    InputEvent *dst = NULL;
+
+    qov = qmp_output_visitor_new();
+    ov = qmp_output_get_visitor(qov);
+    visit_type_InputEvent(ov, &src, NULL, &error_abort);
+    obj = qmp_output_get_qobject(qov);
+    qmp_output_visitor_cleanup(qov);
+    if (!obj) {
+        return NULL;
+    }
+
+    qiv = qmp_input_visitor_new(obj);
+    iv = qmp_input_get_visitor(qiv);
+    visit_type_InputEvent(iv, &dst, NULL, &error_abort);
+    qmp_input_visitor_cleanup(qiv);
+    qobject_decref(obj);
+
+    return dst;
+}
+
+void replay_save_input_event(InputEvent *evt)
+{
+    replay_put_dword(evt->type);
+
+    switch (evt->type) {
+    case INPUT_EVENT_KIND_KEY:
+        replay_put_dword(evt->u.key->key->type);
+
+        switch (evt->u.key->key->type) {
+        case KEY_VALUE_KIND_NUMBER:
+            replay_put_qword(evt->u.key->key->u.number);
+            replay_put_byte(evt->u.key->down);
+            break;
+        case KEY_VALUE_KIND_QCODE:
+            replay_put_dword(evt->u.key->key->u.qcode);
+            replay_put_byte(evt->u.key->down);
+            break;
+        case KEY_VALUE_KIND_MAX:
+            /* keep gcc happy */
+            break;
+        }
+        break;
+    case INPUT_EVENT_KIND_BTN:
+        replay_put_dword(evt->u.btn->button);
+        replay_put_byte(evt->u.btn->down);
+        break;
+    case INPUT_EVENT_KIND_REL:
+        replay_put_dword(evt->u.rel->axis);
+        replay_put_qword(evt->u.rel->value);
+        break;
+    case INPUT_EVENT_KIND_ABS:
+        replay_put_dword(evt->u.abs->axis);
+        replay_put_qword(evt->u.abs->value);
+        break;
+    case INPUT_EVENT_KIND_MAX:
+        /* keep gcc happy */
+        break;
+    }
+}
+
+InputEvent *replay_read_input_event(void)
+{
+    InputEvent evt;
+    KeyValue keyValue;
+    InputKeyEvent key;
+    key.key = &keyValue;
+    InputBtnEvent btn;
+    InputMoveEvent rel;
+    InputMoveEvent abs;
+
+    evt.type = replay_get_dword();
+    switch (evt.type) {
+    case INPUT_EVENT_KIND_KEY:
+        evt.u.key = &key;
+        evt.u.key->key->type = replay_get_dword();
+
+        switch (evt.u.key->key->type) {
+        case KEY_VALUE_KIND_NUMBER:
+            evt.u.key->key->u.number = replay_get_qword();
+            evt.u.key->down = replay_get_byte();
+            break;
+        case KEY_VALUE_KIND_QCODE:
+            evt.u.key->key->u.qcode = (QKeyCode)replay_get_dword();
+            evt.u.key->down = replay_get_byte();
+            break;
+        case KEY_VALUE_KIND_MAX:
+            /* keep gcc happy */
+            break;
+        }
+        break;
+    case INPUT_EVENT_KIND_BTN:
+        evt.u.btn = &btn;
+        evt.u.btn->button = (InputButton)replay_get_dword();
+        evt.u.btn->down = replay_get_byte();
+        break;
+    case INPUT_EVENT_KIND_REL:
+        evt.u.rel = &rel;
+        evt.u.rel->axis = (InputAxis)replay_get_dword();
+        evt.u.rel->value = replay_get_qword();
+        break;
+    case INPUT_EVENT_KIND_ABS:
+        evt.u.abs = &abs;
+        evt.u.abs->axis = (InputAxis)replay_get_dword();
+        evt.u.abs->value = replay_get_qword();
+        break;
+    case INPUT_EVENT_KIND_MAX:
+        /* keep gcc happy */
+        break;
+    }
+
+    return qapi_clone_InputEvent(&evt);
+}
+
+void replay_input_event(QemuConsole *src, InputEvent *evt)
+{
+    if (replay_mode == REPLAY_MODE_PLAY) {
+        /* Nothing */
+    } else if (replay_mode == REPLAY_MODE_RECORD) {
+        replay_add_input_event(qapi_clone_InputEvent(evt));
+    } else {
+        qemu_input_event_send_impl(src, evt);
+    }
+}
+
+void replay_input_sync_event(void)
+{
+    if (replay_mode == REPLAY_MODE_PLAY) {
+        /* Nothing */
+    } else if (replay_mode == REPLAY_MODE_RECORD) {
+        replay_add_input_sync_event();
+    } else {
+        qemu_input_event_sync_impl();
+    }
+}
diff --git a/replay/replay-internal.h b/replay/replay-internal.h
index d40de2b..77e0d29 100644
--- a/replay/replay-internal.h
+++ b/replay/replay-internal.h
@@ -42,6 +42,8 @@ enum ReplayEvents {
 
 enum ReplayAsyncEventKind {
     REPLAY_ASYNC_EVENT_BH,
+    REPLAY_ASYNC_EVENT_INPUT,
+    REPLAY_ASYNC_EVENT_INPUT_SYNC,
     REPLAY_ASYNC_COUNT
 };
 
@@ -124,4 +126,15 @@ void replay_save_events(int checkpoint);
 /*! Read events from the file into the input queue */
 void replay_read_events(int checkpoint);
 
+/* Input events */
+
+/*! Saves input event to the log */
+void replay_save_input_event(InputEvent *evt);
+/*! Reads input event from the log */
+InputEvent *replay_read_input_event(void);
+/*! Adds input event to the queue */
+void replay_add_input_event(struct InputEvent *event);
+/*! Adds input sync event to the queue */
+void replay_add_input_sync_event(void);
+
 #endif
diff --git a/ui/input.c b/ui/input.c
index 643f885..a0f9873 100644
--- a/ui/input.c
+++ b/ui/input.c
@@ -6,6 +6,7 @@
 #include "trace.h"
 #include "ui/input.h"
 #include "ui/console.h"
+#include "sysemu/replay.h"
 
 struct QemuInputHandlerState {
     DeviceState       *dev;
@@ -300,14 +301,10 @@ static void qemu_input_queue_sync(struct QemuInputEventQueueHead *queue)
     QTAILQ_INSERT_TAIL(queue, item, node);
 }
 
-void qemu_input_event_send(QemuConsole *src, InputEvent *evt)
+void qemu_input_event_send_impl(QemuConsole *src, InputEvent *evt)
 {
     QemuInputHandlerState *s;
 
-    if (!runstate_is_running() && !runstate_check(RUN_STATE_SUSPENDED)) {
-        return;
-    }
-
     qemu_input_event_trace(src, evt);
 
     /* pre processing */
@@ -324,14 +321,19 @@ void qemu_input_event_send(QemuConsole *src, InputEvent *evt)
     s->events++;
 }
 
-void qemu_input_event_sync(void)
+void qemu_input_event_send(QemuConsole *src, InputEvent *evt)
 {
-    QemuInputHandlerState *s;
-
     if (!runstate_is_running() && !runstate_check(RUN_STATE_SUSPENDED)) {
         return;
     }
 
+    replay_input_event(src, evt);
+}
+
+void qemu_input_event_sync_impl(void)
+{
+    QemuInputHandlerState *s;
+
     trace_input_event_sync();
 
     QTAILQ_FOREACH(s, &handlers, node) {
@@ -345,6 +347,15 @@ void qemu_input_event_sync(void)
     }
 }
 
+void qemu_input_event_sync(void)
+{
+    if (!runstate_is_running() && !runstate_check(RUN_STATE_SUSPENDED)) {
+        return;
+    }
+
+    replay_input_sync_event();
+}
+
 InputEvent *qemu_input_event_new_key(KeyValue *key, bool down)
 {
     InputEvent *evt = g_new0(InputEvent, 1);
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 26+ messages in thread

* Re: [Qemu-devel] [PULL 00/18] Record/replay core for 2.5-rc1
  2015-11-05 12:13 [Qemu-devel] [PULL 00/18] Record/replay core for 2.5-rc1 Paolo Bonzini
                   ` (17 preceding siblings ...)
  2015-11-05 12:14 ` [Qemu-devel] [PULL 18/18] replay: recording of the user input Paolo Bonzini
@ 2015-11-05 14:00 ` Peter Maydell
  2015-11-05 14:07   ` Paolo Bonzini
  18 siblings, 1 reply; 26+ messages in thread
From: Peter Maydell @ 2015-11-05 14:00 UTC (permalink / raw)
  To: Paolo Bonzini; +Cc: QEMU Developers

On 5 November 2015 at 12:13, Paolo Bonzini <pbonzini@redhat.com> wrote:
> The following changes since commit 6c5f30cad290c745f910481d0e890b3f4fad1f00:
>
>   Merge remote-tracking branch 'remotes/juanquintela/tags/migration/20151104' into staging (2015-11-05 10:10:57 +0000)
>
> are available in the git repository at:
>
>
>   git://github.com/bonzini/qemu.git tags/for-upstream-replay
>
> for you to fetch changes up to 88dcb341cd6163a47346de83d4206591da6a9959:
>
>   replay: recording of the user input (2015-11-05 12:40:48 +0100)
>
> ----------------------------------------------------------------
> So here it is, let's see what happens.

Hi. This got through most of the merge tests, but running linux-user
tests failed:

/home/petmay01/linaro/qemu-for-merges/build/all-linux-static/i386-linux-user/qemu-i386
-L ./gnemul/qemu-i386 i386/ls -l dummyfile
qemu-i386: /home/petmay01/linaro/qemu-for-merges/translate-all.c:146:
tb_unlock: Assertion `have_tb_lock' failed.

Seems to assert the first time we call tb_unlock(). Here's a backtrace:
Program received signal SIGABRT, Aborted.
0x00000000601fa5d9 in raise ()
(gdb) bt
#0  0x00000000601fa5d9 in raise ()
#1  0x000000006019a608 in abort ()
#2  0x0000000060194584 in __assert_fail_base ()
#3  0x00000000601945de in __assert_fail ()
#4  0x0000000060003d5b in tb_unlock () at
/home/petmay01/linaro/qemu-for-merges/translate-all.c:146
#5  0x00000000600073fa in tb_find_slow (cpu=0x62605710, pc=4135504272,
cs_base=0, flags=4194483)
    at /home/petmay01/linaro/qemu-for-merges/cpu-exec.c:279
#6  0x0000000060007581 in tb_find_fast (cpu=0x62605710) at
/home/petmay01/linaro/qemu-for-merges/cpu-exec.c:316
#7  0x0000000060007868 in cpu_x86_exec (cpu=0x62605710) at
/home/petmay01/linaro/qemu-for-merges/cpu-exec.c:423
#8  0x00000000600372b6 in cpu_loop (env=0x6260d990) at
/home/petmay01/linaro/qemu-for-merges/linux-user/main.c:281
#9  0x0000000060039370 in main (argc=6, argv=0x7fffffffe438,
envp=0x7fffffffe470)
    at /home/petmay01/linaro/qemu-for-merges/linux-user/main.c:4666

thanks
-- PMM

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [Qemu-devel] [PULL 00/18] Record/replay core for 2.5-rc1
  2015-11-05 14:00 ` [Qemu-devel] [PULL 00/18] Record/replay core for 2.5-rc1 Peter Maydell
@ 2015-11-05 14:07   ` Paolo Bonzini
  2015-11-06  5:10     ` Pavel Dovgaluk
  0 siblings, 1 reply; 26+ messages in thread
From: Paolo Bonzini @ 2015-11-05 14:07 UTC (permalink / raw)
  To: Peter Maydell; +Cc: QEMU Developers, Pavel Dovgalyuk

On 05/11/2015 15:00, Peter Maydell wrote:
> On 5 November 2015 at 12:13, Paolo Bonzini <pbonzini@redhat.com> wrote:
>> The following changes since commit 6c5f30cad290c745f910481d0e890b3f4fad1f00:
>>
>>   Merge remote-tracking branch 'remotes/juanquintela/tags/migration/20151104' into staging (2015-11-05 10:10:57 +0000)
>>
>> are available in the git repository at:
>>
>>
>>   git://github.com/bonzini/qemu.git tags/for-upstream-replay
>>
>> for you to fetch changes up to 88dcb341cd6163a47346de83d4206591da6a9959:
>>
>>   replay: recording of the user input (2015-11-05 12:40:48 +0100)
>>
>> ----------------------------------------------------------------
>> So here it is, let's see what happens.
> 
> Hi. This got through most of the merge tests, but running linux-user
> tests failed:
> 
> /home/petmay01/linaro/qemu-for-merges/build/all-linux-static/i386-linux-user/qemu-i386
> -L ./gnemul/qemu-i386 i386/ls -l dummyfile
> qemu-i386: /home/petmay01/linaro/qemu-for-merges/translate-all.c:146:
> tb_unlock: Assertion `have_tb_lock' failed.
> 
> Seems to assert the first time we call tb_unlock(). Here's a backtrace:
> Program received signal SIGABRT, Aborted.
> 0x00000000601fa5d9 in raise ()
> (gdb) bt
> #0  0x00000000601fa5d9 in raise ()
> #1  0x000000006019a608 in abort ()
> #2  0x0000000060194584 in __assert_fail_base ()
> #3  0x00000000601945de in __assert_fail ()
> #4  0x0000000060003d5b in tb_unlock () at
> /home/petmay01/linaro/qemu-for-merges/translate-all.c:146
> #5  0x00000000600073fa in tb_find_slow (cpu=0x62605710, pc=4135504272,
> cs_base=0, flags=4194483)
>     at /home/petmay01/linaro/qemu-for-merges/cpu-exec.c:279
> #6  0x0000000060007581 in tb_find_fast (cpu=0x62605710) at
> /home/petmay01/linaro/qemu-for-merges/cpu-exec.c:316
> #7  0x0000000060007868 in cpu_x86_exec (cpu=0x62605710) at
> /home/petmay01/linaro/qemu-for-merges/cpu-exec.c:423
> #8  0x00000000600372b6 in cpu_loop (env=0x6260d990) at
> /home/petmay01/linaro/qemu-for-merges/linux-user/main.c:281
> #9  0x0000000060039370 in main (argc=6, argv=0x7fffffffe438,
> envp=0x7fffffffe470)
>     at /home/petmay01/linaro/qemu-for-merges/linux-user/main.c:4666
> 
> thanks
> -- PMM
> 

Pavel, can you look at it?  I'll take care of squashing the change.

You can get the tree I sent to Peter from github.

Paolo

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [Qemu-devel] [PULL 00/18] Record/replay core for 2.5-rc1
  2015-11-05 14:07   ` Paolo Bonzini
@ 2015-11-06  5:10     ` Pavel Dovgaluk
  0 siblings, 0 replies; 26+ messages in thread
From: Pavel Dovgaluk @ 2015-11-06  5:10 UTC (permalink / raw)
  To: 'Paolo Bonzini', 'Peter Maydell'
  Cc: 'QEMU Developers'

> From: Paolo Bonzini [mailto:pbonzini@redhat.com]
> On 05/11/2015 15:00, Peter Maydell wrote:
> > On 5 November 2015 at 12:13, Paolo Bonzini <pbonzini@redhat.com> wrote:
> >> The following changes since commit 6c5f30cad290c745f910481d0e890b3f4fad1f00:
> >>
> >>   Merge remote-tracking branch 'remotes/juanquintela/tags/migration/20151104' into staging
> (2015-11-05 10:10:57 +0000)
> >>
> >> are available in the git repository at:
> >>
> >>
> >>   git://github.com/bonzini/qemu.git tags/for-upstream-replay
> >>
> >> for you to fetch changes up to 88dcb341cd6163a47346de83d4206591da6a9959:
> >>
> >>   replay: recording of the user input (2015-11-05 12:40:48 +0100)
> >>
> >> ----------------------------------------------------------------
> >> So here it is, let's see what happens.
> >
> > Hi. This got through most of the merge tests, but running linux-user
> > tests failed:

Thanks for the report!

> > /home/petmay01/linaro/qemu-for-merges/build/all-linux-static/i386-linux-user/qemu-i386
> > -L ./gnemul/qemu-i386 i386/ls -l dummyfile
> > qemu-i386: /home/petmay01/linaro/qemu-for-merges/translate-all.c:146:
> > tb_unlock: Assertion `have_tb_lock' failed.
> >
> > Seems to assert the first time we call tb_unlock(). Here's a backtrace:
> > Program received signal SIGABRT, Aborted.
> > 0x00000000601fa5d9 in raise ()
> > (gdb) bt
> > #0  0x00000000601fa5d9 in raise ()
> > #1  0x000000006019a608 in abort ()
> > #2  0x0000000060194584 in __assert_fail_base ()
> > #3  0x00000000601945de in __assert_fail ()
> > #4  0x0000000060003d5b in tb_unlock () at
> > /home/petmay01/linaro/qemu-for-merges/translate-all.c:146
> > #5  0x00000000600073fa in tb_find_slow (cpu=0x62605710, pc=4135504272,
> > cs_base=0, flags=4194483)
> >     at /home/petmay01/linaro/qemu-for-merges/cpu-exec.c:279
> > #6  0x0000000060007581 in tb_find_fast (cpu=0x62605710) at
> > /home/petmay01/linaro/qemu-for-merges/cpu-exec.c:316
> > #7  0x0000000060007868 in cpu_x86_exec (cpu=0x62605710) at
> > /home/petmay01/linaro/qemu-for-merges/cpu-exec.c:423
> > #8  0x00000000600372b6 in cpu_loop (env=0x6260d990) at
> > /home/petmay01/linaro/qemu-for-merges/linux-user/main.c:281
> > #9  0x0000000060039370 in main (argc=6, argv=0x7fffffffe438,
> > envp=0x7fffffffe470)
> >     at /home/petmay01/linaro/qemu-for-merges/linux-user/main.c:4666
> >
> > thanks
> > -- PMM
> >
> 
> Pavel, can you look at it?  I'll take care of squashing the change.

Here is the patch:

diff --git a/replay/replay-user.c b/replay/replay-user.c
index eeaa41d..7d4f9fb 100755
--- a/replay/replay-user.c
+++ b/replay/replay-user.c
@@ -18,7 +18,7 @@ bool replay_exception(void)
 
 bool replay_has_exception(void)
 {
-    return true;
+    return false;
 }
 
 bool replay_interrupt(void)
@@ -28,7 +28,7 @@ bool replay_interrupt(void)
 
 bool replay_has_interrupt(void)
 {
-    return true;
+    return false;
 }

Pavel Dovgalyuk

^ permalink raw reply related	[flat|nested] 26+ messages in thread

* Re: [Qemu-devel] [PULL 02/18] replay: internal functions for replay log
  2015-11-05 12:13 ` [Qemu-devel] [PULL 02/18] replay: internal functions for replay log Paolo Bonzini
@ 2018-05-11  9:27   ` Peter Maydell
  2018-05-11  9:51     ` Paolo Bonzini
  0 siblings, 1 reply; 26+ messages in thread
From: Peter Maydell @ 2018-05-11  9:27 UTC (permalink / raw)
  To: Paolo Bonzini; +Cc: QEMU Developers, Pavel Dovgalyuk

On 5 November 2015 at 12:13, Paolo Bonzini <pbonzini@redhat.com> wrote:
> From: Pavel Dovgalyuk <Pavel.Dovgaluk@ispras.ru>
>
> This patch adds functions to perform read and write operations
> with replay log.
>
> Reviewed-by: Paolo Bonzini <pbonzini@redhat.com>

> +void replay_put_byte(uint8_t byte)
> +{
> +    if (replay_file) {
> +        putc(byte, replay_file);
> +    }
> +}

> +uint8_t replay_get_byte(void)
> +{
> +    uint8_t byte = 0;
> +    if (replay_file) {
> +        byte = getc(replay_file);
> +    }
> +    return byte;
> +}

Coverity (CID 1390576) points out that this function isn't checking
the error return from getc(). That means we could incorrectly return
255 from here and then the return value from replay_get_dword would
be 0xffffffff, which is unfortunate if the place that's using
that uses it as a loop boundary.

Incidentally, is it worth adding something to our coverity model
to tell coverity that data from replay_get_byte() is not tainted?

thanks
-- PMM

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [Qemu-devel] [PULL 02/18] replay: internal functions for replay log
  2018-05-11  9:27   ` Peter Maydell
@ 2018-05-11  9:51     ` Paolo Bonzini
  2018-05-11  9:56       ` Pavel Dovgalyuk
  2018-05-14  6:34       ` Markus Armbruster
  0 siblings, 2 replies; 26+ messages in thread
From: Paolo Bonzini @ 2018-05-11  9:51 UTC (permalink / raw)
  To: Peter Maydell; +Cc: QEMU Developers, Pavel Dovgalyuk

On 11/05/2018 11:27, Peter Maydell wrote:
>> +uint8_t replay_get_byte(void)
>> +{
>> +    uint8_t byte = 0;
>> +    if (replay_file) {
>> +        byte = getc(replay_file);
>> +    }
>> +    return byte;
>> +}
> Coverity (CID 1390576) points out that this function isn't checking
> the error return from getc(). That means we could incorrectly return
> 255 from here and then the return value from replay_get_dword would
> be 0xffffffff, which is unfortunate if the place that's using
> that uses it as a loop boundary.

Thanks!  Pavel can you check it?  How is error checking done in general
for record/replay, should QEMU exit immediately?

> Incidentally, is it worth adding something to our coverity model
> to tell coverity that data from replay_get_byte() is not tainted?

Good idea.  Something like

uint8_t replay_get_byte(void)
{
     uint8_t byte;
     if (!replay_file) {
         return 0;
     }
     return byte;
}

should do.

Paolo

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [Qemu-devel] [PULL 02/18] replay: internal functions for replay log
  2018-05-11  9:51     ` Paolo Bonzini
@ 2018-05-11  9:56       ` Pavel Dovgalyuk
  2018-05-14  6:34       ` Markus Armbruster
  1 sibling, 0 replies; 26+ messages in thread
From: Pavel Dovgalyuk @ 2018-05-11  9:56 UTC (permalink / raw)
  To: 'Paolo Bonzini', 'Peter Maydell'
  Cc: 'QEMU Developers', 'Pavel Dovgalyuk'

> From: Paolo Bonzini [mailto:pbonzini@redhat.com]
> On 11/05/2018 11:27, Peter Maydell wrote:
> >> +uint8_t replay_get_byte(void)
> >> +{
> >> +    uint8_t byte = 0;
> >> +    if (replay_file) {
> >> +        byte = getc(replay_file);
> >> +    }
> >> +    return byte;
> >> +}
> > Coverity (CID 1390576) points out that this function isn't checking
> > the error return from getc(). That means we could incorrectly return
> > 255 from here and then the return value from replay_get_dword would
> > be 0xffffffff, which is unfortunate if the place that's using
> > that uses it as a loop boundary.
> 
> Thanks!  Pavel can you check it?  How is error checking done in general
> for record/replay, should QEMU exit immediately?

Yes, usually there is no sense continuing the replayed execution
in case of an io error. Therefore closing QEMU is fine.

Pavel Dovgalyuk

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [Qemu-devel] [PULL 02/18] replay: internal functions for replay log
  2018-05-11  9:51     ` Paolo Bonzini
  2018-05-11  9:56       ` Pavel Dovgalyuk
@ 2018-05-14  6:34       ` Markus Armbruster
  1 sibling, 0 replies; 26+ messages in thread
From: Markus Armbruster @ 2018-05-14  6:34 UTC (permalink / raw)
  To: Paolo Bonzini; +Cc: Peter Maydell, QEMU Developers, Pavel Dovgalyuk

Paolo Bonzini <pbonzini@redhat.com> writes:

> On 11/05/2018 11:27, Peter Maydell wrote:
>>> +uint8_t replay_get_byte(void)
>>> +{
>>> +    uint8_t byte = 0;
>>> +    if (replay_file) {
>>> +        byte = getc(replay_file);
>>> +    }
>>> +    return byte;
>>> +}
>> Coverity (CID 1390576) points out that this function isn't checking
>> the error return from getc(). That means we could incorrectly return
>> 255 from here and then the return value from replay_get_dword would
>> be 0xffffffff, which is unfortunate if the place that's using
>> that uses it as a loop boundary.
>
> Thanks!  Pavel can you check it?  How is error checking done in general
> for record/replay, should QEMU exit immediately?
>
>> Incidentally, is it worth adding something to our coverity model
>> to tell coverity that data from replay_get_byte() is not tainted?
>
> Good idea.  Something like
>
> uint8_t replay_get_byte(void)
> {
>      uint8_t byte;
>      if (!replay_file) {
>          return 0;
>      }
>      return byte;
> }
>
> should do.

Care to submit a patch?

^ permalink raw reply	[flat|nested] 26+ messages in thread

end of thread, other threads:[~2018-05-14  6:34 UTC | newest]

Thread overview: 26+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-11-05 12:13 [Qemu-devel] [PULL 00/18] Record/replay core for 2.5-rc1 Paolo Bonzini
2015-11-05 12:13 ` [Qemu-devel] [PULL 01/18] replay: global variables and function stubs Paolo Bonzini
2015-11-05 12:13 ` [Qemu-devel] [PULL 02/18] replay: internal functions for replay log Paolo Bonzini
2018-05-11  9:27   ` Peter Maydell
2018-05-11  9:51     ` Paolo Bonzini
2018-05-11  9:56       ` Pavel Dovgalyuk
2018-05-14  6:34       ` Markus Armbruster
2015-11-05 12:13 ` [Qemu-devel] [PULL 03/18] replay: introduce mutex to protect the " Paolo Bonzini
2015-11-05 12:13 ` [Qemu-devel] [PULL 04/18] replay: introduce icount event Paolo Bonzini
2015-11-05 12:13 ` [Qemu-devel] [PULL 05/18] cpu-exec: allow temporary disabling icount Paolo Bonzini
2015-11-05 12:13 ` [Qemu-devel] [PULL 06/18] cpu: replay instructions sequence Paolo Bonzini
2015-11-05 12:13 ` [Qemu-devel] [PULL 07/18] replay: interrupts and exceptions Paolo Bonzini
2015-11-05 12:13 ` [Qemu-devel] [PULL 08/18] replay: asynchronous events infrastructure Paolo Bonzini
2015-11-05 12:13 ` [Qemu-devel] [PULL 09/18] replay: recording and replaying clock ticks Paolo Bonzini
2015-11-05 12:13 ` [Qemu-devel] [PULL 10/18] replay: shutdown event Paolo Bonzini
2015-11-05 12:13 ` [Qemu-devel] [PULL 11/18] icount: improve counting for record/replay Paolo Bonzini
2015-11-05 12:13 ` [Qemu-devel] [PULL 12/18] replay: checkpoints Paolo Bonzini
2015-11-05 12:13 ` [Qemu-devel] [PULL 13/18] bottom halves: introduce bh call function Paolo Bonzini
2015-11-05 12:13 ` [Qemu-devel] [PULL 14/18] replay: ptimer Paolo Bonzini
2015-11-05 12:14 ` [Qemu-devel] [PULL 15/18] replay: initialization and deinitialization Paolo Bonzini
2015-11-05 12:14 ` [Qemu-devel] [PULL 16/18] replay: replay blockers for devices Paolo Bonzini
2015-11-05 12:14 ` [Qemu-devel] [PULL 17/18] replay: command line options Paolo Bonzini
2015-11-05 12:14 ` [Qemu-devel] [PULL 18/18] replay: recording of the user input Paolo Bonzini
2015-11-05 14:00 ` [Qemu-devel] [PULL 00/18] Record/replay core for 2.5-rc1 Peter Maydell
2015-11-05 14:07   ` Paolo Bonzini
2015-11-06  5:10     ` Pavel Dovgaluk

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.