From patchwork Thu Jul 17 11:04:08 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Pavel Dovgalyuk X-Patchwork-Id: 371175 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [IPv6:2001:4830:134:3::11]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id AE366140179 for ; Fri, 18 Jul 2014 00:02:19 +1000 (EST) Received: from localhost ([::1]:44524 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1X7mGH-0005yl-JM for incoming@patchwork.ozlabs.org; Thu, 17 Jul 2014 10:02:17 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:52580) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1X7jh6-0007eW-Bd for qemu-devel@nongnu.org; Thu, 17 Jul 2014 07:17:55 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1X7jgz-00012q-Id for qemu-devel@nongnu.org; Thu, 17 Jul 2014 07:17:48 -0400 Received: from mail.ispras.ru ([83.149.199.45]:47477) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1X7jTp-000552-MH for qemu-devel@nongnu.org; Thu, 17 Jul 2014 07:04:05 -0400 Received: from [10.10.150.172] (unknown [80.250.189.177]) by mail.ispras.ru (Postfix) with ESMTPSA id E02CF540157; Thu, 17 Jul 2014 15:04:04 +0400 (MSK) To: qemu-devel@nongnu.org From: Pavel Dovgalyuk Date: Thu, 17 Jul 2014 15:04:08 +0400 Message-ID: <20140717110408.8352.10100.stgit@PASHA-ISP> In-Reply-To: <20140717110153.8352.80175.stgit@PASHA-ISP> References: <20140717110153.8352.80175.stgit@PASHA-ISP> User-Agent: StGit/0.16 MIME-Version: 1.0 X-detected-operating-system: by eggs.gnu.org: GNU/Linux 3.x X-Received-From: 83.149.199.45 X-Mailman-Approved-At: Thu, 17 Jul 2014 09:36:33 -0400 Cc: peter.maydell@linaro.org, peter.crosthwaite@xilinx.com, mark.burton@greensocs.com, real@ispras.ru, batuzovk@ispras.ru, pavel.dovgaluk@ispras.ru, pbonzini@redhat.com, fred.konrad@greensocs.com Subject: [Qemu-devel] [RFC PATCH v2 23/49] cpu: invent instruction count for accurate replay X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org This patch adds instructions count fields to cpu structure and invents several functions for increasing this counter while executing translation blocks. Signed-off-by: Pavel Dovgalyuk --- cpu-exec.c | 14 ++++- cpus.c | 5 ++ exec.c | 4 + include/exec/cpu-defs.h | 1 include/qom/cpu.h | 4 + replay/Makefile.objs | 1 replay/replay-events.c | 26 +++++++++ replay/replay-internal.c | 14 +++++ replay/replay-internal.h | 37 ++++++++++++- replay/replay.c | 136 ++++++++++++++++++++++++++++++++++++++++++++++ replay/replay.h | 16 +++++ translate-all.c | 7 ++ 12 files changed, 260 insertions(+), 5 deletions(-) create mode 100755 replay/replay-events.c diff --git a/cpu-exec.c b/cpu-exec.c index 66a693c..13c0ec6 100644 --- a/cpu-exec.c +++ b/cpu-exec.c @@ -22,6 +22,7 @@ #include "tcg.h" #include "qemu/atomic.h" #include "sysemu/qtest.h" +#include "qemu/main-loop.h" void cpu_loop_exit(CPUState *cpu) { @@ -283,19 +284,24 @@ int cpu_exec(CPUArchState *env) #else #error unsupported target CPU #endif - cpu->exception_index = -1; - /* prepare setjmp context for exception handling */ for(;;) { if (sigsetjmp(cpu->jmp_env, 0) == 0) { /* if an exception is pending, we execute it here */ if (cpu->exception_index >= 0) { + if (cpu->exception_index == EXCP_REPLAY) { + ret = cpu->exception_index; + cpu->exception_index = -1; + qemu_notify_event(); + break; + } if (cpu->exception_index >= EXCP_INTERRUPT) { /* exit request from the cpu execution loop */ ret = cpu->exception_index; if (ret == EXCP_DEBUG) { cpu_handle_debug_exception(env); } + cpu->exception_index = -1; break; } else { #if defined(CONFIG_USER_ONLY) @@ -601,6 +607,10 @@ int cpu_exec(CPUArchState *env) next_tb = 0; } } + if (cpu->exception_index == EXCP_REPLAY) { + /* go to exception_index checking */ + break; + } if (unlikely(cpu->exit_request)) { cpu->exit_request = 0; cpu->exception_index = EXCP_INTERRUPT; diff --git a/cpus.c b/cpus.c index bbad529..eb2a795 100644 --- a/cpus.c +++ b/cpus.c @@ -937,6 +937,8 @@ static void *qemu_tcg_cpu_thread_fn(void *arg) CPU_FOREACH(cpu) { cpu->thread_id = qemu_get_thread_id(); cpu->created = true; + /* init exception index here */ + cpu->exception_index = -1; } qemu_cond_signal(&qemu_cpu_cond); @@ -1186,6 +1188,7 @@ void qemu_init_vcpu(CPUState *cpu) cpu->nr_cores = smp_cores; cpu->nr_threads = smp_threads; cpu->stopped = true; + cpu->instructions_count = 0; if (kvm_enabled()) { qemu_kvm_start_vcpu(cpu); } else if (tcg_enabled()) { @@ -1307,6 +1310,8 @@ static void tcg_exec_all(void) if (r == EXCP_DEBUG) { cpu_handle_guest_debug(cpu); break; + } else if (r == EXCP_REPLAY) { + break; } } else if (cpu->stop || cpu->stopped) { break; diff --git a/exec.c b/exec.c index 5a2a25e..36adb62 100644 --- a/exec.c +++ b/exec.c @@ -52,6 +52,7 @@ #include "exec/ram_addr.h" #include "qemu/range.h" +#include "replay/replay.h" //#define DEBUG_SUBPAGE @@ -1615,6 +1616,9 @@ static void check_watchpoint(int offset, int len_mask, int flags) if (!cpu->watchpoint_hit) { cpu->watchpoint_hit = wp; tb_check_watchpoint(cpu); + /* Current instruction is already processed by replay. + Set flags that allow skpping this events */ + replay_undo_last_instruction(); if (wp->flags & BP_STOP_BEFORE_ACCESS) { cpu->exception_index = EXCP_DEBUG; cpu_loop_exit(cpu); diff --git a/include/exec/cpu-defs.h b/include/exec/cpu-defs.h index 2dd6206..db9ae1a 100644 --- a/include/exec/cpu-defs.h +++ b/include/exec/cpu-defs.h @@ -59,6 +59,7 @@ typedef uint64_t target_ulong; #define EXCP_DEBUG 0x10002 /* cpu stopped after a breakpoint or singlestep */ #define EXCP_HALTED 0x10003 /* cpu is halted (waiting for external event) */ #define EXCP_YIELD 0x10004 /* cpu wants to yield timeslice to another */ +#define EXCP_REPLAY 0x10005 /* for breaking execution loop to make correct order of events */ /* Only the bottom TB_JMP_PAGE_BITS of the jump cache hash bits vary for addresses on the same page. The top bits are the same. This allows diff --git a/include/qom/cpu.h b/include/qom/cpu.h index 1aafbf5..9c7b5c8 100644 --- a/include/qom/cpu.h +++ b/include/qom/cpu.h @@ -287,6 +287,7 @@ struct CPUState { (absolute value) offset as small as possible. This reduces code size, especially for hosts without large memory offsets. */ volatile sig_atomic_t tcg_exit_req; + uint32_t instructions_count; }; QTAILQ_HEAD(CPUTailQ, CPUState); @@ -466,6 +467,9 @@ static inline bool cpu_has_work(CPUState *cpu) */ bool qemu_cpu_is_self(CPUState *cpu); +//need here for replay work +bool qemu_in_vcpu_thread(void); + /** * qemu_cpu_kick: * @cpu: The vCPU to kick. diff --git a/replay/Makefile.objs b/replay/Makefile.objs index 1148f45..56da09c 100755 --- a/replay/Makefile.objs +++ b/replay/Makefile.objs @@ -1,2 +1,3 @@ obj-y += replay.o obj-y += replay-internal.o +obj-y += replay-events.o diff --git a/replay/replay-events.c b/replay/replay-events.c new file mode 100755 index 0000000..eaffc48 --- /dev/null +++ b/replay/replay-events.c @@ -0,0 +1,26 @@ +/* + * replay-events.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" +#include "replay-internal.h" + +bool replay_has_events(void) +{ + return false; +} + +void replay_save_events(int opt) +{ +} + +void replay_read_events(int opt) +{ +} diff --git a/replay/replay-internal.c b/replay/replay-internal.c index 706b46b..f416317 100755 --- a/replay/replay-internal.c +++ b/replay/replay-internal.c @@ -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_SAVE) { + if (first_cpu != NULL && first_cpu->instructions_count > 0) { + replay_put_event(EVENT_INSTRUCTION); + replay_put_dword(first_cpu->instructions_count); + replay_state.current_step += first_cpu->instructions_count; + first_cpu->instructions_count = 0; + } + } +} diff --git a/replay/replay-internal.h b/replay/replay-internal.h index b959bca..9ebfa83 100755 --- a/replay/replay-internal.h +++ b/replay/replay-internal.h @@ -13,6 +13,21 @@ */ #include +#include "sysemu/sysemu.h" + +/* for async events */ +#define EVENT_ASYNC 24 +/* for instruction event */ +#define EVENT_INSTRUCTION 32 + +typedef struct ReplayState { + /*! Nonzero, when next instruction is repeated one and was already + processed. */ + int skipping_instruction; + /*! Current step - number of processed instructions and timer events. */ + uint64_t current_step; +} ReplayState; +extern ReplayState replay_state; extern volatile unsigned int replay_data_kind; extern volatile unsigned int replay_has_unread_data; @@ -40,11 +55,27 @@ void replay_check_error(void); /*! Reads data type from the file and stores it in the replay_data_kind variable. */ void replay_fetch_data_kind(void); - -/*! Saves queued events (like instructions and sound). */ -void replay_save_instructions(void); /*! Checks that the next data is corresponding to the desired kind. Terminates the program in case of error. */ void validate_data_kind(int kind); +/*! Saves queued events (like instructions and sound). */ +void replay_save_instructions(void); + +/*! 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); + +/* Asynchronous events queue */ + +/*! 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); + #endif diff --git a/replay/replay.c b/replay/replay.c index 2961e17..8a9826e 100755 --- a/replay/replay.c +++ b/replay/replay.c @@ -9,7 +9,9 @@ * */ +#include "qemu-common.h" #include "replay.h" +#include "replay-internal.h" int replay_mode = REPLAY_NONE; /*! Stores current submode for PLAY mode */ @@ -18,8 +20,142 @@ int play_submode = REPLAY_PLAY_UNKNOWN; /* Suffix for the disk images filenames */ char *replay_image_suffix; +ReplayState replay_state; + int replay_get_play_submode(void) { return play_submode; } + +bool skip_async_events(int stop_event) +{ + /* nothing to skip - not all instructions used */ + if (first_cpu != NULL && first_cpu->instructions_count != 0 + && replay_has_unread_data) { + return stop_event == EVENT_INSTRUCTION; + } + + bool res = false; + while (true) { + replay_fetch_data_kind(); + if (stop_event == replay_data_kind) { + res = true; + } + switch (replay_data_kind) { + case EVENT_INSTRUCTION: + first_cpu->instructions_count = replay_get_dword(); + return res; + default: + /* clock, time_t, checkpoint and other events */ + return res; + } + } + + return res; +} + +void skip_async_events_until(unsigned int kind) +{ + if (!skip_async_events(kind)) { + if (replay_data_kind == EVENT_ASYNC && kind == EVENT_INSTRUCTION) { + return; + } + + fprintf(stderr, "%"PRId64": Read data kind %d instead of expected %d\n", + replay_get_current_step(), replay_data_kind, kind); + exit(1); + } +} + +void replay_instruction(int process_events) +{ + if (replay_state.skipping_instruction) { + replay_state.skipping_instruction = 0; + return; + } + + if (replay_file) { + if (replay_mode == REPLAY_SAVE) { + if (process_events && replay_has_events()) { + replay_save_instructions(); + /* events will be after the last instruction */ + replay_save_events(-1); + } else { + /* instruction - increase the step counter */ + ++first_cpu->instructions_count; + } + } else if (replay_mode == REPLAY_PLAY) { + skip_async_events_until(EVENT_INSTRUCTION); + if (first_cpu->instructions_count >= 1) { + ++replay_state.current_step; + --first_cpu->instructions_count; + if (first_cpu->instructions_count == 0) { + replay_has_unread_data = 0; + } + } else { + replay_read_events(-1); + } + } + } +} + +void replay_undo_last_instruction(void) +{ + if (replay_mode == REPLAY_SAVE) { + first_cpu->instructions_count--; + } else { + replay_state.skipping_instruction = 1; + } +} + +bool replay_has_async_request(void) +{ + if (replay_state.skipping_instruction) { + return false; + } + + if (replay_mode == REPLAY_PLAY) { + if (skip_async_events(EVENT_ASYNC)) { + return true; + } + + return false; + } + else if (replay_mode == REPLAY_SAVE) { + if (replay_has_events()) { + return true; + } + } + + return false; +} + +bool replay_has_instruction(void) +{ + if (replay_state.skipping_instruction) { + return true; + } + + if (replay_mode == REPLAY_PLAY) { + skip_async_events(EVENT_INSTRUCTION); + if (replay_data_kind != EVENT_INSTRUCTION + && replay_data_kind != EVENT_ASYNC) { + return false; + } + } + return true; +} + +uint64_t replay_get_current_step(void) +{ + if (first_cpu == NULL) { + return 0; + } + if (replay_file) { + if (replay_mode == REPLAY_SAVE) { + return replay_state.current_step + first_cpu->instructions_count; + } + } + return replay_state.current_step; +} diff --git a/replay/replay.h b/replay/replay.h index a883aa4..1ce7f78 100755 --- a/replay/replay.h +++ b/replay/replay.h @@ -12,6 +12,9 @@ * */ +#include +#include + /* replay modes */ #define REPLAY_NONE 0 #define REPLAY_SAVE 1 @@ -29,4 +32,17 @@ extern int replay_icount; /*! Returns replay play submode */ int replay_get_play_submode(void); +/* Processing the instructions */ + +/*! Returns number of executed instructions. */ +uint64_t replay_get_current_step(void); +/*! Called before instruction execution */ +void replay_instruction(int process_events); +/*! Undo last instruction count, when exception occurs */ +void replay_undo_last_instruction(void); +/*! Returns true if asynchronous event is pending */ +bool replay_has_async_request(void); +/*! Returns non-zero if next event is instruction. */ +bool replay_has_instruction(void); + #endif diff --git a/translate-all.c b/translate-all.c index fcb0697..37582a2 100644 --- a/translate-all.c +++ b/translate-all.c @@ -59,6 +59,7 @@ #include "exec/cputlb.h" #include "translate-all.h" #include "qemu/timer.h" +#include "replay/replay.h" //#define DEBUG_TB_INVALIDATE //#define DEBUG_FLUSH @@ -1171,6 +1172,9 @@ void tb_invalidate_phys_page_range(tb_page_addr_t start, tb_page_addr_t end, cpu_restore_state_from_tb(cpu, current_tb, cpu->mem_io_pc); cpu_get_tb_cpu_state(env, ¤t_pc, ¤t_cs_base, ¤t_flags); + /* Current instruction is already processed by replay. + Set flags that allow skpping this event */ + replay_undo_last_instruction(); } #endif /* TARGET_HAS_PRECISE_SMC */ /* we need to do that to handle the case where a signal @@ -1290,6 +1294,9 @@ static void tb_invalidate_phys_page(tb_page_addr_t addr, cpu_restore_state_from_tb(cpu, current_tb, pc); cpu_get_tb_cpu_state(env, ¤t_pc, ¤t_cs_base, ¤t_flags); + /* Current instruction is already processed by replay. + Set flags that allow skpping this event */ + replay_undo_last_instruction(); } #endif /* TARGET_HAS_PRECISE_SMC */ tb_phys_invalidate(tb, addr);