Deterministic replay and reverse execution
Subsystems (2)
v4 cover Deterministic replay and reverse execution
This set of patches is related to the reverse execution and deterministic replay of qemu execution Our implementation of deterministic replay can be used for deterministic and reverse debugging of guest code through gdb remote interface.
Execution recording writes 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.
Reverse execution has the following features:
* Deterministically replays whole system execution and all contents of the memory, state of the hadrware devices, clocks, and screen of the VM.
* Writes execution log into the file for latter replaying for multiple times on different machines.
* Supports i386, x86_64, and ARM hardware platforms.
* Performs deterministic replay of all operations with keyboard, mouse, network adapters, audio devices, serial interfaces, and physical USB devices connected to the emulator.
* Provides support for gdb reverse debugging commands like reverse-step and reverse-continue.
* Supports auto-checkpointing for convenient reverse debugging.
Usage of the record/replay:
* First, record the execution, by adding '-record fname=replay.bin' to the command line.
* Then you can replay it for the multiple times by using another command line option: '-replay fname=replay.bin'
* Virtual machine should have at least one virtual disk, which is used to store checkpoints. If you want to enable automatic checkpointing, simply add ',period=XX' to record options, where XX is the checkpointing period in seconds.
* Using of the network adapters in record/replay mode is possible with the following command-line options:
- '-net user' (or another host adapter) in record mode
- '-net replay' in replay mode. Every host network adapter should be replaced by 'replay' when replaying the execution.
* Reverse debugging can be used through gdb remote interface. reverse-stepi and reverse-continue commands are supported. Other reverse commands should also work, because they reuse these ones.
* Monitor is extended by the following commands:
- replay_info - prints information about replay mode and current step (number of instructions executed)
- replay_break - sets "breakpoint" at the specified instructions count.
- replay_seek - rewinds (using the checkpoints, if possible) to the specified step of replay log.
Paper with short description of deterministic replay implementation:
http://www.computer.org/csdl/proceedings/csmr/2012/4666/00/4666a553-abs.html
Modifications of qemu include:
* adding missed fields of the virtual devices' states to the vmstate structures to allow deterministic saving and restoring the VM state
* adding virtual clock-based timers to vmstate structures, because virtual clock is the part of the virtual machine state
* modification of block layer to support automatic creation of the overlay files to store the changes and snapshots while recording
* disabling of system reset while loading VM state to avoid generating of interrupts by reset handlers
* adding warpers 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), input from virtual serial ports, incoming network packets, input from connected USB devices
* adding HMP/QMP commands to monitor for controlling replay execution
v4 changes:
* Updated block drivers to support new bdrv_open interface.
* Moved migration patches into separate series (as suggested by Paolo Bonzini)
* Fixed a bug in replay_break operation.
* Fixed rtl8139 migration for replay.
* Fixed 'period' parameter processing for record mode.
* Fixed bug in 'reverse-stepi' implementation.
* Fixed replay without making any snapshots (even the starting one).
* Moved core replay patches into the separate series.
* Fixed reverse step and reverse continue support.
v3 changes:
* Fixed bug with replay of the aio write operations.
* Added virtual clock based on replay icount.
* Removed duplicated saving of interrupt_request CPU field.
* Fixed some coding style issues.
* Renamed QMP commands for controlling reverse execution (as suggested by Eric Blake)
* Replay mode and submode implemented as QAPI enumerations (as suggested by Eric Blake)
* Added description and example for replay-info command (as suggested by Eric Blake)
* Added information about the current breakpoint to the output of replay-info (as suggested by Eric Blake)
* Updated version id for HPET vmstate (as suggested by Paolo Bonzini)
* Removed static fields from parallel vmstate (as suggested by Paolo Bonzini)
* New vmstate fields for mc146818rtc, pckbd, kvmapic, serial, fdc, rtl8139 moved to subsection (as suggested by Paolo Bonzini)
* Disabled textmode cursor blinking, when virtual machine is stopped (as suggested by Paolo Bonzini)
* Extracted saving of exception_index to separate patch (as suggested by Paolo Bonzini)
v2 changes:
* Patches are split to be reviewable and bisectable (as suggested by Kirill Batuzov)
* Added QMP versions of replay commands (as suggested by Eric Blake)
* Removed some optional features of replay to make patches cleaner
* Minor changes and code cleanup were made
---
Pavel Dovgalyuk (25):
acpi: accurate overflow check
mc146818rtc: add missed field to vmstate
replay: global variables and function stubs
sysemu: system functions for replay
replay: internal functions for replay log
cpu-exec: reset exception_index correctly
icount: implement icount requesting
icount: improve enable/disable ticks
replay: introduce icount event
i386: do not cross the pages boundaries in replay mode
cpu-exec: allow temporary disabling icount
replay: interrupts and exceptions
replay: asynchronous events infrastructure
cpu: replay instructions sequence
replay: recording and replaying clock ticks
replay: recording and replaying different timers
cpus: make icount warp deterministic in replay mode
replay: shutdown event
replay: checkpoints
replay: bottom halves
replay: replay aio requests
replay: thread pool
replay: initialization and deinitialization
replay: command line options
replay: recording of the user input
Makefile.target | 1 async.c | 46 +++++- block.c | 92 +++++++++++- block/block-backend.c | 30 ++++ block/qcow2.c | 4 + block/raw-posix.c | 6 + block/raw-win32.c | 4 - cpu-exec.c | 37 +++-- cpus.c | 115 +++++++++++---- dma-helpers.c | 10 + exec.c | 1 hw/acpi/core.c | 7 + hw/block/virtio-blk.c | 10 + hw/ide/ahci.c | 4 - hw/ide/atapi.c | 10 + hw/ide/core.c | 18 ++ hw/timer/arm_timer.c | 2 hw/timer/mc146818rtc.c | 11 + hw/timer/pl031.c | 10 + hw/usb/hcd-uhci.c | 2 include/block/aio.h | 18 ++ include/block/block.h | 15 ++ include/block/thread-pool.h | 4 - include/exec/exec-all.h | 8 + include/qemu-common.h | 3 include/qemu/main-loop.h | 1 include/qemu/timer.h | 27 +++ include/qom/cpu.h | 10 + include/sysemu/block-backend.h | 10 + include/sysemu/cpus.h | 1 include/sysemu/sysemu.h | 2 include/ui/input.h | 2 main-loop.c | 5 + qapi-schema.json | 32 ++++ qemu-io-cmds.c | 2 qemu-options.hx | 27 +++ qemu-timer.c | 44 ++++-- replay/Makefile.objs | 5 + replay/replay-events.c | 292 +++++++++++++++++++++++++++++++++++++ replay/replay-input.c | 108 ++++++++++++++ replay/replay-internal.c | 155 ++++++++++++++++++++ replay/replay-internal.h | 132 +++++++++++++++++ replay/replay-time.c | 191 ++++++++++++++++++++++++ replay/replay.c | 314 ++++++++++++++++++++++++++++++++++++++++ replay/replay.h | 117 +++++++++++++++ savevm.c | 25 +++ stubs/Makefile.objs | 1 stubs/replay.c | 42 +++++ target-i386/cpu.h | 7 + target-i386/translate.c | 14 ++ tests/test-thread-pool.c | 7 + thread-pool.c | 49 ++++-- trace-events | 2 translate-all.c | 30 ++++ ui/input.c | 80 ++++++++-- util/iov.c | 4 + vl.c | 112 +++++++++++++- 57 files changed, 2162 insertions(+), 156 deletions(-) create mode 100755 replay/Makefile.objs create mode 100755 replay/replay-events.c create mode 100755 replay/replay-input.c create mode 100755 replay/replay-internal.c create mode 100755 replay/replay-internal.h create mode 100755 replay/replay-time.c create mode 100755 replay/replay.c create mode 100755 replay/replay.h create mode 100755 stubs/replay.c
Signature · 1 line
Pavel Dovgalyuk
RFC PATCH v4 1/25 acpi: accurate overflow check
Compare clock in ns, because acpi_pm_tmr_update uses rounded to ns value instead of ticks.
--- hw/acpi/core.c | 7 +++++-- 1 files changed, 5 insertions(+), 2 deletions(-)
hw/acpi/core.c +5 -2
@@ -376,8 +376,11 @@ static void acpi_notify_wakeup(Notifier *notifier, void *data)/* ACPI PM1a EVT */ uint16_t acpi_pm1_evt_get_sts (ACPIREGS *ar) { -int64_t d =acpi_pm_tmr_get_clock (); -if (d >= ar->tmr.overflow_time) { +/* Compare ns-clock, not PM timer ticks, because +acpi_pm_tmr_update function uses ns for setting the timer. */ +int64_t d =qemu_clock_get_ns (QEMU_CLOCK_VIRTUAL ); +if (d >=muldiv64 (ar->tmr.overflow_time, +get_ticks_per_sec (),PM_TIMER_FREQUENCY )) { ar->pm1.evt.sts |=ACPI_BITMASK_TIMER_STATUS ; }return ar->pm1.evt.sts;
Re: [Qemu-devel] [RFC PATCH v4 01/25] acpi: accurate overflow check
Quoted 17 lines · Pavel Dovgalyuk
Compare clock in ns, because
acpi_pm_tmr_updateuses rounded to ns value instead of ticks.Signed-off-by Pavel Dovgalyuk <[email protected]>--- hw/acpi/core.c | 7 +++++-- 1 files changed, 5 insertions(+), 2 deletions(-)hw/acpi/core.c +0
-0@@ -376,8 +376,11 @@ static void acpi_notify_wakeup(Notifier *notifier, void *data)/* ACPI PM1a EVT */ uint16_t acpi_pm1_evt_get_sts (ACPIREGS *ar) {
hw/acpi/core.c static void acpi_notify_wakeup(Notifier *notifier, void *data) · line 386
Quoted 10 lines
hw/acpi/core.c +5
-2-int64_t d =acpi_pm_tmr_get_clock (); -if (d >= ar->tmr.overflow_time) { +/* Compare ns-clock, not PM timer ticks, because +acpi_pm_tmr_update function uses ns for setting the timer. */ +int64_t d =qemu_clock_get_ns (QEMU_CLOCK_VIRTUAL ); +if (d >=muldiv64 (ar->tmr.overflow_time, +get_ticks_per_sec (),PM_TIMER_FREQUENCY )) { ar->pm1.evt.sts |=ACPI_BITMASK_TIMER_STATUS ; }return ar->pm1.evt.sts;
The same muldiv64 is in acpi_pm_tmr_update, it could be extracted to a separate function if you so wish.
Paolo
RFC PATCH v4 2/25 mc146818rtc: add missed field to vmstate
In reply to Pavel DovgalyukThis patch adds irq_reinject_on_ack_count field to VMState to allow correct saving/loading the state of MC146818 RTC.
--- hw/timer/mc146818rtc.c | 1 + 1 files changed, 1 insertions(+), 0 deletions(-)
hw/timer/mc146818rtc.c +1 -0
@@ -809,6 +809,7 @@ static void rtc_reset(void *opaque) s->cmos_data[RTC_REG_B ] &= ~(REG_B_PIE |REG_B_AIE |REG_B_SQWE ); s->cmos_data[RTC_REG_C ] &= ~(REG_C_UF |REG_C_IRQF |REG_C_PF |REG_C_AF ); + s->irq_reinject_on_ack_count =0 ;check_update_timer (s);qemu_irq_lower (s->irq);
Re: [Qemu-devel] [RFC PATCH v4 02/25] mc146818rtc: add missed field to vmstate
Quoted 14 lines · Pavel Dovgalyuk
This patch adds
irq_reinject_on_ack_countfield to VMState to allow correct saving/loading the state of MC146818 RTC.Signed-off-by Pavel Dovgalyuk <[email protected]>--- hw/timer/mc146818rtc.c | 1 + 1 files changed, 1 insertions(+), 0 deletions(-)hw/timer/mc146818rtc.c +0
-0
hw/timer/mc146818rtc.c static void rtc_reset(void *opaque) · line 815
Quoted 7 lines
hw/timer/mc146818rtc.c +1
-0@@ -809,6 +809,7 @@ static void rtc_reset(void *opaque) s->cmos_data[RTC_REG_B ] &= ~(REG_B_PIE |REG_B_AIE |REG_B_SQWE ); s->cmos_data[RTC_REG_C ] &= ~(REG_C_UF |REG_C_IRQF |REG_C_PF |REG_C_AF ); + s->irq_reinject_on_ack_count =0 ;check_update_timer (s);qemu_irq_lower (s->irq);
This is already set below. If you need it here, please justify it in the commit message and move up the code that already sets it.
Paolo
RFC PATCH v4 3/25 replay: global variables and function stubs
In reply to Pavel DovgalyukThis patch adds global variables, defines, functions declarations, and function stubs for deterministic VM replay used by external modules.
--- Makefile.target | 1 + qapi-schema.json | 32 ++++++++++++++++++++++++++++++++ replay/Makefile.objs | 1 + replay/replay.c | 25 +++++++++++++++++++++++++ replay/replay.h | 23 +++++++++++++++++++++++ stubs/Makefile.objs | 1 + stubs/replay.c | 8 ++++++++ 7 files changed, 91 insertions(+), 0 deletions(-) create mode 100755 replay/Makefile.objs create mode 100755 replay/replay.c create mode 100755 replay/replay.h create mode 100755 stubs/replay.c
Makefile.target +1 -0
@@ -83,6 +83,7 @@ all: $(PROGS) stap ######################################################### # cpu emulator library obj-y = exec.o translate-all.o cpu-exec.o +obj-y += replay/ obj-y += tcg/tcg.o tcg/optimize.o obj-$(CONFIG_TCG_INTERPRETER) += tci.o obj-$(CONFIG_TCG_INTERPRETER) += disas/tci.o
qapi-schema.json +32 -0
@@ -3508,3 +3508,35 @@ # Since: 2.1 ## { 'command': 'rtc-reset-reinjection' } + +## +# 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.2 +## +{ 'enum': 'ReplayMode', + 'data': [ 'none', 'record', 'play' ] } + +## +# ReplaySubmode: +# +# Submode of the replay subsystem. +# +# @unknown: used for modes different from play. +# +# @normal: normal replay mode. +# +# Since: 2.2 +## +{ 'enum': 'ReplaySubmode', + 'data': [ 'unknown', 'normal' ] }
replay/Makefile.objs new file +1 -0
@@ -0,0 +1 @@ +obj-y += replay.o
replay/replay.c new file +25 -0
@@ -0,0 +1,25 @@ +/* +* replay.c +* +* Copyright (c) 2010-2014 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 "replay.h" + +ReplayMode replay_mode =REPLAY_MODE_NONE ; +/*! Stores current submode for PLAY mode */ +ReplaySubmode play_submode =REPLAY_SUBMODE_UNKNOWN ; + +/* Suffix for the disk images filenames */ +char *replay_image_suffix; + + +ReplaySubmode replay_get_play_submode (void ) +{ +return play_submode; +}
replay/replay.h new file +23 -0
@@ -0,0 +1,23 @@ +#ifndef REPLAY_H +#define REPLAY_H + +/* +* replay.h +* +* Copyright (c) 2010-2014 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; +extern char *replay_image_suffix; + +/*! Returns replay play submode */ +ReplaySubmode replay_get_play_submode (void ); + +#endif
stubs/Makefile.objs +1 -0
@@ -27,6 +27,7 @@ stub-obj-y += notify-event.o stub-obj-y += pci-drive-hot-add.o stub-obj-$(CONFIG_SPICE) += qemu-chr-open-spice.o stub-obj-y += qtest.o +stub-obj-y += replay.o stub-obj-y += reset.o stub-obj-y += runstate-check.o stub-obj-y += set-fd-handler.o
stubs/replay.c new file +8 -0
@@ -0,0 +1,8 @@ +#include "replay/replay.h" + +ReplayMode replay_mode; + +ReplaySubmode replay_get_play_submode (void ) +{ +return 0 ; +}
Re: [Qemu-devel] [RFC PATCH v4 03/25] replay: global variables and function stubs
Quoted 5 lines · Pavel Dovgalyuk
This patch adds global variables, defines, functions declarations, and function stubs for deterministic VM replay used by external modules.
Signed-off-by Pavel Dovgalyuk <[email protected]>---
Just focusing on interface review:
Quoted 10 lines
+++
b/qapi-schema.jsonqapi-schema.json +5
-0@@ -3508,3 +3508,35 @@ # Since: 2.1 ## { 'command': 'rtc-reset-reinjection' } + +## +# ReplayMode: +# +# Mode of the replay subsystem.
qapi-schema.json line 3525
Quoted 10 lines
qapi-schema.json +10
-0+# +# @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.2
You've missed 2.2 freeze; this will have to be 2.3.
Quoted 4 lines
qapi-schema.json +4
-0+## +{ 'enum': 'ReplayMode', + 'data': [ 'none', 'record', 'play' ] } +
qapi-schema.json line 3539
Quoted 10 lines
qapi-schema.json +10
-0+## +# ReplaySubmode: +# +# Submode of the replay subsystem. +# +# @unknown: used for modes different from play. +# +# @normal: normal replay mode. +# +# Since: 2.2
Again, 2.3
Quoted 3 lines
qapi-schema.json +3
-0+## +{ 'enum': 'ReplaySubmode', + 'data': [ 'unknown', 'normal' ] }
Signature · 2 lines
Eric Blake eblake redhat com +1-919-301-3266 Libvirt virtualization library http://libvirt.org
RFC PATCH v4 4/25 sysemu: system functions for replay
In reply to Pavel DovgalyukThis patch removes "static" specifier from several qemu function to make them visible to the replay module. It also invents several system functions that will be used by replay.
--- cpus.c | 4 ++-- include/exec/exec-all.h | 1 + include/qom/cpu.h | 10 ++++++++++ include/sysemu/cpus.h | 1 + include/sysemu/sysemu.h | 1 + savevm.c | 25 ++++++++++++++++++++----- translate-all.c | 8 ++++++++ 7 files changed, 43 insertions(+), 7 deletions(-)
cpus.c +2 -2
@@ -88,7 +88,7 @@ static bool cpu_thread_is_idle(CPUState *cpu)return true; } -static bool all_cpu_threads_idle (void ) +bool all_cpu_threads_idle (void ) {CPUState *cpu;
@@ -1112,7 +1112,7 @@ bool qemu_cpu_is_self(CPUState *cpu)return qemu_thread_is_self (cpu->thread); } -static bool qemu_in_vcpu_thread (void ) +bool qemu_in_vcpu_thread (void ) {return current_cpu &&qemu_cpu_is_self (current_cpu); }
include/exec/exec-all.h +1 -0
@@ -212,6 +212,7 @@ static inline unsigned int tb_phys_hash_func(tb_page_addr_t pc)void tb_free (TranslationBlock *tb);void tb_flush (CPUArchState *env); +void tb_flush_all (void );void tb_phys_invalidate (TranslationBlock *tb,tb_page_addr_t page_addr);#if defined(USE_DIRECT_JUMP )
include/qom/cpu.h +10 -0
@@ -480,6 +480,16 @@ static inline bool cpu_has_work(CPUState *cpu)bool qemu_cpu_is_self (CPUState *cpu);/** +* qemu_in_vcpu_thread: +* +* Checks whether the caller is executing on the vCPU thread +* of the current vCPU. +* +* Returns: %true if called from vCPU's thread, %false otherwise. +*/ +bool qemu_in_vcpu_thread (void ); + +/** * qemu_cpu_kick: * @cpu: The vCPU to kick. *
include/sysemu/cpus.h +1 -0
@@ -6,6 +6,7 @@ void qemu_init_cpu_loop(void);void resume_all_vcpus (void );void pause_all_vcpus (void );void cpu_stop_current (void ); +bool all_cpu_threads_idle (void );void cpu_synchronize_all_states (void );void cpu_synchronize_all_post_reset (void );
include/sysemu/sysemu.h +1 -0
@@ -76,6 +76,7 @@ void qemu_add_machine_init_done_notifier(Notifier *notify);void do_savevm (Monitor *mon,const QDict *qdict);int load_vmstate (const char *name); +int save_vmstate (Monitor *mon,const char *name);void do_delvm (Monitor *mon,const QDict *qdict);void do_info_snapshots (Monitor *mon,const QDict *qdict);
savevm.c +20 -5
@@ -42,7 +42,7 @@#include "qemu/iov.h" #include "block/snapshot.h" #include "block/qapi.h" - +#include "replay/replay.h" #ifndef ETH_P_RARP #define ETH_P_RARP 0x8035
@@ -1039,7 +1039,7 @@ static int del_existing_snapshots(Monitor *mon, const char *name)return 0 ; } -void do_savevm (Monitor *mon,const QDict *qdict) +int save_vmstate (Monitor *mon,const char *name) {BlockDriverState *bs, *bs1;QEMUSnapshotInfo sn1, *sn = &sn1, old_sn1, *old_sn = &old_sn1;
@@ -1049,7 +1049,7 @@ void do_savevm(Monitor *mon, const QDict *qdict)uint64_t vm_state_size;qemu_timeval tv;struct tm tm; -const char *name =qdict_get_try_str (qdict,"name" ); +int success =0 ;/* Verify if there is a device that doesn't support snapshots and is writable */ bs =NULL ;
@@ -1062,14 +1062,19 @@ void do_savevm(Monitor *mon, const QDict *qdict)if (!bdrv_can_snapshot (bs)) {monitor_printf (mon,"Device '%s' is writable but does not support snapshots.\n" ,bdrv_get_device_name (bs)); -return ; +return success; } } bs =find_vmstate_bs ();if (!bs) {monitor_printf (mon,"No block device can accept snapshots\n" ); -return ; +if (replay_mode !=REPLAY_MODE_NONE ) { +fprintf (stderr, +"At least one hdd should be attached to QEMU for replay\n" ); +exit (1 ); + } +return success; } saved_vm_running =runstate_is_running ();
@@ -1118,6 +1123,7 @@ void do_savevm(Monitor *mon, const QDict *qdict)/* create the snapshots */ + success =1 ; bs1 =NULL ;while ((bs1 =bdrv_next (bs1))) {if (bdrv_can_snapshot (bs1)) {
@@ -1127,6 +1133,7 @@ void do_savevm(Monitor *mon, const QDict *qdict)if (ret <0 ) {monitor_printf (mon,"Error while creating snapshot on '%s'\n" ,bdrv_get_device_name (bs1)); + success =0 ; } } }
@@ -1135,6 +1142,14 @@ void do_savevm(Monitor *mon, const QDict *qdict)if (saved_vm_running) {vm_start (); } + +return success; +} + +void do_savevm (Monitor *mon,const QDict *qdict) +{ +const char *name =qdict_get_try_str (qdict,"name" ); +save_vmstate (mon, name); }void qmp_xen_save_devices_state (const char *filename,Error **errp)
translate-all.c +8 -0
@@ -806,6 +806,14 @@ void tb_flush(CPUArchState *env1) tcg_ctx.tb_ctx.tb_flush_count++; } +void tb_flush_all (void ) +{ +CPUState *cpu; +for (cpu = first_cpu ; cpu !=NULL ; cpu =CPU_NEXT (cpu)) { +tb_flush (cpu->env_ptr); + } +} +#ifdef DEBUG_TB_CHECK static void tb_invalidate_check (target_ulong address)
Re: [Qemu-devel] [RFC PATCH v4 04/25] sysemu: system functions for replay
Quoted 6 lines · Pavel Dovgalyuk
This patch removes "static" specifier from several qemu function to make them visible to the replay module. It also invents several system functions that will be used by replay.
Signed-off-by Pavel Dovgalyuk <[email protected]>---
<snip>
Quoted 6 lines
void
do_savevm(Monitor *mon, const QDict *qdict); intload_vmstate(const char *name);
+intsave_vmstate(Monitor *mon, const char *name);
voiddo_delvm(Monitor *mon, const QDict *qdict); voiddo_info_snapshots(Monitor *mon, const QDict *qdict);
<snip>
Quoted 22 lines
savevm.c +3
-3-void do_savevm (Monitor *mon,const QDict *qdict) +int save_vmstate (Monitor *mon,const char *name) {BlockDriverState *bs, *bs1;QEMUSnapshotInfo sn1, *sn = &sn1, old_sn1, *old_sn = &old_sn1;@@ -1049,7 +1049,7 @@ void do_savevm(Monitor *mon, const QDict *qdict)uint64_t vm_state_size;qemu_timeval tv;struct tm tm; -const char *name =qdict_get_try_str (qdict,"name" ); +int success =0 ;/* Verify if there is a device that doesn't support snapshots and is writable */ bs =NULL ;@@ -1062,14 +1062,19 @@ void do_savevm(Monitor *mon, const QDict *qdict)if (!bdrv_can_snapshot (bs)) {monitor_printf (mon,"Device '%s' is writable but does not support snapshots.\n" ,bdrv_get_device_name (bs)); -return ; +return success; }
savevm.c void do_savevm(Monitor *mon, const QDict *qdict) · line 1075
Quoted 10 lines
savevm.c +4
-1} bs =find_vmstate_bs ();if (!bs) {monitor_printf (mon,"No block device can accept snapshots\n" ); -return ; +if (replay_mode !=REPLAY_MODE_NONE ) { +fprintf (stderr, +"At least one hdd should be attached to QEMU for replay\n" ); +exit (1 );
Perhaps we should be doing a proper error_report here?
Quoted 24 lines
savevm.c +4
-0+ } +return success; } saved_vm_running =runstate_is_running ();@@ -1118,6 +1123,7 @@ void do_savevm(Monitor *mon, const QDict *qdict)/* create the snapshots */ + success =1 ; bs1 =NULL ;while ((bs1 =bdrv_next (bs1))) {if (bdrv_can_snapshot (bs1)) {@@ -1127,6 +1133,7 @@ void do_savevm(Monitor *mon, const QDict *qdict)if (ret <0 ) {monitor_printf (mon,"Error while creating snapshot on '%s'\n" ,bdrv_get_device_name (bs1)); + success =0 ; } } }@@ -1135,6 +1142,14 @@ void do_savevm(Monitor *mon, const QDict *qdict)if (saved_vm_running) {vm_start ();
savevm.c void do_savevm(Monitor *mon, const QDict *qdict) · line 1153
Quoted 10 lines
savevm.c +8
-0} + +return success; +} + +void do_savevm (Monitor *mon,const QDict *qdict) +{ +const char *name =qdict_get_try_str (qdict,"name" ); +save_vmstate (mon, name); }
You've re-factored do_savevm() and added a success/fail parameter which isn't used by the caller. A bit of documentation on what success means in this context would be useful for the function.
My personal preference is for success/fail returns is to use unambiguous bool types but we don't mandate that.
Signature · 1 line
Alex Bennée
RFC PATCH v4 5/25 replay: internal functions for replay log
In reply to Pavel DovgalyukThis patch adds functions to perform read and write operations with replay log.
--- replay/Makefile.objs | 1 replay/replay-internal.c | 141 ++++++++++++++++++++++++++++++++++++++++++++++ replay/replay-internal.h | 50 ++++++++++++++++ 3 files changed, 192 insertions(+), 0 deletions(-) create mode 100755 replay/replay-internal.c create mode 100755 replay/replay-internal.h
replay/Makefile.objs +1 -0
@@ -1 +1,2 @@ obj-y += replay.o +obj-y += replay-internal.o
replay/replay-internal.c new file +141 -0
141 lines not on this page · raw message
replay/replay-internal.h new file +50 -0
50 lines not on this page · raw message
Re: [Qemu-devel] [RFC PATCH v4 05/25] replay: internal functions for replay log
Quoted 4 lines · Pavel Dovgalyuk
This patch adds functions to perform read and write operations with replay log.
Signed-off-by Pavel Dovgalyuk <[email protected]>
<snip>
Quoted 17 lines
replay/replay-internal.c new file +17
-0+ +/* File for replay writing */ +FILE *replay_file; + +void replay_put_byte (unsigned char byte) +{ +if (replay_file) { +fwrite (&byte,sizeof (byte),1 , replay_file); + } +} + +void replay_put_event (unsigned char event) +{ +replay_put_byte (event); +} + +
<snip>
replay/replay-internal.c line 46
Quoted 6 lines
replay/replay-internal.c new file +6
-0+void replay_put_dword (unsigned int dword) +{ +if (replay_file) { +fwrite (&dword,sizeof (dword),1 , replay_file); + } +}
Given you use the unambiguous types bellow shouldn't you use uint8_t and uint32_t here to be safe?
<snip>
Quoted 19 lines
replay/replay-internal.c new file +19
-0+ +unsigned char replay_get_byte (void ) +{ +unsigned char byte; +if (replay_file) { +fread (&byte,sizeof (byte),1 , replay_file); + } +return byte; +} + +uint16_t replay_get_word (void ) +{ +uint16_t word; +if (replay_file) { +fread (&word,sizeof (word),1 , replay_file); + } + +return word; +}
replay/replay-internal.c line 90
Quoted 10 lines
replay/replay-internal.c new file +10
-0+ +unsigned int replay_get_dword (void ) +{ +unsigned int dword; +if (replay_file) { +fread (&dword,sizeof (dword),1 , replay_file); + } + +return dword; +}
Ditto for the fetchers
<snip>
Signature · 1 line
Alex Bennée
RFC PATCH v4 6/25 cpu-exec: reset exception_index correctly
In reply to Pavel DovgalyukException index is reset at every entry at every entry into cpu_exec() function. This may cause missing the exceptions while replaying them. This patch moves exception_index reset to the locations where they are processed.
--- cpu-exec.c | 2 +- cpus.c | 1 + 2 files changed, 2 insertions(+), 1 deletions(-)
cpu-exec.c +1 -1
@@ -358,7 +358,6 @@ int cpu_exec(CPUArchState *env) } cc->cpu_exec_enter (cpu); - cpu->exception_index =-1 ;/* Calculate difference between guest clock and host clock. * This delay includes the delay of the last cycle, so
@@ -378,6 +377,7 @@ int cpu_exec(CPUArchState *env)if (ret ==EXCP_DEBUG ) {cpu_handle_debug_exception (env); } + cpu->exception_index =-1 ;break ; }else {#if defined(CONFIG_USER_ONLY )
cpus.c +1 -0
@@ -1016,6 +1016,7 @@ static void *qemu_tcg_cpu_thread_fn(void *arg)CPU_FOREACH (cpu) { cpu->thread_id =qemu_get_thread_id (); cpu->created = true; + cpu->exception_index =-1 ; }qemu_cond_signal (&qemu_cpu_cond);
Re: [Qemu-devel] [RFC PATCH v4 06/25] cpu-exec: reset exception_index correctly
Quoted 37 lines · Pavel Dovgalyuk
Exception index is reset at every entry at every entry into
cpu_exec()function. This may cause missing the exceptions while replaying them. This patch movesexception_indexreset to the locations where they are processed.Signed-off-by Pavel Dovgalyuk <[email protected]>--- cpu-exec.c | 2 +- cpus.c | 1 + 2 files changed, 2 insertions(+), 1 deletions(-)cpu-exec.c +1
-1@@ -358,7 +358,6 @@ int cpu_exec(CPUArchState *env) } cc->cpu_exec_enter (cpu); - cpu->exception_index =-1 ;/* Calculate difference between guest clock and host clock. * This delay includes the delay of the last cycle, so @@ -378,6 +377,7 @@ int cpu_exec(CPUArchState *env)if (ret ==EXCP_DEBUG ) {cpu_handle_debug_exception (env); } + cpu->exception_index =-1 ;break ; }else {#if defined(CONFIG_USER_ONLY )cpus.c +0
-0
cpus.c static void *qemu_tcg_cpu_thread_fn(void *arg) · line 1022
Quoted 7 lines
cpus.c +1
-0@@ -1016,6 +1016,7 @@ static void *qemu_tcg_cpu_thread_fn(void *arg)CPU_FOREACH (cpu) { cpu->thread_id =qemu_get_thread_id (); cpu->created = true; + cpu->exception_index =-1 ; }qemu_cond_signal (&qemu_cpu_cond);
Thanks, I queued this for 2.3 already.
Paolo
Re: [Qemu-devel] [RFC PATCH v4 06/25] cpu-exec: reset exception_index correctly
In reply to Pavel DovgalyukQuoted 39 lines · Pavel Dovgalyuk
Exception index is reset at every entry at every entry into
cpu_exec()function. This may cause missing the exceptions while replaying them. This patch movesexception_indexreset to the locations where they are processed.Signed-off-by Pavel Dovgalyuk <[email protected]>--- cpu-exec.c | 2 +- cpus.c | 1 + 2 files changed, 2 insertions(+), 1 deletions(-)cpu-exec.c +1
-1@@ -358,7 +358,6 @@ int cpu_exec(CPUArchState *env) } cc->cpu_exec_enter (cpu); - cpu->exception_index =-1 ;/* Calculate difference between guest clock and host clock. * This delay includes the delay of the last cycle, so @@ -378,6 +377,7 @@ int cpu_exec(CPUArchState *env)if (ret ==EXCP_DEBUG ) {cpu_handle_debug_exception (env); } + cpu->exception_index =-1 ;break ; }else {#if defined(CONFIG_USER_ONLY )cpus.c +0
-0
cpus.c static void *qemu_tcg_cpu_thread_fn(void *arg) · line 1022
Quoted 7 lines
cpus.c +1
-0@@ -1016,6 +1016,7 @@ static void *qemu_tcg_cpu_thread_fn(void *arg)CPU_FOREACH (cpu) { cpu->thread_id =qemu_get_thread_id (); cpu->created = true; + cpu->exception_index =-1 ; }qemu_cond_signal (&qemu_cpu_cond);
What about user-mode emulation? Do you need to reset cpu->exception_index for it too?
Paolo
Re: [Qemu-devel] [RFC PATCH v4 06/25] cpu-exec: reset exception_index correctly
Quoted 43 lines
From: Paolo Bonzini [mailto:[email protected]] On Behalf Of Paolo Bonzini
Quoted 41 lines · Pavel Dovgalyuk
Exception index is reset at every entry at every entry into
cpu_exec()function. This may cause missing the exceptions while replaying them. This patch movesexception_indexreset to the locations where they are processed.Signed-off-by Pavel Dovgalyuk <[email protected]>--- cpu-exec.c | 2 +- cpus.c | 1 + 2 files changed, 2 insertions(+), 1 deletions(-)cpu-exec.c +1
-1@@ -358,7 +358,6 @@ int cpu_exec(CPUArchState *env) } cc->cpu_exec_enter (cpu); - cpu->exception_index =-1 ;/* Calculate difference between guest clock and host clock. * This delay includes the delay of the last cycle, so @@ -378,6 +377,7 @@ int cpu_exec(CPUArchState *env)if (ret ==EXCP_DEBUG ) {cpu_handle_debug_exception (env); } + cpu->exception_index =-1 ;break ; }else {#if defined(CONFIG_USER_ONLY )cpus.c +1
-0@@ -1016,6 +1016,7 @@ static void *qemu_tcg_cpu_thread_fn(void *arg)CPU_FOREACH (cpu) { cpu->thread_id =qemu_get_thread_id (); cpu->created = true; + cpu->exception_index =-1 ; }
Quoted 8 lines
cpus.c static void *qemu_tcg_cpu_thread_fn(void *arg) · line 1022
Quoted 5 lines
cpus.c +0
-0qemu_cond_signal (&qemu_cpu_cond);What about user-mode emulation? Do you need to reset
cpu->exception_indexfor it too?
Thank you, I missed that.
Pavel Dovgalyuk
RFC PATCH v4 7/25 icount: implement icount requesting
In reply to Pavel DovgalyukReplay uses number of executed instructions to determine corrent events injection moments. This patch introduces new function for querying the instructions counter.
--- cpus.c | 26 +++++++++++++++++++++++--- include/qemu/timer.h | 1 + 2 files changed, 24 insertions(+), 3 deletions(-)
cpus.c +23 -3
@@ -136,8 +136,7 @@ typedef struct TimersState {static TimersState timers_state; -/* Return the virtual CPU time, based on the instruction counter. */ -static int64_t cpu_get_icount_locked (void ) +static int64_t cpu_get_instructions_counter_locked (void ) {int64_t icount;CPUState *cpu = current_cpu;
@@ -145,10 +144,31 @@ static int64_t cpu_get_icount_locked(void) icount = timers_state.qemu_icount;if (cpu) {if (!cpu_can_do_io (cpu)) { -fprintf (stderr,"Bad clock read\n" ); +fprintf (stderr,"Bad icount read\n" ); +exit (1 ); } icount -= (cpu->icount_decr.u16.low + cpu->icount_extra); } +return icount; +} + +int64_t cpu_get_instructions_counter (void ) +{ +/* This function calls are synchnonized to timer changes, +calling cpu_get_instructions_counter_locked without lock is safe */ +int64_t icount = timers_state.qemu_icount; +CPUState *cpu = current_cpu; + +if (cpu) { + icount -= (cpu->icount_decr.u16.low + cpu->icount_extra); + } +return icount; +} + +/* Return the virtual CPU time, based on the instruction counter. */ +static int64_t cpu_get_icount_locked (void ) +{ +int64_t icount =cpu_get_instructions_counter_locked ();return timers_state.qemu_icount_bias +cpu_icount_to_ns (icount); }
include/qemu/timer.h +1 -0
@@ -743,6 +743,7 @@ static inline int64_t get_clock(void)#endif /* icount */ +int64_t cpu_get_instructions_counter (void );int64_t cpu_get_icount (void );int64_t cpu_get_clock (void );int64_t cpu_get_clock_offset (void );
Re: [Qemu-devel] [RFC PATCH v4 07/25] icount: implement icount requesting
Quoted 39 lines · Pavel Dovgalyuk
Replay uses number of executed instructions to determine corrent events injection moments. This patch introduces new function for querying the instructions counter.
Signed-off-by Pavel Dovgalyuk <[email protected]>--- cpus.c | 26 +++++++++++++++++++++++--- include/qemu/timer.h | 1 + 2 files changed, 24 insertions(+), 3 deletions(-)cpus.c +8
-3@@ -136,8 +136,7 @@ typedef struct TimersState {static TimersState timers_state; -/* Return the virtual CPU time, based on the instruction counter. */ -static int64_t cpu_get_icount_locked (void ) +static int64_t cpu_get_instructions_counter_locked (void ) {int64_t icount;CPUState *cpu = current_cpu;@@ -145,10 +144,31 @@ static int64_t cpu_get_icount_locked(void) icount = timers_state.qemu_icount;if (cpu) {if (!cpu_can_do_io (cpu)) { -fprintf (stderr,"Bad clock read\n" ); +fprintf (stderr,"Bad icount read\n" ); +exit (1 ); } icount -= (cpu->icount_decr.u16.low + cpu->icount_extra); } +return icount; +} + +int64_t cpu_get_instructions_counter (void ) +{
cpus.c static int64_t cpu_get_icount_locked(void) · line 166
Quoted 10 lines
cpus.c +10
-0+/* This function calls are synchnonized to timer changes, +calling cpu_get_instructions_counter_locked without lock is safe */ +int64_t icount = timers_state.qemu_icount; +CPUState *cpu = current_cpu; + +if (cpu) { + icount -= (cpu->icount_decr.u16.low + cpu->icount_extra); + } +return icount; +}
This is the same as Frederic's QEMU_CLOCK_ICOUNT clock, right? Any reason why one is better than the other?
Paolo
Quoted 20 lines
cpus.c +4
-0+/* Return the virtual CPU time, based on the instruction counter. */ +static int64_t cpu_get_icount_locked (void ) +{ +int64_t icount =cpu_get_instructions_counter_locked ();return timers_state.qemu_icount_bias +cpu_icount_to_ns (icount); }include/qemu/timer.h +1
-0@@ -743,6 +743,7 @@ static inline int64_t get_clock(void)#endif /* icount */ +int64_t cpu_get_instructions_counter (void );int64_t cpu_get_icount (void );int64_t cpu_get_clock (void );int64_t cpu_get_clock_offset (void );
Re: [Qemu-devel] [RFC PATCH v4 07/25] icount: implement icount requesting
Quoted 46 lines
From: Paolo Bonzini [mailto:[email protected]]
Quoted 44 lines · Pavel Dovgalyuk
Replay uses number of executed instructions to determine corrent events injection moments. This patch introduces new function for querying the instructions counter.
Signed-off-by Pavel Dovgalyuk <[email protected]>--- cpus.c | 26 +++++++++++++++++++++++--- include/qemu/timer.h | 1 + 2 files changed, 24 insertions(+), 3 deletions(-)cpus.c +13
-3@@ -136,8 +136,7 @@ typedef struct TimersState {static TimersState timers_state; -/* Return the virtual CPU time, based on the instruction counter. */ -static int64_t cpu_get_icount_locked (void ) +static int64_t cpu_get_instructions_counter_locked (void ) {int64_t icount;CPUState *cpu = current_cpu;@@ -145,10 +144,31 @@ static int64_t cpu_get_icount_locked(void) icount = timers_state.qemu_icount;if (cpu) {if (!cpu_can_do_io (cpu)) { -fprintf (stderr,"Bad clock read\n" ); +fprintf (stderr,"Bad icount read\n" ); +exit (1 ); } icount -= (cpu->icount_decr.u16.low + cpu->icount_extra); } +return icount; +} + +int64_t cpu_get_instructions_counter (void ) +{ +/* This function calls are synchnonized to timer changes, +calling cpu_get_instructions_counter_locked without lock is safe */ +int64_t icount = timers_state.qemu_icount; +CPUState *cpu = current_cpu; +
Quoted 8 lines
cpus.c static int64_t cpu_get_icount_locked(void) · line 166
Quoted 5 lines
cpus.c +5
-0+if (cpu) { + icount -= (cpu->icount_decr.u16.low + cpu->icount_extra); + } +return icount; +}This is the same as Frederic's
QEMU_CLOCK_ICOUNTclock, right? Any reason why one is better than the other?
Not really. Frederic's QEMU_CLOCK_ICOUNT is measured in nanoseconds. And this counter is measured in instructions.
Pavel Dovgalyuk
Re: [Qemu-devel] [RFC PATCH v4 07/25] icount: implement icount requesting
Quoted 53 lines · Pavel Dovgaluk
Quoted 45 lines
From: Paolo Bonzini [mailto:[email protected]]
Quoted 43 lines · Pavel Dovgalyuk
Replay uses number of executed instructions to determine corrent events injection moments. This patch introduces new function for querying the instructions counter.
Signed-off-by Pavel Dovgalyuk <[email protected]>--- cpus.c | 26 +++++++++++++++++++++++--- include/qemu/timer.h | 1 + 2 files changed, 24 insertions(+), 3 deletions(-)cpus.c +12
-3@@ -136,8 +136,7 @@ typedef struct TimersState {static TimersState timers_state; -/* Return the virtual CPU time, based on the instruction counter. */ -static int64_t cpu_get_icount_locked (void ) +static int64_t cpu_get_instructions_counter_locked (void ) {int64_t icount;CPUState *cpu = current_cpu;@@ -145,10 +144,31 @@ static int64_t cpu_get_icount_locked(void) icount = timers_state.qemu_icount;if (cpu) {if (!cpu_can_do_io (cpu)) { -fprintf (stderr,"Bad clock read\n" ); +fprintf (stderr,"Bad icount read\n" ); +exit (1 ); } icount -= (cpu->icount_decr.u16.low + cpu->icount_extra); } +return icount; +} + +int64_t cpu_get_instructions_counter (void ) +{ +/* This function calls are synchnonized to timer changes, +calling cpu_get_instructions_counter_locked without lock is safe */ +int64_t icount = timers_state.qemu_icount; +CPUState *cpu = current_cpu;Quoted 8 lines
cpus.c static int64_t cpu_get_icount_locked(void) · line 166
Quoted 6 lines
cpus.c +6
-0+ +if (cpu) { + icount -= (cpu->icount_decr.u16.low + cpu->icount_extra); + } +return icount; +}This is the same as Frederic's
QEMU_CLOCK_ICOUNTclock, right? Any reason why one is better than the other?
Quoted 5 lines
Not really. Frederic's
QEMU_CLOCK_ICOUNTis measured in nanoseconds. And this counter is measured in instructions.Pavel Dovgalyuk
So you transformed your implementation to use icount? I didn't saw that in the cover letter.
I guess you replay event's according to the current instruction? I implemented icount clock with the QEMUTimer API so a callback can be notified during the replay at the right instruction.
By the way do you have a git tree somewhere where I can get the patches?
Fred
Re: [Qemu-devel] [RFC PATCH v4 07/25] icount: implement icount requesting
Quoted 55 lines
From: Frederic Konrad [mailto:[email protected]]
Quoted 53 lines · Pavel Dovgaluk
Quoted 53 lines
From: Paolo Bonzini [mailto:[email protected]]
Quoted 39 lines · Pavel Dovgalyuk
Replay uses number of executed instructions to determine corrent events injection moments. This patch introduces new function for querying the instructions counter.
Signed-off-by Pavel Dovgalyuk <[email protected]>--- cpus.c | 26 +++++++++++++++++++++++--- include/qemu/timer.h | 1 + 2 files changed, 24 insertions(+), 3 deletions(-)cpus.c +8
-3@@ -136,8 +136,7 @@ typedef struct TimersState {static TimersState timers_state; -/* Return the virtual CPU time, based on the instruction counter. */ -static int64_t cpu_get_icount_locked (void ) +static int64_t cpu_get_instructions_counter_locked (void ) {int64_t icount;CPUState *cpu = current_cpu;@@ -145,10 +144,31 @@ static int64_t cpu_get_icount_locked(void) icount = timers_state.qemu_icount;if (cpu) {if (!cpu_can_do_io (cpu)) { -fprintf (stderr,"Bad clock read\n" ); +fprintf (stderr,"Bad icount read\n" ); +exit (1 ); } icount -= (cpu->icount_decr.u16.low + cpu->icount_extra); } +return icount; +} + +int64_t cpu_get_instructions_counter (void ) +{cpus.c static int64_t cpu_get_icount_locked(void) · line 166
Quoted 10 lines
cpus.c +10
-0+/* This function calls are synchnonized to timer changes, +calling cpu_get_instructions_counter_locked without lock is safe */ +int64_t icount = timers_state.qemu_icount; +CPUState *cpu = current_cpu; + +if (cpu) { + icount -= (cpu->icount_decr.u16.low + cpu->icount_extra); + } +return icount; +}This is the same as Frederic's
QEMU_CLOCK_ICOUNTclock, right? Any reason why one is better than the other?
Quoted 4 lines
Quoted 3 lines
Not really. Frederic's
QEMU_CLOCK_ICOUNTis measured in nanoseconds. And this counter is measured in instructions.So you transformed your implementation to use icount?
Right, new implementation uses icount.
Quoted 3 lines
I guess you replay event's according to the current instruction? I implemented icount clock with the QEMUTimer API so a callback can be notified during the replay at the right instruction.
We cannot use timers, because there are synchronization events
(like exceptions, interrupts, timer reads) that control the execution correctness.
Quoted 1 line
By the way do you have a git tree somewhere where I can get the patches?
No, there is no public repository. There are only the patches in the mail list.
Pavel Dovgalyuk
RFC PATCH v4 8/25 icount: improve enable/disable ticks
In reply to Pavel DovgalyukThis patch eliminates call of the cpu_get_real_ticks while enabling or disabling the virtual timer in icount mode. These calls are used for cpu_ticks_offset which is not needed in this mode.
--- cpus.c | 12 ++++++++---- 1 files changed, 8 insertions(+), 4 deletions(-)
cpus.c +8 -4
@@ -267,8 +267,10 @@ void cpu_enable_ticks(void)/* Here, the really thing protected by seqlock is cpu_clock_offset. */ seqlock_write_lock (&timers_state.vm_clock_seqlock);if (!timers_state.cpu_ticks_enabled) { - timers_state.cpu_ticks_offset -=cpu_get_real_ticks (); - timers_state.cpu_clock_offset -=get_clock (); +if (!use_icount) { + timers_state.cpu_ticks_offset -=cpu_get_real_ticks (); + timers_state.cpu_clock_offset -=get_clock (); + } timers_state.cpu_ticks_enabled =1 ; }seqlock_write_unlock (&timers_state.vm_clock_seqlock);
@@ -283,8 +285,10 @@ void cpu_disable_ticks(void)/* Here, the really thing protected by seqlock is cpu_clock_offset. */ seqlock_write_lock (&timers_state.vm_clock_seqlock);if (timers_state.cpu_ticks_enabled) { - timers_state.cpu_ticks_offset +=cpu_get_real_ticks (); - timers_state.cpu_clock_offset =cpu_get_clock_locked (); +if (!use_icount) { + timers_state.cpu_ticks_offset +=cpu_get_real_ticks (); + timers_state.cpu_clock_offset =cpu_get_clock_locked (); + } timers_state.cpu_ticks_enabled =0 ; }seqlock_write_unlock (&timers_state.vm_clock_seqlock);
Re: [Qemu-devel] [RFC PATCH v4 08/25] icount: improve enable/disable ticks
Quoted 30 lines · Pavel Dovgalyuk
This patch eliminates call of the
cpu_get_real_tickswhile enabling or disabling the virtual timer in icount mode. These calls are used forcpu_ticks_offsetwhich is not needed in this mode.Signed-off-by Pavel Dovgalyuk <[email protected]>--- cpus.c | 12 ++++++++---- 1 files changed, 8 insertions(+), 4 deletions(-)cpus.c +4
-2@@ -267,8 +267,10 @@ void cpu_enable_ticks(void)/* Here, the really thing protected by seqlock is cpu_clock_offset. */ seqlock_write_lock (&timers_state.vm_clock_seqlock);if (!timers_state.cpu_ticks_enabled) { - timers_state.cpu_ticks_offset -=cpu_get_real_ticks (); - timers_state.cpu_clock_offset -=get_clock (); +if (!use_icount) { + timers_state.cpu_ticks_offset -=cpu_get_real_ticks (); + timers_state.cpu_clock_offset -=get_clock (); + } timers_state.cpu_ticks_enabled =1 ; }seqlock_write_unlock (&timers_state.vm_clock_seqlock);@@ -283,8 +285,10 @@ void cpu_disable_ticks(void)/* Here, the really thing protected by seqlock is cpu_clock_offset. */ seqlock_write_lock (&timers_state.vm_clock_seqlock);
cpus.c void cpu_disable_ticks(void) · line 294
Quoted 10 lines
cpus.c +4
-2if (timers_state.cpu_ticks_enabled) { - timers_state.cpu_ticks_offset +=cpu_get_real_ticks (); - timers_state.cpu_clock_offset =cpu_get_clock_locked (); +if (!use_icount) { + timers_state.cpu_ticks_offset +=cpu_get_real_ticks (); + timers_state.cpu_clock_offset =cpu_get_clock_locked (); + } timers_state.cpu_ticks_enabled =0 ; }seqlock_write_unlock (&timers_state.vm_clock_seqlock);
RFC PATCH v4 9/25 replay: introduce icount event
In reply to Pavel DovgalyukThis 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.
--- replay/replay-internal.c | 14 ++++++++++++++ replay/replay-internal.h | 18 ++++++++++++++++++ replay/replay.c | 45 +++++++++++++++++++++++++++++++++++++++++++++ replay/replay.h | 7 +++++++ 4 files changed, 84 insertions(+), 0 deletions(-)
replay/replay-internal.c +14 -0
@@ -10,6 +10,7 @@*/ #include "qemu-common.h" +#include "replay.h" #include "replay-internal.h" volatile unsigned int replay_data_kind =-1 ;
@@ -139,3 +140,16 @@ void replay_fetch_data_kind(void) } } } + +/*! Saves cached instructions. */ +void replay_save_instructions (void ) +{ +if (replay_file && replay_mode ==REPLAY_MODE_RECORD ) { +int diff = (int )(replay_get_current_step () - replay_state.current_step); +if (first_cpu !=NULL && diff >0 ) { +replay_put_event (EVENT_INSTRUCTION ); +replay_put_dword (diff); + replay_state.current_step += diff; + } + } +}
replay/replay-internal.h +18 -0
@@ -14,6 +14,17 @@#include <stdio.h> +/* for instruction event */ +#define EVENT_INSTRUCTION 32 + +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 volatile unsigned int replay_data_kind;extern volatile unsigned int replay_has_unread_data;
@@ -47,4 +58,11 @@ void replay_save_instructions(void);Terminates the program in case of error. */ void validate_data_kind (int kind); +/*! Skips async events until some sync event will be found. */ +bool skip_async_events (int stop_event); +/*! Skips async events invocations from the input, +until required data kind is found. If the requested data is not found +reports an error and stops the execution. */ +void skip_async_events_until (unsigned int kind); +#endif
replay/replay.c +45 -0
60 lines not on this page · raw message
replay/replay.h +7 -0
@@ -12,6 +12,8 @@* */ +#include <stdbool.h> +#include <stdint.h> #include "qapi-types.h" extern ReplayMode replay_mode;
@@ -20,4 +22,9 @@ extern char *replay_image_suffix;/*! Returns replay play submode */ ReplaySubmode replay_get_play_submode (void ); +/* Processing the instructions */ + +/*! Returns number of executed instructions. */ +uint64_t replay_get_current_step (void ); +#endif
RFC PATCH v4 10/25 i386: do not cross the pages boundaries in replay mode
In reply to Pavel DovgalyukThis patch denies crossing the boundary of the pages in the replay mode, because it can cause an exception. Do it only when boundary is crossed by the first instruction in the block.
If current instruction already crossed the bound - it's ok, because an exception hasn't stopped this code.
--- target-i386/cpu.h | 7 +++++++ target-i386/translate.c | 14 ++++++++++++++ 2 files changed, 21 insertions(+), 0 deletions(-)
target-i386/cpu.h +7 -0
@@ -28,6 +28,13 @@#define TARGET_LONG_BITS 32#endif +/* Maximum instruction code size */ +#ifdef TARGET_X86_64 +#define TARGET_MAX_INSN_SIZE 16 +#else +#define TARGET_MAX_INSN_SIZE 16 +#endif +/* target supports implicit self modifying code */ #define TARGET_HAS_SMC /* support for self modifying code even if the modified instruction is
target-i386/translate.c +14 -0
@@ -8035,6 +8035,20 @@ static inline void gen_intermediate_code_internal(X86CPU *cpu,gen_eob (dc);break ; } +/* Do not cross the boundary of the pages in icount mode, +it can cause an exception. Do it only when boundary is +crossed by the first instruction in the block. +If current instruction already crossed the bound - it's ok, +because an exception hasn't stopped this code. +*/ +if (use_icount + && ((pc_ptr &TARGET_PAGE_MASK ) + != ((pc_ptr +TARGET_MAX_INSN_SIZE -1 ) &TARGET_PAGE_MASK ) + || (pc_ptr & ~TARGET_PAGE_MASK ) ==0 )) { +gen_jmp_im (pc_ptr - dc->cs_base); +gen_eob (dc); +break ; + }/* if too long translation, stop generation too */ if (tcg_ctx.gen_opc_ptr >= gen_opc_end || (pc_ptr - pc_start) >= (TARGET_PAGE_SIZE - 32) ||
Re: [Qemu-devel] [RFC PATCH v4 10/25] i386: do not cross the pages boundaries in replay mode
Quoted 46 lines · Pavel Dovgalyuk
This patch denies crossing the boundary of the pages in the replay mode, because it can cause an exception. Do it only when boundary is crossed by the first instruction in the block.
If current instruction already crossed the bound - it's ok, because an exception hasn't stopped this code.Signed-off-by Pavel Dovgalyuk <[email protected]>--- target-i386/cpu.h | 7 +++++++ target-i386/translate.c | 14 ++++++++++++++ 2 files changed, 21 insertions(+), 0 deletions(-)target-i386/cpu.h +7
-0@@ -28,6 +28,13 @@#define TARGET_LONG_BITS 32#endif +/* Maximum instruction code size */ +#ifdef TARGET_X86_64 +#define TARGET_MAX_INSN_SIZE 16 +#else +#define TARGET_MAX_INSN_SIZE 16 +#endif +/* target supports implicit self modifying code */ #define TARGET_HAS_SMC /* support for self modifying code even if the modified instruction is target-i386/translate.c +7
-0@@ -8035,6 +8035,20 @@ static inline void gen_intermediate_code_internal(X86CPU *cpu,gen_eob (dc);break ; } +/* Do not cross the boundary of the pages in icount mode, +it can cause an exception. Do it only when boundary is +crossed by the first instruction in the block. +If current instruction already crossed the bound - it's ok, +because an exception hasn't stopped this code. +*/ + if (use_icount
target-i386/translate.c static inline void gen_intermediate_code_internal(X86CPU *cpu, · line 8054
Quoted 10 lines
target-i386/translate.c +7
-0+ && ((pc_ptr & TARGET_PAGE_MASK) + != ((pc_ptr + TARGET_MAX_INSN_SIZE - 1) & TARGET_PAGE_MASK) + || (pc_ptr & ~TARGET_PAGE_MASK) == 0)) { +gen_jmp_im (pc_ptr - dc->cs_base); +gen_eob (dc); +break ; + }/* if too long translation, stop generation too */ if (tcg_ctx.gen_opc_ptr >= gen_opc_end || (pc_ptr - pc_start) >= (TARGET_PAGE_SIZE - 32) ||
Why only in icount mode? Does it have a sensible performance problem?
Paolo
Re: [Qemu-devel] [RFC PATCH v4 10/25] i386: do not cross the pages boundaries in replay mode
Quoted 52 lines
From: Paolo Bonzini [mailto:[email protected]]
Quoted 50 lines · Pavel Dovgalyuk
This patch denies crossing the boundary of the pages in the replay mode, because it can cause an exception. Do it only when boundary is crossed by the first instruction in the block.
If current instruction already crossed the bound - it's ok, because an exception hasn't stopped this code.Signed-off-by Pavel Dovgalyuk <[email protected]>--- target-i386/cpu.h | 7 +++++++ target-i386/translate.c | 14 ++++++++++++++ 2 files changed, 21 insertions(+), 0 deletions(-)target-i386/cpu.h +7
-0@@ -28,6 +28,13 @@#define TARGET_LONG_BITS 32#endif +/* Maximum instruction code size */ +#ifdef TARGET_X86_64 +#define TARGET_MAX_INSN_SIZE 16 +#else +#define TARGET_MAX_INSN_SIZE 16 +#endif +/* target supports implicit self modifying code */ #define TARGET_HAS_SMC /* support for self modifying code even if the modified instruction is target-i386/translate.c +12
-0@@ -8035,6 +8035,20 @@ static inline void gen_intermediate_code_internal(X86CPU *cpu,gen_eob (dc);break ; } +/* Do not cross the boundary of the pages in icount mode, +it can cause an exception. Do it only when boundary is +crossed by the first instruction in the block. +If current instruction already crossed the bound - it's ok, +because an exception hasn't stopped this code. +*/ +if (use_icount + && ((pc_ptr &TARGET_PAGE_MASK ) + != ((pc_ptr +TARGET_MAX_INSN_SIZE -1 ) &TARGET_PAGE_MASK ) + || (pc_ptr & ~TARGET_PAGE_MASK ) ==0 )) { +gen_jmp_im (pc_ptr - dc->cs_base); +gen_eob (dc);
Quoted 8 lines
target-i386/translate.c static inline void gen_intermediate_code_internal(X86CPU *cpu, · line 8054
Quoted 6 lines
target-i386/translate.c +2
-0+break ; + }/* if too long translation, stop generation too */ if (tcg_ctx.gen_opc_ptr >= gen_opc_end || (pc_ptr - pc_start) >= (TARGET_PAGE_SIZE - 32) ||Why only in icount mode? Does it have a sensible performance problem?
Maybe. This is the same problem, which was discussed here for ARM: http://lists.gnu.org/archive/html/qemu-devel/2014-10/msg02232.html
But I haven't figured out what I have to do with it.
Pavel Dovgalyuk
Re: [Qemu-devel] [RFC PATCH v4 10/25] i386: do not cross the pages boundaries in replay mode
In reply to Pavel DovgalyukAm 07.11.2014 um 11:32 schrieb Pavel Dovgalyuk:
Quoted 17 lines
This patch denies crossing the boundary of the pages in the replay mode, because it can cause an exception. Do it only when boundary is crossed by the first instruction in the block.
If current instruction already crossed the bound - it's ok, because an exception hasn't stopped this code.Signed-off-by Pavel Dovgalyuk <[email protected]>--- target-i386/cpu.h | 7 +++++++ target-i386/translate.c | 14 ++++++++++++++ 2 files changed, 21 insertions(+), 0 deletions(-)target-i386/cpu.h +0
-0
target-i386/cpu.h line 36
Quoted 9 lines
target-i386/cpu.h +6
-0@@ -28,6 +28,13 @@#define TARGET_LONG_BITS 32#endif +/* Maximum instruction code size */ +#ifdef TARGET_X86_64 +#define TARGET_MAX_INSN_SIZE 16 +#else +#define TARGET_MAX_INSN_SIZE 16 +#endif
Is this a spot-the-difference game? ;)
Seriously, if they're the same values, just drop the #ifdef.
target-i386/cpu.h line 40
Quoted 4 lines
target-i386/cpu.h +1
-0+/* target supports implicit self modifying code */ #define TARGET_HAS_SMC /* support for self modifying code even if the modified instruction is
[snip]
Regards,
Andreas
Signature · 2 lines
SUSE LINUX GmbH, Maxfeldstr. 5, 90409 Nürnberg, Germany GF: Jeff Hawn, Jennifer Guild, Felix Imendörffer; HRB 21284 AG Nürnberg
RFC PATCH v4 11/25 cpu-exec: allow temporary disabling icount
In reply to Pavel DovgalyukThis 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.
--- cpu-exec.c | 6 +++--- include/exec/exec-all.h | 7 ++++--- translate-all.c | 22 ++++++++++++++++++++-- 3 files changed, 27 insertions(+), 8 deletions(-)
cpu-exec.c +3 -3
@@ -198,7 +198,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 (CPUArchState *env,int max_cycles, -TranslationBlock *orig_tb) +TranslationBlock *orig_tb,bool ignore_icount) {CPUState *cpu =ENV_GET_CPU (env);TranslationBlock *tb;
@@ -214,7 +214,7 @@ static void cpu_exec_nocache(CPUArchState *env, int max_cycles,/* tb_gen_code can flush our orig_tb, invalidate it now */ tb_phys_invalidate (orig_tb,-1 ); tb =tb_gen_code (cpu, pc, cs_base, flags, - max_cycles); + max_cycles | (ignore_icount ?CF_IGNORE_ICOUNT :0 )); cpu->current_tb = tb;/* execute the generated code */ trace_exec_tb_nocache (tb, tb->pc);
@@ -516,7 +516,7 @@ int cpu_exec(CPUArchState *env) }else {if (insns_left >0 ) {/* Execute remaining instructions. */ -cpu_exec_nocache (env, insns_left, tb); +cpu_exec_nocache (env, insns_left, tb, false);align_clocks (&sc, cpu); } cpu->exception_index =EXCP_INTERRUPT ;
include/exec/exec-all.h +4 -3
@@ -142,9 +142,10 @@ struct TranslationBlock {uint64_t flags;/* flags defining in which context the code was generated */ uint16_t size;/* size of target code for this block (1 <= size <= TARGET_PAGE_SIZE) */ -uint16_t cflags;/* compile flags */ -#define CF_COUNT_MASK 0x7fff -#define CF_LAST_IO 0x8000/* Last insn may be an IO access. */ +uint32_t cflags;/* compile flags */ +#define CF_COUNT_MASK 0x7fff +#define CF_LAST_IO 0x8000/* Last insn may be an IO access. */ +#define CF_IGNORE_ICOUNT 0x10000/* Do not generate icount code */ void *tc_ptr;/* pointer to the translated code */ /* next matching tb for physical address. */
translate-all.c +20 -2
@@ -207,6 +207,7 @@ static int cpu_restore_state_from_tb(CPUState *cpu, TranslationBlock *tb,TCGContext *s = &tcg_ctx;int j;uintptr_t tc_ptr; +int old_icount = use_icount;#ifdef CONFIG_PROFILER int64_t ti;#endif
@@ -218,6 +219,10 @@ static int cpu_restore_state_from_tb(CPUState *cpu, TranslationBlock *tb,gen_intermediate_code_pc (env, tb); +if (tb->cflags &CF_IGNORE_ICOUNT ) { + use_icount =0 ; + } +if (use_icount) {/* Reset the cycle counter to the start of the block. */ cpu->icount_decr.u16.low += tb->icount;
@@ -227,8 +232,10 @@ static int cpu_restore_state_from_tb(CPUState *cpu, TranslationBlock *tb,/* find opc index corresponding to search_pc */ tc_ptr = (uintptr_t )tb->tc_ptr; -if (searched_pc < tc_ptr) +if (searched_pc < tc_ptr) { + use_icount = old_icount;return -1 ; + } s->tb_next_offset = tb->tb_next_offset;#ifdef USE_DIRECT_JUMP
@@ -240,8 +247,10 @@ static int cpu_restore_state_from_tb(CPUState *cpu, TranslationBlock *tb,#endif j =tcg_gen_code_search_pc (s, (tcg_insn_unit *)tc_ptr, searched_pc - tc_ptr); -if (j <0 ) +if (j <0 ) { + use_icount = old_icount;return -1 ; + }/* now find start of instruction before */ while (s->gen_opc_instr_start[j] ==0 ) { j--;
@@ -254,6 +263,8 @@ static int cpu_restore_state_from_tb(CPUState *cpu, TranslationBlock *tb, s->restore_time +=profile_getclock () - ti; s->restore_count++;#endif + use_icount = old_icount; +return 0 ; }
@@ -264,6 +275,8 @@ bool cpu_restore_state(CPUState *cpu, uintptr_t retaddr) tb =tb_find_pc (retaddr);if (tb) {cpu_restore_state_from_tb (cpu, tb, retaddr); +/* tb could be temporary, generated by exec nocache */ +tb_phys_invalidate (tb,-1 );return true; }return false;
@@ -1045,6 +1058,7 @@ TranslationBlock *tb_gen_code(CPUState *cpu,tb_page_addr_t phys_pc, phys_page2;target_ulong virt_page2;int code_gen_size; +int old_icount = use_icount; phys_pc =get_page_addr_code (env, pc); tb =tb_alloc (pc);
@@ -1060,9 +1074,13 @@ TranslationBlock *tb_gen_code(CPUState *cpu, tb->cs_base = cs_base; tb->flags = flags; tb->cflags = cflags; +if (cflags &CF_IGNORE_ICOUNT ) { + use_icount =0 ; + }cpu_gen_code (env, tb, &code_gen_size); tcg_ctx.code_gen_ptr = (void *)(((uintptr_t )tcg_ctx.code_gen_ptr + code_gen_size +CODE_GEN_ALIGN -1 ) & ~(CODE_GEN_ALIGN -1 )); + use_icount = old_icount;/* check next page if needed */ virt_page2 = (pc + tb->size -1 ) &TARGET_PAGE_MASK ;
Re: [Qemu-devel] [RFC PATCH v4 11/25] cpu-exec: allow temporary disabling icount
Quoted 73 lines · Pavel Dovgalyuk
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 Pavel Dovgalyuk <[email protected]>--- cpu-exec.c | 6 +++--- include/exec/exec-all.h | 7 ++++--- translate-all.c | 22 ++++++++++++++++++++-- 3 files changed, 27 insertions(+), 8 deletions(-)cpu-exec.c +3
-3@@ -198,7 +198,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 (CPUArchState *env,int max_cycles, -TranslationBlock *orig_tb) +TranslationBlock *orig_tb,bool ignore_icount) {CPUState *cpu =ENV_GET_CPU (env);TranslationBlock *tb;@@ -214,7 +214,7 @@ static void cpu_exec_nocache(CPUArchState *env, int max_cycles,/* tb_gen_code can flush our orig_tb, invalidate it now */ tb_phys_invalidate (orig_tb,-1 ); tb =tb_gen_code (cpu, pc, cs_base, flags, - max_cycles); + max_cycles | (ignore_icount ?CF_IGNORE_ICOUNT :0 )); cpu->current_tb = tb;/* execute the generated code */ trace_exec_tb_nocache (tb, tb->pc);@@ -516,7 +516,7 @@ int cpu_exec(CPUArchState *env) }else {if (insns_left >0 ) {/* Execute remaining instructions. */ -cpu_exec_nocache (env, insns_left, tb); +cpu_exec_nocache (env, insns_left, tb, false);align_clocks (&sc, cpu); } cpu->exception_index =EXCP_INTERRUPT ;include/exec/exec-all.h +4
-3@@ -142,9 +142,10 @@ struct TranslationBlock {uint64_t flags;/* flags defining in which context the code was generated */ uint16_t size;/* size of target code for this block (1 <= size <= TARGET_PAGE_SIZE) */ -uint16_t cflags;/* compile flags */ -#define CF_COUNT_MASK 0x7fff -#define CF_LAST_IO 0x8000/* Last insn may be an IO access. */ +uint32_t cflags;/* compile flags */ +#define CF_COUNT_MASK 0x7fff +#define CF_LAST_IO 0x8000/* Last insn may be an IO access. */ +#define CF_IGNORE_ICOUNT 0x10000/* Do not generate icount code */ void *tc_ptr;/* pointer to the translated code */ /* next matching tb for physical address. */ translate-all.c +1
-0@@ -207,6 +207,7 @@ static int cpu_restore_state_from_tb(CPUState *cpu, TranslationBlock *tb,TCGContext *s = &tcg_ctx;int j;uintptr_t tc_ptr; +int old_icount = use_icount;#ifdef CONFIG_PROFILER int64_t ti;#endif
translate-all.c static int cpu_restore_state_from_tb(CPUState *cpu, TranslationBlock *tb, · line 222
Quoted 4 lines
translate-all.c +1
-0@@ -218,6 +219,10 @@ static int cpu_restore_state_from_tb(CPUState *cpu, TranslationBlock *tb,gen_intermediate_code_pc (env, tb); +if (tb->cflags &CF_IGNORE_ICOUNT ) {
Would it be possible to instead have a CF_USE_ICOUNT tbflag, and check it when applicable instead of use_icount? It seems cleaner, because it would avoid playing with global variables, but perhaps it's hard to do it.
Paolo
Quoted 71 lines
translate-all.c +18
-2+ use_icount =0 ; + } +if (use_icount) {/* Reset the cycle counter to the start of the block. */ cpu->icount_decr.u16.low += tb->icount;@@ -227,8 +232,10 @@ static int cpu_restore_state_from_tb(CPUState *cpu, TranslationBlock *tb,/* find opc index corresponding to search_pc */ tc_ptr = (uintptr_t )tb->tc_ptr; -if (searched_pc < tc_ptr) +if (searched_pc < tc_ptr) { + use_icount = old_icount;return -1 ; + } s->tb_next_offset = tb->tb_next_offset;#ifdef USE_DIRECT_JUMP @@ -240,8 +247,10 @@ static int cpu_restore_state_from_tb(CPUState *cpu, TranslationBlock *tb,#endif j =tcg_gen_code_search_pc (s, (tcg_insn_unit *)tc_ptr, searched_pc - tc_ptr); -if (j <0 ) +if (j <0 ) { + use_icount = old_icount;return -1 ; + }/* now find start of instruction before */ while (s->gen_opc_instr_start[j] ==0 ) { j--;@@ -254,6 +263,8 @@ static int cpu_restore_state_from_tb(CPUState *cpu, TranslationBlock *tb, s->restore_time +=profile_getclock () - ti; s->restore_count++;#endif + use_icount = old_icount; +return 0 ; }@@ -264,6 +275,8 @@ bool cpu_restore_state(CPUState *cpu, uintptr_t retaddr) tb =tb_find_pc (retaddr);if (tb) {cpu_restore_state_from_tb (cpu, tb, retaddr); +/* tb could be temporary, generated by exec nocache */ +tb_phys_invalidate (tb,-1 );return true; }return false;@@ -1045,6 +1058,7 @@ TranslationBlock *tb_gen_code(CPUState *cpu,tb_page_addr_t phys_pc, phys_page2;target_ulong virt_page2;int code_gen_size; +int old_icount = use_icount; phys_pc =get_page_addr_code (env, pc); tb =tb_alloc (pc);@@ -1060,9 +1074,13 @@ TranslationBlock *tb_gen_code(CPUState *cpu, tb->cs_base = cs_base; tb->flags = flags; tb->cflags = cflags; +if (cflags &CF_IGNORE_ICOUNT ) { + use_icount =0 ; + }cpu_gen_code (env, tb, &code_gen_size); tcg_ctx.code_gen_ptr = (void *)(((uintptr_t )tcg_ctx.code_gen_ptr + code_gen_size +CODE_GEN_ALIGN -1 ) & ~(CODE_GEN_ALIGN -1 )); + use_icount = old_icount;/* check next page if needed */ virt_page2 = (pc + tb->size -1 ) &TARGET_PAGE_MASK ;
Re: [Qemu-devel] [RFC PATCH v4 11/25] cpu-exec: allow temporary disabling icount
Quoted 79 lines
From: Paolo Bonzini [mailto:[email protected]]
cpu-exec.c static inline tcg_target_ulong cpu_tb_exec(CPUState *cpu, uint8_t
Quoted 16 lines · Pavel Dovgalyuk
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 Pavel Dovgalyuk <[email protected]>--- cpu-exec.c | 6 +++--- include/exec/exec-all.h | 7 ++++--- translate-all.c | 22 ++++++++++++++++++++-- 3 files changed, 27 insertions(+), 8 deletions(-)cpu-exec.c +0
-0@@ -198,7 +198,7 @@ static inline tcg_target_ulong cpu_tb_exec(CPUState *cpu, uint8_t
*tb_ptr)translate-all.c static int cpu_restore_state_from_tb(CPUState *cpu, TranslationBlock
Quoted 49 lines
cpu-exec.c +3
-3/* Execute the code without caching the generated code. An interpreter could be used if available. */ static void cpu_exec_nocache (CPUArchState *env,int max_cycles, -TranslationBlock *orig_tb) +TranslationBlock *orig_tb,bool ignore_icount) {CPUState *cpu =ENV_GET_CPU (env);TranslationBlock *tb;@@ -214,7 +214,7 @@ static void cpu_exec_nocache(CPUArchState *env, int max_cycles,/* tb_gen_code can flush our orig_tb, invalidate it now */ tb_phys_invalidate (orig_tb,-1 ); tb =tb_gen_code (cpu, pc, cs_base, flags, - max_cycles); + max_cycles | (ignore_icount ?CF_IGNORE_ICOUNT :0 )); cpu->current_tb = tb;/* execute the generated code */ trace_exec_tb_nocache (tb, tb->pc);@@ -516,7 +516,7 @@ int cpu_exec(CPUArchState *env) }else {if (insns_left >0 ) {/* Execute remaining instructions. */ -cpu_exec_nocache (env, insns_left, tb); +cpu_exec_nocache (env, insns_left, tb, false);align_clocks (&sc, cpu); } cpu->exception_index =EXCP_INTERRUPT ;include/exec/exec-all.h +4
-3@@ -142,9 +142,10 @@ struct TranslationBlock {uint64_t flags;/* flags defining in which context the code was generated */ uint16_t size;/* size of target code for this block (1 <= size <= TARGET_PAGE_SIZE) */ -uint16_t cflags;/* compile flags */ -#define CF_COUNT_MASK 0x7fff -#define CF_LAST_IO 0x8000/* Last insn may be an IO access. */ +uint32_t cflags;/* compile flags */ +#define CF_COUNT_MASK 0x7fff +#define CF_LAST_IO 0x8000/* Last insn may be an IO access. */ +#define CF_IGNORE_ICOUNT 0x10000/* Do not generate icount code */ void *tc_ptr;/* pointer to the translated code */ /* next matching tb for physical address. */ translate-all.c +0
-0@@ -207,6 +207,7 @@ static int cpu_restore_state_from_tb(CPUState *cpu, TranslationBlock*tb,
translate-all.c static int cpu_restore_state_from_tb(CPUState *cpu, TranslationBlock
Quoted 8 lines
translate-all.c +1
-0TCGContext *s = &tcg_ctx;int j;uintptr_t tc_ptr; +int old_icount = use_icount;#ifdef CONFIG_PROFILER int64_t ti;#endif @@ -218,6 +219,10 @@ static int cpu_restore_state_from_tb(CPUState *cpu, TranslationBlock*tb,
Quoted 1 line
Quoted 7 lines
Quoted 3 lines
gen_intermediate_code_pc(env, tb);+ if (
tb->cflags&CF_IGNORE_ICOUNT) {Would it be possible to instead have a
CF_USE_ICOUNTtbflag, and check it when applicable instead ofuse_icount? It seems cleaner, because it would avoid playing with global variables, but perhaps it's hard to do it.
Using context-specific flag is better than using global variable like use_icount. But I could not test such changes because they will affect all of the platforms (and will be also hard to implement for i386).
Pavel Dovgalyuk
Re: [Qemu-devel] [RFC PATCH v4 11/25] cpu-exec: allow temporary disabling icount
In reply to Pavel DovgalyukReview
Quoted 3 lines · Pavel Dovgalyuk
cpu_restore_state_from_tb(cpu, tb, retaddr);(quoted diff) +2
-0+ /* tb could be temporary, generated by exec nocache */ + tb_phys_invalidate(tb, -1);
Would you need to do the same sequence as cpu_exec_nocache in this case?
cpu->current_tb = NULL;
tb_phys_invalidate(tb, -1);
tb_free(tb);In this case, perhaps something like this would be better:
cpu-exec.c +1 -1
@@ -209,7 +209,7 @@ static void cpu_exec_nocache(CPUArchState *env, 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); + max_cycles |CF_NOCACHE ); cpu->current_tb = tb;/* execute the generated code */ trace_exec_tb_nocache (tb, tb->pc);
include/exec/exec-all.h +1 -0
@@ -148,6 +148,7 @@ struct TranslationBlock {#define CF_COUNT_MASK 0x7fff#define CF_LAST_IO 0x8000/* Last insn may be an IO access. */ #define CF_LAST_IO 0x8000/* Last insn may be an IO access. */ +#define CF_NOCACHE 0x40000/* To be freed after execution */ void *tc_ptr;/* pointer to the translated code */ /* next matching tb for physical address. */
translate-all.c +6 -0
@@ -264,6 +264,12 @@ bool cpu_restore_state(CPUState *cpu, uintptr_t retaddr) tb =tb_find_pc (retaddr);if (tb) {cpu_restore_state_from_tb (cpu, tb, retaddr); +if (tb->cflags &CF_NOCACHE ) { +/* one-shot translation, invalidate it immediately */ + cpu->current_tb =NULL ; +tb_phys_invalidate (tb,-1 ); +tb_free (tb); + }return true; }return false;
I pushed it to an icount branch on my github repository, together with other patches that introduce CF_USE_ICOUNT instead of touching the use_icount global variable. Can you please take a look and, if it works, incorporate it in your patch series?
Thanks,
Paolo
Re: [Qemu-devel] [RFC PATCH v4 11/25] cpu-exec: allow temporary disabling icount
Quoted 7 lines
From: Paolo Bonzini [mailto:[email protected]] On Behalf Of Paolo Bonzini
Review
Quoted 3 lines · Pavel Dovgalyuk
cpu_restore_state_from_tb(cpu, tb, retaddr);(quoted diff) +2
-0+ /* tb could be temporary, generated by exec nocache */ + tb_phys_invalidate(tb, -1);Would you need to do the same sequence as
cpu_exec_nocachein this case?
Right.
Quoted 50 lines
cpu->current_tb = NULL; tb_phys_invalidate(tb, -1); tb_free(tb);In this case, perhaps something like this would be better:
cpu-exec.c +1
-1@@ -209,7 +209,7 @@ static void cpu_exec_nocache(CPUArchState *env, 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); + max_cycles |CF_NOCACHE ); cpu->current_tb = tb;/* execute the generated code */ trace_exec_tb_nocache (tb, tb->pc);include/exec/exec-all.h +1
-0@@ -148,6 +148,7 @@ struct TranslationBlock {#define CF_COUNT_MASK 0x7fff#define CF_LAST_IO 0x8000/* Last insn may be an IO access. */ #define CF_LAST_IO 0x8000/* Last insn may be an IO access. */ +#define CF_NOCACHE 0x40000/* To be freed after execution */ void *tc_ptr;/* pointer to the translated code */ /* next matching tb for physical address. */ translate-all.c +6
-0@@ -264,6 +264,12 @@ bool cpu_restore_state(CPUState *cpu, uintptr_t retaddr) tb =tb_find_pc (retaddr);if (tb) {cpu_restore_state_from_tb (cpu, tb, retaddr); +if (tb->cflags &CF_NOCACHE ) { +/* one-shot translation, invalidate it immediately */ + cpu->current_tb =NULL ; +tb_phys_invalidate (tb,-1 ); +tb_free (tb); + }return true; }return false;
Quoted 4 lines
I pushed it to an icount branch on my github repository, together with other patches that introduce
CF_USE_ICOUNTinstead of touching theuse_icountglobal variable. Can you please take a look and, if it works, incorporate it in your patch series?
Ok, I'll check it.
I noticed that you missed this patch in your branch: http://lists.nongnu.org/archive/html/qemu-devel/2014-10/msg04034.html
Pavel Dovgalyuk
RFC PATCH v4 12/25 replay: interrupts and exceptions
In reply to Pavel DovgalyukThis 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.
--- cpu-exec.c | 28 +++++++++++++++++++----- replay/replay-internal.h | 4 +++ replay/replay.c | 53 ++++++++++++++++++++++++++++++++++++++++++++++ replay/replay.h | 17 +++++++++++++++ 4 files changed, 96 insertions(+), 6 deletions(-)
cpu-exec.c +22 -6
@@ -24,6 +24,7 @@#include "qemu/atomic.h" #include "sysemu/qtest.h" #include "qemu/timer.h" +#include "replay/replay.h" /* -icount align implementation. */
@@ -390,10 +391,21 @@ int cpu_exec(CPUArchState *env) ret = cpu->exception_index;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 (env,1 ,tb_find_fast (env), true); +break ; } next_tb =0 ;/* force lookup of first TB */
@@ -409,21 +421,24 @@ int cpu_exec(CPUArchState *env) cpu->exception_index =EXCP_DEBUG ;cpu_loop_exit (cpu); } -if (interrupt_request &CPU_INTERRUPT_HALT ) { +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 ) { +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 ) { +if ((interrupt_request &CPU_INTERRUPT_RESET ) + &&replay_interrupt ()) {cpu_reset (cpu); }#endif
@@ -431,7 +446,8 @@ int cpu_exec(CPUArchState *env)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)) { +if (replay_interrupt () + && cc->cpu_exec_interrupt (cpu, interrupt_request)) { next_tb =0 ; }/* Don't use the cached interrupt_request value,
replay/replay-internal.h +4 -0
@@ -14,6 +14,10 @@#include <stdio.h> +/* for software interrupt */ +#define EVENT_INTERRUPT 15 +/* for emulated exceptions */ +#define EVENT_EXCEPTION 23/* for instruction event */ #define EVENT_INSTRUCTION 32
replay/replay.c +53 -0
56 lines not on this page · raw message
replay/replay.h +17 -0
@@ -27,4 +27,21 @@ ReplaySubmode replay_get_play_submode(void);/*! Returns number of executed instructions. */ uint64_t replay_get_current_step (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
RFC PATCH v4 13/25 replay: asynchronous events infrastructure
In reply to Pavel DovgalyukThis 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.
--- replay/Makefile.objs | 1 replay/replay-events.c | 217 ++++++++++++++++++++++++++++++++++++++++++++++ replay/replay-internal.h | 27 ++++++ replay/replay.h | 4 + 4 files changed, 249 insertions(+), 0 deletions(-) create mode 100755 replay/replay-events.c
replay/Makefile.objs +1 -0
@@ -1,2 +1,3 @@ obj-y += replay.o obj-y += replay-internal.o +obj-y += replay-events.o
replay/replay-events.c new file +217 -0
217 lines not on this page · raw message
replay/replay-internal.h +27 -0
@@ -18,9 +18,15 @@#define EVENT_INTERRUPT 15/* for emulated exceptions */ #define EVENT_EXCEPTION 23 +/* for async events */ +#define EVENT_ASYNC_OPT 25/* for instruction event */ #define EVENT_INSTRUCTION 32 +/* Asynchronous events IDs */ + +#define REPLAY_ASYNC_COUNT 0 + typedef struct ReplayState { /*! Current step - number of processed instructions and timer events. */ uint64_t current_step;
@@ -69,4 +75,25 @@ bool skip_async_events(int stop_event);reports an error and stops the execution. */ void skip_async_events_until (unsigned int kind); +/* 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 opt); +/*! Read events from the file into the input queue */ +void replay_read_events (int opt); +/*! Adds specified async event to the queue */ +void replay_add_event (int event_id,void *opaque); +#endif
replay/replay.h +4 -0
@@ -43,5 +43,9 @@ 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 );#endif
Re: [Qemu-devel] [RFC PATCH v4 13/25] replay: asynchronous events infrastructure
Quoted 20 lines · Pavel Dovgalyuk
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 <[email protected]>--- replay/Makefile.objs | 1 replay/replay-events.c | 217 ++++++++++++++++++++++++++++++++++++++++++++++ replay/replay-internal.h | 27 ++++++ replay/replay.h | 4 + 4 files changed, 249 insertions(+), 0 deletions(-) create mode 100755 replay/replay-events.creplay/Makefile.objs +0
-0
replay/Makefile.objs line 3
Quoted 4 lines
replay/Makefile.objs +1
-0@@ -1,2 +1,3 @@ obj-y += replay.o obj-y += replay-internal.o +obj-y += replay-events.o
Please ensure that text files always end in newline.
Signature · 2 lines
Eric Blake eblake redhat com +1-919-301-3266 Libvirt virtualization library http://libvirt.org
RFC PATCH v4 14/25 cpu: replay instructions sequence
In reply to Pavel DovgalyukThis 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.
--- cpu-exec.c | 1 + cpus.c | 28 ++++++++++++++++++---------- replay/replay.c | 18 ++++++++++++++++++ replay/replay.h | 4 ++++ 4 files changed, 41 insertions(+), 10 deletions(-)
cpu-exec.c +1 -0
@@ -537,6 +537,7 @@ int cpu_exec(CPUArchState *env) } cpu->exception_index =EXCP_INTERRUPT ; next_tb =0 ; +qemu_notify_event ();cpu_loop_exit (cpu); }break ;
cpus.c +18 -10
@@ -41,6 +41,7 @@#include "qemu/seqlock.h" #include "qapi-event.h" #include "hw/nmi.h" +#include "replay/replay.h" #ifndef _WIN32#include "qemu/compatfd.h"
@@ -1358,18 +1359,22 @@ static int tcg_cpu_exec(CPUArchState *env) + cpu->icount_extra); cpu->icount_decr.u16.low =0 ; cpu->icount_extra =0 ; - deadline =qemu_clock_deadline_ns_all (QEMU_CLOCK_VIRTUAL ); +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 ; - } +/* 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 =qemu_icount_round (deadline); + }else { + count =replay_get_instructions (); + } timers_state.qemu_icount += count; decr = (count >0xffff ) ?0xffff : count; count -= decr;
@@ -1387,6 +1392,9 @@ static int tcg_cpu_exec(CPUArchState *env) + cpu->icount_extra); cpu->icount_decr.u32 =0 ; cpu->icount_extra =0 ; +if (replay_mode ==REPLAY_MODE_PLAY ) { +replay_exec_instructions (); + } }return ret; }
replay/replay.c +18 -0
@@ -69,6 +69,24 @@ uint64_t replay_get_current_step(void)return cpu_get_instructions_counter (); } +int replay_get_instructions (void ) +{ +if (skip_async_events (EVENT_INSTRUCTION )) { +return replay_state.instructions_count; + } +return 0 ; +} + +void replay_exec_instructions (void ) +{ +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 && count !=0 ) { + replay_has_unread_data =0 ; + } +} +bool replay_exception (void ) {if (replay_mode ==REPLAY_MODE_RECORD ) {
replay/replay.h +4 -0
@@ -26,6 +26,10 @@ ReplaySubmode replay_get_play_submode(void);/*! 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_exec_instructions (void );/* Interrupts and exceptions */
RFC PATCH v4 15/25 replay: recording and replaying clock ticks
In reply to Pavel DovgalyukClock 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, rdtsc, and some other timers). 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.
--- include/qemu/timer.h | 20 ++++++++++-- qemu-timer.c | 3 +- replay/Makefile.objs | 3 +- replay/replay-internal.h | 11 ++++++ replay/replay-time.c | 79 ++++++++++++++++++++++++++++++++++++++++++++++ replay/replay.h | 21 ++++++++++++ stubs/replay.c | 9 +++++ 7 files changed, 142 insertions(+), 4 deletions(-) create mode 100755 replay/replay-time.c
include/qemu/timer.h +18 -2
@@ -4,6 +4,7 @@#include "qemu/typedefs.h" #include "qemu-common.h" #include "qemu/notify.h" +#include "replay/replay.h" /* timers */
@@ -699,8 +700,8 @@ static inline int64_t get_ticks_per_sec(void)* Low level clock functions */ -/* real time host monotonic timer */ -static inline int64_t get_clock_realtime (void ) +/* real time host monotonic timer implementation */ +static inline int64_t get_clock_realtime_impl (void ) {struct timeval tv;
@@ -708,6 +709,12 @@ static inline int64_t get_clock_realtime(void)return tv.tv_sec *1000000000LL + (tv.tv_usec *1000 ); } +/* real time host monotonic timer interface */ +static inline int64_t get_clock_realtime (void ) +{ +return REPLAY_CLOCK (REPLAY_CLOCK_HOST ,get_clock_realtime_impl ()); +} +/* Warning: don't insert tracepoints into these functions, they are also used by simpletrace backend and tracepoints would cause an infinite recursion! */
@@ -752,6 +759,8 @@ int64_t cpu_icount_to_ns(int64_t icount);/*******************************************/ /* host CPU ticks (if available) */ +#define cpu_get_real_ticks cpu_get_real_ticks_impl +#if defined(_ARCH_PPC)static inline int64_t cpu_get_real_ticks (void )
@@ -905,6 +914,13 @@ static inline int64_t cpu_get_real_ticks (void) }#endif +#undef cpu_get_real_ticks + +static inline int64_t cpu_get_real_ticks (void ) +{ +return REPLAY_CLOCK (REPLAY_CLOCK_REAL_TICKS ,cpu_get_real_ticks_impl ()); +} +#ifdef CONFIG_PROFILER static inline int64_t profile_getclock (void ) {
qemu-timer.c +2 -1
@@ -25,6 +25,7 @@#include "sysemu/sysemu.h" #include "monitor/monitor.h" #include "ui/console.h" +#include "replay/replay.h" #include "hw/hw.h"
@@ -562,7 +563,7 @@ int64_t qemu_clock_get_ns(QEMUClockType type) now =get_clock_realtime (); last = clock->last; clock->last = now; -if (now < last) { +if (now < last && replay_mode ==REPLAY_MODE_NONE ) {notifier_list_notify (&clock->reset_notifiers, &now); }return now;
replay/Makefile.objs +2 -1
@@ -1,3 +1,4 @@ obj-y += replay.o obj-y += replay-internal.o -obj-y += replay-events.o +obj-y += replay-events.o +obj-y += replay-time.o
replay/replay-internal.h +11 -0
@@ -22,12 +22,17 @@#define EVENT_ASYNC_OPT 25/* for instruction event */ #define EVENT_INSTRUCTION 32 +/* for clock read/writes */ +#define EVENT_CLOCK 64 +/* some of grteater codes are reserved for clocks */ /* Asynchronous events IDs */ #define REPLAY_ASYNC_COUNT 0 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. */
@@ -75,6 +80,12 @@ bool skip_async_events(int stop_event);reports an error and stops the execution. */ void skip_async_events_until (unsigned int kind); +/*! Reads next clock value from the file. +If clock kind read from the file is different from the parameter, +the value is not used. +If the parameter is -1, the clock value is read to the cache anyway. */ +void replay_read_next_clock (unsigned int kind); +/* Asynchronous events queue */ /*! Initializes events' processing internals */
replay/replay-time.c new file +79 -0
79 lines not on this page · raw message
replay/replay.h +21 -0
@@ -16,6 +16,14 @@#include <stdint.h> #include "qapi-types.h" +/* replay clock kinds */ +/* rdtsc */ +#define REPLAY_CLOCK_REAL_TICKS 0 +/* host_clock */ +#define REPLAY_CLOCK_HOST 1 + +#define REPLAY_CLOCK_COUNT 2 +extern ReplayMode replay_mode;extern char *replay_image_suffix;
@@ -47,6 +55,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 (unsigned int kind,int64_t clock); +/*! Read the specified clock from the log or return cached data */ +int64_t replay_read_clock (unsigned int 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 */
stubs/replay.c +9 -0
@@ -6,3 +6,12 @@ ReplaySubmode replay_get_play_submode(void) {return 0 ; } + +int64_t replay_save_clock (unsigned int kind,int64_t clock) +{ +} + +int64_t replay_read_clock (unsigned int kind) +{ +return 0 ; +}
RFC PATCH v4 16/25 replay: recording and replaying different timers
In reply to Pavel DovgalyukThis patch introduces functions for recording and replaying realtime sources, that do not use qemu-clock interface. These include return value of time() function in time_t and struct tm forms. Patch also adds warning to get_timedate function to prevent its usage in recording mode, because it may lead to non-determinism.
--- hw/timer/mc146818rtc.c | 10 ++++ hw/timer/pl031.c | 10 ++++ include/qemu-common.h | 1 replay/replay-internal.h | 4 ++ replay/replay-time.c | 112 ++++++++++++++++++++++++++++++++++++++++++++++ replay/replay.h | 8 +++ vl.c | 17 ++++++- 7 files changed, 157 insertions(+), 5 deletions(-)
hw/timer/mc146818rtc.c +9 -1
@@ -28,6 +28,7 @@#include "qapi/visitor.h" #include "qapi-event.h" #include "qmp-commands.h" +#include "replay/replay.h" #ifdef TARGET_I386 #include "hw/i386/apic.h"
@@ -703,7 +704,14 @@ static void rtc_set_date_from_host(ISADevice *dev)RTCState *s =MC146818_RTC (dev);struct tm tm; -qemu_get_timedate (&tm,0 ); +if (replay_mode ==REPLAY_MODE_RECORD ) { +qemu_get_timedate_no_warning (&tm,0 ); +replay_save_tm (&tm); + }else if (replay_mode ==REPLAY_MODE_PLAY ) { +replay_read_tm (&tm); + }else { +qemu_get_timedate_no_warning (&tm,0 ); + } s->base_rtc =mktimegm (&tm); s->last_update =qemu_clock_get_ns (rtc_clock);
hw/timer/pl031.c +9 -1
@@ -14,6 +14,7 @@#include "hw/sysbus.h" #include "qemu/timer.h" #include "sysemu/sysemu.h" +#include "replay/replay.h" //#define DEBUG_PL031
@@ -200,7 +201,14 @@ static int pl031_init(SysBusDevice *dev)sysbus_init_mmio (dev, &s->iomem);sysbus_init_irq (dev, &s->irq); -qemu_get_timedate (&tm,0 ); +if (replay_mode ==REPLAY_MODE_RECORD ) { +qemu_get_timedate_no_warning (&tm,0 ); +replay_save_tm (&tm); + }else if (replay_mode ==REPLAY_MODE_PLAY ) { +replay_read_tm (&tm); + }else { +qemu_get_timedate_no_warning (&tm,0 ); + } s->tick_offset =mktimegm (&tm) -qemu_clock_get_ns (rtc_clock) /get_ticks_per_sec ();
include/qemu-common.h +1 -0
@@ -129,6 +129,7 @@ void dump_drift_info(FILE *f, fprintf_function cpu_fprintf);int qemu_main (int argc,char **argv,char **envp);#endif +void qemu_get_timedate_no_warning (struct tm *tm,int offset);void qemu_get_timedate (struct tm *tm,int offset);int qemu_timedate_diff (struct tm *tm);
replay/replay-internal.h +4 -0
@@ -14,6 +14,10 @@#include <stdio.h> +/* for time_t event */ +#define EVENT_TIME_T 1 +/* for tm event */ +#define EVENT_TM 2/* for software interrupt */ #define EVENT_INTERRUPT 15/* for emulated exceptions */
replay/replay-time.c +112 -0
115 lines not on this page · raw message
replay/replay.h +8 -0
@@ -14,6 +14,7 @@#include <stdbool.h> #include <stdint.h> +#include <time.h> #include "qapi-types.h" /* replay clock kinds */
@@ -67,6 +68,13 @@ int64_t replay_read_clock(unsigned int kind); : replay_mode == REPLAY_MODE_RECORD \ ? replay_save_clock((clock), (value)) \ : (value)) +/*! Returns result of time() function execution in normal and record modes. +In play mode returns value read from the log. */ +time_t replay_time (void ); +/*! Saves struct tm value to the log */ +void replay_save_tm (struct tm *tm); +/*! Reads struct tm value from the log. Stops execution in case of error */ +void replay_read_tm (struct tm *tm);/* Asynchronous events queue */
vl.c +14 -3
@@ -118,6 +118,7 @@ int main(int argc, char **argv)#include "qapi/opts-visitor.h" #include "qom/object_interfaces.h" #include "qapi-event.h" +#include "replay/replay.h" #define DEFAULT_RAM_SIZE 128
@@ -767,7 +768,7 @@ void vm_start(void)/***********************************************************/ /* host time/date access */ -void qemu_get_timedate (struct tm *tm,int offset) +void qemu_get_timedate_no_warning (struct tm *tm,int offset) {time_t ti;
@@ -784,6 +785,16 @@ void qemu_get_timedate(struct tm *tm, int offset) } } +/* host time/date access with replay warning */ +void qemu_get_timedate (struct tm *tm,int offset) +{ +if (replay_mode ==REPLAY_MODE_RECORD ) { +fprintf (stderr,"REPLAY WARNING! qemu_get_timedate " +"function may lead to non-determinism\n" ); + } +qemu_get_timedate_no_warning (tm, offset); +} +int qemu_timedate_diff (struct tm *tm) {time_t seconds;
@@ -799,7 +810,7 @@ int qemu_timedate_diff(struct tm *tm)else seconds =mktimegm (tm) + rtc_date_offset; -return seconds -time (NULL ); +return seconds -replay_time (); }static void configure_rtc_date_offset (const char *startdate,int legacy)
@@ -837,7 +848,7 @@ static void configure_rtc_date_offset(const char *startdate, int legacy) "'2006-06-17T16:01:21' or '2006-06-17'\n");exit (1 ); } - rtc_date_offset =time (NULL ) - rtc_start_date; + rtc_date_offset =replay_time () - rtc_start_date; } }
RFC PATCH v4 17/25 cpus: make icount warp deterministic in replay mode
In reply to Pavel DovgalyukThis patch adds saving and replaying warping parameters in record and replay modes. These parameters affect on virtual clock values and therefore should be deterministic.
--- cpus.c | 24 +++++++++++++++++------- 1 files changed, 17 insertions(+), 7 deletions(-)
cpus.c +17 -7
@@ -370,7 +370,9 @@ static void icount_warp_rt(void *opaque)seqlock_write_lock (&timers_state.vm_clock_seqlock);if (runstate_is_running ()) { -int64_t clock =qemu_clock_get_ns (QEMU_CLOCK_REALTIME ); +int64_t clock =qemu_clock_get_ns (replay_mode ==REPLAY_MODE_NONE + ?QEMU_CLOCK_REALTIME + :QEMU_CLOCK_HOST );int64_t warp_delta; warp_delta = clock - vm_clock_warp_start;
@@ -444,7 +446,9 @@ void qemu_clock_warp(QEMUClockType type) }/* We want to use the earliest deadline from ALL vm_clocks */ - clock =qemu_clock_get_ns (QEMU_CLOCK_REALTIME ); + clock =qemu_clock_get_ns (replay_mode ==REPLAY_MODE_NONE + ?QEMU_CLOCK_REALTIME + :QEMU_CLOCK_HOST ); deadline =qemu_clock_deadline_ns_all (QEMU_CLOCK_VIRTUAL );if (deadline <0 ) {return ;
@@ -537,8 +541,10 @@ void configure_icount(QemuOpts *opts, Error **errp)return ; } icount_align_option =qemu_opt_get_bool (opts,"align" , false); - icount_warp_timer =timer_new_ns (QEMU_CLOCK_REALTIME , - icount_warp_rt,NULL ); + icount_warp_timer =timer_new_ns (replay_mode ==REPLAY_MODE_NONE + ?QEMU_CLOCK_REALTIME + :QEMU_CLOCK_HOST , + icount_warp_rt,NULL );if (strcmp (option,"auto" ) !=0 ) { errno =0 ; icount_time_shift =strtol (option, &rem_str,0 );
@@ -562,10 +568,14 @@ void configure_icount(QemuOpts *opts, Error **errp)the virtual time trigger catches emulated time passing too fast. Realtime triggers occur even when idle, so use them less frequently than VM triggers. */ - icount_rt_timer =timer_new_ms (QEMU_CLOCK_REALTIME , - icount_adjust_rt,NULL ); + icount_rt_timer =timer_new_ms (replay_mode ==REPLAY_MODE_NONE + ?QEMU_CLOCK_REALTIME + :QEMU_CLOCK_HOST , + icount_adjust_rt,NULL );timer_mod (icount_rt_timer, -qemu_clock_get_ms (QEMU_CLOCK_REALTIME ) +1000 ); +qemu_clock_get_ms (replay_mode ==REPLAY_MODE_NONE + ?QEMU_CLOCK_REALTIME + :QEMU_CLOCK_HOST ) +1000 ); icount_vm_timer =timer_new_ns (QEMU_CLOCK_VIRTUAL , icount_adjust_vm,NULL ); timer_mod(icount_vm_timer,
Re: [Qemu-devel] [RFC PATCH v4 17/25] cpus: make icount warp deterministic in replay mode
Quoted 3 lines · Pavel Dovgalyuk
This patch adds saving and replaying warping parameters in record and replay modes. These parameters affect on virtual clock values and therefore should be deterministic.
Why are QEMU_CLOCK_REALTIME timers not recorded/replayed like QEMU_CLOCK_HOST is?
Paolo
Quoted 63 lines
Signed-off-by Pavel Dovgalyuk <[email protected]>--- cpus.c | 24 +++++++++++++++++------- 1 files changed, 17 insertions(+), 7 deletions(-)cpus.c +17
-7@@ -370,7 +370,9 @@ static void icount_warp_rt(void *opaque)seqlock_write_lock (&timers_state.vm_clock_seqlock);if (runstate_is_running ()) { -int64_t clock =qemu_clock_get_ns (QEMU_CLOCK_REALTIME ); +int64_t clock =qemu_clock_get_ns (replay_mode ==REPLAY_MODE_NONE + ?QEMU_CLOCK_REALTIME + :QEMU_CLOCK_HOST );int64_t warp_delta; warp_delta = clock - vm_clock_warp_start;@@ -444,7 +446,9 @@ void qemu_clock_warp(QEMUClockType type) }/* We want to use the earliest deadline from ALL vm_clocks */ - clock =qemu_clock_get_ns (QEMU_CLOCK_REALTIME ); + clock =qemu_clock_get_ns (replay_mode ==REPLAY_MODE_NONE + ?QEMU_CLOCK_REALTIME + :QEMU_CLOCK_HOST ); deadline =qemu_clock_deadline_ns_all (QEMU_CLOCK_VIRTUAL );if (deadline <0 ) {return ;@@ -537,8 +541,10 @@ void configure_icount(QemuOpts *opts, Error **errp)return ; } icount_align_option =qemu_opt_get_bool (opts,"align" , false); - icount_warp_timer =timer_new_ns (QEMU_CLOCK_REALTIME , - icount_warp_rt,NULL ); + icount_warp_timer =timer_new_ns (replay_mode ==REPLAY_MODE_NONE + ?QEMU_CLOCK_REALTIME + :QEMU_CLOCK_HOST , + icount_warp_rt,NULL );if (strcmp (option,"auto" ) !=0 ) { errno =0 ; icount_time_shift =strtol (option, &rem_str,0 );@@ -562,10 +568,14 @@ void configure_icount(QemuOpts *opts, Error **errp)the virtual time trigger catches emulated time passing too fast. Realtime triggers occur even when idle, so use them less frequently than VM triggers. */ - icount_rt_timer =timer_new_ms (QEMU_CLOCK_REALTIME , - icount_adjust_rt,NULL ); + icount_rt_timer =timer_new_ms (replay_mode ==REPLAY_MODE_NONE + ?QEMU_CLOCK_REALTIME + :QEMU_CLOCK_HOST , + icount_adjust_rt,NULL );timer_mod (icount_rt_timer, -qemu_clock_get_ms (QEMU_CLOCK_REALTIME ) +1000 ); +qemu_clock_get_ms (replay_mode ==REPLAY_MODE_NONE + ?QEMU_CLOCK_REALTIME + :QEMU_CLOCK_HOST ) +1000 ); icount_vm_timer =timer_new_ns (QEMU_CLOCK_VIRTUAL , icount_adjust_vm,NULL ); timer_mod(icount_vm_timer,
Re: [Qemu-devel] [RFC PATCH v4 17/25] cpus: make icount warp deterministic in replay mode
Quoted 8 lines
From: Paolo Bonzini [mailto:[email protected]]
Quoted 3 lines · Pavel Dovgalyuk
This patch adds saving and replaying warping parameters in record and replay modes. These parameters affect on virtual clock values and therefore should be deterministic.
Why are
QEMU_CLOCK_REALTIMEtimers not recorded/replayed likeQEMU_CLOCK_HOSTis?
We cannot record all QEMU_CLOCK_REALTIME timers, because they are simulator-related timers, not the VM-related ones. If we'll record them then we'll have to replay simulator execution. And we want just to replay VM allowing different realtime events to be non-replayable (like screen refresh, monitor events handling, and so on).
Pavel Dovgalyuk
Quoted 64 lines
Quoted 64 lines
Signed-off-by Pavel Dovgalyuk <[email protected]>--- cpus.c | 24 +++++++++++++++++------- 1 files changed, 17 insertions(+), 7 deletions(-)cpus.c +17
-7@@ -370,7 +370,9 @@ static void icount_warp_rt(void *opaque)seqlock_write_lock (&timers_state.vm_clock_seqlock);if (runstate_is_running ()) { -int64_t clock =qemu_clock_get_ns (QEMU_CLOCK_REALTIME ); +int64_t clock =qemu_clock_get_ns (replay_mode ==REPLAY_MODE_NONE + ?QEMU_CLOCK_REALTIME + :QEMU_CLOCK_HOST );int64_t warp_delta; warp_delta = clock - vm_clock_warp_start;@@ -444,7 +446,9 @@ void qemu_clock_warp(QEMUClockType type) }/* We want to use the earliest deadline from ALL vm_clocks */ - clock =qemu_clock_get_ns (QEMU_CLOCK_REALTIME ); + clock =qemu_clock_get_ns (replay_mode ==REPLAY_MODE_NONE + ?QEMU_CLOCK_REALTIME + :QEMU_CLOCK_HOST ); deadline =qemu_clock_deadline_ns_all (QEMU_CLOCK_VIRTUAL );if (deadline <0 ) {return ;@@ -537,8 +541,10 @@ void configure_icount(QemuOpts *opts, Error **errp)return ; } icount_align_option =qemu_opt_get_bool (opts,"align" , false); - icount_warp_timer =timer_new_ns (QEMU_CLOCK_REALTIME , - icount_warp_rt,NULL ); + icount_warp_timer =timer_new_ns (replay_mode ==REPLAY_MODE_NONE + ?QEMU_CLOCK_REALTIME + :QEMU_CLOCK_HOST , + icount_warp_rt,NULL );if (strcmp (option,"auto" ) !=0 ) { errno =0 ; icount_time_shift =strtol (option, &rem_str,0 );@@ -562,10 +568,14 @@ void configure_icount(QemuOpts *opts, Error **errp)the virtual time trigger catches emulated time passing too fast. Realtime triggers occur even when idle, so use them less frequently than VM triggers. */ - icount_rt_timer =timer_new_ms (QEMU_CLOCK_REALTIME , - icount_adjust_rt,NULL ); + icount_rt_timer =timer_new_ms (replay_mode ==REPLAY_MODE_NONE + ?QEMU_CLOCK_REALTIME + :QEMU_CLOCK_HOST , + icount_adjust_rt,NULL );timer_mod (icount_rt_timer, -qemu_clock_get_ms (QEMU_CLOCK_REALTIME ) +1000 ); +qemu_clock_get_ms (replay_mode ==REPLAY_MODE_NONE + ?QEMU_CLOCK_REALTIME + :QEMU_CLOCK_HOST ) +1000 ); icount_vm_timer =timer_new_ns (QEMU_CLOCK_VIRTUAL , icount_adjust_vm,NULL ); timer_mod(icount_vm_timer,
Re: [Qemu-devel] [RFC PATCH v4 17/25] cpus: make icount warp deterministic in replay mode
Quoted 6 lines · Pavel Dovgaluk
Quoted 6 lines
From: Paolo Bonzini [mailto:[email protected]]
Quoted 3 lines · Pavel Dovgalyuk
This patch adds saving and replaying warping parameters in record and replay modes. These parameters affect on virtual clock values and therefore should be deterministic.
Quoted 7 lines
Quoted 2 lines
Why are
QEMU_CLOCK_REALTIMEtimers not recorded/replayed likeQEMU_CLOCK_HOSTis?We cannot record all
QEMU_CLOCK_REALTIMEtimers, because they are simulator-related timers, not the VM-related ones. If we'll record them then we'll have to replay simulator execution. And we want just to replay VM allowing different realtime events to be non-replayable (like screen refresh, monitor events handling, and so on).
Hmm... I think you want the icount_rt timer to use what QEMU_CLOCK_VIRTUAL does in !use_icount mode. Maybe you can add a fourth clock, QEMU_CLOCK_VIRTUAL_RT and use this one independent of the replay mode. This clock can then be traced like QEMU_CLOCK_HOST.
The problem is that QEMU_CLOCK_HOST can move backwards or forwards, sometimes by as much as 1 hour, so it's not the best match for this case.
Paolo
RFC PATCH v4 18/25 replay: shutdown event
In reply to Pavel DovgalyukThis patch records and replays simulator shutdown event.
--- include/sysemu/sysemu.h | 1 + replay/replay-internal.h | 2 ++ replay/replay.c | 11 +++++++++++ replay/replay.h | 5 +++++ vl.c | 8 +++++++- 5 files changed, 26 insertions(+), 1 deletions(-)
include/sysemu/sysemu.h +1 -0
@@ -57,6 +57,7 @@ void qemu_register_suspend_notifier(Notifier *notifier);void qemu_system_wakeup_request (WakeupReason reason);void qemu_system_wakeup_enable (WakeupReason reason,bool enabled);void qemu_register_wakeup_notifier (Notifier *notifier); +void qemu_system_shutdown_request_impl (void );void qemu_system_shutdown_request (void );void qemu_system_powerdown_request (void );void qemu_register_powerdown_notifier (Notifier *notifier);
replay/replay-internal.h +2 -0
@@ -20,6 +20,8 @@#define EVENT_TM 2/* for software interrupt */ #define EVENT_INTERRUPT 15 +/* for shutdown request */ +#define EVENT_SHUTDOWN 20/* for emulated exceptions */ #define EVENT_EXCEPTION 23/* for async events */
replay/replay.c +11 -0
@@ -43,6 +43,10 @@ bool skip_async_events(int stop_event) res = true; }switch (replay_data_kind) { +case EVENT_SHUTDOWN : + replay_has_unread_data =0 ; +qemu_system_shutdown_request_impl (); +break ;case EVENT_INSTRUCTION : replay_state.instructions_count =replay_get_dword ();return res;
@@ -139,3 +143,10 @@ bool replay_has_interrupt(void) }return false; } + +void replay_shutdown_request (void ) +{ +if (replay_mode ==REPLAY_MODE_RECORD ) { +replay_put_event (EVENT_SHUTDOWN ); + } +}
replay/replay.h +5 -0
@@ -76,6 +76,11 @@ void replay_save_tm(struct tm *tm);/*! Reads struct tm value from the log. Stops execution in case of error */ void replay_read_tm (struct tm *tm); +/* Events */ + +/*! Called when qemu shutdown is requested. */ +void replay_shutdown_request (void ); +/* Asynchronous events queue */ /*! Disables storing events in the queue */
vl.c +7 -1
@@ -1792,13 +1792,19 @@ void qemu_system_killed(int signal, pid_t pid)qemu_system_shutdown_request (); } -void qemu_system_shutdown_request (void ) +void qemu_system_shutdown_request_impl (void ) {trace_qemu_system_shutdown_request (); shutdown_requested =1 ;qemu_notify_event (); } +void qemu_system_shutdown_request (void ) +{ +replay_shutdown_request (); +qemu_system_shutdown_request_impl (); +} +static void qemu_system_powerdown (void ) {qapi_event_send_powerdown (&error_abort);
RFC PATCH v4 19/25 replay: checkpoints
In reply to Pavel DovgalyukThis patch introduces checkpoints that synchronize cpu thread and iothread. When checkpoint is met in the code all asynchronous events from the queue are executed.
--- block.c | 11 +++++++++++ cpus.c | 2 +- include/qemu/timer.h | 6 ++++-- qemu-timer.c | 41 +++++++++++++++++++++++++++++++++-------- replay/replay-internal.h | 3 +++ replay/replay.c | 28 ++++++++++++++++++++++++++++ replay/replay.h | 6 ++++++ stubs/replay.c | 11 +++++++++++ vl.c | 3 ++- 9 files changed, 99 insertions(+), 12 deletions(-)
block.c +11 -0
@@ -1919,6 +1919,11 @@ void bdrv_drain_all(void)BlockDriverState *bs;while (busy) { +if (!replay_checkpoint (8 )) { +/* Do not wait anymore, we stopped at some place in +the middle of execution during replay */ +return ; + } busy = false; QTAILQ_FOREACH(bs, &bdrv_states, device_list) {
@@ -1935,6 +1940,12 @@ void bdrv_drain_all(void) busy |= bs_busy; } } +if (replay_mode ==REPLAY_MODE_PLAY ) { +/* Skip checkpoints from the log */ +while (replay_checkpoint (8 )) { +/* Nothing */ + } + } }/* make a BlockDriverState anonymous by removing from bdrv_state and
cpus.c +1 -1
@@ -406,7 +406,7 @@ void qtest_clock_warp(int64_t dest) timers_state.qemu_icount_bias += warp;seqlock_write_unlock (&timers_state.vm_clock_seqlock); -qemu_clock_run_timers (QEMU_CLOCK_VIRTUAL ); +qemu_clock_run_timers (QEMU_CLOCK_VIRTUAL , false); clock =qemu_clock_get_ns (QEMU_CLOCK_VIRTUAL ); }qemu_clock_notify (QEMU_CLOCK_VIRTUAL );
include/qemu/timer.h +4 -2
@@ -232,13 +232,14 @@ void qemu_clock_unregister_reset_notifier(QEMUClockType type,/** * qemu_clock_run_timers: * @type: clock on which to operate +* @run_all: true, when called from qemu_clock_run_all_timers * * Run all the timers associated with the default timer list * of a clock. * * Returns: true if any timer ran. */ -bool qemu_clock_run_timers (QEMUClockType type); +bool qemu_clock_run_timers (QEMUClockType type,bool run_all);/** * qemu_clock_run_all_timers:
@@ -329,12 +330,13 @@ QEMUClockType timerlist_get_clock(QEMUTimerList *timer_list);/** * timerlist_run_timers: * @timer_list: the timer list to use +* @run_all: true, when called from qemu_clock_run_all_timers * * Call all expired timers associated with the timer list. * * Returns: true if any timer expired */ -bool timerlist_run_timers (QEMUTimerList *timer_list); +bool timerlist_run_timers (QEMUTimerList *timer_list,bool run_all);/** * timerlist_notify:
qemu-timer.c +33 -8
80 lines not on this page · raw message
replay/replay-internal.h +3 -0
@@ -32,6 +32,9 @@#define EVENT_CLOCK 64/* some of grteater codes are reserved for clocks */ +/* for checkpoint event */ +#define EVENT_CHECKPOINT 96 +/* Asynchronous events IDs */ #define REPLAY_ASYNC_COUNT 0
replay/replay.c +28 -0
@@ -150,3 +150,31 @@ void replay_shutdown_request(void)replay_put_event (EVENT_SHUTDOWN ); } } + +/* Used checkpoints: 2 3 5 6 7 8 9 */ +int replay_checkpoint (unsigned int checkpoint) +{ +replay_save_instructions (); + +if (replay_file) { +if (replay_mode ==REPLAY_MODE_PLAY ) { +if (!skip_async_events (EVENT_CHECKPOINT + checkpoint)) { +if (replay_data_kind ==EVENT_ASYNC_OPT ) { +replay_read_events (checkpoint); +replay_fetch_data_kind (); +return replay_data_kind !=EVENT_ASYNC_OPT ; + } +return 0 ; + } + replay_has_unread_data =0 ; +replay_read_events (checkpoint); +replay_fetch_data_kind (); +return replay_data_kind !=EVENT_ASYNC_OPT ; + }else if (replay_mode ==REPLAY_MODE_RECORD ) { +replay_put_event (EVENT_CHECKPOINT + checkpoint); +replay_save_events (checkpoint); + } + } + +return 1 ; +}
replay/replay.h +6 -0
@@ -80,6 +80,12 @@ void replay_read_tm(struct tm *tm);/*! 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. */ +int replay_checkpoint (unsigned int checkpoint);/* Asynchronous events queue */
stubs/replay.c +11 -0
@@ -1,4 +1,5 @@#include "replay/replay.h" +#include "sysemu/sysemu.h" ReplayMode replay_mode;
@@ -15,3 +16,13 @@ int64_t replay_read_clock(unsigned int kind) {return 0 ; } + +int replay_checkpoint (unsigned int checkpoint) +{ +return 0 ; +} + +int runstate_is_running (void ) +{ +return 0 ; +}
vl.c +2 -1
@@ -1847,7 +1847,8 @@ static bool main_loop_should_exit(void)return true; } } -if (qemu_reset_requested ()) { +if (qemu_reset_requested_get () &&replay_checkpoint (7 )) { +qemu_reset_requested ();pause_all_vcpus ();cpu_synchronize_all_states ();qemu_system_reset (VMRESET_REPORT );
RFC PATCH v4 20/25 replay: bottom halves
In reply to Pavel DovgalyukThis patch introduces bottom half event for replay queue. It saves the events into the queue and process them at the checkpoints and instructions execution.
--- async.c | 46 ++++++++++++++++++++++++++++++++++++++++------ dma-helpers.c | 4 +++- hw/ide/ahci.c | 4 +++- hw/ide/core.c | 4 +++- hw/timer/arm_timer.c | 2 +- hw/usb/hcd-uhci.c | 2 +- include/block/aio.h | 18 ++++++++++++++++++ include/qemu/main-loop.h | 1 + main-loop.c | 5 +++++ replay/replay-events.c | 16 ++++++++++++++++ replay/replay-internal.h | 3 ++- replay/replay.h | 2 ++ stubs/replay.c | 4 ++++ 13 files changed, 99 insertions(+), 12 deletions(-)
async.c +40 -6
@@ -27,6 +27,7 @@#include "block/thread-pool.h" #include "qemu/main-loop.h" #include "qemu/atomic.h" +#include "replay/replay.h" /***********************************************************/ /* bottom halves (can be seen as timers which expire ASAP) */
@@ -39,24 +40,53 @@ struct QEMUBH {bool scheduled;bool idle;bool deleted; +bool replay; +uint64_t id; };QEMUBH *aio_bh_new (AioContext *ctx,QEMUBHFunc *cb,void *opaque) { -QEMUBH *bh; +QEMUBH *bh, **last; bh =g_malloc0 (sizeof (QEMUBH )); bh->ctx = ctx; bh->cb = cb; bh->opaque = opaque;qemu_mutex_lock (&ctx->bh_lock); - bh->next = ctx->first_bh; -/* Make sure that the members are ready before putting bh into list */ -smp_wmb (); - ctx->first_bh = bh; +if (replay_mode !=REPLAY_MODE_NONE ) { +/* Slower way, but this is a queue and not a stack. +Replay will process the BH in the same order they +came into the queue. */ + last = &ctx->first_bh; +while (*last) { + last = &(*last)->next; + } +smp_wmb (); + *last = bh; + }else { + bh->next = ctx->first_bh; +/* Make sure that the members are ready before putting bh into list */ +smp_wmb (); + ctx->first_bh = bh; + }qemu_mutex_unlock (&ctx->bh_lock);return bh; } +QEMUBH *aio_bh_new_replay (AioContext *ctx,QEMUBHFunc *cb,void *opaque, +uint64_t id) +{ +QEMUBH *bh =aio_bh_new (ctx, cb, opaque); + bh->replay = true; + bh->id = id; +return bh; +} + +void aio_bh_call (void *opaque) +{ +QEMUBH *bh = (QEMUBH *)opaque; + bh->cb (bh->opaque); +} +/* Multiple occurrences of aio_bh_poll cannot be called concurrently */ int aio_bh_poll (AioContext *ctx) {
@@ -79,7 +109,11 @@ int aio_bh_poll(AioContext *ctx)if (!bh->idle) ret =1 ; bh->idle =0 ; - bh->cb (bh->opaque); +if (!bh->replay) { +aio_bh_call (bh); + }else { +replay_add_bh_event (bh, bh->id); + } } }
dma-helpers.c +3 -1
@@ -13,6 +13,7 @@#include "qemu/range.h" #include "qemu/thread.h" #include "qemu/main-loop.h" +#include "replay/replay.h" /* #define DEBUG_IOMMU */
@@ -96,7 +97,8 @@ static void continue_after_map_failure(void *opaque) {DMAAIOCB *dbs = (DMAAIOCB *)opaque; - dbs->bh =qemu_bh_new (reschedule_dma, dbs); + dbs->bh =qemu_bh_new_replay (reschedule_dma, dbs, +replay_get_current_step ());qemu_bh_schedule (dbs->bh); }
hw/ide/ahci.c +3 -1
@@ -33,6 +33,7 @@#include "internal.h" #include <hw/ide/pci.h> #include <hw/ide/ahci.h> +#include "replay/replay.h" /* #define DEBUG_AHCI */
@@ -1192,7 +1193,8 @@ static void ahci_cmd_done(IDEDMA *dma)if (!ad->check_bh) {/* maybe we still have something to process, check later */ - ad->check_bh =qemu_bh_new (ahci_check_cmd_bh, ad); + ad->check_bh =qemu_bh_new_replay (ahci_check_cmd_bh, ad, +replay_get_current_step ());qemu_bh_schedule (ad->check_bh); } }
hw/ide/core.c +3 -1
@@ -32,6 +32,7 @@#include "sysemu/dma.h" #include "hw/block/block.h" #include "sysemu/block-backend.h" +#include "replay/replay.h" #include <hw/ide/internal.h>
@@ -448,7 +449,8 @@ BlockAIOCB *ide_issue_trim(BlockBackend *blk, iocb =blk_aio_get (&trim_aiocb_info, blk, cb, opaque); iocb->blk = blk; - iocb->bh =qemu_bh_new (ide_trim_bh_cb, iocb); + iocb->bh =qemu_bh_new_replay (ide_trim_bh_cb, iocb, +replay_get_current_step ()); iocb->ret =0 ; iocb->qiov = qiov; iocb->i =-1 ;
hw/timer/arm_timer.c +1 -1
@@ -168,7 +168,7 @@ static arm_timer_state *arm_timer_init(uint32_t freq) s->freq = freq; s->control =TIMER_CTRL_IE ; - bh =qemu_bh_new (arm_timer_tick, s); + bh =qemu_bh_new_replay (arm_timer_tick, s,0 ); s->timer =ptimer_init (bh);vmstate_register (NULL ,-1 , &vmstate_arm_timer, s);return s;
hw/usb/hcd-uhci.c +1 -1
@@ -1224,7 +1224,7 @@ static int usb_uhci_common_initfn(PCIDevice *dev) USB_SPEED_MASK_LOW | USB_SPEED_MASK_FULL); } } - s->bh =qemu_bh_new (uhci_bh, s); + s->bh =qemu_bh_new_replay (uhci_bh, s,0 ); s->frame_timer =timer_new_ns (QEMU_CLOCK_VIRTUAL , uhci_frame_timer, s); s->num_ports_vmstate =NB_PORTS ;QTAILQ_INIT (&s->queues);
include/block/aio.h +18 -0
@@ -35,6 +35,8 @@ struct BlockAIOCB {const AIOCBInfo *aiocb_info;BlockDriverState *bs;BlockCompletionFunc *cb; +bool replay; +uint64_t replay_step;void *opaque;int refcnt; };
@@ -144,6 +146,17 @@ void aio_context_release(AioContext *ctx);QEMUBH *aio_bh_new (AioContext *ctx,QEMUBHFunc *cb,void *opaque);/** +* aio_bh_new_replay: Allocate a new bottom half structure for replay. +* +* This function calls aio_bh_new function and also fills replay parameters +* of the BH structure. BH created with this function in record/replay mode +* are executed through the replay queue only at checkpoints and instructions +* executions. +*/ +QEMUBH *aio_bh_new_replay (AioContext *ctx,QEMUBHFunc *cb,void *opaque, +uint64_t id); + +/** * aio_notify: Force processing of pending events. * * Similar to signaling a condition variable, aio_notify forces
@@ -159,6 +172,11 @@ QEMUBH *aio_bh_new(AioContext *ctx, QEMUBHFunc *cb, void *opaque);void aio_notify (AioContext *ctx);/** +* aio_bh_call: Executes callback function of the specified BH. +*/ +void aio_bh_call (void *opaque); + +/** * aio_bh_poll: Poll bottom halves for an AioContext. * * These are internal functions used by the QEMU main loop.
include/qemu/main-loop.h +1 -0
@@ -306,6 +306,7 @@ void qemu_iohandler_fill(GArray *pollfds);void qemu_iohandler_poll (GArray *pollfds,int rc);QEMUBH *qemu_bh_new (QEMUBHFunc *cb,void *opaque); +QEMUBH *qemu_bh_new_replay (QEMUBHFunc *cb,void *opaque,uint64_t id);void qemu_bh_schedule_idle (QEMUBH *bh);#endif
main-loop.c +5 -0
@@ -508,3 +508,8 @@ QEMUBH *qemu_bh_new(QEMUBHFunc *cb, void *opaque) {return aio_bh_new (qemu_aio_context, cb, opaque); } + +QEMUBH *qemu_bh_new_replay (QEMUBHFunc *cb,void *opaque,uint64_t id) +{ +return aio_bh_new_replay (qemu_aio_context, cb, opaque, id); +}
replay/replay-events.c +16 -0
@@ -36,6 +36,9 @@ static bool replay_events_enabled = false;static void replay_run_event (Event *event) {switch (event->event_kind) { +case REPLAY_ASYNC_EVENT_BH : +aio_bh_call (event->opaque); +break ;default :fprintf (stderr,"Replay: invalid async event ID (%d) in the queue\n" , event->event_kind);
@@ -119,6 +122,11 @@ void replay_add_event(int event_kind, void *opaque)replay_add_event_internal (event_kind, opaque,NULL ,0 ); } +void replay_add_bh_event (void *bh,uint64_t id) +{ +replay_add_event_internal (REPLAY_ASYNC_EVENT_BH , bh,NULL , id); +} +void replay_save_events (int opt) {qemu_mutex_lock (&lock);
@@ -132,6 +140,9 @@ void replay_save_events(int opt)/* save event-specific data */ switch (event->event_kind) { +case REPLAY_ASYNC_EVENT_BH : +replay_put_qword (event->id); +break ; } }
@@ -158,6 +169,11 @@ void replay_read_events(int opt) }/* Execute some events without searching them in the queue */ switch (read_event_kind) { +case REPLAY_ASYNC_EVENT_BH : +if (read_id ==-1 ) { + read_id =replay_get_qword (); + } +break ;default :fprintf (stderr,"Unknown ID %d of replay event\n" , read_event_kind);exit (1 );
replay/replay-internal.h +2 -1
@@ -37,7 +37,8 @@/* Asynchronous events IDs */ -#define REPLAY_ASYNC_COUNT 0 +#define REPLAY_ASYNC_EVENT_BH 0 +#define REPLAY_ASYNC_COUNT 1 typedef struct ReplayState { /*! Cached clock values. */
replay/replay.h +2 -0
@@ -91,5 +91,7 @@ int replay_checkpoint(unsigned int checkpoint);/*! Disables storing events in the queue */ void replay_disable_events (void ); +/*! Adds BH event to the queue */ +void replay_add_bh_event (void *bh,uint64_t id);#endif
stubs/replay.c +4 -0
@@ -26,3 +26,7 @@ int runstate_is_running(void) {return 0 ; } + +void replay_add_bh_event (void *bh,uint64_t id) +{ +}
RFC PATCH v4 21/25 replay: replay aio requests
In reply to Pavel DovgalyukThis patch adds identifier to aio requests. ID is used for creating bottom halves and identifying them while replaying.
The patch also introduces several functions that make possible replaying of the aio requests.
--- block.c | 81 ++++++++++++++++++++++++++++++++++++---- block/block-backend.c | 30 ++++++++++++++- block/qcow2.c | 4 ++ dma-helpers.c | 6 ++- hw/block/virtio-blk.c | 10 ++--- hw/ide/atapi.c | 10 +++-- hw/ide/core.c | 14 ++++--- include/block/block.h | 15 +++++++ include/qemu-common.h | 2 + include/sysemu/block-backend.h | 10 +++++ qemu-io-cmds.c | 2 - stubs/replay.c | 5 ++ trace-events | 2 + util/iov.c | 4 ++ 14 files changed, 167 insertions(+), 28 deletions(-)
block.c +72 -9
@@ -83,7 +83,8 @@ static BlockAIOCB *bdrv_co_aio_rw_vector(BlockDriverState *bs,BdrvRequestFlags flags, BlockCompletionFunc *cb, void *opaque, - bool is_write); + bool is_write, + bool aio_replay); static void coroutine_fn bdrv_co_do_rw(void *opaque); static int coroutine_fn bdrv_co_do_write_zeroes(BlockDriverState *bs,int64_t sector_num,int nb_sectors,BdrvRequestFlags flags);
@@ -4342,7 +4343,19 @@ BlockAIOCB *bdrv_aio_readv(BlockDriverState *bs, int64_t sector_num,trace_bdrv_aio_readv (bs, sector_num, nb_sectors, opaque);return bdrv_co_aio_rw_vector (bs, sector_num, qiov, nb_sectors,0 , - cb, opaque, false); + cb, opaque, false, false); +} + +BlockAIOCB *bdrv_aio_readv_replay (BlockDriverState *bs, +int64_t sector_num, +QEMUIOVector *qiov,int nb_sectors, +BlockCompletionFunc *cb, +void *opaque) +{ +trace_bdrv_aio_readv_replay (bs, sector_num, nb_sectors, opaque); + +return bdrv_co_aio_rw_vector (bs, sector_num, qiov, nb_sectors,0 , + cb, opaque, false, true); } BlockAIOCB *bdrv_aio_writev(BlockDriverState *bs, int64_t sector_num,
@@ -4352,7 +4365,19 @@ BlockAIOCB *bdrv_aio_writev(BlockDriverState *bs, int64_t sector_num,trace_bdrv_aio_writev (bs, sector_num, nb_sectors, opaque);return bdrv_co_aio_rw_vector (bs, sector_num, qiov, nb_sectors,0 , - cb, opaque, true); + cb, opaque, true, false); +} + +BlockAIOCB *bdrv_aio_writev_replay (BlockDriverState *bs, +int64_t sector_num, +QEMUIOVector *qiov,int nb_sectors, +BlockCompletionFunc *cb, +void *opaque) +{ +trace_bdrv_aio_writev_replay (bs, sector_num, nb_sectors, opaque); + +return bdrv_co_aio_rw_vector (bs, sector_num, qiov, nb_sectors,0 , + cb, opaque, true, true); } BlockAIOCB *bdrv_aio_write_zeroes(BlockDriverState *bs,
@@ -4363,7 +4388,7 @@ BlockAIOCB *bdrv_aio_write_zeroes(BlockDriverState *bs,return bdrv_co_aio_rw_vector (bs, sector_num,NULL , nb_sectors,BDRV_REQ_ZERO_WRITE | flags, - cb, opaque, true); + cb, opaque, true, true); }
@@ -4505,7 +4530,8 @@ static int multiwrite_merge(BlockDriverState *bs, BlockRequest *reqs,* requests. However, the fields opaque and error are left unmodified as they * are used to signal failure for a single request to the caller. */ -int bdrv_aio_multiwrite (BlockDriverState *bs,BlockRequest *reqs,int num_reqs) +int bdrv_aio_multiwrite (BlockDriverState *bs,BlockRequest *reqs,int num_reqs, +bool replay) {MultiwriteCB *mcb;int i;
@@ -4543,7 +4569,7 @@ int bdrv_aio_multiwrite(BlockDriverState *bs, BlockRequest *reqs, int num_reqs)bdrv_co_aio_rw_vector (bs, reqs[i].sector, reqs[i].qiov, reqs[i].nb_sectors, reqs[i].flags, multiwrite_cb, mcb, - true); + true, replay); }return 0 ;
@@ -4688,7 +4714,12 @@ static void coroutine_fn bdrv_co_do_rw(void *opaque) acb->req.nb_sectors, acb->req.qiov, acb->req.flags); } - acb->bh =aio_bh_new (bdrv_get_aio_context (bs), bdrv_co_em_bh, acb); +if (acb->common.replay) { + acb->bh =aio_bh_new_replay (bdrv_get_aio_context (bs), bdrv_co_em_bh, + acb, acb->common.replay_step); + }else { + acb->bh =aio_bh_new (bdrv_get_aio_context (bs), bdrv_co_em_bh, acb); + }qemu_bh_schedule (acb->bh); }
@@ -4699,7 +4730,8 @@ static BlockAIOCB *bdrv_co_aio_rw_vector(BlockDriverState *bs,BdrvRequestFlags flags, BlockCompletionFunc *cb, void *opaque, - bool is_write) + bool is_write, + bool aio_replay) { Coroutine *co;BlockAIOCBCoroutine *acb;
@@ -4710,6 +4742,11 @@ static BlockAIOCB *bdrv_co_aio_rw_vector(BlockDriverState *bs, acb->req.qiov = qiov; acb->req.flags = flags; acb->is_write = is_write; + acb->done =NULL ; + acb->common.replay = aio_replay; +if (aio_replay) { + acb->common.replay_step =replay_get_current_step (); + } co =qemu_coroutine_create (bdrv_co_do_rw);qemu_coroutine_enter (co, acb);
@@ -4723,7 +4760,12 @@ static void coroutine_fn bdrv_aio_flush_co_entry(void *opaque)BlockDriverState *bs = acb->common.bs; acb->req.error =bdrv_co_flush (bs); - acb->bh =aio_bh_new (bdrv_get_aio_context (bs), bdrv_co_em_bh, acb); +if (acb->common.replay) { + acb->bh =aio_bh_new_replay (bdrv_get_aio_context (bs), bdrv_co_em_bh, + acb, acb->common.replay_step); + }else { + acb->bh =aio_bh_new (bdrv_get_aio_context (bs), bdrv_co_em_bh, acb); + }qemu_bh_schedule (acb->bh); }
@@ -4743,6 +4785,25 @@ BlockAIOCB *bdrv_aio_flush(BlockDriverState *bs,return &acb->common; } +BlockAIOCB *bdrv_aio_flush_replay (BlockDriverState *bs, +BlockCompletionFunc *cb,void *opaque) +{ +trace_bdrv_aio_flush (bs, opaque); + +Coroutine *co; +BlockAIOCBCoroutine *acb; + + acb =qemu_aio_get (&bdrv_em_co_aiocb_info, bs, cb, opaque); + acb->done =NULL ; + acb->common.replay = true; + acb->common.replay_step =replay_get_current_step (); + + co =qemu_coroutine_create (bdrv_aio_flush_co_entry); +qemu_coroutine_enter (co, acb); + +return &acb->common; +} + static void coroutine_fn bdrv_aio_discard_co_entry(void *opaque) {BlockAIOCBCoroutine *acb = opaque;
@@ -4793,6 +4854,8 @@ void *qemu_aio_get(const AIOCBInfo *aiocb_info, BlockDriverState *bs, acb->cb = cb; acb->opaque = opaque; acb->refcnt =1 ; + acb->replay_step =0 ; + acb->replay = false;return acb; }
block/block-backend.c +29 -1
@@ -451,6 +451,14 @@ BlockAIOCB *blk_aio_readv(BlockBackend *blk, int64_t sector_num,return bdrv_aio_readv (blk->bs, sector_num, iov, nb_sectors, cb, opaque); } +BlockAIOCB *blk_aio_readv_replay (BlockBackend *blk,int64_t sector_num, +QEMUIOVector *iov,int nb_sectors, +BlockCompletionFunc *cb,void *opaque) +{ +return bdrv_aio_readv_replay (blk->bs, sector_num, iov, nb_sectors, + cb, opaque); +} +BlockAIOCB *blk_aio_writev (BlockBackend *blk,int64_t sector_num,QEMUIOVector *iov,int nb_sectors,BlockCompletionFunc *cb,void *opaque)
@@ -458,12 +466,26 @@ BlockAIOCB *blk_aio_writev(BlockBackend *blk, int64_t sector_num,return bdrv_aio_writev (blk->bs, sector_num, iov, nb_sectors, cb, opaque); } +BlockAIOCB *blk_aio_writev_replay (BlockBackend *blk,int64_t sector_num, +QEMUIOVector *iov,int nb_sectors, +BlockCompletionFunc *cb,void *opaque) +{ +return bdrv_aio_writev_replay (blk->bs, sector_num, iov, nb_sectors, + cb, opaque); +} +BlockAIOCB *blk_aio_flush (BlockBackend *blk,BlockCompletionFunc *cb,void *opaque) {return bdrv_aio_flush (blk->bs, cb, opaque); } +BlockAIOCB *blk_aio_flush_replay (BlockBackend *blk, +BlockCompletionFunc *cb,void *opaque) +{ +return bdrv_aio_flush_replay (blk->bs, cb, opaque); +} +BlockAIOCB *blk_aio_discard (BlockBackend *blk,int64_t sector_num,int nb_sectors,BlockCompletionFunc *cb,void *opaque)
@@ -483,7 +505,13 @@ void blk_aio_cancel_async(BlockAIOCB *acb)int blk_aio_multiwrite (BlockBackend *blk,BlockRequest *reqs,int num_reqs) { -return bdrv_aio_multiwrite (blk->bs, reqs, num_reqs); +return bdrv_aio_multiwrite (blk->bs, reqs, num_reqs, false); +} + +int blk_aio_multiwrite_replay (BlockBackend *blk,BlockRequest *reqs, +int num_reqs) +{ +return bdrv_aio_multiwrite (blk->bs, reqs, num_reqs, true); }int blk_ioctl (BlockBackend *blk,unsigned long int req,void *buf)
block/qcow2.c +4 -0
@@ -1140,6 +1140,8 @@ static coroutine_fn int qcow2_co_readv(BlockDriverState *bs, int64_t sector_num,uint8_t *cluster_data =NULL ;qemu_iovec_init (&hd_qiov, qiov->niov); + hd_qiov.replay = qiov->replay; + hd_qiov.replay_step = qiov->replay_step;qemu_co_mutex_lock (&s->lock);
@@ -1297,6 +1299,8 @@ static coroutine_fn int qcow2_co_writev(BlockDriverState *bs, remaining_sectors);qemu_iovec_init (&hd_qiov, qiov->niov); + hd_qiov.replay = qiov->replay; + hd_qiov.replay_step = qiov->replay_step; s->cluster_cache_offset =-1 ;/* disable compressed cache */
dma-helpers.c +4 -2
@@ -212,6 +212,8 @@ BlockAIOCB *dma_blk_io( dbs->io_func = io_func; dbs->bh =NULL ;qemu_iovec_init (&dbs->iov, sg->nsg); + dbs->iov.replay = true; + dbs->iov.replay_step =replay_get_current_step ();dma_blk_cb (dbs,0 );return &dbs->common; }
@@ -221,7 +223,7 @@ BlockAIOCB *dma_blk_read(BlockBackend *blk, QEMUSGList *sg, uint64_t sector, void (*cb)(void *opaque, int ret), void *opaque) { - return dma_blk_io(blk, sg, sector, blk_aio_readv, cb, opaque, + return dma_blk_io(blk, sg, sector, blk_aio_readv_replay, cb, opaque,DMA_DIRECTION_FROM_DEVICE ); }
@@ -229,7 +231,7 @@ BlockAIOCB *dma_blk_write(BlockBackend *blk, QEMUSGList *sg, uint64_t sector, void (*cb)(void *opaque, int ret), void *opaque) { - return dma_blk_io(blk, sg, sector, blk_aio_writev, cb, opaque, + return dma_blk_io(blk, sg, sector, blk_aio_writev_replay, cb, opaque,DMA_DIRECTION_TO_DEVICE ); }
hw/block/virtio-blk.c +5 -5
@@ -265,7 +265,7 @@ void virtio_submit_multiwrite(BlockBackend *blk, MultiReqBuffer *mrb)return ; } - ret =blk_aio_multiwrite (blk, mrb->blkreq, mrb->num_writes); + ret =blk_aio_multiwrite_replay (blk, mrb->blkreq, mrb->num_writes);if (ret !=0 ) {for (i =0 ; i < mrb->num_writes; i++) {if (mrb->blkreq[i].error) {
@@ -286,7 +286,7 @@ static void virtio_blk_handle_flush(VirtIOBlockReq *req, MultiReqBuffer *mrb)* Make sure all outstanding writes are posted to the backing device. */ virtio_submit_multiwrite (req->dev->blk, mrb); -blk_aio_flush (req->dev->blk, virtio_blk_flush_complete, req); +blk_aio_flush_replay (req->dev->blk, virtio_blk_flush_complete, req); } static bool virtio_blk_sect_range_ok(VirtIOBlock *dev,
@@ -357,9 +357,9 @@ static void virtio_blk_handle_read(VirtIOBlockReq *req)block_acct_start (blk_get_stats (req->dev->blk), &req->acct, req->qiov.size,BLOCK_ACCT_READ ); -blk_aio_readv (req->dev->blk, sector, &req->qiov, - req->qiov.size /BDRV_SECTOR_SIZE , - virtio_blk_rw_complete, req); +blk_aio_readv_replay (req->dev->blk, sector, &req->qiov, + req->qiov.size /BDRV_SECTOR_SIZE , + virtio_blk_rw_complete, req); }void virtio_blk_handle_request (VirtIOBlockReq *req,MultiReqBuffer *mrb)
hw/ide/atapi.c +6 -4
@@ -25,7 +25,7 @@#include "hw/ide/internal.h" #include "hw/scsi/scsi.h" -#include "sysemu/block-backend.h" +#include "replay/replay.h" static void ide_atapi_cmd_read_dma_cb (void *opaque,int ret);
@@ -350,10 +350,12 @@ static void ide_atapi_cmd_read_dma_cb(void *opaque, int ret) s->bus->dma->iov.iov_base = (void *)(s->io_buffer + data_offset); s->bus->dma->iov.iov_len = n *4 *512 ;qemu_iovec_init_external (&s->bus->dma->qiov, &s->bus->dma->iov,1 ); + s->bus->dma->qiov.replay = true; + s->bus->dma->qiov.replay_step =replay_get_current_step (); - s->bus->dma->aiocb =blk_aio_readv (s->blk, (int64_t )s->lba <<2 , - &s->bus->dma->qiov, n *4 , - ide_atapi_cmd_read_dma_cb, s); + s->bus->dma->aiocb =blk_aio_readv_replay (s->blk, (int64_t )s->lba <<2 , + &s->bus->dma->qiov, n *4 , + ide_atapi_cmd_read_dma_cb, s);return ; eot:
hw/ide/core.c +9 -5
@@ -629,11 +629,13 @@ void ide_sector_read(IDEState *s) s->iov.iov_base = s->io_buffer; s->iov.iov_len = n *BDRV_SECTOR_SIZE ;qemu_iovec_init_external (&s->qiov, &s->iov,1 ); + s->qiov.replay = true; + s->qiov.replay_step =replay_get_current_step ();block_acct_start (blk_get_stats (s->blk), &s->acct, n *BDRV_SECTOR_SIZE ,BLOCK_ACCT_READ ); - s->pio_aiocb =blk_aio_readv (s->blk, sector_num, &s->qiov, n, - ide_sector_read_cb, s); + s->pio_aiocb =blk_aio_readv_replay (s->blk, sector_num, &s->qiov, n, + ide_sector_read_cb, s); }static void dma_buf_commit (IDEState *s)
@@ -881,11 +883,13 @@ void ide_sector_write(IDEState *s) s->iov.iov_base = s->io_buffer; s->iov.iov_len = n *BDRV_SECTOR_SIZE ;qemu_iovec_init_external (&s->qiov, &s->iov,1 ); + s->qiov.replay = true; + s->qiov.replay_step =replay_get_current_step ();block_acct_start (blk_get_stats (s->blk), &s->acct, n *BDRV_SECTOR_SIZE ,BLOCK_ACCT_READ ); - s->pio_aiocb =blk_aio_writev (s->blk, sector_num, &s->qiov, n, - ide_sector_write_cb, s); + s->pio_aiocb =blk_aio_writev_replay (s->blk, sector_num, &s->qiov, n, + ide_sector_write_cb, s); }static void ide_flush_cb (void *opaque,int ret)
@@ -921,7 +925,7 @@ void ide_flush_cache(IDEState *s) s->status |=BUSY_STAT ;block_acct_start (blk_get_stats (s->blk), &s->acct,0 ,BLOCK_ACCT_FLUSH ); - s->pio_aiocb =blk_aio_flush (s->blk, ide_flush_cb, s); + s->pio_aiocb =blk_aio_flush_replay (s->blk, ide_flush_cb, s); }static void ide_cfata_metadata_inquiry (IDEState *s)
include/block/block.h +14 -1
@@ -284,11 +284,24 @@ typedef void BlockDriverDirtyHandler(BlockDriverState *bs, int64_t sector,BlockAIOCB *bdrv_aio_readv (BlockDriverState *bs,int64_t sector_num,QEMUIOVector *iov,int nb_sectors,BlockCompletionFunc *cb,void *opaque); +BlockAIOCB *bdrv_aio_readv_replay (BlockDriverState *bs, +int64_t sector_num, +QEMUIOVector *iov,int nb_sectors, +BlockCompletionFunc *cb, +void *opaque);BlockAIOCB *bdrv_aio_writev (BlockDriverState *bs,int64_t sector_num,QEMUIOVector *iov,int nb_sectors,BlockCompletionFunc *cb,void *opaque); +BlockAIOCB *bdrv_aio_writev_replay (BlockDriverState *bs, +int64_t sector_num, +QEMUIOVector *iov,int nb_sectors, +BlockCompletionFunc *cb, +void *opaque);BlockAIOCB *bdrv_aio_flush (BlockDriverState *bs,BlockCompletionFunc *cb,void *opaque); +BlockAIOCB *bdrv_aio_flush_replay (BlockDriverState *bs, +BlockCompletionFunc *cb, +void *opaque);BlockAIOCB *bdrv_aio_discard (BlockDriverState *bs,int64_t sector_num,int nb_sectors,BlockCompletionFunc *cb,void *opaque);
@@ -309,7 +322,7 @@ typedef struct BlockRequest { } BlockRequest;int bdrv_aio_multiwrite (BlockDriverState *bs,BlockRequest *reqs, -int num_reqs); +int num_reqs,bool replay);/* sg packet commands */ int bdrv_ioctl (BlockDriverState *bs,unsigned long int req,void *buf);
include/qemu-common.h +2 -0
@@ -320,6 +320,8 @@ typedef struct QEMUIOVector {int niov;int nalloc;size_t size; +bool replay; +uint64_t replay_step; } QEMUIOVector;void qemu_iovec_init (QEMUIOVector *qiov,int alloc_hint);
include/sysemu/block-backend.h +10 -0
@@ -94,17 +94,27 @@ void blk_get_geometry(BlockBackend *blk, uint64_t *nb_sectors_ptr);BlockAIOCB *blk_aio_readv (BlockBackend *blk,int64_t sector_num,QEMUIOVector *iov,int nb_sectors,BlockCompletionFunc *cb,void *opaque); +BlockAIOCB *blk_aio_readv_replay (BlockBackend *blk,int64_t sector_num, +QEMUIOVector *iov,int nb_sectors, +BlockCompletionFunc *cb,void *opaque);BlockAIOCB *blk_aio_writev (BlockBackend *blk,int64_t sector_num,QEMUIOVector *iov,int nb_sectors,BlockCompletionFunc *cb,void *opaque); +BlockAIOCB *blk_aio_writev_replay (BlockBackend *blk,int64_t sector_num, +QEMUIOVector *iov,int nb_sectors, +BlockCompletionFunc *cb,void *opaque);BlockAIOCB *blk_aio_flush (BlockBackend *blk,BlockCompletionFunc *cb,void *opaque); +BlockAIOCB *blk_aio_flush_replay (BlockBackend *blk, +BlockCompletionFunc *cb,void *opaque);BlockAIOCB *blk_aio_discard (BlockBackend *blk,int64_t sector_num,int nb_sectors,BlockCompletionFunc *cb,void *opaque);void blk_aio_cancel (BlockAIOCB *acb);void blk_aio_cancel_async (BlockAIOCB *acb);int blk_aio_multiwrite (BlockBackend *blk,BlockRequest *reqs,int num_reqs); +int blk_aio_multiwrite_replay (BlockBackend *blk,BlockRequest *reqs, +int num_reqs);int blk_ioctl (BlockBackend *blk,unsigned long int req,void *buf);BlockAIOCB *blk_aio_ioctl (BlockBackend *blk,unsigned long int req,void *buf,BlockCompletionFunc *cb,void *opaque);
qemu-io-cmds.c +1 -1
@@ -583,7 +583,7 @@ static int do_aio_multiwrite(BlockDriverState *bs, BlockRequest* reqs, *total += reqs[i].qiov->size; } - ret =bdrv_aio_multiwrite (bs, reqs, num_reqs); + ret =bdrv_aio_multiwrite (bs, reqs, num_reqs, false);if (ret <0 ) {return ret; }
stubs/replay.c +5 -0
@@ -30,3 +30,8 @@ int runstate_is_running(void)void replay_add_bh_event (void *bh,uint64_t id) { } + +uint64_t replay_get_current_step (void ) +{ +return 0 ; +}
trace-events +2 -0
@@ -64,7 +64,9 @@ bdrv_aio_multiwrite(void *mcb, int num_callbacks, int num_reqs) "mcb %p num_call bdrv_aio_discard(void *bs, int64_t sector_num, int nb_sectors, void *opaque) "bs %p sector_num %"PRId64" nb_sectors %d opaque %p" bdrv_aio_flush(void *bs, void *opaque) "bs %p opaque %p" bdrv_aio_readv(void *bs, int64_t sector_num, int nb_sectors, void *opaque) "bs %p sector_num %"PRId64" nb_sectors %d opaque %p" +bdrv_aio_readv_replay(void *bs, int64_t sector_num, int nb_sectors, void *opaque) "bs %p sector_num %"PRId64" nb_sectors %d opaque %p" bdrv_aio_writev(void *bs, int64_t sector_num, int nb_sectors, void *opaque) "bs %p sector_num %"PRId64" nb_sectors %d opaque %p" +bdrv_aio_writev_replay(void *bs, int64_t sector_num, int nb_sectors, void *opaque) "bs %p sector_num %"PRId64" nb_sectors %d opaque %p" bdrv_aio_write_zeroes(void *bs, int64_t sector_num, int nb_sectors, int flags, void *opaque) "bs %p sector_num %"PRId64" nb_sectors %d flags %#x opaque %p" bdrv_lock_medium(void *bs, bool locked) "bs %p locked %d" bdrv_co_readv(void *bs, int64_t sector_num, int nb_sector) "bs %p sector_num %"PRId64" nb_sectors %d"
util/iov.c +4 -0
@@ -257,6 +257,8 @@ void qemu_iovec_init(QEMUIOVector *qiov, int alloc_hint) qiov->niov =0 ; qiov->nalloc = alloc_hint; qiov->size =0 ; + qiov->replay = false; + qiov->replay_step =0 ; }void qemu_iovec_init_external (QEMUIOVector *qiov,struct iovec *iov,int niov)
@@ -267,6 +269,8 @@ void qemu_iovec_init_external(QEMUIOVector *qiov, struct iovec *iov, int niov) qiov->niov = niov; qiov->nalloc =-1 ; qiov->size =0 ; + qiov->replay = false; + qiov->replay_step =0 ;for (i =0 ; i < niov; i++) qiov->size += iov[i].iov_len; }
RFC PATCH v4 22/25 replay: thread pool
In reply to Pavel DovgalyukThis patch modifies thread pool to allow replaying asynchronous thread tasks synchronously in replay mode.
--- block/raw-posix.c | 6 ++++- block/raw-win32.c | 4 +++- include/block/thread-pool.h | 4 +++- replay/replay-events.c | 11 ++++++++++ replay/replay-internal.h | 3 ++- replay/replay.h | 2 ++ stubs/replay.c | 4 ++++ tests/test-thread-pool.c | 7 ++++-- thread-pool.c | 49 ++++++++++++++++++++++++++++++------------- 9 files changed, 67 insertions(+), 23 deletions(-)
block/raw-posix.c +4 -2
@@ -1078,7 +1078,9 @@ static BlockAIOCB *paio_submit(BlockDriverState *bs, int fd,trace_paio_submit (acb, opaque, sector_num, nb_sectors, type); pool =aio_get_thread_pool (bdrv_get_aio_context (bs)); -return thread_pool_submit_aio (pool, aio_worker, acb, cb, opaque); +return thread_pool_submit_aio (pool, aio_worker, acb, cb, opaque, + qiov ? qiov->replay : false, + qiov ? qiov->replay_step :0 ); } static BlockAIOCB *raw_aio_submit(BlockDriverState *bs,
@@ -1970,7 +1972,7 @@ static BlockAIOCB *hdev_aio_ioctl(BlockDriverState *bs, acb->aio_ioctl_buf = buf; acb->aio_ioctl_cmd = req; pool =aio_get_thread_pool (bdrv_get_aio_context (bs)); - return thread_pool_submit_aio(pool, aio_worker, acb, cb, opaque); + return thread_pool_submit_aio(pool, aio_worker, acb, cb, opaque, false, 0); }#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
block/raw-win32.c +3 -1
@@ -158,7 +158,9 @@ static BlockAIOCB *paio_submit(BlockDriverState *bs, HANDLE hfile,trace_paio_submit (acb, opaque, sector_num, nb_sectors, type); pool =aio_get_thread_pool (bdrv_get_aio_context (bs)); -return thread_pool_submit_aio (pool, aio_worker, acb, cb, opaque); +return thread_pool_submit_aio (pool, aio_worker, acb, cb, opaque, + qiov ? qiov->replay : false, + qiov ? qiov->replay_step :0 ); }int qemu_ftruncate64 (int fd,int64_t length)
include/block/thread-pool.h +3 -1
@@ -29,9 +29,11 @@ void thread_pool_free(ThreadPool *pool);BlockAIOCB *thread_pool_submit_aio (ThreadPool *pool,ThreadPoolFunc *func,void *arg, -BlockCompletionFunc *cb,void *opaque); +BlockCompletionFunc *cb,void *opaque, +bool replay,uint64_t replay_step); int coroutine_fn thread_pool_submit_co(ThreadPool *pool, ThreadPoolFunc *func, void *arg);void thread_pool_submit (ThreadPool *pool,ThreadPoolFunc *func,void *arg); +void thread_pool_work (ThreadPool *pool,void *r);#endif
replay/replay-events.c +11 -0
@@ -12,6 +12,7 @@#include "qemu-common.h" #include "replay.h" #include "replay-internal.h" +#include "block/thread-pool.h" typedef struct Event { int event_kind;
@@ -39,6 +40,9 @@ static void replay_run_event(Event *event)case REPLAY_ASYNC_EVENT_BH :aio_bh_call (event->opaque);break ; +case REPLAY_ASYNC_EVENT_THREAD : +thread_pool_work ((ThreadPool *)event->opaque, event->opaque2); +break ;default :fprintf (stderr,"Replay: invalid async event ID (%d) in the queue\n" , event->event_kind);
@@ -127,6 +131,11 @@ void replay_add_bh_event(void *bh, uint64_t id)replay_add_event_internal (REPLAY_ASYNC_EVENT_BH , bh,NULL , id); } +void replay_add_thread_event (void *opaque,void *opaque2,uint64_t id) +{ +replay_add_event_internal (REPLAY_ASYNC_EVENT_THREAD , opaque, opaque2, id); +} +void replay_save_events (int opt) {qemu_mutex_lock (&lock);
@@ -141,6 +150,7 @@ void replay_save_events(int opt)/* save event-specific data */ switch (event->event_kind) {case REPLAY_ASYNC_EVENT_BH : +case REPLAY_ASYNC_EVENT_THREAD :replay_put_qword (event->id);break ; }
@@ -170,6 +180,7 @@ void replay_read_events(int opt)/* Execute some events without searching them in the queue */ switch (read_event_kind) {case REPLAY_ASYNC_EVENT_BH : +case REPLAY_ASYNC_EVENT_THREAD :if (read_id ==-1 ) { read_id =replay_get_qword (); }
replay/replay-internal.h +2 -1
@@ -38,7 +38,8 @@/* Asynchronous events IDs */ #define REPLAY_ASYNC_EVENT_BH 0 -#define REPLAY_ASYNC_COUNT 1 +#define REPLAY_ASYNC_EVENT_THREAD 1 +#define REPLAY_ASYNC_COUNT 2 typedef struct ReplayState { /*! Cached clock values. */
replay/replay.h +2 -0
@@ -93,5 +93,7 @@ int replay_checkpoint(unsigned int checkpoint);void replay_disable_events (void );/*! Adds BH event to the queue */ void replay_add_bh_event (void *bh,uint64_t id); +/*! Adds thread event to the queue */ +void replay_add_thread_event (void *pool,void *req,uint64_t id);#endif
stubs/replay.c +4 -0
@@ -35,3 +35,7 @@ uint64_t replay_get_current_step(void) {return 0 ; } + +void replay_add_thread_event (void *opaque,void *opaque2,uint64_t id) +{ +}
tests/test-thread-pool.c +4 -3
@@ -56,7 +56,7 @@ static void test_submit_aio(void) {WorkerTestData data = { .n =0 , .ret = -EINPROGRESS }; data.aiocb =thread_pool_submit_aio (pool, worker_cb, &data, - done_cb, &data); + done_cb, &data, false,0 );/* The callbacks are not called until after the first wait. */ active =1 ;
@@ -120,7 +120,8 @@ static void test_submit_many(void)for (i =0 ; i <100 ; i++) { data[i].n =0 ; data[i].ret = -EINPROGRESS ; -thread_pool_submit_aio (pool, worker_cb, &data[i], done_cb, &data[i]); +thread_pool_submit_aio (pool, worker_cb, &data[i], done_cb, &data[i], + false,0 ); } active =100 ;
@@ -149,7 +150,7 @@ static void do_test_cancel(bool sync) data[i].n =0 ; data[i].ret = -EINPROGRESS ; data[i].aiocb =thread_pool_submit_aio (pool, long_cb, &data[i], - done_cb, &data[i]); + done_cb, &data[i], false,0 ); }/* Starting the threads may be left to a bottom half. Let it
thread-pool.c +34 -15
99 lines not on this page · raw message
RFC PATCH v4 23/25 replay: initialization and deinitialization
In reply to Pavel DovgalyukThis patch introduces the functions for enabling the record/replay and for freeing the resources when simulator closes.
--- block.c | 2 - exec.c | 1 replay/replay-internal.h | 2 + replay/replay.c | 134 ++++++++++++++++++++++++++++++++++++++++++++++ replay/replay.h | 13 ++++ stubs/replay.c | 1 vl.c | 5 ++ 7 files changed, 157 insertions(+), 1 deletions(-)
block.c +1 -1
@@ -1941,7 +1941,7 @@ void bdrv_drain_all(void) busy |= bs_busy; } } -if (replay_mode ==REPLAY_MODE_PLAY ) { +if (replay_mode ==REPLAY_MODE_PLAY && replay_checkpoints) {/* Skip checkpoints from the log */ while (replay_checkpoint (8 )) {/* Nothing */
exec.c +1 -0
@@ -794,6 +794,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;
replay/replay-internal.h +2 -0
@@ -34,6 +34,8 @@/* for checkpoint event */ #define EVENT_CHECKPOINT 96 +/* end of log event */ +#define EVENT_END 127/* Asynchronous events IDs */
replay/replay.c +134 -0
157 lines not on this page · raw message
replay/replay.h +13 -0
@@ -17,6 +17,8 @@#include <time.h> #include "qapi-types.h" +struct QemuOpts ; +/* replay clock kinds */ /* rdtsc */ #define REPLAY_CLOCK_REAL_TICKS 0
@@ -27,10 +29,21 @@extern ReplayMode replay_mode;extern char *replay_image_suffix; +/*! Is set to true after finishing initialization */ +extern bool replay_checkpoints;/*! Returns replay play submode */ ReplaySubmode replay_get_play_submode (void ); +/* Replay process control functions */ + +/*! Enables recording or saving event log with specified parameters */ +void replay_configure (struct QemuOpts *opts,int mode); +/*! Initializes timers used for snapshotting and enables events recording */ +void replay_init_timer (void ); +/*! Closes replay log file and frees other resources. */ +void replay_finish (void ); +/* Processing the instructions */ /*! Returns number of executed instructions. */
stubs/replay.c +1 -0
@@ -2,6 +2,7 @@#include "sysemu/sysemu.h" ReplayMode replay_mode; +bool replay_checkpoints;ReplaySubmode replay_get_play_submode (void ) {
vl.c +5 -0
@@ -4363,7 +4363,12 @@ int main(int argc, char **argv, char **envp) } } +replay_init_timer (); +main_loop (); +if (replay_mode !=REPLAY_MODE_NONE ) { +replay_disable_events (); + }bdrv_close_all ();pause_all_vcpus ();res_free ();
RFC PATCH v4 24/25 replay: command line options
In reply to Pavel DovgalyukThis patch introduces command line options for enabling recording or replaying virtual machine behavior. "-record" option starts recording of the execution and saves it into the log, specified with "fname" parameter. "-replay" option is intended for replaying previously saved log.
--- cpus.c | 15 ++++++++-- qemu-options.hx | 27 +++++++++++++++++++ vl.c | 79 ++++++++++++++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 116 insertions(+), 5 deletions(-)
cpus.c +12 -3
@@ -933,12 +933,21 @@ static void qemu_wait_io_event_common(CPUState *cpu)static void qemu_tcg_wait_io_event (void ) {CPUState *cpu; +GMainContext *context =g_main_context_default (); -while (all_cpu_threads_idle ()) { -/* Start accounting real time to the virtual clock if the CPUs -are idle. */ +if (replay_mode ==REPLAY_MODE_PLAY + &&all_cpu_threads_idle () && first_cpu->halted) { +/* wakeup iothread when there is no code to execute in replay mode */ qemu_clock_warp (QEMU_CLOCK_VIRTUAL ); +g_main_context_wakeup (context);qemu_cond_wait (tcg_halt_cond, &qemu_global_mutex); + }else { +while (all_cpu_threads_idle ()) { +/* Start accounting real time to the virtual clock if the CPUs +are idle. */ +qemu_clock_warp (QEMU_CLOCK_VIRTUAL ); +qemu_cond_wait (tcg_halt_cond, &qemu_global_mutex); + } }while (iothread_requesting_mutex) {
qemu-options.hx +27 -0
@@ -3380,6 +3380,33 @@ Dump json-encoded vmstate information for current machine type to file in @var{file} ETEXI +DEF("record", HAS_ARG, QEMU_OPTION_record, + "-record fname=<filename>[,suffix=<suffix>,snapshot=<on/off>]\n" + " writes replay file for latter replaying\n", + QEMU_ARCH_ALL) +STEXI +@item -record fname=@var{file}[,suffix=@var{suffix},snapshot=@var{snapshot}] +Writes compact execution trace into @var{file}. +Changes for disk images are written +into separate files with @var{suffix} added. If no @var{suffix} is +specified, "replay_qcow" is used as suffix. +If @var{snapshot} parameter is set as off, then original disk image will be +modified. Default value is on. +ETEXI + +DEF("replay", HAS_ARG, QEMU_OPTION_replay, + "-replay fname=<filename>[,suffix=<suffix>,snapshot=<on/off>]\n" + " plays saved replay file\n", QEMU_ARCH_ALL) +STEXI +@item -replay fname=@var{filename}[,suffix=@var{suffix},snapshot=@var{snapshot}] +Plays compact execution trace from @var{filename}. +Changes for disk images and VM states are read +from separate files with @var{suffix} added. If no @var{suffix} is +specified, "replay_qcow" is used as suffix. +If @var{snapshot} parameter is set as off, then original disk image will be +modified. Default value is on. +ETEXI + HXCOMM This is the last statement. Insert new options before this line! STEXI @end table
vl.c +77 -2
157 lines not on this page · raw message
RFC PATCH v4 25/25 replay: recording of the user input
In reply to Pavel DovgalyukThis records user input (keyboard and mouse events) in record mode and replays these input events in replay mode.
--- include/ui/input.h | 2 + replay/Makefile.objs | 1 replay/replay-events.c | 48 ++++++++++++++++++++ replay/replay-input.c | 108 ++++++++++++++++++++++++++++++++++++++++++++++ replay/replay-internal.h | 11 ++++- replay/replay.h | 5 ++ ui/input.c | 80 ++++++++++++++++++++++++++-------- 7 files changed, 235 insertions(+), 20 deletions(-) create mode 100755 replay/replay-input.c
include/ui/input.h +2 -0
@@ -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);
replay/Makefile.objs +1 -0
@@ -2,3 +2,4 @@ obj-y += replay.o obj-y += replay-internal.o obj-y += replay-events.o obj-y += replay-time.o +obj-y += replay-input.o
replay/replay-events.c +48 -0
84 lines not on this page · raw message
replay/replay-input.c new file +108 -0
108 lines not on this page · raw message
replay/replay-internal.h +10 -1
@@ -41,7 +41,9 @@#define REPLAY_ASYNC_EVENT_BH 0#define REPLAY_ASYNC_EVENT_THREAD 1 -#define REPLAY_ASYNC_COUNT 2 +#define REPLAY_ASYNC_EVENT_INPUT 2 +#define REPLAY_ASYNC_EVENT_INPUT_SYNC 3 +#define REPLAY_ASYNC_COUNT 4 typedef struct ReplayState { /*! Cached clock values. */
@@ -120,4 +122,11 @@ void replay_read_events(int opt);/*! Adds specified async event to the queue */ void replay_add_event (int event_id,void *opaque); +/* 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 ); +#endif
replay/replay.h +5 -0
@@ -18,6 +18,7 @@#include "qapi-types.h" struct QemuOpts ; +struct InputEvent ;/* replay clock kinds */ /* rdtsc */
@@ -108,5 +109,9 @@ void replay_disable_events(void);void replay_add_bh_event (void *bh,uint64_t id);/*! Adds thread event to the queue */ void replay_add_thread_event (void *pool,void *req,uint64_t id); +/*! 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
ui/input.c +61 -19
142 lines not on this page · raw message