From patchwork Thu Sep 3 10:55:59 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Claudio Fontana X-Patchwork-Id: 274707 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-13.0 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_PATCH, MAILING_LIST_MULTI, SIGNED_OFF_BY, SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED,USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id B1F88C433E2 for ; Thu, 3 Sep 2020 10:59:22 +0000 (UTC) Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 44FD0206A5 for ; Thu, 3 Sep 2020 10:59:22 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 44FD0206A5 Authentication-Results: mail.kernel.org; dmarc=none (p=none dis=none) header.from=suse.de Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Received: from localhost ([::1]:48320 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1kDmxd-0008Aa-BQ for qemu-devel@archiver.kernel.org; Thu, 03 Sep 2020 06:59:21 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:59246) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1kDmun-0002rG-7t for qemu-devel@nongnu.org; Thu, 03 Sep 2020 06:56:25 -0400 Received: from mx2.suse.de ([195.135.220.15]:48694) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1kDmuh-0004W1-Qy for qemu-devel@nongnu.org; Thu, 03 Sep 2020 06:56:24 -0400 X-Virus-Scanned: by amavisd-new at test-mx.suse.de Received: from relay2.suse.de (unknown [195.135.221.27]) by mx2.suse.de (Postfix) with ESMTP id 9E8D4B15A; Thu, 3 Sep 2020 10:56:18 +0000 (UTC) From: Claudio Fontana To: Paolo Bonzini , Richard Henderson , =?utf-8?q?Alex_Benn=C3=A9e?= , Peter Maydell , =?utf-8?q?Philippe_Mathieu-?= =?utf-8?b?RGF1ZMOp?= , Roman Bolshakov Subject: [PATCH v7 01/16] cpu-timers, icount: new modules Date: Thu, 3 Sep 2020 12:55:59 +0200 Message-Id: <20200903105614.17772-2-cfontana@suse.de> X-Mailer: git-send-email 2.26.2 In-Reply-To: <20200903105614.17772-1-cfontana@suse.de> References: <20200903105614.17772-1-cfontana@suse.de> MIME-Version: 1.0 Received-SPF: pass client-ip=195.135.220.15; envelope-from=cfontana@suse.de; helo=mx2.suse.de X-detected-operating-system: by eggs.gnu.org: First seen = 2020/09/03 00:06:01 X-ACL-Warn: Detected OS = Linux 2.2.x-3.x (no timestamps) [generic] X-Spam_score_int: -41 X-Spam_score: -4.2 X-Spam_bar: ---- X-Spam_report: (-4.2 / 5.0 requ) BAYES_00=-1.9, RCVD_IN_DNSWL_MED=-2.3, RCVD_IN_MSPIKE_H3=0.001, RCVD_IN_MSPIKE_WL=0.001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Laurent Vivier , Thomas Huth , Alberto Garcia , Eduardo Habkost , Pavel Dovgalyuk , Marcelo Tosatti , Richard Henderson , qemu-devel@nongnu.org, Markus Armbruster , Colin Xu , Wenchao Wang , haxm-team@intel.com, Sunil Muthuswamy , Claudio Fontana Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: "Qemu-devel" refactoring of cpus.c continues with cpu timer state extraction. cpu-timers: responsible for the softmmu cpu timers state, including cpu clocks and ticks. icount: counts the TCG instructions executed. As such it is specific to the TCG accelerator. Therefore, it is built only under CONFIG_TCG. One complication is due to qtest, which uses an icount field to warp time as part of qtest (qtest_clock_warp). In order to solve this problem, provide a separate counter for qtest. This requires fixing assumptions scattered in the code that qtest_enabled() implies icount_enabled(), checking each specific case. Signed-off-by: Claudio Fontana Reviewed-by: Richard Henderson [remove redundant initialization with qemu_spice_init] Reviewed-by: Alex Bennée [fix lingering calls to icount_get] Signed-off-by: Claudio Fontana --- MAINTAINERS | 2 + accel/qtest.c | 6 +- accel/tcg/cpu-exec.c | 39 +- accel/tcg/tcg-all.c | 7 +- accel/tcg/translate-all.c | 3 +- dma-helpers.c | 4 +- exec.c | 4 - hw/core/ptimer.c | 8 +- hw/i386/x86.c | 1 + include/exec/cpu-all.h | 4 + include/exec/exec-all.h | 4 +- include/qemu/timer.h | 24 +- include/sysemu/cpu-timers.h | 87 ++++ include/sysemu/cpus.h | 12 +- include/sysemu/qtest.h | 2 + replay/replay.c | 4 +- softmmu/cpu-timers.c | 284 +++++++++++++ softmmu/cpus.c | 744 +---------------------------------- softmmu/icount.c | 492 +++++++++++++++++++++++ softmmu/meson.build | 10 +- softmmu/qtest.c | 34 +- softmmu/timers-state.h | 69 ++++ softmmu/vl.c | 6 +- stubs/clock-warp.c | 7 - stubs/cpu-get-clock.c | 3 +- stubs/cpu-get-icount.c | 21 - stubs/icount.c | 45 +++ stubs/meson.build | 4 +- stubs/qemu-timer-notify-cb.c | 8 + stubs/qtest.c | 5 + target/alpha/translate.c | 3 +- target/arm/helper.c | 3 +- target/riscv/csr.c | 4 +- tests/ptimer-test-stubs.c | 5 +- tests/test-timed-average.c | 2 +- util/main-loop.c | 12 +- util/qemu-timer.c | 10 +- 37 files changed, 1135 insertions(+), 847 deletions(-) create mode 100644 include/sysemu/cpu-timers.h create mode 100644 softmmu/cpu-timers.c create mode 100644 softmmu/icount.c create mode 100644 softmmu/timers-state.h delete mode 100644 stubs/clock-warp.c delete mode 100644 stubs/cpu-get-icount.c create mode 100644 stubs/icount.c create mode 100644 stubs/qemu-timer-notify-cb.c diff --git a/MAINTAINERS b/MAINTAINERS index b5ba553ee0..b3447056ed 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -2287,6 +2287,8 @@ F: softmmu/vl.c F: softmmu/main.c F: softmmu/cpus.c F: softmmu/cpu-throttle.c +F: softmmu/cpu-timers.c +F: softmmu/icount.c F: qapi/run-state.json Human Monitor (HMP) diff --git a/accel/qtest.c b/accel/qtest.c index 5b88f55921..119d0f16a4 100644 --- a/accel/qtest.c +++ b/accel/qtest.c @@ -19,14 +19,10 @@ #include "sysemu/accel.h" #include "sysemu/qtest.h" #include "sysemu/cpus.h" +#include "sysemu/cpu-timers.h" static int qtest_init_accel(MachineState *ms) { - QemuOpts *opts = qemu_opts_create(qemu_find_opts("icount"), NULL, 0, - &error_abort); - qemu_opt_set(opts, "shift", "0", &error_abort); - configure_icount(opts, &error_abort); - qemu_opts_del(opts); return 0; } diff --git a/accel/tcg/cpu-exec.c b/accel/tcg/cpu-exec.c index 66d38f9d85..ee9d22d92c 100644 --- a/accel/tcg/cpu-exec.c +++ b/accel/tcg/cpu-exec.c @@ -19,6 +19,7 @@ #include "qemu/osdep.h" #include "qemu-common.h" +#include "qemu/qemu-print.h" #include "cpu.h" #include "trace.h" #include "disas/disas.h" @@ -36,6 +37,8 @@ #include "hw/i386/apic.h" #endif #include "sysemu/cpus.h" +#include "exec/cpu-all.h" +#include "sysemu/cpu-timers.h" #include "sysemu/replay.h" /* -icount align implementation. */ @@ -56,6 +59,9 @@ typedef struct SyncClocks { #define MAX_DELAY_PRINT_RATE 2000000000LL #define MAX_NB_PRINTS 100 +static int64_t max_delay; +static int64_t max_advance; + static void align_clocks(SyncClocks *sc, CPUState *cpu) { int64_t cpu_icount; @@ -98,9 +104,9 @@ static void print_delay(const SyncClocks *sc) (-sc->diff_clk / (float)1000000000LL < (threshold_delay - THRESHOLD_REDUCE))) { threshold_delay = (-sc->diff_clk / 1000000000LL) + 1; - printf("Warning: The guest is now late by %.1f to %.1f seconds\n", - threshold_delay - 1, - threshold_delay); + qemu_printf("Warning: The guest is now late by %.1f to %.1f seconds\n", + threshold_delay - 1, + threshold_delay); nb_prints++; last_realtime_clock = sc->realtime_clock; } @@ -614,7 +620,7 @@ static inline bool cpu_handle_interrupt(CPUState *cpu, /* Finally, check if we need to exit to the main loop. */ if (unlikely(atomic_read(&cpu->exit_request)) - || (use_icount + || (icount_enabled() && cpu_neg(cpu)->icount_decr.u16.low + cpu->icount_extra == 0)) { atomic_set(&cpu->exit_request, 0); if (cpu->exception_index == -1) { @@ -655,7 +661,7 @@ static inline void cpu_loop_exec_tb(CPUState *cpu, TranslationBlock *tb, } /* Instruction counter expired. */ - assert(use_icount); + assert(icount_enabled()); #ifndef CONFIG_USER_ONLY /* Ensure global icount has gone forward */ cpu_update_icount(cpu); @@ -758,3 +764,26 @@ int cpu_exec(CPUState *cpu) return ret; } + +#ifndef CONFIG_USER_ONLY + +void dump_drift_info(void) +{ + if (!icount_enabled()) { + return; + } + + qemu_printf("Host - Guest clock %"PRIi64" ms\n", + (cpu_get_clock() - cpu_get_icount()) / SCALE_MS); + if (icount_align_option) { + qemu_printf("Max guest delay %"PRIi64" ms\n", + -max_delay / SCALE_MS); + qemu_printf("Max guest advance %"PRIi64" ms\n", + max_advance / SCALE_MS); + } else { + qemu_printf("Max guest delay NA\n"); + qemu_printf("Max guest advance NA\n"); + } +} + +#endif /* !CONFIG_USER_ONLY */ diff --git a/accel/tcg/tcg-all.c b/accel/tcg/tcg-all.c index eace2c113b..f1feea20c8 100644 --- a/accel/tcg/tcg-all.c +++ b/accel/tcg/tcg-all.c @@ -29,6 +29,7 @@ #include "qom/object.h" #include "cpu.h" #include "sysemu/cpus.h" +#include "sysemu/cpu-timers.h" #include "qemu/main-loop.h" #include "tcg/tcg.h" #include "qapi/error.h" @@ -65,7 +66,7 @@ static void tcg_handle_interrupt(CPUState *cpu, int mask) qemu_cpu_kick(cpu); } else { atomic_set(&cpu_neg(cpu)->icount_decr.u16.high, -1); - if (use_icount && + if (icount_enabled() && !cpu->can_do_io && (mask & ~old_mask) != 0) { cpu_abort(cpu, "Raised interrupt while not in I/O function"); @@ -104,7 +105,7 @@ static bool check_tcg_memory_orders_compatible(void) static bool default_mttcg_enabled(void) { - if (use_icount || TCG_OVERSIZED_GUEST) { + if (icount_enabled() || TCG_OVERSIZED_GUEST) { return false; } else { #ifdef TARGET_SUPPORTS_MTTCG @@ -146,7 +147,7 @@ static void tcg_set_thread(Object *obj, const char *value, Error **errp) if (strcmp(value, "multi") == 0) { if (TCG_OVERSIZED_GUEST) { error_setg(errp, "No MTTCG when guest word size > hosts"); - } else if (use_icount) { + } else if (icount_enabled()) { error_setg(errp, "No MTTCG when icount is enabled"); } else { #ifndef TARGET_SUPPORTS_MTTCG diff --git a/accel/tcg/translate-all.c b/accel/tcg/translate-all.c index 2d83013633..c39ff7b047 100644 --- a/accel/tcg/translate-all.c +++ b/accel/tcg/translate-all.c @@ -57,6 +57,7 @@ #include "qemu/main-loop.h" #include "exec/log.h" #include "sysemu/cpus.h" +#include "sysemu/cpu-timers.h" #include "sysemu/tcg.h" /* #define DEBUG_TB_INVALIDATE */ @@ -369,7 +370,7 @@ static int cpu_restore_state_from_tb(CPUState *cpu, TranslationBlock *tb, found: if (reset_icount && (tb_cflags(tb) & CF_USE_ICOUNT)) { - assert(use_icount); + assert(icount_enabled()); /* Reset the cycle counter to the start of the block and shift if to the number of actually executed instructions */ cpu_neg(cpu)->icount_decr.u16.low += num_insns - i; diff --git a/dma-helpers.c b/dma-helpers.c index 41ef24a63b..03c92e0cc6 100644 --- a/dma-helpers.c +++ b/dma-helpers.c @@ -13,7 +13,7 @@ #include "trace/trace-root.h" #include "qemu/thread.h" #include "qemu/main-loop.h" -#include "sysemu/cpus.h" +#include "sysemu/cpu-timers.h" #include "qemu/range.h" /* #define DEBUG_IOMMU */ @@ -151,7 +151,7 @@ static void dma_blk_cb(void *opaque, int ret) * from several sectors. This code splits all SGs into several * groups. SGs in every group do not overlap. */ - if (mem && use_icount && dbs->dir == DMA_DIRECTION_FROM_DEVICE) { + if (mem && icount_enabled() && dbs->dir == DMA_DIRECTION_FROM_DEVICE) { int i; for (i = 0 ; i < dbs->iov.niov ; ++i) { if (ranges_overlap((intptr_t)dbs->iov.iov[i].iov_base, diff --git a/exec.c b/exec.c index 7683afb6a8..9da1b3db32 100644 --- a/exec.c +++ b/exec.c @@ -102,10 +102,6 @@ uintptr_t qemu_host_page_size; intptr_t qemu_host_page_mask; #if !defined(CONFIG_USER_ONLY) -/* 0 = Do not count executed instructions. - 1 = Precise instruction counting. - 2 = Adaptive rate instruction counting. */ -int use_icount; typedef struct PhysPageEntry PhysPageEntry; diff --git a/hw/core/ptimer.c b/hw/core/ptimer.c index b5a54e2536..c6d2beb1da 100644 --- a/hw/core/ptimer.c +++ b/hw/core/ptimer.c @@ -7,11 +7,11 @@ */ #include "qemu/osdep.h" -#include "qemu/timer.h" #include "hw/ptimer.h" #include "migration/vmstate.h" #include "qemu/host-utils.h" #include "sysemu/replay.h" +#include "sysemu/cpu-timers.h" #include "sysemu/qtest.h" #include "block/aio.h" #include "sysemu/cpus.h" @@ -134,7 +134,8 @@ static void ptimer_reload(ptimer_state *s, int delta_adjust) * on the current generation of host machines. */ - if (s->enabled == 1 && (delta * period < 10000) && !use_icount) { + if (s->enabled == 1 && (delta * period < 10000) && + !icount_enabled() && !qtest_enabled()) { period = 10000 / delta; period_frac = 0; } @@ -217,7 +218,8 @@ uint64_t ptimer_get_count(ptimer_state *s) uint32_t period_frac = s->period_frac; uint64_t period = s->period; - if (!oneshot && (s->delta * period < 10000) && !use_icount) { + if (!oneshot && (s->delta * period < 10000) && + !icount_enabled() && !qtest_enabled()) { period = 10000 / s->delta; period_frac = 0; } diff --git a/hw/i386/x86.c b/hw/i386/x86.c index c1954db152..309632c948 100644 --- a/hw/i386/x86.c +++ b/hw/i386/x86.c @@ -34,6 +34,7 @@ #include "sysemu/numa.h" #include "sysemu/replay.h" #include "sysemu/sysemu.h" +#include "sysemu/cpu-timers.h" #include "trace.h" #include "hw/i386/x86.h" diff --git a/include/exec/cpu-all.h b/include/exec/cpu-all.h index f6439c4705..61e13b5038 100644 --- a/include/exec/cpu-all.h +++ b/include/exec/cpu-all.h @@ -407,8 +407,12 @@ static inline bool tlb_hit(target_ulong tlb_addr, target_ulong addr) return tlb_hit_page(tlb_addr, addr & TARGET_PAGE_MASK); } +#ifdef CONFIG_TCG +void dump_drift_info(void); void dump_exec_info(void); void dump_opcount_info(void); +#endif /* CONFIG_TCG */ + #endif /* !CONFIG_USER_ONLY */ /* Returns: 0 on success, -1 on error */ diff --git a/include/exec/exec-all.h b/include/exec/exec-all.h index 3cf88272df..e019b505a5 100644 --- a/include/exec/exec-all.h +++ b/include/exec/exec-all.h @@ -25,7 +25,7 @@ #ifdef CONFIG_TCG #include "exec/cpu_ldst.h" #endif -#include "sysemu/cpus.h" +#include "sysemu/cpu-timers.h" /* allow to see translation results - the slowdown should be negligible, so we leave it */ #define DEBUG_DISAS @@ -497,7 +497,7 @@ static inline uint32_t tb_cflags(const TranslationBlock *tb) static inline uint32_t curr_cflags(void) { return (parallel_cpus ? CF_PARALLEL : 0) - | (use_icount ? CF_USE_ICOUNT : 0); + | (icount_enabled() ? CF_USE_ICOUNT : 0); } /* TranslationBlock invalidate API */ diff --git a/include/qemu/timer.h b/include/qemu/timer.h index 6a8b48b5a9..2f7afc1f68 100644 --- a/include/qemu/timer.h +++ b/include/qemu/timer.h @@ -166,8 +166,8 @@ bool qemu_clock_expired(QEMUClockType type); * * Determine whether a clock should be used for deadline * calculations. Some clocks, for instance vm_clock with - * use_icount set, do not count in nanoseconds. Such clocks - * are not used for deadline calculations, and are presumed + * icount_enabled() set, do not count in nanoseconds. + * Such clocks are not used for deadline calculations, and are presumed * to interrupt any poll using qemu_notify/aio_notify * etc. * @@ -224,13 +224,6 @@ void qemu_clock_notify(QEMUClockType type); */ void qemu_clock_enable(QEMUClockType type, bool enabled); -/** - * qemu_start_warp_timer: - * - * Starts a timer for virtual clock update - */ -void qemu_start_warp_timer(void); - /** * qemu_clock_run_timers: * @type: clock on which to operate @@ -791,12 +784,6 @@ static inline int64_t qemu_soonest_timeout(int64_t timeout1, int64_t timeout2) */ void init_clocks(QEMUTimerListNotifyCB *notify_cb); -int64_t cpu_get_ticks(void); -/* Caller must hold BQL */ -void cpu_enable_ticks(void); -/* Caller must hold BQL */ -void cpu_disable_ticks(void); - static inline int64_t get_max_clock_jump(void) { /* This should be small enough to prevent excessive interrupts from being @@ -850,13 +837,6 @@ static inline int64_t get_clock(void) } #endif -/* icount */ -int64_t cpu_get_icount_raw(void); -int64_t cpu_get_icount(void); -int64_t cpu_get_clock(void); -int64_t cpu_icount_to_ns(int64_t icount); -void cpu_update_icount(CPUState *cpu); - /*******************************************/ /* host CPU ticks (if available) */ diff --git a/include/sysemu/cpu-timers.h b/include/sysemu/cpu-timers.h new file mode 100644 index 0000000000..4b621fea51 --- /dev/null +++ b/include/sysemu/cpu-timers.h @@ -0,0 +1,87 @@ +/* + * CPU timers state API + * + * Copyright 2020 SUSE LLC + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + * + */ +#ifndef SYSEMU_CPU_TIMERS_H +#define SYSEMU_CPU_TIMERS_H + +#include "qemu/timer.h" + +/* init the whole cpu timers API, including icount, ticks, and cpu_throttle */ +void cpu_timers_init(void); + +/* icount - Instruction Counter API */ + +/* + * icount enablement state: + * + * 0 = Disabled - Do not count executed instructions. + * 1 = Enabled - Fixed conversion of insn to ns via "shift" option + * 2 = Enabled - Runtime adaptive algorithm to compute shift + */ +#ifdef CONFIG_TCG +extern int use_icount; +#define icount_enabled() (use_icount) +#else +#define icount_enabled() 0 +#endif + +/* + * Update the icount with the executed instructions. Called by + * cpus-tcg vCPU thread so the main-loop can see time has moved forward. + */ +void cpu_update_icount(CPUState *cpu); + +/* get raw icount value */ +int64_t cpu_get_icount_raw(void); + +/* return the virtual CPU time in ns, based on the instruction counter. */ +int64_t cpu_get_icount(void); +/* + * convert an instruction counter value to ns, based on the icount shift. + * This shift is set as a fixed value with the icount "shift" option + * (precise mode), or it is constantly approximated and corrected at + * runtime in adaptive mode. + */ +int64_t cpu_icount_to_ns(int64_t icount); + +/* configure the icount options, including "shift" */ +void configure_icount(QemuOpts *opts, Error **errp); + +/* used by tcg vcpu thread to calc icount budget */ +int64_t qemu_icount_round(int64_t count); + +/* if the CPUs are idle, start accounting real time to virtual clock. */ +void qemu_start_warp_timer(void); +void qemu_account_warp_timer(void); + +/* + * CPU Ticks and Clock + */ + +/* Caller must hold BQL */ +void cpu_enable_ticks(void); +/* Caller must hold BQL */ +void cpu_disable_ticks(void); + +/* + * return the time elapsed in VM between vm_start and vm_stop. Unless + * icount is active, cpu_get_ticks() uses units of the host CPU cycle + * counter. + */ +int64_t cpu_get_ticks(void); + +/* + * Returns the monotonic time elapsed in VM, i.e., + * the time between vm_start and vm_stop + */ +int64_t cpu_get_clock(void); + +void qemu_timer_notify_cb(void *opaque, QEMUClockType type); + +#endif /* SYSEMU_CPU_TIMERS_H */ diff --git a/include/sysemu/cpus.h b/include/sysemu/cpus.h index 3c1da6a018..149de000a0 100644 --- a/include/sysemu/cpus.h +++ b/include/sysemu/cpus.h @@ -4,33 +4,23 @@ #include "qemu/timer.h" /* cpus.c */ +bool all_cpu_threads_idle(void); bool qemu_in_vcpu_thread(void); void qemu_init_cpu_loop(void); void resume_all_vcpus(void); void pause_all_vcpus(void); void cpu_stop_current(void); -void cpu_ticks_init(void); -void configure_icount(QemuOpts *opts, Error **errp); -extern int use_icount; extern int icount_align_option; -/* drift information for info jit command */ -extern int64_t max_delay; -extern int64_t max_advance; -void dump_drift_info(void); - /* Unblock cpu */ void qemu_cpu_kick_self(void); -void qemu_timer_notify_cb(void *opaque, QEMUClockType type); void cpu_synchronize_all_states(void); void cpu_synchronize_all_post_reset(void); void cpu_synchronize_all_post_init(void); void cpu_synchronize_all_pre_loadvm(void); -void qtest_clock_warp(int64_t dest); - #ifndef CONFIG_USER_ONLY /* vl.c */ /* *-user doesn't have configurable SMP topology */ diff --git a/include/sysemu/qtest.h b/include/sysemu/qtest.h index eedd3664f0..4c53537ef3 100644 --- a/include/sysemu/qtest.h +++ b/include/sysemu/qtest.h @@ -30,4 +30,6 @@ void qtest_server_set_send_handler(void (*send)(void *, const char *), void *opaque); void qtest_server_inproc_recv(void *opaque, const char *buf); +int64_t qtest_get_virtual_clock(void); + #endif diff --git a/replay/replay.c b/replay/replay.c index 83ed9e0e24..7e4a1ba78e 100644 --- a/replay/replay.c +++ b/replay/replay.c @@ -11,10 +11,10 @@ #include "qemu/osdep.h" #include "qapi/error.h" +#include "sysemu/cpu-timers.h" #include "sysemu/replay.h" #include "sysemu/runstate.h" #include "replay-internal.h" -#include "qemu/timer.h" #include "qemu/main-loop.h" #include "qemu/option.h" #include "sysemu/cpus.h" @@ -345,7 +345,7 @@ void replay_start(void) error_reportf_err(replay_blockers->data, "Record/replay: "); exit(1); } - if (!use_icount) { + if (!icount_enabled()) { error_report("Please enable icount to use record/replay"); exit(1); } diff --git a/softmmu/cpu-timers.c b/softmmu/cpu-timers.c new file mode 100644 index 0000000000..6c6c56090f --- /dev/null +++ b/softmmu/cpu-timers.c @@ -0,0 +1,284 @@ +/* + * QEMU System Emulator + * + * Copyright (c) 2003-2008 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "qemu/osdep.h" +#include "qemu-common.h" +#include "qemu/cutils.h" +#include "migration/vmstate.h" +#include "qapi/error.h" +#include "qemu/error-report.h" +#include "exec/exec-all.h" +#include "sysemu/cpus.h" +#include "sysemu/qtest.h" +#include "qemu/main-loop.h" +#include "qemu/option.h" +#include "qemu/seqlock.h" +#include "sysemu/replay.h" +#include "sysemu/runstate.h" +#include "hw/core/cpu.h" +#include "sysemu/cpu-timers.h" +#include "sysemu/cpu-throttle.h" +#include "timers-state.h" + +/* clock and ticks */ + +static int64_t cpu_get_ticks_locked(void) +{ + int64_t ticks = timers_state.cpu_ticks_offset; + if (timers_state.cpu_ticks_enabled) { + ticks += cpu_get_host_ticks(); + } + + if (timers_state.cpu_ticks_prev > ticks) { + /* Non increasing ticks may happen if the host uses software suspend. */ + timers_state.cpu_ticks_offset += timers_state.cpu_ticks_prev - ticks; + ticks = timers_state.cpu_ticks_prev; + } + + timers_state.cpu_ticks_prev = ticks; + return ticks; +} + +/* + * return the time elapsed in VM between vm_start and vm_stop. Unless + * icount is active, cpu_get_ticks() uses units of the host CPU cycle + * counter. + */ +int64_t cpu_get_ticks(void) +{ + int64_t ticks; + + if (icount_enabled()) { + return cpu_get_icount(); + } + + qemu_spin_lock(&timers_state.vm_clock_lock); + ticks = cpu_get_ticks_locked(); + qemu_spin_unlock(&timers_state.vm_clock_lock); + return ticks; +} + +int64_t cpu_get_clock_locked(void) +{ + int64_t time; + + time = timers_state.cpu_clock_offset; + if (timers_state.cpu_ticks_enabled) { + time += get_clock(); + } + + return time; +} + +/* + * Return the monotonic time elapsed in VM, i.e., + * the time between vm_start and vm_stop + */ +int64_t cpu_get_clock(void) +{ + int64_t ti; + unsigned start; + + do { + start = seqlock_read_begin(&timers_state.vm_clock_seqlock); + ti = cpu_get_clock_locked(); + } while (seqlock_read_retry(&timers_state.vm_clock_seqlock, start)); + + return ti; +} + +/* + * enable cpu_get_ticks() + * Caller must hold BQL which serves as mutex for vm_clock_seqlock. + */ +void cpu_enable_ticks(void) +{ + seqlock_write_lock(&timers_state.vm_clock_seqlock, + &timers_state.vm_clock_lock); + if (!timers_state.cpu_ticks_enabled) { + timers_state.cpu_ticks_offset -= cpu_get_host_ticks(); + timers_state.cpu_clock_offset -= get_clock(); + timers_state.cpu_ticks_enabled = 1; + } + seqlock_write_unlock(&timers_state.vm_clock_seqlock, + &timers_state.vm_clock_lock); +} + +/* + * disable cpu_get_ticks() : the clock is stopped. You must not call + * cpu_get_ticks() after that. + * Caller must hold BQL which serves as mutex for vm_clock_seqlock. + */ +void cpu_disable_ticks(void) +{ + seqlock_write_lock(&timers_state.vm_clock_seqlock, + &timers_state.vm_clock_lock); + if (timers_state.cpu_ticks_enabled) { + timers_state.cpu_ticks_offset += cpu_get_host_ticks(); + timers_state.cpu_clock_offset = cpu_get_clock_locked(); + timers_state.cpu_ticks_enabled = 0; + } + seqlock_write_unlock(&timers_state.vm_clock_seqlock, + &timers_state.vm_clock_lock); +} + +static bool icount_state_needed(void *opaque) +{ + return icount_enabled(); +} + +static bool warp_timer_state_needed(void *opaque) +{ + TimersState *s = opaque; + return s->icount_warp_timer != NULL; +} + +static bool adjust_timers_state_needed(void *opaque) +{ + TimersState *s = opaque; + return s->icount_rt_timer != NULL; +} + +static bool shift_state_needed(void *opaque) +{ + return icount_enabled() == 2; +} + +/* + * Subsection for warp timer migration is optional, because may not be created + */ +static const VMStateDescription icount_vmstate_warp_timer = { + .name = "timer/icount/warp_timer", + .version_id = 1, + .minimum_version_id = 1, + .needed = warp_timer_state_needed, + .fields = (VMStateField[]) { + VMSTATE_INT64(vm_clock_warp_start, TimersState), + VMSTATE_TIMER_PTR(icount_warp_timer, TimersState), + VMSTATE_END_OF_LIST() + } +}; + +static const VMStateDescription icount_vmstate_adjust_timers = { + .name = "timer/icount/timers", + .version_id = 1, + .minimum_version_id = 1, + .needed = adjust_timers_state_needed, + .fields = (VMStateField[]) { + VMSTATE_TIMER_PTR(icount_rt_timer, TimersState), + VMSTATE_TIMER_PTR(icount_vm_timer, TimersState), + VMSTATE_END_OF_LIST() + } +}; + +static const VMStateDescription icount_vmstate_shift = { + .name = "timer/icount/shift", + .version_id = 1, + .minimum_version_id = 1, + .needed = shift_state_needed, + .fields = (VMStateField[]) { + VMSTATE_INT16(icount_time_shift, TimersState), + VMSTATE_END_OF_LIST() + } +}; + +/* + * This is a subsection for icount migration. + */ +static const VMStateDescription icount_vmstate_timers = { + .name = "timer/icount", + .version_id = 1, + .minimum_version_id = 1, + .needed = icount_state_needed, + .fields = (VMStateField[]) { + VMSTATE_INT64(qemu_icount_bias, TimersState), + VMSTATE_INT64(qemu_icount, TimersState), + VMSTATE_END_OF_LIST() + }, + .subsections = (const VMStateDescription * []) { + &icount_vmstate_warp_timer, + &icount_vmstate_adjust_timers, + &icount_vmstate_shift, + NULL + } +}; + +static const VMStateDescription vmstate_timers = { + .name = "timer", + .version_id = 2, + .minimum_version_id = 1, + .fields = (VMStateField[]) { + VMSTATE_INT64(cpu_ticks_offset, TimersState), + VMSTATE_UNUSED(8), + VMSTATE_INT64_V(cpu_clock_offset, TimersState, 2), + VMSTATE_END_OF_LIST() + }, + .subsections = (const VMStateDescription * []) { + &icount_vmstate_timers, + NULL + } +}; + +static void do_nothing(CPUState *cpu, run_on_cpu_data unused) +{ +} + +void qemu_timer_notify_cb(void *opaque, QEMUClockType type) +{ + if (!icount_enabled() || type != QEMU_CLOCK_VIRTUAL) { + qemu_notify_event(); + return; + } + + if (qemu_in_vcpu_thread()) { + /* + * A CPU is currently running; kick it back out to the + * tcg_cpu_exec() loop so it will recalculate its + * icount deadline immediately. + */ + qemu_cpu_kick(current_cpu); + } else if (first_cpu) { + /* + * qemu_cpu_kick is not enough to kick a halted CPU out of + * qemu_tcg_wait_io_event. async_run_on_cpu, instead, + * causes cpu_thread_is_idle to return false. This way, + * handle_icount_deadline can run. + * If we have no CPUs at all for some reason, we don't + * need to do anything. + */ + async_run_on_cpu(first_cpu, do_nothing, RUN_ON_CPU_NULL); + } +} + +TimersState timers_state; + +/* initialize timers state and the cpu throttle for convenience */ +void cpu_timers_init(void) +{ + seqlock_init(&timers_state.vm_clock_seqlock); + qemu_spin_init(&timers_state.vm_clock_lock); + vmstate_register(NULL, 0, &vmstate_timers, &timers_state); + + cpu_throttle_init(); +} diff --git a/softmmu/cpus.c b/softmmu/cpus.c index a802e899ab..773018ef1a 100644 --- a/softmmu/cpus.c +++ b/softmmu/cpus.c @@ -58,11 +58,10 @@ #include "hw/nmi.h" #include "sysemu/replay.h" #include "sysemu/runstate.h" +#include "sysemu/cpu-timers.h" #include "hw/boards.h" #include "hw/hw.h" -#include "sysemu/cpu-throttle.h" - #ifdef CONFIG_LINUX #include @@ -83,9 +82,6 @@ static QemuMutex qemu_global_mutex; -int64_t max_delay; -int64_t max_advance; - bool cpu_is_stopped(CPUState *cpu) { return cpu->stopped || !runstate_is_running(); @@ -116,7 +112,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; @@ -128,688 +124,9 @@ static bool all_cpu_threads_idle(void) return true; } -/***********************************************************/ -/* guest cycle counter */ - -/* Protected by TimersState seqlock */ - -static bool icount_sleep = true; -/* Arbitrarily pick 1MIPS as the minimum allowable speed. */ -#define MAX_ICOUNT_SHIFT 10 - -typedef struct TimersState { - /* Protected by BQL. */ - int64_t cpu_ticks_prev; - int64_t cpu_ticks_offset; - - /* Protect fields that can be respectively read outside the - * BQL, and written from multiple threads. - */ - QemuSeqLock vm_clock_seqlock; - QemuSpin vm_clock_lock; - - int16_t cpu_ticks_enabled; - - /* Conversion factor from emulated instructions to virtual clock ticks. */ - int16_t icount_time_shift; - - /* Compensate for varying guest execution speed. */ - int64_t qemu_icount_bias; - - int64_t vm_clock_warp_start; - int64_t cpu_clock_offset; - - /* Only written by TCG thread */ - int64_t qemu_icount; - - /* for adjusting icount */ - QEMUTimer *icount_rt_timer; - QEMUTimer *icount_vm_timer; - QEMUTimer *icount_warp_timer; -} TimersState; - -static TimersState timers_state; bool mttcg_enabled; -/* The current number of executed instructions is based on what we - * originally budgeted minus the current state of the decrementing - * icount counters in extra/u16.low. - */ -static int64_t cpu_get_icount_executed(CPUState *cpu) -{ - return (cpu->icount_budget - - (cpu_neg(cpu)->icount_decr.u16.low + cpu->icount_extra)); -} - -/* - * Update the global shared timer_state.qemu_icount to take into - * account executed instructions. This is done by the TCG vCPU - * thread so the main-loop can see time has moved forward. - */ -static void cpu_update_icount_locked(CPUState *cpu) -{ - int64_t executed = cpu_get_icount_executed(cpu); - cpu->icount_budget -= executed; - - atomic_set_i64(&timers_state.qemu_icount, - timers_state.qemu_icount + executed); -} - -/* - * Update the global shared timer_state.qemu_icount to take into - * account executed instructions. This is done by the TCG vCPU - * thread so the main-loop can see time has moved forward. - */ -void cpu_update_icount(CPUState *cpu) -{ - seqlock_write_lock(&timers_state.vm_clock_seqlock, - &timers_state.vm_clock_lock); - cpu_update_icount_locked(cpu); - seqlock_write_unlock(&timers_state.vm_clock_seqlock, - &timers_state.vm_clock_lock); -} - -static int64_t cpu_get_icount_raw_locked(void) -{ - CPUState *cpu = current_cpu; - - if (cpu && cpu->running) { - if (!cpu->can_do_io) { - error_report("Bad icount read"); - exit(1); - } - /* Take into account what has run */ - cpu_update_icount_locked(cpu); - } - /* The read is protected by the seqlock, but needs atomic64 to avoid UB */ - return atomic_read_i64(&timers_state.qemu_icount); -} - -static int64_t cpu_get_icount_locked(void) -{ - int64_t icount = cpu_get_icount_raw_locked(); - return atomic_read_i64(&timers_state.qemu_icount_bias) + - cpu_icount_to_ns(icount); -} - -int64_t cpu_get_icount_raw(void) -{ - int64_t icount; - unsigned start; - - do { - start = seqlock_read_begin(&timers_state.vm_clock_seqlock); - icount = cpu_get_icount_raw_locked(); - } while (seqlock_read_retry(&timers_state.vm_clock_seqlock, start)); - - return icount; -} - -/* Return the virtual CPU time, based on the instruction counter. */ -int64_t cpu_get_icount(void) -{ - int64_t icount; - unsigned start; - - do { - start = seqlock_read_begin(&timers_state.vm_clock_seqlock); - icount = cpu_get_icount_locked(); - } while (seqlock_read_retry(&timers_state.vm_clock_seqlock, start)); - - return icount; -} - -int64_t cpu_icount_to_ns(int64_t icount) -{ - return icount << atomic_read(&timers_state.icount_time_shift); -} - -static int64_t cpu_get_ticks_locked(void) -{ - int64_t ticks = timers_state.cpu_ticks_offset; - if (timers_state.cpu_ticks_enabled) { - ticks += cpu_get_host_ticks(); - } - - if (timers_state.cpu_ticks_prev > ticks) { - /* Non increasing ticks may happen if the host uses software suspend. */ - timers_state.cpu_ticks_offset += timers_state.cpu_ticks_prev - ticks; - ticks = timers_state.cpu_ticks_prev; - } - - timers_state.cpu_ticks_prev = ticks; - return ticks; -} - -/* return the time elapsed in VM between vm_start and vm_stop. Unless - * icount is active, cpu_get_ticks() uses units of the host CPU cycle - * counter. - */ -int64_t cpu_get_ticks(void) -{ - int64_t ticks; - - if (use_icount) { - return cpu_get_icount(); - } - - qemu_spin_lock(&timers_state.vm_clock_lock); - ticks = cpu_get_ticks_locked(); - qemu_spin_unlock(&timers_state.vm_clock_lock); - return ticks; -} - -static int64_t cpu_get_clock_locked(void) -{ - int64_t time; - - time = timers_state.cpu_clock_offset; - if (timers_state.cpu_ticks_enabled) { - time += get_clock(); - } - - return time; -} - -/* Return the monotonic time elapsed in VM, i.e., - * the time between vm_start and vm_stop - */ -int64_t cpu_get_clock(void) -{ - int64_t ti; - unsigned start; - - do { - start = seqlock_read_begin(&timers_state.vm_clock_seqlock); - ti = cpu_get_clock_locked(); - } while (seqlock_read_retry(&timers_state.vm_clock_seqlock, start)); - - return ti; -} - -/* enable cpu_get_ticks() - * Caller must hold BQL which serves as mutex for vm_clock_seqlock. - */ -void cpu_enable_ticks(void) -{ - seqlock_write_lock(&timers_state.vm_clock_seqlock, - &timers_state.vm_clock_lock); - if (!timers_state.cpu_ticks_enabled) { - timers_state.cpu_ticks_offset -= cpu_get_host_ticks(); - timers_state.cpu_clock_offset -= get_clock(); - timers_state.cpu_ticks_enabled = 1; - } - seqlock_write_unlock(&timers_state.vm_clock_seqlock, - &timers_state.vm_clock_lock); -} - -/* disable cpu_get_ticks() : the clock is stopped. You must not call - * cpu_get_ticks() after that. - * Caller must hold BQL which serves as mutex for vm_clock_seqlock. - */ -void cpu_disable_ticks(void) -{ - seqlock_write_lock(&timers_state.vm_clock_seqlock, - &timers_state.vm_clock_lock); - if (timers_state.cpu_ticks_enabled) { - timers_state.cpu_ticks_offset += cpu_get_host_ticks(); - timers_state.cpu_clock_offset = cpu_get_clock_locked(); - timers_state.cpu_ticks_enabled = 0; - } - seqlock_write_unlock(&timers_state.vm_clock_seqlock, - &timers_state.vm_clock_lock); -} - -/* Correlation between real and virtual time is always going to be - fairly approximate, so ignore small variation. - When the guest is idle real and virtual time will be aligned in - the IO wait loop. */ -#define ICOUNT_WOBBLE (NANOSECONDS_PER_SECOND / 10) - -static void icount_adjust(void) -{ - int64_t cur_time; - int64_t cur_icount; - int64_t delta; - - /* Protected by TimersState mutex. */ - static int64_t last_delta; - - /* If the VM is not running, then do nothing. */ - if (!runstate_is_running()) { - return; - } - - seqlock_write_lock(&timers_state.vm_clock_seqlock, - &timers_state.vm_clock_lock); - cur_time = REPLAY_CLOCK_LOCKED(REPLAY_CLOCK_VIRTUAL_RT, - cpu_get_clock_locked()); - cur_icount = cpu_get_icount_locked(); - - delta = cur_icount - cur_time; - /* FIXME: This is a very crude algorithm, somewhat prone to oscillation. */ - if (delta > 0 - && last_delta + ICOUNT_WOBBLE < delta * 2 - && timers_state.icount_time_shift > 0) { - /* The guest is getting too far ahead. Slow time down. */ - atomic_set(&timers_state.icount_time_shift, - timers_state.icount_time_shift - 1); - } - if (delta < 0 - && last_delta - ICOUNT_WOBBLE > delta * 2 - && timers_state.icount_time_shift < MAX_ICOUNT_SHIFT) { - /* The guest is getting too far behind. Speed time up. */ - atomic_set(&timers_state.icount_time_shift, - timers_state.icount_time_shift + 1); - } - last_delta = delta; - atomic_set_i64(&timers_state.qemu_icount_bias, - cur_icount - (timers_state.qemu_icount - << timers_state.icount_time_shift)); - seqlock_write_unlock(&timers_state.vm_clock_seqlock, - &timers_state.vm_clock_lock); -} - -static void icount_adjust_rt(void *opaque) -{ - timer_mod(timers_state.icount_rt_timer, - qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL_RT) + 1000); - icount_adjust(); -} - -static void icount_adjust_vm(void *opaque) -{ - timer_mod(timers_state.icount_vm_timer, - qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + - NANOSECONDS_PER_SECOND / 10); - icount_adjust(); -} - -static int64_t qemu_icount_round(int64_t count) -{ - int shift = atomic_read(&timers_state.icount_time_shift); - return (count + (1 << shift) - 1) >> shift; -} - -static void icount_warp_rt(void) -{ - unsigned seq; - int64_t warp_start; - - /* The icount_warp_timer is rescheduled soon after vm_clock_warp_start - * changes from -1 to another value, so the race here is okay. - */ - do { - seq = seqlock_read_begin(&timers_state.vm_clock_seqlock); - warp_start = timers_state.vm_clock_warp_start; - } while (seqlock_read_retry(&timers_state.vm_clock_seqlock, seq)); - - if (warp_start == -1) { - return; - } - - seqlock_write_lock(&timers_state.vm_clock_seqlock, - &timers_state.vm_clock_lock); - if (runstate_is_running()) { - int64_t clock = REPLAY_CLOCK_LOCKED(REPLAY_CLOCK_VIRTUAL_RT, - cpu_get_clock_locked()); - int64_t warp_delta; - - warp_delta = clock - timers_state.vm_clock_warp_start; - if (use_icount == 2) { - /* - * In adaptive mode, do not let QEMU_CLOCK_VIRTUAL run too - * far ahead of real time. - */ - int64_t cur_icount = cpu_get_icount_locked(); - int64_t delta = clock - cur_icount; - warp_delta = MIN(warp_delta, delta); - } - atomic_set_i64(&timers_state.qemu_icount_bias, - timers_state.qemu_icount_bias + warp_delta); - } - timers_state.vm_clock_warp_start = -1; - seqlock_write_unlock(&timers_state.vm_clock_seqlock, - &timers_state.vm_clock_lock); - - if (qemu_clock_expired(QEMU_CLOCK_VIRTUAL)) { - qemu_clock_notify(QEMU_CLOCK_VIRTUAL); - } -} - -static void icount_timer_cb(void *opaque) -{ - /* No need for a checkpoint because the timer already synchronizes - * with CHECKPOINT_CLOCK_VIRTUAL_RT. - */ - icount_warp_rt(); -} - -void qtest_clock_warp(int64_t dest) -{ - int64_t clock = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); - AioContext *aio_context; - assert(qtest_enabled()); - aio_context = qemu_get_aio_context(); - while (clock < dest) { - int64_t deadline = qemu_clock_deadline_ns_all(QEMU_CLOCK_VIRTUAL, - QEMU_TIMER_ATTR_ALL); - int64_t warp = qemu_soonest_timeout(dest - clock, deadline); - - seqlock_write_lock(&timers_state.vm_clock_seqlock, - &timers_state.vm_clock_lock); - atomic_set_i64(&timers_state.qemu_icount_bias, - timers_state.qemu_icount_bias + warp); - seqlock_write_unlock(&timers_state.vm_clock_seqlock, - &timers_state.vm_clock_lock); - - qemu_clock_run_timers(QEMU_CLOCK_VIRTUAL); - timerlist_run_timers(aio_context->tlg.tl[QEMU_CLOCK_VIRTUAL]); - clock = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); - } - qemu_clock_notify(QEMU_CLOCK_VIRTUAL); -} - -void qemu_start_warp_timer(void) -{ - int64_t clock; - int64_t deadline; - - if (!use_icount) { - return; - } - - /* Nothing to do if the VM is stopped: QEMU_CLOCK_VIRTUAL timers - * do not fire, so computing the deadline does not make sense. - */ - if (!runstate_is_running()) { - return; - } - - if (replay_mode != REPLAY_MODE_PLAY) { - if (!all_cpu_threads_idle()) { - return; - } - - if (qtest_enabled()) { - /* When testing, qtest commands advance icount. */ - return; - } - - replay_checkpoint(CHECKPOINT_CLOCK_WARP_START); - } else { - /* warp clock deterministically in record/replay mode */ - if (!replay_checkpoint(CHECKPOINT_CLOCK_WARP_START)) { - /* vCPU is sleeping and warp can't be started. - It is probably a race condition: notification sent - to vCPU was processed in advance and vCPU went to sleep. - Therefore we have to wake it up for doing someting. */ - if (replay_has_checkpoint()) { - qemu_clock_notify(QEMU_CLOCK_VIRTUAL); - } - return; - } - } - - /* We want to use the earliest deadline from ALL vm_clocks */ - clock = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL_RT); - deadline = qemu_clock_deadline_ns_all(QEMU_CLOCK_VIRTUAL, - ~QEMU_TIMER_ATTR_EXTERNAL); - if (deadline < 0) { - static bool notified; - if (!icount_sleep && !notified) { - warn_report("icount sleep disabled and no active timers"); - notified = true; - } - return; - } - - if (deadline > 0) { - /* - * Ensure QEMU_CLOCK_VIRTUAL proceeds even when the virtual CPU goes to - * sleep. Otherwise, the CPU might be waiting for a future timer - * interrupt to wake it up, but the interrupt never comes because - * the vCPU isn't running any insns and thus doesn't advance the - * QEMU_CLOCK_VIRTUAL. - */ - if (!icount_sleep) { - /* - * We never let VCPUs sleep in no sleep icount mode. - * If there is a pending QEMU_CLOCK_VIRTUAL timer we just advance - * to the next QEMU_CLOCK_VIRTUAL event and notify it. - * It is useful when we want a deterministic execution time, - * isolated from host latencies. - */ - seqlock_write_lock(&timers_state.vm_clock_seqlock, - &timers_state.vm_clock_lock); - atomic_set_i64(&timers_state.qemu_icount_bias, - timers_state.qemu_icount_bias + deadline); - seqlock_write_unlock(&timers_state.vm_clock_seqlock, - &timers_state.vm_clock_lock); - qemu_clock_notify(QEMU_CLOCK_VIRTUAL); - } else { - /* - * We do stop VCPUs and only advance QEMU_CLOCK_VIRTUAL after some - * "real" time, (related to the time left until the next event) has - * passed. The QEMU_CLOCK_VIRTUAL_RT clock will do this. - * This avoids that the warps are visible externally; for example, - * you will not be sending network packets continuously instead of - * every 100ms. - */ - seqlock_write_lock(&timers_state.vm_clock_seqlock, - &timers_state.vm_clock_lock); - if (timers_state.vm_clock_warp_start == -1 - || timers_state.vm_clock_warp_start > clock) { - timers_state.vm_clock_warp_start = clock; - } - seqlock_write_unlock(&timers_state.vm_clock_seqlock, - &timers_state.vm_clock_lock); - timer_mod_anticipate(timers_state.icount_warp_timer, - clock + deadline); - } - } else if (deadline == 0) { - qemu_clock_notify(QEMU_CLOCK_VIRTUAL); - } -} - -static void qemu_account_warp_timer(void) -{ - if (!use_icount || !icount_sleep) { - return; - } - - /* Nothing to do if the VM is stopped: QEMU_CLOCK_VIRTUAL timers - * do not fire, so computing the deadline does not make sense. - */ - if (!runstate_is_running()) { - return; - } - - /* warp clock deterministically in record/replay mode */ - if (!replay_checkpoint(CHECKPOINT_CLOCK_WARP_ACCOUNT)) { - return; - } - - timer_del(timers_state.icount_warp_timer); - icount_warp_rt(); -} - -static bool icount_state_needed(void *opaque) -{ - return use_icount; -} - -static bool warp_timer_state_needed(void *opaque) -{ - TimersState *s = opaque; - return s->icount_warp_timer != NULL; -} - -static bool adjust_timers_state_needed(void *opaque) -{ - TimersState *s = opaque; - return s->icount_rt_timer != NULL; -} - -static bool shift_state_needed(void *opaque) -{ - return use_icount == 2; -} - -/* - * Subsection for warp timer migration is optional, because may not be created - */ -static const VMStateDescription icount_vmstate_warp_timer = { - .name = "timer/icount/warp_timer", - .version_id = 1, - .minimum_version_id = 1, - .needed = warp_timer_state_needed, - .fields = (VMStateField[]) { - VMSTATE_INT64(vm_clock_warp_start, TimersState), - VMSTATE_TIMER_PTR(icount_warp_timer, TimersState), - VMSTATE_END_OF_LIST() - } -}; - -static const VMStateDescription icount_vmstate_adjust_timers = { - .name = "timer/icount/timers", - .version_id = 1, - .minimum_version_id = 1, - .needed = adjust_timers_state_needed, - .fields = (VMStateField[]) { - VMSTATE_TIMER_PTR(icount_rt_timer, TimersState), - VMSTATE_TIMER_PTR(icount_vm_timer, TimersState), - VMSTATE_END_OF_LIST() - } -}; - -static const VMStateDescription icount_vmstate_shift = { - .name = "timer/icount/shift", - .version_id = 1, - .minimum_version_id = 1, - .needed = shift_state_needed, - .fields = (VMStateField[]) { - VMSTATE_INT16(icount_time_shift, TimersState), - VMSTATE_END_OF_LIST() - } -}; - -/* - * This is a subsection for icount migration. - */ -static const VMStateDescription icount_vmstate_timers = { - .name = "timer/icount", - .version_id = 1, - .minimum_version_id = 1, - .needed = icount_state_needed, - .fields = (VMStateField[]) { - VMSTATE_INT64(qemu_icount_bias, TimersState), - VMSTATE_INT64(qemu_icount, TimersState), - VMSTATE_END_OF_LIST() - }, - .subsections = (const VMStateDescription*[]) { - &icount_vmstate_warp_timer, - &icount_vmstate_adjust_timers, - &icount_vmstate_shift, - NULL - } -}; - -static const VMStateDescription vmstate_timers = { - .name = "timer", - .version_id = 2, - .minimum_version_id = 1, - .fields = (VMStateField[]) { - VMSTATE_INT64(cpu_ticks_offset, TimersState), - VMSTATE_UNUSED(8), - VMSTATE_INT64_V(cpu_clock_offset, TimersState, 2), - VMSTATE_END_OF_LIST() - }, - .subsections = (const VMStateDescription*[]) { - &icount_vmstate_timers, - NULL - } -}; - -void cpu_ticks_init(void) -{ - seqlock_init(&timers_state.vm_clock_seqlock); - qemu_spin_init(&timers_state.vm_clock_lock); - vmstate_register(NULL, 0, &vmstate_timers, &timers_state); - cpu_throttle_init(); -} - -void configure_icount(QemuOpts *opts, Error **errp) -{ - const char *option = qemu_opt_get(opts, "shift"); - bool sleep = qemu_opt_get_bool(opts, "sleep", true); - bool align = qemu_opt_get_bool(opts, "align", false); - long time_shift = -1; - - if (!option) { - if (qemu_opt_get(opts, "align") != NULL) { - error_setg(errp, "Please specify shift option when using align"); - } - return; - } - - if (align && !sleep) { - error_setg(errp, "align=on and sleep=off are incompatible"); - return; - } - - if (strcmp(option, "auto") != 0) { - if (qemu_strtol(option, NULL, 0, &time_shift) < 0 - || time_shift < 0 || time_shift > MAX_ICOUNT_SHIFT) { - error_setg(errp, "icount: Invalid shift value"); - return; - } - } else if (icount_align_option) { - error_setg(errp, "shift=auto and align=on are incompatible"); - return; - } else if (!icount_sleep) { - error_setg(errp, "shift=auto and sleep=off are incompatible"); - return; - } - - icount_sleep = sleep; - if (icount_sleep) { - timers_state.icount_warp_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL_RT, - icount_timer_cb, NULL); - } - - icount_align_option = align; - - if (time_shift >= 0) { - timers_state.icount_time_shift = time_shift; - use_icount = 1; - return; - } - - use_icount = 2; - - /* 125MIPS seems a reasonable initial guess at the guest speed. - It will be corrected fairly quickly anyway. */ - timers_state.icount_time_shift = 3; - - /* Have both realtime and virtual time triggers for speed adjustment. - The realtime trigger catches emulated time passing too slowly, - the virtual time trigger catches emulated time passing too fast. - Realtime triggers occur even when idle, so use them less frequently - than VM triggers. */ - timers_state.vm_clock_warp_start = -1; - timers_state.icount_rt_timer = timer_new_ms(QEMU_CLOCK_VIRTUAL_RT, - icount_adjust_rt, NULL); - timer_mod(timers_state.icount_rt_timer, - qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL_RT) + 1000); - timers_state.icount_vm_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, - icount_adjust_vm, NULL); - timer_mod(timers_state.icount_vm_timer, - qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + - NANOSECONDS_PER_SECOND / 10); -} - /***********************************************************/ /* TCG vCPU kick timer * @@ -854,35 +171,6 @@ static void qemu_cpu_kick_rr_cpus(void) }; } -static void do_nothing(CPUState *cpu, run_on_cpu_data unused) -{ -} - -void qemu_timer_notify_cb(void *opaque, QEMUClockType type) -{ - if (!use_icount || type != QEMU_CLOCK_VIRTUAL) { - qemu_notify_event(); - return; - } - - if (qemu_in_vcpu_thread()) { - /* A CPU is currently running; kick it back out to the - * tcg_cpu_exec() loop so it will recalculate its - * icount deadline immediately. - */ - qemu_cpu_kick(current_cpu); - } else if (first_cpu) { - /* qemu_cpu_kick is not enough to kick a halted CPU out of - * qemu_tcg_wait_io_event. async_run_on_cpu, instead, - * causes cpu_thread_is_idle to return false. This way, - * handle_icount_deadline can run. - * If we have no CPUs at all for some reason, we don't - * need to do anything. - */ - async_run_on_cpu(first_cpu, do_nothing, RUN_ON_CPU_NULL); - } -} - static void kick_tcg_thread(void *opaque) { timer_mod(tcg_kick_vcpu_timer, qemu_tcg_next_kick()); @@ -1288,7 +576,7 @@ static void notify_aio_contexts(void) static void handle_icount_deadline(void) { assert(qemu_in_vcpu_thread()); - if (use_icount) { + if (icount_enabled()) { int64_t deadline = qemu_clock_deadline_ns_all(QEMU_CLOCK_VIRTUAL, QEMU_TIMER_ATTR_ALL); @@ -1300,7 +588,7 @@ static void handle_icount_deadline(void) static void prepare_icount_for_run(CPUState *cpu) { - if (use_icount) { + if (icount_enabled()) { int insns_left; /* These should always be cleared by process_icount_data after @@ -1325,7 +613,7 @@ static void prepare_icount_for_run(CPUState *cpu) static void process_icount_data(CPUState *cpu) { - if (use_icount) { + if (icount_enabled()) { /* Account for executed instructions */ cpu_update_icount(cpu); @@ -1486,7 +774,7 @@ static void *qemu_tcg_rr_cpu_thread_fn(void *arg) atomic_mb_set(&cpu->exit_request, 0); } - if (use_icount && all_cpu_threads_idle()) { + if (icount_enabled() && all_cpu_threads_idle()) { /* * When all cpus are sleeping (e.g in WFI), to avoid a deadlock * in the main_loop, wake it up in order to start the warp timer. @@ -1639,7 +927,7 @@ static void *qemu_tcg_cpu_thread_fn(void *arg) CPUState *cpu = arg; assert(tcg_enabled()); - g_assert(!use_icount); + g_assert(!icount_enabled()); rcu_register_thread(); tcg_register_thread(); @@ -2218,21 +1506,3 @@ void qmp_inject_nmi(Error **errp) nmi_monitor_handle(monitor_get_cpu_index(), errp); } -void dump_drift_info(void) -{ - if (!use_icount) { - return; - } - - qemu_printf("Host - Guest clock %"PRIi64" ms\n", - (cpu_get_clock() - cpu_get_icount())/SCALE_MS); - if (icount_align_option) { - qemu_printf("Max guest delay %"PRIi64" ms\n", - -max_delay / SCALE_MS); - qemu_printf("Max guest advance %"PRIi64" ms\n", - max_advance / SCALE_MS); - } else { - qemu_printf("Max guest delay NA\n"); - qemu_printf("Max guest advance NA\n"); - } -} diff --git a/softmmu/icount.c b/softmmu/icount.c new file mode 100644 index 0000000000..4e26bf445d --- /dev/null +++ b/softmmu/icount.c @@ -0,0 +1,492 @@ +/* + * QEMU System Emulator + * + * Copyright (c) 2003-2008 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "qemu/osdep.h" +#include "qemu-common.h" +#include "qemu/cutils.h" +#include "migration/vmstate.h" +#include "qapi/error.h" +#include "qemu/error-report.h" +#include "exec/exec-all.h" +#include "sysemu/cpus.h" +#include "sysemu/qtest.h" +#include "qemu/main-loop.h" +#include "qemu/option.h" +#include "qemu/seqlock.h" +#include "sysemu/replay.h" +#include "sysemu/runstate.h" +#include "hw/core/cpu.h" +#include "sysemu/cpu-timers.h" +#include "sysemu/cpu-throttle.h" +#include "timers-state.h" + +/* + * ICOUNT: Instruction Counter + * + * this module is split off from cpu-timers because the icount part + * is TCG-specific, and does not need to be built for other accels. + */ +static bool icount_sleep = true; +/* Arbitrarily pick 1MIPS as the minimum allowable speed. */ +#define MAX_ICOUNT_SHIFT 10 + +/* + * 0 = Do not count executed instructions. + * 1 = Fixed conversion of insn to ns via "shift" option + * 2 = Runtime adaptive algorithm to compute shift + */ +int use_icount; + +static void icount_enable_precise(void) +{ + use_icount = 1; +} + +static void icount_enable_adaptive(void) +{ + use_icount = 2; +} + +/* + * The current number of executed instructions is based on what we + * originally budgeted minus the current state of the decrementing + * icount counters in extra/u16.low. + */ +static int64_t cpu_get_icount_executed(CPUState *cpu) +{ + return (cpu->icount_budget - + (cpu_neg(cpu)->icount_decr.u16.low + cpu->icount_extra)); +} + +/* + * Update the global shared timer_state.qemu_icount to take into + * account executed instructions. This is done by the TCG vCPU + * thread so the main-loop can see time has moved forward. + */ +static void cpu_update_icount_locked(CPUState *cpu) +{ + int64_t executed = cpu_get_icount_executed(cpu); + cpu->icount_budget -= executed; + + atomic_set_i64(&timers_state.qemu_icount, + timers_state.qemu_icount + executed); +} + +/* + * Update the global shared timer_state.qemu_icount to take into + * account executed instructions. This is done by the TCG vCPU + * thread so the main-loop can see time has moved forward. + */ +void cpu_update_icount(CPUState *cpu) +{ + seqlock_write_lock(&timers_state.vm_clock_seqlock, + &timers_state.vm_clock_lock); + cpu_update_icount_locked(cpu); + seqlock_write_unlock(&timers_state.vm_clock_seqlock, + &timers_state.vm_clock_lock); +} + +static int64_t cpu_get_icount_raw_locked(void) +{ + CPUState *cpu = current_cpu; + + if (cpu && cpu->running) { + if (!cpu->can_do_io) { + error_report("Bad icount read"); + exit(1); + } + /* Take into account what has run */ + cpu_update_icount_locked(cpu); + } + /* The read is protected by the seqlock, but needs atomic64 to avoid UB */ + return atomic_read_i64(&timers_state.qemu_icount); +} + +static int64_t cpu_get_icount_locked(void) +{ + int64_t icount = cpu_get_icount_raw_locked(); + return atomic_read_i64(&timers_state.qemu_icount_bias) + + cpu_icount_to_ns(icount); +} + +int64_t cpu_get_icount_raw(void) +{ + int64_t icount; + unsigned start; + + do { + start = seqlock_read_begin(&timers_state.vm_clock_seqlock); + icount = cpu_get_icount_raw_locked(); + } while (seqlock_read_retry(&timers_state.vm_clock_seqlock, start)); + + return icount; +} + +/* Return the virtual CPU time, based on the instruction counter. */ +int64_t cpu_get_icount(void) +{ + int64_t icount; + unsigned start; + + do { + start = seqlock_read_begin(&timers_state.vm_clock_seqlock); + icount = cpu_get_icount_locked(); + } while (seqlock_read_retry(&timers_state.vm_clock_seqlock, start)); + + return icount; +} + +int64_t cpu_icount_to_ns(int64_t icount) +{ + return icount << atomic_read(&timers_state.icount_time_shift); +} + +/* + * Correlation between real and virtual time is always going to be + * fairly approximate, so ignore small variation. + * When the guest is idle real and virtual time will be aligned in + * the IO wait loop. + */ +#define ICOUNT_WOBBLE (NANOSECONDS_PER_SECOND / 10) + +static void icount_adjust(void) +{ + int64_t cur_time; + int64_t cur_icount; + int64_t delta; + + /* Protected by TimersState mutex. */ + static int64_t last_delta; + + /* If the VM is not running, then do nothing. */ + if (!runstate_is_running()) { + return; + } + + seqlock_write_lock(&timers_state.vm_clock_seqlock, + &timers_state.vm_clock_lock); + cur_time = REPLAY_CLOCK_LOCKED(REPLAY_CLOCK_VIRTUAL_RT, + cpu_get_clock_locked()); + cur_icount = cpu_get_icount_locked(); + + delta = cur_icount - cur_time; + /* FIXME: This is a very crude algorithm, somewhat prone to oscillation. */ + if (delta > 0 + && last_delta + ICOUNT_WOBBLE < delta * 2 + && timers_state.icount_time_shift > 0) { + /* The guest is getting too far ahead. Slow time down. */ + atomic_set(&timers_state.icount_time_shift, + timers_state.icount_time_shift - 1); + } + if (delta < 0 + && last_delta - ICOUNT_WOBBLE > delta * 2 + && timers_state.icount_time_shift < MAX_ICOUNT_SHIFT) { + /* The guest is getting too far behind. Speed time up. */ + atomic_set(&timers_state.icount_time_shift, + timers_state.icount_time_shift + 1); + } + last_delta = delta; + atomic_set_i64(&timers_state.qemu_icount_bias, + cur_icount - (timers_state.qemu_icount + << timers_state.icount_time_shift)); + seqlock_write_unlock(&timers_state.vm_clock_seqlock, + &timers_state.vm_clock_lock); +} + +static void icount_adjust_rt(void *opaque) +{ + timer_mod(timers_state.icount_rt_timer, + qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL_RT) + 1000); + icount_adjust(); +} + +static void icount_adjust_vm(void *opaque) +{ + timer_mod(timers_state.icount_vm_timer, + qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + + NANOSECONDS_PER_SECOND / 10); + icount_adjust(); +} + +int64_t qemu_icount_round(int64_t count) +{ + int shift = atomic_read(&timers_state.icount_time_shift); + return (count + (1 << shift) - 1) >> shift; +} + +static void icount_warp_rt(void) +{ + unsigned seq; + int64_t warp_start; + + /* + * The icount_warp_timer is rescheduled soon after vm_clock_warp_start + * changes from -1 to another value, so the race here is okay. + */ + do { + seq = seqlock_read_begin(&timers_state.vm_clock_seqlock); + warp_start = timers_state.vm_clock_warp_start; + } while (seqlock_read_retry(&timers_state.vm_clock_seqlock, seq)); + + if (warp_start == -1) { + return; + } + + seqlock_write_lock(&timers_state.vm_clock_seqlock, + &timers_state.vm_clock_lock); + if (runstate_is_running()) { + int64_t clock = REPLAY_CLOCK_LOCKED(REPLAY_CLOCK_VIRTUAL_RT, + cpu_get_clock_locked()); + int64_t warp_delta; + + warp_delta = clock - timers_state.vm_clock_warp_start; + if (icount_enabled() == 2) { + /* + * In adaptive mode, do not let QEMU_CLOCK_VIRTUAL run too + * far ahead of real time. + */ + int64_t cur_icount = cpu_get_icount_locked(); + int64_t delta = clock - cur_icount; + warp_delta = MIN(warp_delta, delta); + } + atomic_set_i64(&timers_state.qemu_icount_bias, + timers_state.qemu_icount_bias + warp_delta); + } + timers_state.vm_clock_warp_start = -1; + seqlock_write_unlock(&timers_state.vm_clock_seqlock, + &timers_state.vm_clock_lock); + + if (qemu_clock_expired(QEMU_CLOCK_VIRTUAL)) { + qemu_clock_notify(QEMU_CLOCK_VIRTUAL); + } +} + +static void icount_timer_cb(void *opaque) +{ + /* + * No need for a checkpoint because the timer already synchronizes + * with CHECKPOINT_CLOCK_VIRTUAL_RT. + */ + icount_warp_rt(); +} + +void qemu_start_warp_timer(void) +{ + int64_t clock; + int64_t deadline; + + assert(icount_enabled()); + + /* + * Nothing to do if the VM is stopped: QEMU_CLOCK_VIRTUAL timers + * do not fire, so computing the deadline does not make sense. + */ + if (!runstate_is_running()) { + return; + } + + if (replay_mode != REPLAY_MODE_PLAY) { + if (!all_cpu_threads_idle()) { + return; + } + + if (qtest_enabled()) { + /* When testing, qtest commands advance icount. */ + return; + } + + replay_checkpoint(CHECKPOINT_CLOCK_WARP_START); + } else { + /* warp clock deterministically in record/replay mode */ + if (!replay_checkpoint(CHECKPOINT_CLOCK_WARP_START)) { + /* + * vCPU is sleeping and warp can't be started. + * It is probably a race condition: notification sent + * to vCPU was processed in advance and vCPU went to sleep. + * Therefore we have to wake it up for doing someting. + */ + if (replay_has_checkpoint()) { + qemu_clock_notify(QEMU_CLOCK_VIRTUAL); + } + return; + } + } + + /* We want to use the earliest deadline from ALL vm_clocks */ + clock = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL_RT); + deadline = qemu_clock_deadline_ns_all(QEMU_CLOCK_VIRTUAL, + ~QEMU_TIMER_ATTR_EXTERNAL); + if (deadline < 0) { + static bool notified; + if (!icount_sleep && !notified) { + warn_report("icount sleep disabled and no active timers"); + notified = true; + } + return; + } + + if (deadline > 0) { + /* + * Ensure QEMU_CLOCK_VIRTUAL proceeds even when the virtual CPU goes to + * sleep. Otherwise, the CPU might be waiting for a future timer + * interrupt to wake it up, but the interrupt never comes because + * the vCPU isn't running any insns and thus doesn't advance the + * QEMU_CLOCK_VIRTUAL. + */ + if (!icount_sleep) { + /* + * We never let VCPUs sleep in no sleep icount mode. + * If there is a pending QEMU_CLOCK_VIRTUAL timer we just advance + * to the next QEMU_CLOCK_VIRTUAL event and notify it. + * It is useful when we want a deterministic execution time, + * isolated from host latencies. + */ + seqlock_write_lock(&timers_state.vm_clock_seqlock, + &timers_state.vm_clock_lock); + atomic_set_i64(&timers_state.qemu_icount_bias, + timers_state.qemu_icount_bias + deadline); + seqlock_write_unlock(&timers_state.vm_clock_seqlock, + &timers_state.vm_clock_lock); + qemu_clock_notify(QEMU_CLOCK_VIRTUAL); + } else { + /* + * We do stop VCPUs and only advance QEMU_CLOCK_VIRTUAL after some + * "real" time, (related to the time left until the next event) has + * passed. The QEMU_CLOCK_VIRTUAL_RT clock will do this. + * This avoids that the warps are visible externally; for example, + * you will not be sending network packets continuously instead of + * every 100ms. + */ + seqlock_write_lock(&timers_state.vm_clock_seqlock, + &timers_state.vm_clock_lock); + if (timers_state.vm_clock_warp_start == -1 + || timers_state.vm_clock_warp_start > clock) { + timers_state.vm_clock_warp_start = clock; + } + seqlock_write_unlock(&timers_state.vm_clock_seqlock, + &timers_state.vm_clock_lock); + timer_mod_anticipate(timers_state.icount_warp_timer, + clock + deadline); + } + } else if (deadline == 0) { + qemu_clock_notify(QEMU_CLOCK_VIRTUAL); + } +} + +void qemu_account_warp_timer(void) +{ + if (!icount_enabled() || !icount_sleep) { + return; + } + + /* + * Nothing to do if the VM is stopped: QEMU_CLOCK_VIRTUAL timers + * do not fire, so computing the deadline does not make sense. + */ + if (!runstate_is_running()) { + return; + } + + /* warp clock deterministically in record/replay mode */ + if (!replay_checkpoint(CHECKPOINT_CLOCK_WARP_ACCOUNT)) { + return; + } + + timer_del(timers_state.icount_warp_timer); + icount_warp_rt(); +} + +void configure_icount(QemuOpts *opts, Error **errp) +{ + const char *option = qemu_opt_get(opts, "shift"); + bool sleep = qemu_opt_get_bool(opts, "sleep", true); + bool align = qemu_opt_get_bool(opts, "align", false); + long time_shift = -1; + + if (!option) { + if (qemu_opt_get(opts, "align") != NULL) { + error_setg(errp, "Please specify shift option when using align"); + } + return; + } + + if (align && !sleep) { + error_setg(errp, "align=on and sleep=off are incompatible"); + return; + } + + if (strcmp(option, "auto") != 0) { + if (qemu_strtol(option, NULL, 0, &time_shift) < 0 + || time_shift < 0 || time_shift > MAX_ICOUNT_SHIFT) { + error_setg(errp, "icount: Invalid shift value"); + return; + } + } else if (icount_align_option) { + error_setg(errp, "shift=auto and align=on are incompatible"); + return; + } else if (!icount_sleep) { + error_setg(errp, "shift=auto and sleep=off are incompatible"); + return; + } + + icount_sleep = sleep; + if (icount_sleep) { + timers_state.icount_warp_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL_RT, + icount_timer_cb, NULL); + } + + icount_align_option = align; + + if (time_shift >= 0) { + timers_state.icount_time_shift = time_shift; + icount_enable_precise(); + return; + } + + icount_enable_adaptive(); + + /* + * 125MIPS seems a reasonable initial guess at the guest speed. + * It will be corrected fairly quickly anyway. + */ + timers_state.icount_time_shift = 3; + + /* + * Have both realtime and virtual time triggers for speed adjustment. + * The realtime trigger catches emulated time passing too slowly, + * the virtual time trigger catches emulated time passing too fast. + * Realtime triggers occur even when idle, so use them less frequently + * than VM triggers. + */ + timers_state.vm_clock_warp_start = -1; + timers_state.icount_rt_timer = timer_new_ms(QEMU_CLOCK_VIRTUAL_RT, + icount_adjust_rt, NULL); + timer_mod(timers_state.icount_rt_timer, + qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL_RT) + 1000); + timers_state.icount_vm_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, + icount_adjust_vm, NULL); + timer_mod(timers_state.icount_vm_timer, + qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + + NANOSECONDS_PER_SECOND / 10); +} diff --git a/softmmu/meson.build b/softmmu/meson.build index 95d38df259..36c96e7b15 100644 --- a/softmmu/meson.build +++ b/softmmu/meson.build @@ -1,4 +1,4 @@ -specific_ss.add(when: 'CONFIG_SOFTMMU', if_true: files( +specific_ss.add(when: 'CONFIG_SOFTMMU', if_true: [files( 'arch_init.c', 'balloon.c', 'cpus.c', @@ -7,4 +7,10 @@ specific_ss.add(when: 'CONFIG_SOFTMMU', if_true: files( 'memory.c', 'memory_mapping.c', 'qtest.c', - 'vl.c')) + 'vl.c', + 'cpu-timers.c', +)]) + +specific_ss.add(when: ['CONFIG_SOFTMMU', 'CONFIG_TCG'], if_true: [files( + 'icount.c' +)]) diff --git a/softmmu/qtest.c b/softmmu/qtest.c index 4e439caec7..8f70658481 100644 --- a/softmmu/qtest.c +++ b/softmmu/qtest.c @@ -21,7 +21,7 @@ #include "exec/memory.h" #include "hw/irq.h" #include "sysemu/accel.h" -#include "sysemu/cpus.h" +#include "sysemu/cpu-timers.h" #include "qemu/config-file.h" #include "qemu/option.h" #include "qemu/error-report.h" @@ -273,6 +273,38 @@ static void qtest_irq_handler(void *opaque, int n, int level) } } +static int64_t qtest_clock_counter; + +int64_t qtest_get_virtual_clock(void) +{ + return atomic_read_i64(&qtest_clock_counter); +} + +static void qtest_set_virtual_clock(int64_t count) +{ + atomic_set_i64(&qtest_clock_counter, count); +} + +static void qtest_clock_warp(int64_t dest) +{ + int64_t clock = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); + AioContext *aio_context; + assert(qtest_enabled()); + aio_context = qemu_get_aio_context(); + while (clock < dest) { + int64_t deadline = qemu_clock_deadline_ns_all(QEMU_CLOCK_VIRTUAL, + QEMU_TIMER_ATTR_ALL); + int64_t warp = qemu_soonest_timeout(dest - clock, deadline); + + qtest_set_virtual_clock(qtest_get_virtual_clock() + warp); + + qemu_clock_run_timers(QEMU_CLOCK_VIRTUAL); + timerlist_run_timers(aio_context->tlg.tl[QEMU_CLOCK_VIRTUAL]); + clock = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); + } + qemu_clock_notify(QEMU_CLOCK_VIRTUAL); +} + static void qtest_process_command(CharBackend *chr, gchar **words) { const gchar *command; diff --git a/softmmu/timers-state.h b/softmmu/timers-state.h new file mode 100644 index 0000000000..db4e60f18f --- /dev/null +++ b/softmmu/timers-state.h @@ -0,0 +1,69 @@ +/* + * QEMU System Emulator + * + * Copyright (c) 2003-2008 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef TIMERS_STATE_H +#define TIMERS_STATE_H + +/* timers state, for sharing between icount and cpu-timers */ + +typedef struct TimersState { + /* Protected by BQL. */ + int64_t cpu_ticks_prev; + int64_t cpu_ticks_offset; + + /* + * Protect fields that can be respectively read outside the + * BQL, and written from multiple threads. + */ + QemuSeqLock vm_clock_seqlock; + QemuSpin vm_clock_lock; + + int16_t cpu_ticks_enabled; + + /* Conversion factor from emulated instructions to virtual clock ticks. */ + int16_t icount_time_shift; + + /* Compensate for varying guest execution speed. */ + int64_t qemu_icount_bias; + + int64_t vm_clock_warp_start; + int64_t cpu_clock_offset; + + /* Only written by TCG thread */ + int64_t qemu_icount; + + /* for adjusting icount */ + QEMUTimer *icount_rt_timer; + QEMUTimer *icount_vm_timer; + QEMUTimer *icount_warp_timer; +} TimersState; + +extern TimersState timers_state; + +/* + * icount needs this internal from cpu-timers when adjusting the icount shift. + */ +int64_t cpu_get_clock_locked(void); + +#endif /* TIMERS_STATE_H */ diff --git a/softmmu/vl.c b/softmmu/vl.c index 0cc86b0766..13a2dfd5e0 100644 --- a/softmmu/vl.c +++ b/softmmu/vl.c @@ -74,6 +74,7 @@ #include "hw/audio/soundhw.h" #include "audio/audio.h" #include "sysemu/cpus.h" +#include "sysemu/cpu-timers.h" #include "migration/colo.h" #include "migration/postcopy-ram.h" #include "sysemu/kvm.h" @@ -2802,7 +2803,7 @@ static void configure_accelerators(const char *progname) error_report("falling back to %s", ac->name); } - if (use_icount && !(tcg_enabled() || qtest_enabled())) { + if (icount_enabled() && !tcg_enabled()) { error_report("-icount is not allowed with hardware virtualization"); exit(1); } @@ -4237,7 +4238,8 @@ void qemu_init(int argc, char **argv, char **envp) semihosting_arg_fallback(kernel_filename, kernel_cmdline); } - cpu_ticks_init(); + /* initialize cpu timers and VCPU throttle modules */ + cpu_timers_init(); if (default_net) { QemuOptsList *net = qemu_find_opts("net"); diff --git a/stubs/clock-warp.c b/stubs/clock-warp.c deleted file mode 100644 index b53e5dd94c..0000000000 --- a/stubs/clock-warp.c +++ /dev/null @@ -1,7 +0,0 @@ -#include "qemu/osdep.h" -#include "qemu/timer.h" - -void qemu_start_warp_timer(void) -{ -} - diff --git a/stubs/cpu-get-clock.c b/stubs/cpu-get-clock.c index 5a92810e87..9e92404816 100644 --- a/stubs/cpu-get-clock.c +++ b/stubs/cpu-get-clock.c @@ -1,5 +1,6 @@ #include "qemu/osdep.h" -#include "qemu/timer.h" +#include "sysemu/cpu-timers.h" +#include "qemu/main-loop.h" int64_t cpu_get_clock(void) { diff --git a/stubs/cpu-get-icount.c b/stubs/cpu-get-icount.c deleted file mode 100644 index b35f844638..0000000000 --- a/stubs/cpu-get-icount.c +++ /dev/null @@ -1,21 +0,0 @@ -#include "qemu/osdep.h" -#include "qemu/timer.h" -#include "sysemu/cpus.h" -#include "qemu/main-loop.h" - -int use_icount; - -int64_t cpu_get_icount(void) -{ - abort(); -} - -int64_t cpu_get_icount_raw(void) -{ - abort(); -} - -void qemu_timer_notify_cb(void *opaque, QEMUClockType type) -{ - qemu_notify_event(); -} diff --git a/stubs/icount.c b/stubs/icount.c new file mode 100644 index 0000000000..61e28cbaf9 --- /dev/null +++ b/stubs/icount.c @@ -0,0 +1,45 @@ +#include "qemu/osdep.h" +#include "qapi/error.h" +#include "sysemu/cpu-timers.h" + +/* icount - Instruction Counter API */ + +int use_icount; + +void cpu_update_icount(CPUState *cpu) +{ + abort(); +} +void configure_icount(QemuOpts *opts, Error **errp) +{ + /* signal error */ + error_setg(errp, "cannot configure icount, TCG support not available"); +} +int64_t cpu_get_icount_raw(void) +{ + abort(); + return 0; +} +int64_t cpu_get_icount(void) +{ + abort(); + return 0; +} +int64_t cpu_icount_to_ns(int64_t icount) +{ + abort(); + return 0; +} +int64_t qemu_icount_round(int64_t count) +{ + abort(); + return 0; +} +void qemu_start_warp_timer(void) +{ + abort(); +} +void qemu_account_warp_timer(void) +{ + abort(); +} diff --git a/stubs/meson.build b/stubs/meson.build index 019bd79c7a..57fec4f8c8 100644 --- a/stubs/meson.build +++ b/stubs/meson.build @@ -3,10 +3,10 @@ stub_ss.add(files('bdrv-next-monitor-owned.c')) stub_ss.add(files('blk-commit-all.c')) stub_ss.add(files('blockdev-close-all-bdrv-states.c')) stub_ss.add(files('change-state-handler.c')) -stub_ss.add(files('clock-warp.c')) stub_ss.add(files('cmos.c')) stub_ss.add(files('cpu-get-clock.c')) -stub_ss.add(files('cpu-get-icount.c')) +stub_ss.add(files('qemu-timer-notify-cb.c')) +stub_ss.add(files('icount.c')) stub_ss.add(files('dump.c')) stub_ss.add(files('error-printf.c')) stub_ss.add(files('fd-register.c')) diff --git a/stubs/qemu-timer-notify-cb.c b/stubs/qemu-timer-notify-cb.c new file mode 100644 index 0000000000..845e46f8e0 --- /dev/null +++ b/stubs/qemu-timer-notify-cb.c @@ -0,0 +1,8 @@ +#include "qemu/osdep.h" +#include "sysemu/cpu-timers.h" +#include "qemu/main-loop.h" + +void qemu_timer_notify_cb(void *opaque, QEMUClockType type) +{ + qemu_notify_event(); +} diff --git a/stubs/qtest.c b/stubs/qtest.c index 891eb954fb..4666a49d7d 100644 --- a/stubs/qtest.c +++ b/stubs/qtest.c @@ -18,3 +18,8 @@ bool qtest_driver(void) { return false; } + +int64_t qtest_get_virtual_clock(void) +{ + return 0; +} diff --git a/target/alpha/translate.c b/target/alpha/translate.c index 8870284f57..36be602179 100644 --- a/target/alpha/translate.c +++ b/target/alpha/translate.c @@ -20,6 +20,7 @@ #include "qemu/osdep.h" #include "cpu.h" #include "sysemu/cpus.h" +#include "sysemu/cpu-timers.h" #include "disas/disas.h" #include "qemu/host-utils.h" #include "exec/exec-all.h" @@ -1329,7 +1330,7 @@ static DisasJumpType gen_mfpr(DisasContext *ctx, TCGv va, int regno) case 249: /* VMTIME */ helper = gen_helper_get_vmtime; do_helper: - if (use_icount) { + if (icount_enabled()) { gen_io_start(); helper(va); return DISAS_PC_STALE; diff --git a/target/arm/helper.c b/target/arm/helper.c index 44d666627a..dc2b91084c 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -24,6 +24,7 @@ #include "hw/irq.h" #include "hw/semihosting/semihost.h" #include "sysemu/cpus.h" +#include "sysemu/cpu-timers.h" #include "sysemu/kvm.h" #include "sysemu/tcg.h" #include "qemu/range.h" @@ -1206,7 +1207,7 @@ static int64_t cycles_ns_per(uint64_t cycles) static bool instructions_supported(CPUARMState *env) { - return use_icount == 1 /* Precise instruction counting */; + return icount_enabled() == 1; /* Precise instruction counting */ } static uint64_t instructions_get_count(CPUARMState *env) diff --git a/target/riscv/csr.c b/target/riscv/csr.c index 200001de74..5231404a70 100644 --- a/target/riscv/csr.c +++ b/target/riscv/csr.c @@ -299,7 +299,7 @@ static int write_vstart(CPURISCVState *env, int csrno, target_ulong val) static int read_instret(CPURISCVState *env, int csrno, target_ulong *val) { #if !defined(CONFIG_USER_ONLY) - if (use_icount) { + if (icount_enabled()) { *val = cpu_get_icount(); } else { *val = cpu_get_host_ticks(); @@ -314,7 +314,7 @@ static int read_instret(CPURISCVState *env, int csrno, target_ulong *val) static int read_instreth(CPURISCVState *env, int csrno, target_ulong *val) { #if !defined(CONFIG_USER_ONLY) - if (use_icount) { + if (icount_enabled()) { *val = cpu_get_icount() >> 32; } else { *val = cpu_get_host_ticks() >> 32; diff --git a/tests/ptimer-test-stubs.c b/tests/ptimer-test-stubs.c index ed393d9082..e935a1395e 100644 --- a/tests/ptimer-test-stubs.c +++ b/tests/ptimer-test-stubs.c @@ -12,6 +12,7 @@ #include "qemu/main-loop.h" #include "sysemu/replay.h" #include "migration/vmstate.h" +#include "sysemu/cpu-timers.h" #include "ptimer-test.h" @@ -30,8 +31,8 @@ QEMUTimerListGroup main_loop_tlg; int64_t ptimer_test_time_ns; -/* Do not artificially limit period - see hw/core/ptimer.c. */ -int use_icount = 1; +/* under qtest_enabled(), will not artificially limit period - see hw/core/ptimer.c. */ +int use_icount; bool qtest_allowed; void timer_init_full(QEMUTimer *ts, diff --git a/tests/test-timed-average.c b/tests/test-timed-average.c index e2bcf5fe13..82c92500df 100644 --- a/tests/test-timed-average.c +++ b/tests/test-timed-average.c @@ -11,7 +11,7 @@ */ #include "qemu/osdep.h" - +#include "sysemu/cpu-timers.h" #include "qemu/timed-average.h" /* This is the clock for QEMU_CLOCK_VIRTUAL */ diff --git a/util/main-loop.c b/util/main-loop.c index f69f055013..4015d58967 100644 --- a/util/main-loop.c +++ b/util/main-loop.c @@ -27,7 +27,7 @@ #include "qemu/cutils.h" #include "qemu/timer.h" #include "sysemu/qtest.h" -#include "sysemu/cpus.h" +#include "sysemu/cpu-timers.h" #include "sysemu/replay.h" #include "qemu/main-loop.h" #include "block/aio.h" @@ -517,9 +517,13 @@ void main_loop_wait(int nonblocking) mlpoll.state = ret < 0 ? MAIN_LOOP_POLL_ERR : MAIN_LOOP_POLL_OK; notifier_list_notify(&main_loop_poll_notifiers, &mlpoll); - /* CPU thread can infinitely wait for event after - missing the warp */ - qemu_start_warp_timer(); + if (icount_enabled()) { + /* + * CPU thread can infinitely wait for event after + * missing the warp + */ + qemu_start_warp_timer(); + } qemu_clock_run_all_timers(); } diff --git a/util/qemu-timer.c b/util/qemu-timer.c index 878d80fd5e..aeb6b613b8 100644 --- a/util/qemu-timer.c +++ b/util/qemu-timer.c @@ -26,8 +26,10 @@ #include "qemu/main-loop.h" #include "qemu/timer.h" #include "qemu/lockable.h" +#include "sysemu/cpu-timers.h" #include "sysemu/replay.h" #include "sysemu/cpus.h" +#include "sysemu/qtest.h" #ifdef CONFIG_POSIX #include @@ -134,7 +136,7 @@ static void qemu_clock_init(QEMUClockType type, QEMUTimerListNotifyCB *notify_cb bool qemu_clock_use_for_deadline(QEMUClockType type) { - return !(use_icount && (type == QEMU_CLOCK_VIRTUAL)); + return !(icount_enabled() && (type == QEMU_CLOCK_VIRTUAL)); } void qemu_clock_notify(QEMUClockType type) @@ -416,7 +418,7 @@ static bool timer_mod_ns_locked(QEMUTimerList *timer_list, static void timerlist_rearm(QEMUTimerList *timer_list) { /* Interrupt execution to force deadline recalculation. */ - if (timer_list->clock->type == QEMU_CLOCK_VIRTUAL) { + if (icount_enabled() && timer_list->clock->type == QEMU_CLOCK_VIRTUAL) { qemu_start_warp_timer(); } timerlist_notify(timer_list); @@ -633,8 +635,10 @@ int64_t qemu_clock_get_ns(QEMUClockType type) return get_clock(); default: case QEMU_CLOCK_VIRTUAL: - if (use_icount) { + if (icount_enabled()) { return cpu_get_icount(); + } else if (qtest_enabled()) { /* for qtest_clock_warp */ + return qtest_get_virtual_clock(); } else { return cpu_get_clock(); } From patchwork Thu Sep 3 10:56:00 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Claudio Fontana X-Patchwork-Id: 274708 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-13.0 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_PATCH, MAILING_LIST_MULTI, SIGNED_OFF_BY, SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED,USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 570B4C433E2 for ; Thu, 3 Sep 2020 10:59:03 +0000 (UTC) Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id E8CFE206A5 for ; Thu, 3 Sep 2020 10:59:02 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org E8CFE206A5 Authentication-Results: mail.kernel.org; dmarc=none (p=none dis=none) header.from=suse.de Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Received: from localhost ([::1]:47442 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1kDmxK-0007on-2B for qemu-devel@archiver.kernel.org; Thu, 03 Sep 2020 06:59:02 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:59200) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1kDmul-0002m0-8q for qemu-devel@nongnu.org; Thu, 03 Sep 2020 06:56:23 -0400 Received: from mx2.suse.de ([195.135.220.15]:48736) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1kDmui-0004W8-An for qemu-devel@nongnu.org; Thu, 03 Sep 2020 06:56:22 -0400 X-Virus-Scanned: by amavisd-new at test-mx.suse.de Received: from relay2.suse.de (unknown [195.135.221.27]) by mx2.suse.de (Postfix) with ESMTP id 4B42DB609; Thu, 3 Sep 2020 10:56:19 +0000 (UTC) From: Claudio Fontana To: Paolo Bonzini , Richard Henderson , =?utf-8?q?Alex_Benn=C3=A9e?= , Peter Maydell , =?utf-8?q?Philippe_Mathieu-?= =?utf-8?b?RGF1ZMOp?= , Roman Bolshakov Subject: [PATCH v7 02/16] icount: rename functions to be consistent with the module name Date: Thu, 3 Sep 2020 12:56:00 +0200 Message-Id: <20200903105614.17772-3-cfontana@suse.de> X-Mailer: git-send-email 2.26.2 In-Reply-To: <20200903105614.17772-1-cfontana@suse.de> References: <20200903105614.17772-1-cfontana@suse.de> MIME-Version: 1.0 Received-SPF: pass client-ip=195.135.220.15; envelope-from=cfontana@suse.de; helo=mx2.suse.de X-detected-operating-system: by eggs.gnu.org: First seen = 2020/09/03 00:06:01 X-ACL-Warn: Detected OS = Linux 2.2.x-3.x (no timestamps) [generic] X-Spam_score_int: -41 X-Spam_score: -4.2 X-Spam_bar: ---- X-Spam_report: (-4.2 / 5.0 requ) BAYES_00=-1.9, RCVD_IN_DNSWL_MED=-2.3, RCVD_IN_MSPIKE_H3=0.001, RCVD_IN_MSPIKE_WL=0.001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Laurent Vivier , Thomas Huth , Alberto Garcia , Eduardo Habkost , Pavel Dovgalyuk , Marcelo Tosatti , Richard Henderson , qemu-devel@nongnu.org, Markus Armbruster , Colin Xu , Wenchao Wang , haxm-team@intel.com, Sunil Muthuswamy , Claudio Fontana Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: "Qemu-devel" Signed-off-by: Claudio Fontana Reviewed-by: Richard Henderson Reviewed-by: Alex Bennée --- accel/tcg/cpu-exec.c | 6 +++--- docs/replay.txt | 6 +++--- include/sysemu/cpu-timers.h | 16 +++++++------- include/sysemu/replay.h | 4 ++-- replay/replay.c | 2 +- softmmu/cpu-timers.c | 6 +++--- softmmu/cpus.c | 6 +++--- softmmu/icount.c | 42 ++++++++++++++++++------------------- softmmu/vl.c | 2 +- stubs/icount.c | 16 +++++++------- target/arm/helper.c | 4 ++-- target/riscv/csr.c | 4 ++-- util/main-loop.c | 2 +- util/qemu-timer.c | 4 ++-- 14 files changed, 60 insertions(+), 60 deletions(-) diff --git a/accel/tcg/cpu-exec.c b/accel/tcg/cpu-exec.c index ee9d22d92c..b44e92b753 100644 --- a/accel/tcg/cpu-exec.c +++ b/accel/tcg/cpu-exec.c @@ -71,7 +71,7 @@ static void align_clocks(SyncClocks *sc, CPUState *cpu) } cpu_icount = cpu->icount_extra + cpu_neg(cpu)->icount_decr.u16.low; - sc->diff_clk += cpu_icount_to_ns(sc->last_cpu_icount - cpu_icount); + sc->diff_clk += icount_to_ns(sc->last_cpu_icount - cpu_icount); sc->last_cpu_icount = cpu_icount; if (sc->diff_clk > VM_CLOCK_ADVANCE) { @@ -664,7 +664,7 @@ static inline void cpu_loop_exec_tb(CPUState *cpu, TranslationBlock *tb, assert(icount_enabled()); #ifndef CONFIG_USER_ONLY /* Ensure global icount has gone forward */ - cpu_update_icount(cpu); + icount_update(cpu); /* Refill decrementer and continue execution. */ insns_left = MIN(0xffff, cpu->icount_budget); cpu_neg(cpu)->icount_decr.u16.low = insns_left; @@ -774,7 +774,7 @@ void dump_drift_info(void) } qemu_printf("Host - Guest clock %"PRIi64" ms\n", - (cpu_get_clock() - cpu_get_icount()) / SCALE_MS); + (cpu_get_clock() - icount_get()) / SCALE_MS); if (icount_align_option) { qemu_printf("Max guest delay %"PRIi64" ms\n", -max_delay / SCALE_MS); diff --git a/docs/replay.txt b/docs/replay.txt index 70c27edb36..8952e6d852 100644 --- a/docs/replay.txt +++ b/docs/replay.txt @@ -184,11 +184,11 @@ is then incremented (which is called "warping" the virtual clock) as soon as the timer fires or the CPUs need to go out of the idle state. Two functions are used for this purpose; because these actions change virtual machine state and must be deterministic, each of them creates a -checkpoint. qemu_start_warp_timer checks if the CPUs are idle and if so -starts accounting real time to virtual clock. qemu_account_warp_timer +checkpoint. icount_start_warp_timer checks if the CPUs are idle and if so +starts accounting real time to virtual clock. icount_account_warp_timer is called when the CPUs get an interrupt or when the warp timer fires, and it warps the virtual clock by the amount of real time that has passed -since qemu_start_warp_timer. +since icount_start_warp_timer. Bottom halves ------------- diff --git a/include/sysemu/cpu-timers.h b/include/sysemu/cpu-timers.h index 4b621fea51..7726e005cd 100644 --- a/include/sysemu/cpu-timers.h +++ b/include/sysemu/cpu-timers.h @@ -35,30 +35,30 @@ extern int use_icount; * Update the icount with the executed instructions. Called by * cpus-tcg vCPU thread so the main-loop can see time has moved forward. */ -void cpu_update_icount(CPUState *cpu); +void icount_update(CPUState *cpu); /* get raw icount value */ -int64_t cpu_get_icount_raw(void); +int64_t icount_get_raw(void); /* return the virtual CPU time in ns, based on the instruction counter. */ -int64_t cpu_get_icount(void); +int64_t icount_get(void); /* * convert an instruction counter value to ns, based on the icount shift. * This shift is set as a fixed value with the icount "shift" option * (precise mode), or it is constantly approximated and corrected at * runtime in adaptive mode. */ -int64_t cpu_icount_to_ns(int64_t icount); +int64_t icount_to_ns(int64_t icount); /* configure the icount options, including "shift" */ -void configure_icount(QemuOpts *opts, Error **errp); +void icount_configure(QemuOpts *opts, Error **errp); /* used by tcg vcpu thread to calc icount budget */ -int64_t qemu_icount_round(int64_t count); +int64_t icount_round(int64_t count); /* if the CPUs are idle, start accounting real time to virtual clock. */ -void qemu_start_warp_timer(void); -void qemu_account_warp_timer(void); +void icount_start_warp_timer(void); +void icount_account_warp_timer(void); /* * CPU Ticks and Clock diff --git a/include/sysemu/replay.h b/include/sysemu/replay.h index 5471bb514d..a140d69a73 100644 --- a/include/sysemu/replay.h +++ b/include/sysemu/replay.h @@ -109,12 +109,12 @@ int64_t replay_read_clock(ReplayClockKind kind); #define REPLAY_CLOCK(clock, value) \ (replay_mode == REPLAY_MODE_PLAY ? replay_read_clock((clock)) \ : replay_mode == REPLAY_MODE_RECORD \ - ? replay_save_clock((clock), (value), cpu_get_icount_raw()) \ + ? replay_save_clock((clock), (value), icount_get_raw()) \ : (value)) #define REPLAY_CLOCK_LOCKED(clock, value) \ (replay_mode == REPLAY_MODE_PLAY ? replay_read_clock((clock)) \ : replay_mode == REPLAY_MODE_RECORD \ - ? replay_save_clock((clock), (value), cpu_get_icount_raw_locked()) \ + ? replay_save_clock((clock), (value), icount_get_raw_locked()) \ : (value)) /* Processing data from random generators */ diff --git a/replay/replay.c b/replay/replay.c index 7e4a1ba78e..4c1457b07e 100644 --- a/replay/replay.c +++ b/replay/replay.c @@ -64,7 +64,7 @@ bool replay_next_event_is(int event) uint64_t replay_get_current_icount(void) { - return cpu_get_icount_raw(); + return icount_get_raw(); } int replay_get_instructions(void) diff --git a/softmmu/cpu-timers.c b/softmmu/cpu-timers.c index 6c6c56090f..7efec17fea 100644 --- a/softmmu/cpu-timers.c +++ b/softmmu/cpu-timers.c @@ -70,7 +70,7 @@ int64_t cpu_get_ticks(void) int64_t ticks; if (icount_enabled()) { - return cpu_get_icount(); + return icount_get(); } qemu_spin_lock(&timers_state.vm_clock_lock); @@ -160,7 +160,7 @@ static bool adjust_timers_state_needed(void *opaque) return s->icount_rt_timer != NULL; } -static bool shift_state_needed(void *opaque) +static bool icount_shift_state_needed(void *opaque) { return icount_enabled() == 2; } @@ -196,7 +196,7 @@ static const VMStateDescription icount_vmstate_shift = { .name = "timer/icount/shift", .version_id = 1, .minimum_version_id = 1, - .needed = shift_state_needed, + .needed = icount_shift_state_needed, .fields = (VMStateField[]) { VMSTATE_INT16(icount_time_shift, TimersState), VMSTATE_END_OF_LIST() diff --git a/softmmu/cpus.c b/softmmu/cpus.c index 773018ef1a..54fdb2761c 100644 --- a/softmmu/cpus.c +++ b/softmmu/cpus.c @@ -560,7 +560,7 @@ static int64_t tcg_get_icount_limit(void) deadline = INT32_MAX; } - return qemu_icount_round(deadline); + return icount_round(deadline); } else { return replay_get_instructions(); } @@ -615,7 +615,7 @@ static void process_icount_data(CPUState *cpu) { if (icount_enabled()) { /* Account for executed instructions */ - cpu_update_icount(cpu); + icount_update(cpu); /* Reset the counters */ cpu_neg(cpu)->icount_decr.u16.low = 0; @@ -716,7 +716,7 @@ static void *qemu_tcg_rr_cpu_thread_fn(void *arg) replay_mutex_lock(); qemu_mutex_lock_iothread(); /* Account partial waits to QEMU_CLOCK_VIRTUAL. */ - qemu_account_warp_timer(); + icount_account_warp_timer(); /* Run the timers here. This is much more efficient than * waking up the I/O thread and waiting for completion. diff --git a/softmmu/icount.c b/softmmu/icount.c index 4e26bf445d..40854a863e 100644 --- a/softmmu/icount.c +++ b/softmmu/icount.c @@ -73,7 +73,7 @@ static void icount_enable_adaptive(void) * originally budgeted minus the current state of the decrementing * icount counters in extra/u16.low. */ -static int64_t cpu_get_icount_executed(CPUState *cpu) +static int64_t icount_get_executed(CPUState *cpu) { return (cpu->icount_budget - (cpu_neg(cpu)->icount_decr.u16.low + cpu->icount_extra)); @@ -84,9 +84,9 @@ static int64_t cpu_get_icount_executed(CPUState *cpu) * account executed instructions. This is done by the TCG vCPU * thread so the main-loop can see time has moved forward. */ -static void cpu_update_icount_locked(CPUState *cpu) +static void icount_update_locked(CPUState *cpu) { - int64_t executed = cpu_get_icount_executed(cpu); + int64_t executed = icount_get_executed(cpu); cpu->icount_budget -= executed; atomic_set_i64(&timers_state.qemu_icount, @@ -98,16 +98,16 @@ static void cpu_update_icount_locked(CPUState *cpu) * account executed instructions. This is done by the TCG vCPU * thread so the main-loop can see time has moved forward. */ -void cpu_update_icount(CPUState *cpu) +void icount_update(CPUState *cpu) { seqlock_write_lock(&timers_state.vm_clock_seqlock, &timers_state.vm_clock_lock); - cpu_update_icount_locked(cpu); + icount_update_locked(cpu); seqlock_write_unlock(&timers_state.vm_clock_seqlock, &timers_state.vm_clock_lock); } -static int64_t cpu_get_icount_raw_locked(void) +static int64_t icount_get_raw_locked(void) { CPUState *cpu = current_cpu; @@ -117,47 +117,47 @@ static int64_t cpu_get_icount_raw_locked(void) exit(1); } /* Take into account what has run */ - cpu_update_icount_locked(cpu); + icount_update_locked(cpu); } /* The read is protected by the seqlock, but needs atomic64 to avoid UB */ return atomic_read_i64(&timers_state.qemu_icount); } -static int64_t cpu_get_icount_locked(void) +static int64_t icount_get_locked(void) { - int64_t icount = cpu_get_icount_raw_locked(); + int64_t icount = icount_get_raw_locked(); return atomic_read_i64(&timers_state.qemu_icount_bias) + - cpu_icount_to_ns(icount); + icount_to_ns(icount); } -int64_t cpu_get_icount_raw(void) +int64_t icount_get_raw(void) { int64_t icount; unsigned start; do { start = seqlock_read_begin(&timers_state.vm_clock_seqlock); - icount = cpu_get_icount_raw_locked(); + icount = icount_get_raw_locked(); } while (seqlock_read_retry(&timers_state.vm_clock_seqlock, start)); return icount; } /* Return the virtual CPU time, based on the instruction counter. */ -int64_t cpu_get_icount(void) +int64_t icount_get(void) { int64_t icount; unsigned start; do { start = seqlock_read_begin(&timers_state.vm_clock_seqlock); - icount = cpu_get_icount_locked(); + icount = icount_get_locked(); } while (seqlock_read_retry(&timers_state.vm_clock_seqlock, start)); return icount; } -int64_t cpu_icount_to_ns(int64_t icount) +int64_t icount_to_ns(int64_t icount) { return icount << atomic_read(&timers_state.icount_time_shift); } @@ -188,7 +188,7 @@ static void icount_adjust(void) &timers_state.vm_clock_lock); cur_time = REPLAY_CLOCK_LOCKED(REPLAY_CLOCK_VIRTUAL_RT, cpu_get_clock_locked()); - cur_icount = cpu_get_icount_locked(); + cur_icount = icount_get_locked(); delta = cur_icount - cur_time; /* FIXME: This is a very crude algorithm, somewhat prone to oscillation. */ @@ -229,7 +229,7 @@ static void icount_adjust_vm(void *opaque) icount_adjust(); } -int64_t qemu_icount_round(int64_t count) +int64_t icount_round(int64_t count) { int shift = atomic_read(&timers_state.icount_time_shift); return (count + (1 << shift) - 1) >> shift; @@ -266,7 +266,7 @@ static void icount_warp_rt(void) * In adaptive mode, do not let QEMU_CLOCK_VIRTUAL run too * far ahead of real time. */ - int64_t cur_icount = cpu_get_icount_locked(); + int64_t cur_icount = icount_get_locked(); int64_t delta = clock - cur_icount; warp_delta = MIN(warp_delta, delta); } @@ -291,7 +291,7 @@ static void icount_timer_cb(void *opaque) icount_warp_rt(); } -void qemu_start_warp_timer(void) +void icount_start_warp_timer(void) { int64_t clock; int64_t deadline; @@ -394,7 +394,7 @@ void qemu_start_warp_timer(void) } } -void qemu_account_warp_timer(void) +void icount_account_warp_timer(void) { if (!icount_enabled() || !icount_sleep) { return; @@ -417,7 +417,7 @@ void qemu_account_warp_timer(void) icount_warp_rt(); } -void configure_icount(QemuOpts *opts, Error **errp) +void icount_configure(QemuOpts *opts, Error **errp) { const char *option = qemu_opt_get(opts, "shift"); bool sleep = qemu_opt_get_bool(opts, "sleep", true); diff --git a/softmmu/vl.c b/softmmu/vl.c index 13a2dfd5e0..4a3e2b5a98 100644 --- a/softmmu/vl.c +++ b/softmmu/vl.c @@ -2693,7 +2693,7 @@ static void user_register_global_props(void) static int do_configure_icount(void *opaque, QemuOpts *opts, Error **errp) { - configure_icount(opts, errp); + icount_configure(opts, errp); return 0; } diff --git a/stubs/icount.c b/stubs/icount.c index 61e28cbaf9..f13c43568b 100644 --- a/stubs/icount.c +++ b/stubs/icount.c @@ -6,40 +6,40 @@ int use_icount; -void cpu_update_icount(CPUState *cpu) +void icount_update(CPUState *cpu) { abort(); } -void configure_icount(QemuOpts *opts, Error **errp) +void icount_configure(QemuOpts *opts, Error **errp) { /* signal error */ error_setg(errp, "cannot configure icount, TCG support not available"); } -int64_t cpu_get_icount_raw(void) +int64_t icount_get_raw(void) { abort(); return 0; } -int64_t cpu_get_icount(void) +int64_t icount_get(void) { abort(); return 0; } -int64_t cpu_icount_to_ns(int64_t icount) +int64_t icount_to_ns(int64_t icount) { abort(); return 0; } -int64_t qemu_icount_round(int64_t count) +int64_t icount_round(int64_t count) { abort(); return 0; } -void qemu_start_warp_timer(void) +void icount_start_warp_timer(void) { abort(); } -void qemu_account_warp_timer(void) +void icount_account_warp_timer(void) { abort(); } diff --git a/target/arm/helper.c b/target/arm/helper.c index dc2b91084c..2e74614d6d 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -1212,12 +1212,12 @@ static bool instructions_supported(CPUARMState *env) static uint64_t instructions_get_count(CPUARMState *env) { - return (uint64_t)cpu_get_icount_raw(); + return (uint64_t)icount_get_raw(); } static int64_t instructions_ns_per(uint64_t icount) { - return cpu_icount_to_ns((int64_t)icount); + return icount_to_ns((int64_t)icount); } #endif diff --git a/target/riscv/csr.c b/target/riscv/csr.c index 5231404a70..a6738b87ec 100644 --- a/target/riscv/csr.c +++ b/target/riscv/csr.c @@ -300,7 +300,7 @@ static int read_instret(CPURISCVState *env, int csrno, target_ulong *val) { #if !defined(CONFIG_USER_ONLY) if (icount_enabled()) { - *val = cpu_get_icount(); + *val = icount_get(); } else { *val = cpu_get_host_ticks(); } @@ -315,7 +315,7 @@ static int read_instreth(CPURISCVState *env, int csrno, target_ulong *val) { #if !defined(CONFIG_USER_ONLY) if (icount_enabled()) { - *val = cpu_get_icount() >> 32; + *val = icount_get() >> 32; } else { *val = cpu_get_host_ticks() >> 32; } diff --git a/util/main-loop.c b/util/main-loop.c index 4015d58967..744b42fc54 100644 --- a/util/main-loop.c +++ b/util/main-loop.c @@ -522,7 +522,7 @@ void main_loop_wait(int nonblocking) * CPU thread can infinitely wait for event after * missing the warp */ - qemu_start_warp_timer(); + icount_start_warp_timer(); } qemu_clock_run_all_timers(); } diff --git a/util/qemu-timer.c b/util/qemu-timer.c index aeb6b613b8..9a0e3bacaa 100644 --- a/util/qemu-timer.c +++ b/util/qemu-timer.c @@ -419,7 +419,7 @@ static void timerlist_rearm(QEMUTimerList *timer_list) { /* Interrupt execution to force deadline recalculation. */ if (icount_enabled() && timer_list->clock->type == QEMU_CLOCK_VIRTUAL) { - qemu_start_warp_timer(); + icount_start_warp_timer(); } timerlist_notify(timer_list); } @@ -636,7 +636,7 @@ int64_t qemu_clock_get_ns(QEMUClockType type) default: case QEMU_CLOCK_VIRTUAL: if (icount_enabled()) { - return cpu_get_icount(); + return icount_get(); } else if (qtest_enabled()) { /* for qtest_clock_warp */ return qtest_get_virtual_clock(); } else { From patchwork Thu Sep 3 10:56:01 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Claudio Fontana X-Patchwork-Id: 274709 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-13.0 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_PATCH, MAILING_LIST_MULTI, SIGNED_OFF_BY, SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED,USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 92868C433E9 for ; Thu, 3 Sep 2020 10:57:31 +0000 (UTC) Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 4472A206A5 for ; Thu, 3 Sep 2020 10:57:31 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 4472A206A5 Authentication-Results: mail.kernel.org; dmarc=none (p=none dis=none) header.from=suse.de Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Received: from localhost ([::1]:39760 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1kDmvq-0004bm-7s for qemu-devel@archiver.kernel.org; Thu, 03 Sep 2020 06:57:30 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:59236) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1kDmum-0002pV-JE for qemu-devel@nongnu.org; Thu, 03 Sep 2020 06:56:24 -0400 Received: from mx2.suse.de ([195.135.220.15]:48772) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1kDmui-0004WF-6H for qemu-devel@nongnu.org; Thu, 03 Sep 2020 06:56:24 -0400 X-Virus-Scanned: by amavisd-new at test-mx.suse.de Received: from relay2.suse.de (unknown [195.135.221.27]) by mx2.suse.de (Postfix) with ESMTP id EE882B1B9; Thu, 3 Sep 2020 10:56:19 +0000 (UTC) From: Claudio Fontana To: Paolo Bonzini , Richard Henderson , =?utf-8?q?Alex_Benn=C3=A9e?= , Peter Maydell , =?utf-8?q?Philippe_Mathieu-?= =?utf-8?b?RGF1ZMOp?= , Roman Bolshakov Subject: [PATCH v7 03/16] cpus: prepare new CpusAccel cpu accelerator interface Date: Thu, 3 Sep 2020 12:56:01 +0200 Message-Id: <20200903105614.17772-4-cfontana@suse.de> X-Mailer: git-send-email 2.26.2 In-Reply-To: <20200903105614.17772-1-cfontana@suse.de> References: <20200903105614.17772-1-cfontana@suse.de> MIME-Version: 1.0 Received-SPF: pass client-ip=195.135.220.15; envelope-from=cfontana@suse.de; helo=mx2.suse.de X-detected-operating-system: by eggs.gnu.org: First seen = 2020/09/03 00:06:01 X-ACL-Warn: Detected OS = Linux 2.2.x-3.x (no timestamps) [generic] X-Spam_score_int: -41 X-Spam_score: -4.2 X-Spam_bar: ---- X-Spam_report: (-4.2 / 5.0 requ) BAYES_00=-1.9, RCVD_IN_DNSWL_MED=-2.3, RCVD_IN_MSPIKE_H3=0.001, RCVD_IN_MSPIKE_WL=0.001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Laurent Vivier , Thomas Huth , Alberto Garcia , Eduardo Habkost , Pavel Dovgalyuk , Marcelo Tosatti , Richard Henderson , qemu-devel@nongnu.org, Markus Armbruster , Colin Xu , Wenchao Wang , haxm-team@intel.com, Sunil Muthuswamy , Claudio Fontana Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: "Qemu-devel" The new interface starts unused, will start being used by the next patches. It provides methods for each accelerator to start a vcpu, kick a vcpu, synchronize state, get cpu virtual clock and elapsed ticks. In qemu_wait_io_event, make it clear that APC is used only for HAX on Windows. Signed-off-by: Claudio Fontana Reviewed-by: Richard Henderson --- hw/core/cpu.c | 1 + hw/i386/x86.c | 2 +- include/sysemu/cpu-timers.h | 9 +- include/sysemu/cpus.h | 36 ++++++ include/sysemu/hw_accel.h | 69 +----------- softmmu/cpu-timers.c | 9 +- softmmu/cpus.c | 195 ++++++++++++++++++++++++++------- stubs/cpu-synchronize-state.c | 9 ++ stubs/cpus-get-virtual-clock.c | 8 ++ stubs/meson.build | 2 + util/qemu-timer.c | 8 +- 11 files changed, 225 insertions(+), 123 deletions(-) create mode 100644 stubs/cpu-synchronize-state.c create mode 100644 stubs/cpus-get-virtual-clock.c diff --git a/hw/core/cpu.c b/hw/core/cpu.c index 22bc3f974a..fa8602493b 100644 --- a/hw/core/cpu.c +++ b/hw/core/cpu.c @@ -33,6 +33,7 @@ #include "hw/qdev-properties.h" #include "trace/trace-root.h" #include "qemu/plugin.h" +#include "sysemu/hw_accel.h" CPUInterruptHandler cpu_interrupt_handler; diff --git a/hw/i386/x86.c b/hw/i386/x86.c index 309632c948..72cb42734f 100644 --- a/hw/i386/x86.c +++ b/hw/i386/x86.c @@ -240,7 +240,7 @@ static long get_file_size(FILE *f) /* TSC handling */ uint64_t cpu_get_tsc(CPUX86State *env) { - return cpu_get_ticks(); + return cpus_get_elapsed_ticks(); } /* IRQ handling */ diff --git a/include/sysemu/cpu-timers.h b/include/sysemu/cpu-timers.h index 7726e005cd..ed6ee5c46c 100644 --- a/include/sysemu/cpu-timers.h +++ b/include/sysemu/cpu-timers.h @@ -70,9 +70,8 @@ void cpu_enable_ticks(void); void cpu_disable_ticks(void); /* - * return the time elapsed in VM between vm_start and vm_stop. Unless - * icount is active, cpu_get_ticks() uses units of the host CPU cycle - * counter. + * return the time elapsed in VM between vm_start and vm_stop. + * cpu_get_ticks() uses units of the host CPU cycle counter. */ int64_t cpu_get_ticks(void); @@ -84,4 +83,8 @@ int64_t cpu_get_clock(void); void qemu_timer_notify_cb(void *opaque, QEMUClockType type); +/* get the VIRTUAL clock and VM elapsed ticks via the cpus accel interface */ +int64_t cpus_get_virtual_clock(void); +int64_t cpus_get_elapsed_ticks(void); + #endif /* SYSEMU_CPU_TIMERS_H */ diff --git a/include/sysemu/cpus.h b/include/sysemu/cpus.h index 149de000a0..26171697f5 100644 --- a/include/sysemu/cpus.h +++ b/include/sysemu/cpus.h @@ -4,7 +4,43 @@ #include "qemu/timer.h" /* cpus.c */ + +/* CPU execution threads */ + +typedef struct CpusAccel { + void (*create_vcpu_thread)(CPUState *cpu); /* MANDATORY */ + void (*kick_vcpu_thread)(CPUState *cpu); + + void (*synchronize_post_reset)(CPUState *cpu); + void (*synchronize_post_init)(CPUState *cpu); + void (*synchronize_state)(CPUState *cpu); + void (*synchronize_pre_loadvm)(CPUState *cpu); + + int64_t (*get_virtual_clock)(void); + int64_t (*get_elapsed_ticks)(void); +} CpusAccel; + +/* register accel-specific cpus interface implementation */ +void cpus_register_accel(const CpusAccel *i); + +/* interface available for cpus accelerator threads */ + +/* For temporary buffers for forming a name */ +#define VCPU_THREAD_NAME_SIZE 16 + +void cpus_kick_thread(CPUState *cpu); +bool cpu_work_list_empty(CPUState *cpu); +bool cpu_thread_is_idle(CPUState *cpu); bool all_cpu_threads_idle(void); +bool cpu_can_run(CPUState *cpu); +void qemu_wait_io_event_common(CPUState *cpu); +void qemu_wait_io_event(CPUState *cpu); +void cpu_thread_signal_created(CPUState *cpu); +void cpu_thread_signal_destroyed(CPUState *cpu); +void cpu_handle_guest_debug(CPUState *cpu); + +/* end interface for cpus accelerator threads */ + bool qemu_in_vcpu_thread(void); void qemu_init_cpu_loop(void); void resume_all_vcpus(void); diff --git a/include/sysemu/hw_accel.h b/include/sysemu/hw_accel.h index e128f8b06b..ffed6192a3 100644 --- a/include/sysemu/hw_accel.h +++ b/include/sysemu/hw_accel.h @@ -1,5 +1,5 @@ /* - * QEMU Hardware accelertors support + * QEMU Hardware accelerators support * * Copyright 2016 Google, Inc. * @@ -17,68 +17,9 @@ #include "sysemu/hvf.h" #include "sysemu/whpx.h" -static inline void cpu_synchronize_state(CPUState *cpu) -{ - if (kvm_enabled()) { - kvm_cpu_synchronize_state(cpu); - } - if (hax_enabled()) { - hax_cpu_synchronize_state(cpu); - } - if (hvf_enabled()) { - hvf_cpu_synchronize_state(cpu); - } - if (whpx_enabled()) { - whpx_cpu_synchronize_state(cpu); - } -} - -static inline void cpu_synchronize_post_reset(CPUState *cpu) -{ - if (kvm_enabled()) { - kvm_cpu_synchronize_post_reset(cpu); - } - if (hax_enabled()) { - hax_cpu_synchronize_post_reset(cpu); - } - if (hvf_enabled()) { - hvf_cpu_synchronize_post_reset(cpu); - } - if (whpx_enabled()) { - whpx_cpu_synchronize_post_reset(cpu); - } -} - -static inline void cpu_synchronize_post_init(CPUState *cpu) -{ - if (kvm_enabled()) { - kvm_cpu_synchronize_post_init(cpu); - } - if (hax_enabled()) { - hax_cpu_synchronize_post_init(cpu); - } - if (hvf_enabled()) { - hvf_cpu_synchronize_post_init(cpu); - } - if (whpx_enabled()) { - whpx_cpu_synchronize_post_init(cpu); - } -} - -static inline void cpu_synchronize_pre_loadvm(CPUState *cpu) -{ - if (kvm_enabled()) { - kvm_cpu_synchronize_pre_loadvm(cpu); - } - if (hax_enabled()) { - hax_cpu_synchronize_pre_loadvm(cpu); - } - if (hvf_enabled()) { - hvf_cpu_synchronize_pre_loadvm(cpu); - } - if (whpx_enabled()) { - whpx_cpu_synchronize_pre_loadvm(cpu); - } -} +void cpu_synchronize_state(CPUState *cpu); +void cpu_synchronize_post_reset(CPUState *cpu); +void cpu_synchronize_post_init(CPUState *cpu); +void cpu_synchronize_pre_loadvm(CPUState *cpu); #endif /* QEMU_HW_ACCEL_H */ diff --git a/softmmu/cpu-timers.c b/softmmu/cpu-timers.c index 7efec17fea..1eb7c675c1 100644 --- a/softmmu/cpu-timers.c +++ b/softmmu/cpu-timers.c @@ -61,18 +61,13 @@ static int64_t cpu_get_ticks_locked(void) } /* - * return the time elapsed in VM between vm_start and vm_stop. Unless - * icount is active, cpu_get_ticks() uses units of the host CPU cycle - * counter. + * return the time elapsed in VM between vm_start and vm_stop. + * cpu_get_ticks() uses units of the host CPU cycle counter. */ int64_t cpu_get_ticks(void) { int64_t ticks; - if (icount_enabled()) { - return icount_get(); - } - qemu_spin_lock(&timers_state.vm_clock_lock); ticks = cpu_get_ticks_locked(); qemu_spin_unlock(&timers_state.vm_clock_lock); diff --git a/softmmu/cpus.c b/softmmu/cpus.c index 54fdb2761c..bbf099b3ca 100644 --- a/softmmu/cpus.c +++ b/softmmu/cpus.c @@ -87,7 +87,7 @@ bool cpu_is_stopped(CPUState *cpu) return cpu->stopped || !runstate_is_running(); } -static inline bool cpu_work_list_empty(CPUState *cpu) +bool cpu_work_list_empty(CPUState *cpu) { bool ret; @@ -97,7 +97,7 @@ static inline bool cpu_work_list_empty(CPUState *cpu) return ret; } -static bool cpu_thread_is_idle(CPUState *cpu) +bool cpu_thread_is_idle(CPUState *cpu) { if (cpu->stop || !cpu_work_list_empty(cpu)) { return false; @@ -215,6 +215,11 @@ void hw_error(const char *fmt, ...) abort(); } +/* + * The chosen accelerator is supposed to register this. + */ +static const CpusAccel *cpus_accel; + void cpu_synchronize_all_states(void) { CPUState *cpu; @@ -251,6 +256,102 @@ void cpu_synchronize_all_pre_loadvm(void) } } +void cpu_synchronize_state(CPUState *cpu) +{ + if (cpus_accel && cpus_accel->synchronize_state) { + cpus_accel->synchronize_state(cpu); + } + if (kvm_enabled()) { + kvm_cpu_synchronize_state(cpu); + } + if (hax_enabled()) { + hax_cpu_synchronize_state(cpu); + } + if (whpx_enabled()) { + whpx_cpu_synchronize_state(cpu); + } +} + +void cpu_synchronize_post_reset(CPUState *cpu) +{ + if (cpus_accel && cpus_accel->synchronize_post_reset) { + cpus_accel->synchronize_post_reset(cpu); + } + if (kvm_enabled()) { + kvm_cpu_synchronize_post_reset(cpu); + } + if (hax_enabled()) { + hax_cpu_synchronize_post_reset(cpu); + } + if (whpx_enabled()) { + whpx_cpu_synchronize_post_reset(cpu); + } +} + +void cpu_synchronize_post_init(CPUState *cpu) +{ + if (cpus_accel && cpus_accel->synchronize_post_init) { + cpus_accel->synchronize_post_init(cpu); + } + if (kvm_enabled()) { + kvm_cpu_synchronize_post_init(cpu); + } + if (hax_enabled()) { + hax_cpu_synchronize_post_init(cpu); + } + if (whpx_enabled()) { + whpx_cpu_synchronize_post_init(cpu); + } +} + +void cpu_synchronize_pre_loadvm(CPUState *cpu) +{ + if (cpus_accel && cpus_accel->synchronize_pre_loadvm) { + cpus_accel->synchronize_pre_loadvm(cpu); + } + if (kvm_enabled()) { + kvm_cpu_synchronize_pre_loadvm(cpu); + } + if (hax_enabled()) { + hax_cpu_synchronize_pre_loadvm(cpu); + } + if (hvf_enabled()) { + hvf_cpu_synchronize_pre_loadvm(cpu); + } + if (whpx_enabled()) { + whpx_cpu_synchronize_pre_loadvm(cpu); + } +} + +int64_t cpus_get_virtual_clock(void) +{ + if (cpus_accel && cpus_accel->get_virtual_clock) { + return cpus_accel->get_virtual_clock(); + } + if (icount_enabled()) { + return icount_get(); + } else if (qtest_enabled()) { /* for qtest_clock_warp */ + return qtest_get_virtual_clock(); + } + return cpu_get_clock(); +} + +/* + * return the time elapsed in VM between vm_start and vm_stop. Unless + * icount is active, cpus_get_elapsed_ticks() uses units of the host CPU cycle + * counter. + */ +int64_t cpus_get_elapsed_ticks(void) +{ + if (cpus_accel && cpus_accel->get_elapsed_ticks) { + return cpus_accel->get_elapsed_ticks(); + } + if (icount_enabled()) { + return icount_get(); + } + return cpu_get_ticks(); +} + static int do_vm_stop(RunState state, bool send_stop) { int ret = 0; @@ -279,7 +380,7 @@ int vm_shutdown(void) return do_vm_stop(RUN_STATE_SHUTDOWN, false); } -static bool cpu_can_run(CPUState *cpu) +bool cpu_can_run(CPUState *cpu) { if (cpu->stop) { return false; @@ -290,7 +391,7 @@ static bool cpu_can_run(CPUState *cpu) return true; } -static void cpu_handle_guest_debug(CPUState *cpu) +void cpu_handle_guest_debug(CPUState *cpu) { gdb_set_stop_cpu(cpu); qemu_system_debug_request(); @@ -396,7 +497,7 @@ static void qemu_cpu_stop(CPUState *cpu, bool exit) qemu_cond_broadcast(&qemu_pause_cond); } -static void qemu_wait_io_event_common(CPUState *cpu) +void qemu_wait_io_event_common(CPUState *cpu) { atomic_mb_set(&cpu->thread_kicked, false); if (cpu->stop) { @@ -421,7 +522,7 @@ static void qemu_tcg_rr_wait_io_event(void) } } -static void qemu_wait_io_event(CPUState *cpu) +void qemu_wait_io_event(CPUState *cpu) { bool slept = false; @@ -437,8 +538,8 @@ static void qemu_wait_io_event(CPUState *cpu) } #ifdef _WIN32 - /* Eat dummy APC queued by qemu_cpu_kick_thread. */ - if (!tcg_enabled()) { + /* Eat dummy APC queued by cpus_kick_thread. */ + if (hax_enabled()) { SleepEx(0, TRUE); } #endif @@ -467,8 +568,7 @@ static void *qemu_kvm_cpu_thread_fn(void *arg) kvm_init_cpu_signals(cpu); /* signal CPU creation */ - cpu->created = true; - qemu_cond_signal(&qemu_cpu_cond); + cpu_thread_signal_created(cpu); qemu_guest_random_seed_thread_part2(cpu->random_seed); do { @@ -482,8 +582,7 @@ static void *qemu_kvm_cpu_thread_fn(void *arg) } while (!cpu->unplug || cpu_can_run(cpu)); qemu_kvm_destroy_vcpu(cpu); - cpu->created = false; - qemu_cond_signal(&qemu_cpu_cond); + cpu_thread_signal_destroyed(cpu); qemu_mutex_unlock_iothread(); rcu_unregister_thread(); return NULL; @@ -511,8 +610,7 @@ static void *qemu_dummy_cpu_thread_fn(void *arg) sigaddset(&waitset, SIG_IPI); /* signal CPU creation */ - cpu->created = true; - qemu_cond_signal(&qemu_cpu_cond); + cpu_thread_signal_created(cpu); qemu_guest_random_seed_thread_part2(cpu->random_seed); do { @@ -660,8 +758,7 @@ static void deal_with_unplugged_cpus(void) CPU_FOREACH(cpu) { if (cpu->unplug && !cpu_can_run(cpu)) { qemu_tcg_destroy_vcpu(cpu); - cpu->created = false; - qemu_cond_signal(&qemu_cpu_cond); + cpu_thread_signal_destroyed(cpu); break; } } @@ -688,9 +785,8 @@ static void *qemu_tcg_rr_cpu_thread_fn(void *arg) qemu_thread_get_self(cpu->thread); cpu->thread_id = qemu_get_thread_id(); - cpu->created = true; cpu->can_do_io = 1; - qemu_cond_signal(&qemu_cpu_cond); + cpu_thread_signal_created(cpu); qemu_guest_random_seed_thread_part2(cpu->random_seed); /* wait for initial kick-off after machine start */ @@ -800,11 +896,9 @@ static void *qemu_hax_cpu_thread_fn(void *arg) qemu_thread_get_self(cpu->thread); cpu->thread_id = qemu_get_thread_id(); - cpu->created = true; current_cpu = cpu; - hax_init_vcpu(cpu); - qemu_cond_signal(&qemu_cpu_cond); + cpu_thread_signal_created(cpu); qemu_guest_random_seed_thread_part2(cpu->random_seed); do { @@ -843,8 +937,7 @@ static void *qemu_hvf_cpu_thread_fn(void *arg) hvf_init_vcpu(cpu); /* signal CPU creation */ - cpu->created = true; - qemu_cond_signal(&qemu_cpu_cond); + cpu_thread_signal_created(cpu); qemu_guest_random_seed_thread_part2(cpu->random_seed); do { @@ -858,8 +951,7 @@ static void *qemu_hvf_cpu_thread_fn(void *arg) } while (!cpu->unplug || cpu_can_run(cpu)); hvf_vcpu_destroy(cpu); - cpu->created = false; - qemu_cond_signal(&qemu_cpu_cond); + cpu_thread_signal_destroyed(cpu); qemu_mutex_unlock_iothread(); rcu_unregister_thread(); return NULL; @@ -884,8 +976,7 @@ static void *qemu_whpx_cpu_thread_fn(void *arg) } /* signal CPU creation */ - cpu->created = true; - qemu_cond_signal(&qemu_cpu_cond); + cpu_thread_signal_created(cpu); qemu_guest_random_seed_thread_part2(cpu->random_seed); do { @@ -902,8 +993,7 @@ static void *qemu_whpx_cpu_thread_fn(void *arg) } while (!cpu->unplug || cpu_can_run(cpu)); whpx_destroy_vcpu(cpu); - cpu->created = false; - qemu_cond_signal(&qemu_cpu_cond); + cpu_thread_signal_destroyed(cpu); qemu_mutex_unlock_iothread(); rcu_unregister_thread(); return NULL; @@ -936,10 +1026,9 @@ static void *qemu_tcg_cpu_thread_fn(void *arg) qemu_thread_get_self(cpu->thread); cpu->thread_id = qemu_get_thread_id(); - cpu->created = true; cpu->can_do_io = 1; current_cpu = cpu; - qemu_cond_signal(&qemu_cpu_cond); + cpu_thread_signal_created(cpu); qemu_guest_random_seed_thread_part2(cpu->random_seed); /* process any pending work */ @@ -980,14 +1069,13 @@ static void *qemu_tcg_cpu_thread_fn(void *arg) } while (!cpu->unplug || cpu_can_run(cpu)); qemu_tcg_destroy_vcpu(cpu); - cpu->created = false; - qemu_cond_signal(&qemu_cpu_cond); + cpu_thread_signal_destroyed(cpu); qemu_mutex_unlock_iothread(); rcu_unregister_thread(); return NULL; } -static void qemu_cpu_kick_thread(CPUState *cpu) +void cpus_kick_thread(CPUState *cpu) { #ifndef _WIN32 int err; @@ -1017,7 +1105,10 @@ static void qemu_cpu_kick_thread(CPUState *cpu) void qemu_cpu_kick(CPUState *cpu) { qemu_cond_broadcast(cpu->halt_cond); - if (tcg_enabled()) { + + if (cpus_accel && cpus_accel->kick_vcpu_thread) { + cpus_accel->kick_vcpu_thread(cpu); + } else if (tcg_enabled()) { if (qemu_tcg_mttcg_enabled()) { cpu_exit(cpu); } else { @@ -1031,14 +1122,14 @@ void qemu_cpu_kick(CPUState *cpu) */ cpu->exit_request = 1; } - qemu_cpu_kick_thread(cpu); + cpus_kick_thread(cpu); } } void qemu_cpu_kick_self(void) { assert(current_cpu); - qemu_cpu_kick_thread(current_cpu); + cpus_kick_thread(current_cpu); } bool qemu_cpu_is_self(CPUState *cpu) @@ -1088,6 +1179,21 @@ void qemu_cond_timedwait_iothread(QemuCond *cond, int ms) qemu_cond_timedwait(cond, &qemu_global_mutex, ms); } +/* signal CPU creation */ +void cpu_thread_signal_created(CPUState *cpu) +{ + cpu->created = true; + qemu_cond_signal(&qemu_cpu_cond); +} + +/* signal CPU destruction */ +void cpu_thread_signal_destroyed(CPUState *cpu) +{ + cpu->created = false; + qemu_cond_signal(&qemu_cpu_cond); +} + + static bool all_vcpus_paused(void) { CPUState *cpu; @@ -1163,9 +1269,6 @@ void cpu_remove_sync(CPUState *cpu) qemu_mutex_lock_iothread(); } -/* For temporary buffers for forming a name */ -#define VCPU_THREAD_NAME_SIZE 16 - static void qemu_tcg_init_vcpu(CPUState *cpu) { char thread_name[VCPU_THREAD_NAME_SIZE]; @@ -1286,6 +1389,13 @@ static void qemu_whpx_start_vcpu(CPUState *cpu) #endif } +void cpus_register_accel(const CpusAccel *ca) +{ + assert(ca != NULL); + assert(ca->create_vcpu_thread != NULL); /* mandatory */ + cpus_accel = ca; +} + static void qemu_dummy_start_vcpu(CPUState *cpu) { char thread_name[VCPU_THREAD_NAME_SIZE]; @@ -1316,7 +1426,10 @@ void qemu_init_vcpu(CPUState *cpu) cpu_address_space_init(cpu, 0, "cpu-memory", cpu->memory); } - if (kvm_enabled()) { + if (cpus_accel) { + /* accelerator already implements the CpusAccel interface */ + cpus_accel->create_vcpu_thread(cpu); + } else if (kvm_enabled()) { qemu_kvm_start_vcpu(cpu); } else if (hax_enabled()) { qemu_hax_start_vcpu(cpu); diff --git a/stubs/cpu-synchronize-state.c b/stubs/cpu-synchronize-state.c new file mode 100644 index 0000000000..d9211da66c --- /dev/null +++ b/stubs/cpu-synchronize-state.c @@ -0,0 +1,9 @@ +#include "qemu/osdep.h" +#include "sysemu/hw_accel.h" + +void cpu_synchronize_state(CPUState *cpu) +{ +} +void cpu_synchronize_post_init(CPUState *cpu) +{ +} diff --git a/stubs/cpus-get-virtual-clock.c b/stubs/cpus-get-virtual-clock.c new file mode 100644 index 0000000000..fd447d53f3 --- /dev/null +++ b/stubs/cpus-get-virtual-clock.c @@ -0,0 +1,8 @@ +#include "qemu/osdep.h" +#include "sysemu/cpu-timers.h" +#include "qemu/main-loop.h" + +int64_t cpus_get_virtual_clock(void) +{ + return cpu_get_clock(); +} diff --git a/stubs/meson.build b/stubs/meson.build index 57fec4f8c8..54d4a3f6d4 100644 --- a/stubs/meson.build +++ b/stubs/meson.build @@ -5,6 +5,7 @@ stub_ss.add(files('blockdev-close-all-bdrv-states.c')) stub_ss.add(files('change-state-handler.c')) stub_ss.add(files('cmos.c')) stub_ss.add(files('cpu-get-clock.c')) +stub_ss.add(files('cpus-get-virtual-clock.c')) stub_ss.add(files('qemu-timer-notify-cb.c')) stub_ss.add(files('icount.c')) stub_ss.add(files('dump.c')) @@ -45,6 +46,7 @@ stub_ss.add(files('vmgenid.c')) stub_ss.add(files('vmstate.c')) stub_ss.add(files('vm-stop.c')) stub_ss.add(files('win32-kbd-hook.c')) +stub_ss.add(files('cpu-synchronize-state.c')) if have_system stub_ss.add(files('semihost.c')) endif diff --git a/util/qemu-timer.c b/util/qemu-timer.c index 9a0e3bacaa..2f05e52046 100644 --- a/util/qemu-timer.c +++ b/util/qemu-timer.c @@ -635,13 +635,7 @@ int64_t qemu_clock_get_ns(QEMUClockType type) return get_clock(); default: case QEMU_CLOCK_VIRTUAL: - if (icount_enabled()) { - return icount_get(); - } else if (qtest_enabled()) { /* for qtest_clock_warp */ - return qtest_get_virtual_clock(); - } else { - return cpu_get_clock(); - } + return cpus_get_virtual_clock(); case QEMU_CLOCK_HOST: return REPLAY_CLOCK(REPLAY_CLOCK_HOST, get_clock_realtime()); case QEMU_CLOCK_VIRTUAL_RT: From patchwork Thu Sep 3 10:56:06 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Claudio Fontana X-Patchwork-Id: 274706 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-13.0 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_PATCH, MAILING_LIST_MULTI, SIGNED_OFF_BY, SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED,USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 6C272C433E9 for ; Thu, 3 Sep 2020 11:01:20 +0000 (UTC) Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 2BF3E20767 for ; Thu, 3 Sep 2020 11:01:20 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 2BF3E20767 Authentication-Results: mail.kernel.org; dmarc=none (p=none dis=none) header.from=suse.de Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Received: from localhost ([::1]:55364 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1kDmzX-0002oR-4f for qemu-devel@archiver.kernel.org; Thu, 03 Sep 2020 07:01:19 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:59290) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1kDmup-0002wj-8l for qemu-devel@nongnu.org; Thu, 03 Sep 2020 06:56:27 -0400 Received: from mx2.suse.de ([195.135.220.15]:48918) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1kDmum-0004Y2-6P for qemu-devel@nongnu.org; Thu, 03 Sep 2020 06:56:26 -0400 X-Virus-Scanned: by amavisd-new at test-mx.suse.de Received: from relay2.suse.de (unknown [195.135.221.27]) by mx2.suse.de (Postfix) with ESMTP id 4CABBB6A5; Thu, 3 Sep 2020 10:56:23 +0000 (UTC) From: Claudio Fontana To: Paolo Bonzini , Richard Henderson , =?utf-8?q?Alex_Benn=C3=A9e?= , Peter Maydell , =?utf-8?q?Philippe_Mathieu-?= =?utf-8?b?RGF1ZMOp?= , Roman Bolshakov Subject: [PATCH v7 08/16] cpus: extract out whpx-specific code to target/i386/ Date: Thu, 3 Sep 2020 12:56:06 +0200 Message-Id: <20200903105614.17772-9-cfontana@suse.de> X-Mailer: git-send-email 2.26.2 In-Reply-To: <20200903105614.17772-1-cfontana@suse.de> References: <20200903105614.17772-1-cfontana@suse.de> MIME-Version: 1.0 Received-SPF: pass client-ip=195.135.220.15; envelope-from=cfontana@suse.de; helo=mx2.suse.de X-detected-operating-system: by eggs.gnu.org: First seen = 2020/09/03 00:06:01 X-ACL-Warn: Detected OS = Linux 2.2.x-3.x (no timestamps) [generic] X-Spam_score_int: -41 X-Spam_score: -4.2 X-Spam_bar: ---- X-Spam_report: (-4.2 / 5.0 requ) BAYES_00=-1.9, RCVD_IN_DNSWL_MED=-2.3, RCVD_IN_MSPIKE_H3=0.001, RCVD_IN_MSPIKE_WL=0.001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Laurent Vivier , Thomas Huth , Alberto Garcia , Eduardo Habkost , Pavel Dovgalyuk , Marcelo Tosatti , Richard Henderson , qemu-devel@nongnu.org, Markus Armbruster , Colin Xu , Wenchao Wang , haxm-team@intel.com, Sunil Muthuswamy , Claudio Fontana Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: "Qemu-devel" register a "CpusAccel" interface for WHPX as well. Signed-off-by: Claudio Fontana Reviewed-by: Richard Henderson --- MAINTAINERS | 1 + softmmu/cpus.c | 79 --------------------------------- target/i386/meson.build | 5 ++- target/i386/whpx-all.c | 3 ++ target/i386/whpx-cpus.c | 96 +++++++++++++++++++++++++++++++++++++++++ target/i386/whpx-cpus.h | 17 ++++++++ 6 files changed, 121 insertions(+), 80 deletions(-) create mode 100644 target/i386/whpx-cpus.c create mode 100644 target/i386/whpx-cpus.h diff --git a/MAINTAINERS b/MAINTAINERS index 5cd2960b46..1185606972 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -451,6 +451,7 @@ WHPX CPUs M: Sunil Muthuswamy S: Supported F: target/i386/whpx-all.c +F: target/i386/whpx-cpus.c F: target/i386/whp-dispatch.h F: accel/stubs/whpx-stub.c F: include/sysemu/whpx.h diff --git a/softmmu/cpus.c b/softmmu/cpus.c index cadaec5b95..a99eacd6a6 100644 --- a/softmmu/cpus.c +++ b/softmmu/cpus.c @@ -34,7 +34,6 @@ #include "sysemu/hw_accel.h" #include "sysemu/kvm.h" #include "sysemu/hvf.h" -#include "sysemu/whpx.h" #include "exec/exec-all.h" #include "qemu/thread.h" #include "qemu/plugin.h" @@ -178,9 +177,6 @@ void cpu_synchronize_state(CPUState *cpu) if (cpus_accel && cpus_accel->synchronize_state) { cpus_accel->synchronize_state(cpu); } - if (whpx_enabled()) { - whpx_cpu_synchronize_state(cpu); - } } void cpu_synchronize_post_reset(CPUState *cpu) @@ -188,9 +184,6 @@ void cpu_synchronize_post_reset(CPUState *cpu) if (cpus_accel && cpus_accel->synchronize_post_reset) { cpus_accel->synchronize_post_reset(cpu); } - if (whpx_enabled()) { - whpx_cpu_synchronize_post_reset(cpu); - } } void cpu_synchronize_post_init(CPUState *cpu) @@ -198,9 +191,6 @@ void cpu_synchronize_post_init(CPUState *cpu) if (cpus_accel && cpus_accel->synchronize_post_init) { cpus_accel->synchronize_post_init(cpu); } - if (whpx_enabled()) { - whpx_cpu_synchronize_post_init(cpu); - } } void cpu_synchronize_pre_loadvm(CPUState *cpu) @@ -211,9 +201,6 @@ void cpu_synchronize_pre_loadvm(CPUState *cpu) if (hvf_enabled()) { hvf_cpu_synchronize_pre_loadvm(cpu); } - if (whpx_enabled()) { - whpx_cpu_synchronize_pre_loadvm(cpu); - } } int64_t cpus_get_virtual_clock(void) @@ -445,48 +432,6 @@ static void *qemu_hvf_cpu_thread_fn(void *arg) return NULL; } -static void *qemu_whpx_cpu_thread_fn(void *arg) -{ - CPUState *cpu = arg; - int r; - - rcu_register_thread(); - - qemu_mutex_lock_iothread(); - qemu_thread_get_self(cpu->thread); - cpu->thread_id = qemu_get_thread_id(); - current_cpu = cpu; - - r = whpx_init_vcpu(cpu); - if (r < 0) { - fprintf(stderr, "whpx_init_vcpu failed: %s\n", strerror(-r)); - exit(1); - } - - /* signal CPU creation */ - cpu_thread_signal_created(cpu); - qemu_guest_random_seed_thread_part2(cpu->random_seed); - - do { - if (cpu_can_run(cpu)) { - r = whpx_vcpu_exec(cpu); - if (r == EXCP_DEBUG) { - cpu_handle_guest_debug(cpu); - } - } - while (cpu_thread_is_idle(cpu)) { - qemu_cond_wait(cpu->halt_cond, &qemu_global_mutex); - } - qemu_wait_io_event_common(cpu); - } while (!cpu->unplug || cpu_can_run(cpu)); - - whpx_destroy_vcpu(cpu); - cpu_thread_signal_destroyed(cpu); - qemu_mutex_unlock_iothread(); - rcu_unregister_thread(); - return NULL; -} - void cpus_kick_thread(CPUState *cpu) { #ifndef _WIN32 @@ -501,12 +446,6 @@ void cpus_kick_thread(CPUState *cpu) fprintf(stderr, "qemu:%s: %s", __func__, strerror(err)); exit(1); } -#else /* _WIN32 */ - if (!qemu_cpu_is_self(cpu)) { - if (whpx_enabled()) { - whpx_vcpu_kick(cpu); - } - } #endif } @@ -681,22 +620,6 @@ static void qemu_hvf_start_vcpu(CPUState *cpu) cpu, QEMU_THREAD_JOINABLE); } -static void qemu_whpx_start_vcpu(CPUState *cpu) -{ - char thread_name[VCPU_THREAD_NAME_SIZE]; - - cpu->thread = g_malloc0(sizeof(QemuThread)); - cpu->halt_cond = g_malloc0(sizeof(QemuCond)); - qemu_cond_init(cpu->halt_cond); - snprintf(thread_name, VCPU_THREAD_NAME_SIZE, "CPU %d/WHPX", - cpu->cpu_index); - qemu_thread_create(cpu->thread, thread_name, qemu_whpx_cpu_thread_fn, - cpu, QEMU_THREAD_JOINABLE); -#ifdef _WIN32 - cpu->hThread = qemu_thread_get_handle(cpu->thread); -#endif -} - void cpus_register_accel(const CpusAccel *ca) { assert(ca != NULL); @@ -726,8 +649,6 @@ void qemu_init_vcpu(CPUState *cpu) cpus_accel->create_vcpu_thread(cpu); } else if (hvf_enabled()) { qemu_hvf_start_vcpu(cpu); - } else if (whpx_enabled()) { - qemu_whpx_start_vcpu(cpu); } else { g_assert_not_reached(); } diff --git a/target/i386/meson.build b/target/i386/meson.build index 1db619841c..a1a02f3e99 100644 --- a/target/i386/meson.build +++ b/target/i386/meson.build @@ -30,7 +30,10 @@ i386_softmmu_ss.add(files( )) i386_softmmu_ss.add(when: 'CONFIG_HYPERV', if_true: files('hyperv.c'), if_false: files('hyperv-stub.c')) i386_softmmu_ss.add(when: 'CONFIG_KVM', if_true: files('kvm.c')) -i386_softmmu_ss.add(when: 'CONFIG_WHPX', if_true: files('whpx-all.c')) +i386_softmmu_ss.add(when: 'CONFIG_WHPX', if_true: files( + 'whpx-all.c', + 'whpx-cpus.c', +)) i386_softmmu_ss.add(when: 'CONFIG_HAX', if_true: files( 'hax-all.c', 'hax-mem.c', diff --git a/target/i386/whpx-all.c b/target/i386/whpx-all.c index c78baac6df..8b6986c864 100644 --- a/target/i386/whpx-all.c +++ b/target/i386/whpx-all.c @@ -24,6 +24,8 @@ #include "migration/blocker.h" #include "whp-dispatch.h" +#include "whpx-cpus.h" + #include #include @@ -1575,6 +1577,7 @@ static int whpx_accel_init(MachineState *ms) whpx_memory_init(); cpu_interrupt_handler = whpx_handle_interrupt; + cpus_register_accel(&whpx_cpus); printf("Windows Hypervisor Platform accelerator is operational\n"); return 0; diff --git a/target/i386/whpx-cpus.c b/target/i386/whpx-cpus.c new file mode 100644 index 0000000000..d9bd5a2d36 --- /dev/null +++ b/target/i386/whpx-cpus.c @@ -0,0 +1,96 @@ +/* + * QEMU Windows Hypervisor Platform accelerator (WHPX) + * + * Copyright Microsoft Corp. 2017 + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + * + */ + +#include "qemu/osdep.h" +#include "sysemu/kvm_int.h" +#include "qemu/main-loop.h" +#include "sysemu/cpus.h" +#include "qemu/guest-random.h" + +#include "sysemu/whpx.h" +#include "whpx-cpus.h" + +#include +#include + +static void *whpx_cpu_thread_fn(void *arg) +{ + CPUState *cpu = arg; + int r; + + rcu_register_thread(); + + qemu_mutex_lock_iothread(); + qemu_thread_get_self(cpu->thread); + cpu->thread_id = qemu_get_thread_id(); + current_cpu = cpu; + + r = whpx_init_vcpu(cpu); + if (r < 0) { + fprintf(stderr, "whpx_init_vcpu failed: %s\n", strerror(-r)); + exit(1); + } + + /* signal CPU creation */ + cpu_thread_signal_created(cpu); + qemu_guest_random_seed_thread_part2(cpu->random_seed); + + do { + if (cpu_can_run(cpu)) { + r = whpx_vcpu_exec(cpu); + if (r == EXCP_DEBUG) { + cpu_handle_guest_debug(cpu); + } + } + while (cpu_thread_is_idle(cpu)) { + qemu_cond_wait_iothread(cpu->halt_cond); + } + qemu_wait_io_event_common(cpu); + } while (!cpu->unplug || cpu_can_run(cpu)); + + whpx_destroy_vcpu(cpu); + cpu_thread_signal_destroyed(cpu); + qemu_mutex_unlock_iothread(); + rcu_unregister_thread(); + return NULL; +} + +static void whpx_start_vcpu_thread(CPUState *cpu) +{ + char thread_name[VCPU_THREAD_NAME_SIZE]; + + cpu->thread = g_malloc0(sizeof(QemuThread)); + cpu->halt_cond = g_malloc0(sizeof(QemuCond)); + qemu_cond_init(cpu->halt_cond); + snprintf(thread_name, VCPU_THREAD_NAME_SIZE, "CPU %d/WHPX", + cpu->cpu_index); + qemu_thread_create(cpu->thread, thread_name, whpx_cpu_thread_fn, + cpu, QEMU_THREAD_JOINABLE); +#ifdef _WIN32 + cpu->hThread = qemu_thread_get_handle(cpu->thread); +#endif +} + +static void whpx_kick_vcpu_thread(CPUState *cpu) +{ + if (!qemu_cpu_is_self(cpu)) { + whpx_vcpu_kick(cpu); + } +} + +const CpusAccel whpx_cpus = { + .create_vcpu_thread = whpx_start_vcpu_thread, + .kick_vcpu_thread = whpx_kick_vcpu_thread, + + .synchronize_post_reset = whpx_cpu_synchronize_post_reset, + .synchronize_post_init = whpx_cpu_synchronize_post_init, + .synchronize_state = whpx_cpu_synchronize_state, + .synchronize_pre_loadvm = whpx_cpu_synchronize_pre_loadvm, +}; diff --git a/target/i386/whpx-cpus.h b/target/i386/whpx-cpus.h new file mode 100644 index 0000000000..2393944954 --- /dev/null +++ b/target/i386/whpx-cpus.h @@ -0,0 +1,17 @@ +/* + * Accelerator CPUS Interface + * + * Copyright 2020 SUSE LLC + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#ifndef WHPX_CPUS_H +#define WHPX_CPUS_H + +#include "sysemu/cpus.h" + +extern const CpusAccel whpx_cpus; + +#endif /* WHPX_CPUS_H */ From patchwork Thu Sep 3 10:56:08 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Claudio Fontana X-Patchwork-Id: 274705 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-13.0 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_PATCH, MAILING_LIST_MULTI, SIGNED_OFF_BY, SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED,USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 2D43EC433E2 for ; Thu, 3 Sep 2020 11:01:41 +0000 (UTC) Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id DE4FF20767 for ; Thu, 3 Sep 2020 11:01:40 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org DE4FF20767 Authentication-Results: mail.kernel.org; dmarc=none (p=none dis=none) header.from=suse.de Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Received: from localhost ([::1]:56792 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1kDmzr-0003O8-Uh for qemu-devel@archiver.kernel.org; Thu, 03 Sep 2020 07:01:39 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:59366) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1kDmuz-0003HS-5r for qemu-devel@nongnu.org; Thu, 03 Sep 2020 06:56:37 -0400 Received: from mx2.suse.de ([195.135.220.15]:48962) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1kDmux-0004Yk-Cu for qemu-devel@nongnu.org; Thu, 03 Sep 2020 06:56:36 -0400 X-Virus-Scanned: by amavisd-new at test-mx.suse.de Received: from relay2.suse.de (unknown [195.135.221.27]) by mx2.suse.de (Postfix) with ESMTP id 9CF6AB6A6; Thu, 3 Sep 2020 10:56:24 +0000 (UTC) From: Claudio Fontana To: Paolo Bonzini , Richard Henderson , =?utf-8?q?Alex_Benn=C3=A9e?= , Peter Maydell , =?utf-8?q?Philippe_Mathieu-?= =?utf-8?b?RGF1ZMOp?= , Roman Bolshakov Subject: [PATCH v7 10/16] cpus: cleanup now unneeded includes Date: Thu, 3 Sep 2020 12:56:08 +0200 Message-Id: <20200903105614.17772-11-cfontana@suse.de> X-Mailer: git-send-email 2.26.2 In-Reply-To: <20200903105614.17772-1-cfontana@suse.de> References: <20200903105614.17772-1-cfontana@suse.de> MIME-Version: 1.0 Received-SPF: pass client-ip=195.135.220.15; envelope-from=cfontana@suse.de; helo=mx2.suse.de X-detected-operating-system: by eggs.gnu.org: First seen = 2020/09/03 00:06:01 X-ACL-Warn: Detected OS = Linux 2.2.x-3.x (no timestamps) [generic] X-Spam_score_int: -41 X-Spam_score: -4.2 X-Spam_bar: ---- X-Spam_report: (-4.2 / 5.0 requ) BAYES_00=-1.9, RCVD_IN_DNSWL_MED=-2.3, RCVD_IN_MSPIKE_H3=0.001, RCVD_IN_MSPIKE_WL=0.001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Laurent Vivier , Thomas Huth , Alberto Garcia , Eduardo Habkost , Pavel Dovgalyuk , Marcelo Tosatti , Richard Henderson , qemu-devel@nongnu.org, Markus Armbruster , Colin Xu , Wenchao Wang , haxm-team@intel.com, Sunil Muthuswamy , Claudio Fontana Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: "Qemu-devel" Signed-off-by: Claudio Fontana Reviewed-by: Richard Henderson Reviewed-by: Alex Bennée --- softmmu/cpus.c | 7 ------- 1 file changed, 7 deletions(-) diff --git a/softmmu/cpus.c b/softmmu/cpus.c index 2420a447eb..3d8350fba9 100644 --- a/softmmu/cpus.c +++ b/softmmu/cpus.c @@ -29,20 +29,13 @@ #include "qapi/qapi-commands-misc.h" #include "qapi/qapi-events-run-state.h" #include "qapi/qmp/qerror.h" -#include "sysemu/tcg.h" #include "exec/gdbstub.h" #include "sysemu/hw_accel.h" -#include "sysemu/kvm.h" #include "exec/exec-all.h" #include "qemu/thread.h" #include "qemu/plugin.h" #include "sysemu/cpus.h" -#include "qemu/main-loop.h" -#include "qemu/option.h" -#include "qemu/bitmap.h" -#include "qemu/seqlock.h" #include "qemu/guest-random.h" -#include "tcg/tcg.h" #include "hw/nmi.h" #include "sysemu/replay.h" #include "sysemu/runstate.h" From patchwork Thu Sep 3 10:56:09 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Claudio Fontana X-Patchwork-Id: 274704 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-13.0 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_PATCH, MAILING_LIST_MULTI, SIGNED_OFF_BY, SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED,USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 4B13BC433E2 for ; Thu, 3 Sep 2020 11:03:35 +0000 (UTC) Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 0EA5720767 for ; Thu, 3 Sep 2020 11:03:34 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 0EA5720767 Authentication-Results: mail.kernel.org; dmarc=none (p=none dis=none) header.from=suse.de Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Received: from localhost ([::1]:35470 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1kDn1h-0006KJ-VX for qemu-devel@archiver.kernel.org; Thu, 03 Sep 2020 07:03:33 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:59380) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1kDmuz-0003IN-V0 for qemu-devel@nongnu.org; Thu, 03 Sep 2020 06:56:37 -0400 Received: from mx2.suse.de ([195.135.220.15]:48990) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1kDmuy-0004Yy-3v for qemu-devel@nongnu.org; Thu, 03 Sep 2020 06:56:37 -0400 X-Virus-Scanned: by amavisd-new at test-mx.suse.de Received: from relay2.suse.de (unknown [195.135.221.27]) by mx2.suse.de (Postfix) with ESMTP id 50DC4B6A9; Thu, 3 Sep 2020 10:56:25 +0000 (UTC) From: Claudio Fontana To: Paolo Bonzini , Richard Henderson , =?utf-8?q?Alex_Benn=C3=A9e?= , Peter Maydell , =?utf-8?q?Philippe_Mathieu-?= =?utf-8?b?RGF1ZMOp?= , Roman Bolshakov Subject: [PATCH v7 11/16] cpus: remove checks for non-NULL cpus_accel Date: Thu, 3 Sep 2020 12:56:09 +0200 Message-Id: <20200903105614.17772-12-cfontana@suse.de> X-Mailer: git-send-email 2.26.2 In-Reply-To: <20200903105614.17772-1-cfontana@suse.de> References: <20200903105614.17772-1-cfontana@suse.de> MIME-Version: 1.0 Received-SPF: pass client-ip=195.135.220.15; envelope-from=cfontana@suse.de; helo=mx2.suse.de X-detected-operating-system: by eggs.gnu.org: First seen = 2020/09/03 00:06:01 X-ACL-Warn: Detected OS = Linux 2.2.x-3.x (no timestamps) [generic] X-Spam_score_int: -41 X-Spam_score: -4.2 X-Spam_bar: ---- X-Spam_report: (-4.2 / 5.0 requ) BAYES_00=-1.9, RCVD_IN_DNSWL_MED=-2.3, RCVD_IN_MSPIKE_H3=0.001, RCVD_IN_MSPIKE_WL=0.001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Laurent Vivier , Thomas Huth , Alberto Garcia , Eduardo Habkost , Pavel Dovgalyuk , Marcelo Tosatti , Richard Henderson , qemu-devel@nongnu.org, Markus Armbruster , Colin Xu , Wenchao Wang , haxm-team@intel.com, Sunil Muthuswamy , Claudio Fontana Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: "Qemu-devel" now that all accelerators support the CpusAccel interface, we can remove most checks for non-NULL cpus_accel, we just add a sanity check/assert at vcpu creation. Signed-off-by: Claudio Fontana Reviewed-by: Richard Henderson --- softmmu/cpus.c | 33 +++++++++++++++++++++------------ 1 file changed, 21 insertions(+), 12 deletions(-) diff --git a/softmmu/cpus.c b/softmmu/cpus.c index 3d8350fba9..f32ecb4bb9 100644 --- a/softmmu/cpus.c +++ b/softmmu/cpus.c @@ -166,34 +166,46 @@ void cpu_synchronize_all_pre_loadvm(void) void cpu_synchronize_state(CPUState *cpu) { - if (cpus_accel && cpus_accel->synchronize_state) { + if (cpus_accel->synchronize_state) { cpus_accel->synchronize_state(cpu); } } void cpu_synchronize_post_reset(CPUState *cpu) { - if (cpus_accel && cpus_accel->synchronize_post_reset) { + if (cpus_accel->synchronize_post_reset) { cpus_accel->synchronize_post_reset(cpu); } } void cpu_synchronize_post_init(CPUState *cpu) { - if (cpus_accel && cpus_accel->synchronize_post_init) { + if (cpus_accel->synchronize_post_init) { cpus_accel->synchronize_post_init(cpu); } } void cpu_synchronize_pre_loadvm(CPUState *cpu) { - if (cpus_accel && cpus_accel->synchronize_pre_loadvm) { + if (cpus_accel->synchronize_pre_loadvm) { cpus_accel->synchronize_pre_loadvm(cpu); } } int64_t cpus_get_virtual_clock(void) { + /* + * XXX + * + * need to check that cpus_accel is not NULL, because qcow2 calls + * qemu_get_clock_ns(CLOCK_VIRTUAL) without any accel initialized and + * with ticks disabled in some io-tests: + * 030 040 041 060 099 120 127 140 156 161 172 181 191 192 195 203 229 249 256 267 + * + * is this expected? + * + * XXX + */ if (cpus_accel && cpus_accel->get_virtual_clock) { return cpus_accel->get_virtual_clock(); } @@ -207,7 +219,7 @@ int64_t cpus_get_virtual_clock(void) */ int64_t cpus_get_elapsed_ticks(void) { - if (cpus_accel && cpus_accel->get_elapsed_ticks) { + if (cpus_accel->get_elapsed_ticks) { return cpus_accel->get_elapsed_ticks(); } return cpu_get_ticks(); @@ -399,7 +411,7 @@ void cpus_kick_thread(CPUState *cpu) void qemu_cpu_kick(CPUState *cpu) { qemu_cond_broadcast(cpu->halt_cond); - if (cpus_accel && cpus_accel->kick_vcpu_thread) { + if (cpus_accel->kick_vcpu_thread) { cpus_accel->kick_vcpu_thread(cpu); } else { /* default */ cpus_kick_thread(cpu); @@ -573,12 +585,9 @@ void qemu_init_vcpu(CPUState *cpu) cpu_address_space_init(cpu, 0, "cpu-memory", cpu->memory); } - if (cpus_accel) { - /* accelerator already implements the CpusAccel interface */ - cpus_accel->create_vcpu_thread(cpu); - } else { - g_assert_not_reached(); - } + /* accelerators all implement the CpusAccel interface */ + g_assert(cpus_accel != NULL && cpus_accel->create_vcpu_thread != NULL); + cpus_accel->create_vcpu_thread(cpu); while (!cpu->created) { qemu_cond_wait(&qemu_cpu_cond, &qemu_global_mutex); From patchwork Thu Sep 3 10:56:10 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Claudio Fontana X-Patchwork-Id: 274703 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-13.0 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_PATCH, MAILING_LIST_MULTI, SIGNED_OFF_BY, SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED,USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 87B0CC433E9 for ; Thu, 3 Sep 2020 11:03:52 +0000 (UTC) Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 4896D20767 for ; Thu, 3 Sep 2020 11:03:52 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 4896D20767 Authentication-Results: mail.kernel.org; dmarc=none (p=none dis=none) header.from=suse.de Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Received: from localhost ([::1]:36908 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1kDn1z-0006xy-7B for qemu-devel@archiver.kernel.org; Thu, 03 Sep 2020 07:03:51 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:59402) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1kDmv0-0003LI-WD for qemu-devel@nongnu.org; Thu, 03 Sep 2020 06:56:39 -0400 Received: from mx2.suse.de ([195.135.220.15]:48994) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1kDmuy-0004Z2-BQ for qemu-devel@nongnu.org; Thu, 03 Sep 2020 06:56:38 -0400 X-Virus-Scanned: by amavisd-new at test-mx.suse.de Received: from relay2.suse.de (unknown [195.135.221.27]) by mx2.suse.de (Postfix) with ESMTP id EEC77B6AB; Thu, 3 Sep 2020 10:56:25 +0000 (UTC) From: Claudio Fontana To: Paolo Bonzini , Richard Henderson , =?utf-8?q?Alex_Benn=C3=A9e?= , Peter Maydell , =?utf-8?q?Philippe_Mathieu-?= =?utf-8?b?RGF1ZMOp?= , Roman Bolshakov Subject: [PATCH v7 12/16] cpus: add handle_interrupt to the CpusAccel interface Date: Thu, 3 Sep 2020 12:56:10 +0200 Message-Id: <20200903105614.17772-13-cfontana@suse.de> X-Mailer: git-send-email 2.26.2 In-Reply-To: <20200903105614.17772-1-cfontana@suse.de> References: <20200903105614.17772-1-cfontana@suse.de> MIME-Version: 1.0 Received-SPF: pass client-ip=195.135.220.15; envelope-from=cfontana@suse.de; helo=mx2.suse.de X-detected-operating-system: by eggs.gnu.org: First seen = 2020/09/03 00:06:01 X-ACL-Warn: Detected OS = Linux 2.2.x-3.x (no timestamps) [generic] X-Spam_score_int: -41 X-Spam_score: -4.2 X-Spam_bar: ---- X-Spam_report: (-4.2 / 5.0 requ) BAYES_00=-1.9, RCVD_IN_DNSWL_MED=-2.3, RCVD_IN_MSPIKE_H3=0.001, RCVD_IN_MSPIKE_WL=0.001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Laurent Vivier , Thomas Huth , Alberto Garcia , Eduardo Habkost , Pavel Dovgalyuk , Marcelo Tosatti , Richard Henderson , qemu-devel@nongnu.org, Markus Armbruster , Colin Xu , Wenchao Wang , haxm-team@intel.com, Sunil Muthuswamy , Claudio Fontana Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: "Qemu-devel" kvm: uses the generic handler qtest: uses the generic handler whpx: changed to use the generic handler (identical implementation) hax: changed to use the generic handler (identical implementation) hvf: changed to use the generic handler (identical implementation) tcg: adapt tcg-cpus to point to the tcg-specific handler Signed-off-by: Claudio Fontana Reviewed-by: Richard Henderson --- accel/tcg/tcg-all.c | 26 -------------------------- accel/tcg/tcg-cpus.c | 28 ++++++++++++++++++++++++++++ hw/core/cpu.c | 13 ------------- include/hw/core/cpu.h | 14 -------------- include/sysemu/cpus.h | 2 ++ softmmu/cpus.c | 18 ++++++++++++++++++ target/i386/hax-all.c | 10 ---------- target/i386/hvf/hvf.c | 9 --------- target/i386/whpx-all.c | 10 ---------- 9 files changed, 48 insertions(+), 82 deletions(-) diff --git a/accel/tcg/tcg-all.c b/accel/tcg/tcg-all.c index 01957b130d..af9bf5c5bb 100644 --- a/accel/tcg/tcg-all.c +++ b/accel/tcg/tcg-all.c @@ -47,31 +47,6 @@ typedef struct TCGState { #define TCG_STATE(obj) \ OBJECT_CHECK(TCGState, (obj), TYPE_TCG_ACCEL) -/* mask must never be zero, except for A20 change call */ -static void tcg_handle_interrupt(CPUState *cpu, int mask) -{ - int old_mask; - g_assert(qemu_mutex_iothread_locked()); - - old_mask = cpu->interrupt_request; - cpu->interrupt_request |= mask; - - /* - * If called from iothread context, wake the target cpu in - * case its halted. - */ - if (!qemu_cpu_is_self(cpu)) { - qemu_cpu_kick(cpu); - } else { - atomic_set(&cpu_neg(cpu)->icount_decr.u16.high, -1); - if (icount_enabled() && - !cpu->can_do_io - && (mask & ~old_mask) != 0) { - cpu_abort(cpu, "Raised interrupt while not in I/O function"); - } - } -} - /* * We default to false if we know other options have been enabled * which are currently incompatible with MTTCG. Otherwise when each @@ -128,7 +103,6 @@ static int tcg_init(MachineState *ms) TCGState *s = TCG_STATE(current_accel()); tcg_exec_init(s->tb_size * 1024 * 1024); - cpu_interrupt_handler = tcg_handle_interrupt; mttcg_enabled = s->mttcg_enabled; cpus_register_accel(&tcg_cpus); diff --git a/accel/tcg/tcg-cpus.c b/accel/tcg/tcg-cpus.c index 72696f6d86..2bb209e2c6 100644 --- a/accel/tcg/tcg-cpus.c +++ b/accel/tcg/tcg-cpus.c @@ -533,9 +533,37 @@ static int64_t tcg_get_elapsed_ticks(void) return cpu_get_ticks(); } +/* mask must never be zero, except for A20 change call */ +static void tcg_handle_interrupt(CPUState *cpu, int mask) +{ + int old_mask; + g_assert(qemu_mutex_iothread_locked()); + + old_mask = cpu->interrupt_request; + cpu->interrupt_request |= mask; + + /* + * If called from iothread context, wake the target cpu in + * case its halted. + */ + if (!qemu_cpu_is_self(cpu)) { + qemu_cpu_kick(cpu); + } else { + atomic_set(&cpu_neg(cpu)->icount_decr.u16.high, -1); + if (icount_enabled() && + !cpu->can_do_io + && (mask & ~old_mask) != 0) { + cpu_abort(cpu, "Raised interrupt while not in I/O function"); + } + } +} + const CpusAccel tcg_cpus = { .create_vcpu_thread = tcg_start_vcpu_thread, .kick_vcpu_thread = tcg_kick_vcpu_thread, + + .handle_interrupt = tcg_handle_interrupt, + .get_virtual_clock = tcg_get_virtual_clock, .get_elapsed_ticks = tcg_get_elapsed_ticks, }; diff --git a/hw/core/cpu.c b/hw/core/cpu.c index fa8602493b..451b3d5ee7 100644 --- a/hw/core/cpu.c +++ b/hw/core/cpu.c @@ -35,8 +35,6 @@ #include "qemu/plugin.h" #include "sysemu/hw_accel.h" -CPUInterruptHandler cpu_interrupt_handler; - CPUState *cpu_by_arch_id(int64_t id) { CPUState *cpu; @@ -394,17 +392,6 @@ static vaddr cpu_adjust_watchpoint_address(CPUState *cpu, vaddr addr, int len) return addr; } -static void generic_handle_interrupt(CPUState *cpu, int mask) -{ - cpu->interrupt_request |= mask; - - if (!qemu_cpu_is_self(cpu)) { - qemu_cpu_kick(cpu); - } -} - -CPUInterruptHandler cpu_interrupt_handler = generic_handle_interrupt; - static void cpu_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/include/hw/core/cpu.h b/include/hw/core/cpu.h index 8f145733ce..efd33d87fd 100644 --- a/include/hw/core/cpu.h +++ b/include/hw/core/cpu.h @@ -838,12 +838,6 @@ bool cpu_exists(int64_t id); */ CPUState *cpu_by_arch_id(int64_t id); -#ifndef CONFIG_USER_ONLY - -typedef void (*CPUInterruptHandler)(CPUState *, int); - -extern CPUInterruptHandler cpu_interrupt_handler; - /** * cpu_interrupt: * @cpu: The CPU to set an interrupt on. @@ -851,17 +845,9 @@ extern CPUInterruptHandler cpu_interrupt_handler; * * Invokes the interrupt handler. */ -static inline void cpu_interrupt(CPUState *cpu, int mask) -{ - cpu_interrupt_handler(cpu, mask); -} - -#else /* USER_ONLY */ void cpu_interrupt(CPUState *cpu, int mask); -#endif /* USER_ONLY */ - #ifdef NEED_CPU_H #ifdef CONFIG_SOFTMMU diff --git a/include/sysemu/cpus.h b/include/sysemu/cpus.h index 26171697f5..231685955d 100644 --- a/include/sysemu/cpus.h +++ b/include/sysemu/cpus.h @@ -16,6 +16,8 @@ typedef struct CpusAccel { void (*synchronize_state)(CPUState *cpu); void (*synchronize_pre_loadvm)(CPUState *cpu); + void (*handle_interrupt)(CPUState *cpu, int mask); + int64_t (*get_virtual_clock)(void); int64_t (*get_elapsed_ticks)(void); } CpusAccel; diff --git a/softmmu/cpus.c b/softmmu/cpus.c index f32ecb4bb9..7068666579 100644 --- a/softmmu/cpus.c +++ b/softmmu/cpus.c @@ -225,6 +225,24 @@ int64_t cpus_get_elapsed_ticks(void) return cpu_get_ticks(); } +static void generic_handle_interrupt(CPUState *cpu, int mask) +{ + cpu->interrupt_request |= mask; + + if (!qemu_cpu_is_self(cpu)) { + qemu_cpu_kick(cpu); + } +} + +void cpu_interrupt(CPUState *cpu, int mask) +{ + if (cpus_accel->handle_interrupt) { + cpus_accel->handle_interrupt(cpu, mask); + } else { + generic_handle_interrupt(cpu, mask); + } +} + static int do_vm_stop(RunState state, bool send_stop) { int ret = 0; diff --git a/target/i386/hax-all.c b/target/i386/hax-all.c index b66ddeb8bf..fd1ab673d7 100644 --- a/target/i386/hax-all.c +++ b/target/i386/hax-all.c @@ -297,15 +297,6 @@ int hax_vm_destroy(struct hax_vm *vm) return 0; } -static void hax_handle_interrupt(CPUState *cpu, int mask) -{ - cpu->interrupt_request |= mask; - - if (!qemu_cpu_is_self(cpu)) { - qemu_cpu_kick(cpu); - } -} - static int hax_init(ram_addr_t ram_size, int max_cpus) { struct hax_state *hax = NULL; @@ -350,7 +341,6 @@ static int hax_init(ram_addr_t ram_size, int max_cpus) qversion.cur_version = hax_cur_version; qversion.min_version = hax_min_version; hax_notify_qemu_version(hax->vm->fd, &qversion); - cpu_interrupt_handler = hax_handle_interrupt; return ret; error: diff --git a/target/i386/hvf/hvf.c b/target/i386/hvf/hvf.c index 7ac6987c1b..ed9356565c 100644 --- a/target/i386/hvf/hvf.c +++ b/target/i386/hvf/hvf.c @@ -262,14 +262,6 @@ static void update_apic_tpr(CPUState *cpu) #define VECTORING_INFO_VECTOR_MASK 0xff -static void hvf_handle_interrupt(CPUState * cpu, int mask) -{ - cpu->interrupt_request |= mask; - if (!qemu_cpu_is_self(cpu)) { - qemu_cpu_kick(cpu); - } -} - void hvf_handle_io(CPUArchState *env, uint16_t port, void *buffer, int direction, int size, int count) { @@ -894,7 +886,6 @@ static int hvf_accel_init(MachineState *ms) } hvf_state = s; - cpu_interrupt_handler = hvf_handle_interrupt; memory_listener_register(&hvf_memory_listener, &address_space_memory); cpus_register_accel(&hvf_cpus); return 0; diff --git a/target/i386/whpx-all.c b/target/i386/whpx-all.c index 8b6986c864..b3d17fbe04 100644 --- a/target/i386/whpx-all.c +++ b/target/i386/whpx-all.c @@ -1413,15 +1413,6 @@ static void whpx_memory_init(void) memory_listener_register(&whpx_memory_listener, &address_space_memory); } -static void whpx_handle_interrupt(CPUState *cpu, int mask) -{ - cpu->interrupt_request |= mask; - - if (!qemu_cpu_is_self(cpu)) { - qemu_cpu_kick(cpu); - } -} - /* * Load the functions from the given library, using the given handle. If a * handle is provided, it is used, otherwise the library is opened. The @@ -1576,7 +1567,6 @@ static int whpx_accel_init(MachineState *ms) whpx_memory_init(); - cpu_interrupt_handler = whpx_handle_interrupt; cpus_register_accel(&whpx_cpus); printf("Windows Hypervisor Platform accelerator is operational\n"); From patchwork Thu Sep 3 10:56:13 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Claudio Fontana X-Patchwork-Id: 274702 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-13.0 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_PATCH, MAILING_LIST_MULTI, SIGNED_OFF_BY, SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED,USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 076FEC433E2 for ; Thu, 3 Sep 2020 11:04:53 +0000 (UTC) Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id C2E5720767 for ; Thu, 3 Sep 2020 11:04:52 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org C2E5720767 Authentication-Results: mail.kernel.org; dmarc=none (p=none dis=none) header.from=suse.de Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Received: from localhost ([::1]:43388 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1kDn2x-0001H1-QW for qemu-devel@archiver.kernel.org; Thu, 03 Sep 2020 07:04:51 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:59434) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1kDmv3-0003Nu-Jo for qemu-devel@nongnu.org; Thu, 03 Sep 2020 06:56:41 -0400 Received: from mx2.suse.de ([195.135.220.15]:49070) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1kDmv0-0004Zi-7w for qemu-devel@nongnu.org; Thu, 03 Sep 2020 06:56:41 -0400 X-Virus-Scanned: by amavisd-new at test-mx.suse.de Received: from relay2.suse.de (unknown [195.135.221.27]) by mx2.suse.de (Postfix) with ESMTP id EE0FBB6AC; Thu, 3 Sep 2020 10:56:27 +0000 (UTC) From: Claudio Fontana To: Paolo Bonzini , Richard Henderson , =?utf-8?q?Alex_Benn=C3=A9e?= , Peter Maydell , =?utf-8?q?Philippe_Mathieu-?= =?utf-8?b?RGF1ZMOp?= , Roman Bolshakov Subject: [PATCH v7 15/16] hax: remove hax specific functions from global includes Date: Thu, 3 Sep 2020 12:56:13 +0200 Message-Id: <20200903105614.17772-16-cfontana@suse.de> X-Mailer: git-send-email 2.26.2 In-Reply-To: <20200903105614.17772-1-cfontana@suse.de> References: <20200903105614.17772-1-cfontana@suse.de> MIME-Version: 1.0 Received-SPF: pass client-ip=195.135.220.15; envelope-from=cfontana@suse.de; helo=mx2.suse.de X-detected-operating-system: by eggs.gnu.org: First seen = 2020/09/03 00:06:01 X-ACL-Warn: Detected OS = Linux 2.2.x-3.x (no timestamps) [generic] X-Spam_score_int: -41 X-Spam_score: -4.2 X-Spam_bar: ---- X-Spam_report: (-4.2 / 5.0 requ) BAYES_00=-1.9, RCVD_IN_DNSWL_MED=-2.3, RCVD_IN_MSPIKE_H3=0.001, RCVD_IN_MSPIKE_WL=0.001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Laurent Vivier , Thomas Huth , Alberto Garcia , Eduardo Habkost , Pavel Dovgalyuk , Marcelo Tosatti , Richard Henderson , qemu-devel@nongnu.org, Markus Armbruster , Colin Xu , Wenchao Wang , haxm-team@intel.com, Sunil Muthuswamy , Claudio Fontana Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: "Qemu-devel" Signed-off-by: Claudio Fontana Reviewed-by: Richard Henderson --- accel/stubs/hax-stub.c | 10 ---------- include/sysemu/hax.h | 17 ----------------- target/i386/hax-all.c | 1 - target/i386/hax-cpus.c | 1 - target/i386/hax-cpus.h | 16 ++++++++++++++++ target/i386/hax-mem.c | 2 +- target/i386/hax-posix.c | 3 +-- target/i386/hax-windows.c | 2 +- target/i386/hax-windows.h | 2 ++ 9 files changed, 21 insertions(+), 33 deletions(-) diff --git a/accel/stubs/hax-stub.c b/accel/stubs/hax-stub.c index 7ad190cae2..1a9da83185 100644 --- a/accel/stubs/hax-stub.c +++ b/accel/stubs/hax-stub.c @@ -21,13 +21,3 @@ int hax_sync_vcpus(void) { return 0; } - -int hax_init_vcpu(CPUState *cpu) -{ - return -ENOSYS; -} - -int hax_smp_cpu_exec(CPUState *cpu) -{ - return -ENOSYS; -} diff --git a/include/sysemu/hax.h b/include/sysemu/hax.h index 9b27e65cc7..12fb54f990 100644 --- a/include/sysemu/hax.h +++ b/include/sysemu/hax.h @@ -22,29 +22,12 @@ #ifndef QEMU_HAX_H #define QEMU_HAX_H - int hax_sync_vcpus(void); -int hax_init_vcpu(CPUState *cpu); -int hax_smp_cpu_exec(CPUState *cpu); -int hax_populate_ram(uint64_t va, uint64_t size); - -void hax_cpu_synchronize_state(CPUState *cpu); -void hax_cpu_synchronize_post_reset(CPUState *cpu); -void hax_cpu_synchronize_post_init(CPUState *cpu); -void hax_cpu_synchronize_pre_loadvm(CPUState *cpu); #ifdef CONFIG_HAX int hax_enabled(void); -#include "qemu/bitops.h" -#include "exec/memory.h" -int hax_vcpu_destroy(CPUState *cpu); -void hax_raise_event(CPUState *cpu); -void hax_reset_vcpu_state(void *opaque); -#include "target/i386/hax-interface.h" -#include "target/i386/hax-i386.h" - #else /* CONFIG_HAX */ #define hax_enabled() (0) diff --git a/target/i386/hax-all.c b/target/i386/hax-all.c index fd1ab673d7..fecfe8cd6e 100644 --- a/target/i386/hax-all.c +++ b/target/i386/hax-all.c @@ -28,7 +28,6 @@ #include "exec/address-spaces.h" #include "qemu-common.h" -#include "hax-i386.h" #include "sysemu/accel.h" #include "sysemu/reset.h" #include "sysemu/runstate.h" diff --git a/target/i386/hax-cpus.c b/target/i386/hax-cpus.c index 9aad98bc7a..99770e590c 100644 --- a/target/i386/hax-cpus.c +++ b/target/i386/hax-cpus.c @@ -22,7 +22,6 @@ #include "qemu/osdep.h" #include "qemu/error-report.h" #include "qemu/main-loop.h" -#include "hax-i386.h" #include "sysemu/runstate.h" #include "sysemu/cpus.h" #include "qemu/guest-random.h" diff --git a/target/i386/hax-cpus.h b/target/i386/hax-cpus.h index a64417fe2d..ee8ab7a631 100644 --- a/target/i386/hax-cpus.h +++ b/target/i386/hax-cpus.h @@ -14,4 +14,20 @@ extern const CpusAccel hax_cpus; +#include "hax-interface.h" +#include "hax-i386.h" + +int hax_init_vcpu(CPUState *cpu); +int hax_smp_cpu_exec(CPUState *cpu); +int hax_populate_ram(uint64_t va, uint64_t size); + +void hax_cpu_synchronize_state(CPUState *cpu); +void hax_cpu_synchronize_post_reset(CPUState *cpu); +void hax_cpu_synchronize_post_init(CPUState *cpu); +void hax_cpu_synchronize_pre_loadvm(CPUState *cpu); + +int hax_vcpu_destroy(CPUState *cpu); +void hax_raise_event(CPUState *cpu); +void hax_reset_vcpu_state(void *opaque); + #endif /* HAX_CPUS_H */ diff --git a/target/i386/hax-mem.c b/target/i386/hax-mem.c index 6bb5a24917..71e637cf16 100644 --- a/target/i386/hax-mem.c +++ b/target/i386/hax-mem.c @@ -13,7 +13,7 @@ #include "exec/address-spaces.h" #include "qemu/error-report.h" -#include "target/i386/hax-i386.h" +#include "hax-cpus.h" #include "qemu/queue.h" #define DEBUG_HAX_MEM 0 diff --git a/target/i386/hax-posix.c b/target/i386/hax-posix.c index 6fb7867d11..735a749d4b 100644 --- a/target/i386/hax-posix.c +++ b/target/i386/hax-posix.c @@ -14,9 +14,8 @@ #include "qemu/osdep.h" #include -#include "target/i386/hax-i386.h" - #include "sysemu/cpus.h" +#include "hax-cpus.h" hax_fd hax_mod_open(void) { diff --git a/target/i386/hax-windows.c b/target/i386/hax-windows.c index 469b48e608..6c82dfb54f 100644 --- a/target/i386/hax-windows.c +++ b/target/i386/hax-windows.c @@ -12,7 +12,7 @@ #include "qemu/osdep.h" #include "cpu.h" -#include "hax-i386.h" +#include "hax-cpus.h" /* * return 0 when success, -1 when driver not loaded, diff --git a/target/i386/hax-windows.h b/target/i386/hax-windows.h index 12cbd813dc..a5ce12d663 100644 --- a/target/i386/hax-windows.h +++ b/target/i386/hax-windows.h @@ -23,6 +23,8 @@ #include #include +#include "hax-cpus.h" + #define HAX_INVALID_FD INVALID_HANDLE_VALUE static inline void hax_mod_close(struct hax_state *hax)