From patchwork Tue Jan 16 14:17:17 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paolo Bonzini X-Patchwork-Id: 861655 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=nongnu.org (client-ip=2001:4830:134:3::11; helo=lists.gnu.org; envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org; receiver=) Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.b="LwSzBs3+"; dkim-atps=neutral Received: from lists.gnu.org (lists.gnu.org [IPv6:2001:4830:134:3::11]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 3zLYDX4VM6z9s7v for ; Wed, 17 Jan 2018 01:55:24 +1100 (AEDT) Received: from localhost ([::1]:39438 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1ebSe2-0007up-LB for incoming@patchwork.ozlabs.org; Tue, 16 Jan 2018 09:55:22 -0500 Received: from eggs.gnu.org ([2001:4830:134:3::10]:50616) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1ebS4K-0003KB-MI for qemu-devel@nongnu.org; Tue, 16 Jan 2018 09:18:30 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1ebS4J-00056n-3b for qemu-devel@nongnu.org; Tue, 16 Jan 2018 09:18:28 -0500 Received: from mail-wr0-x244.google.com ([2a00:1450:400c:c0c::244]:39389) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_128_CBC_SHA1:16) (Exim 4.71) (envelope-from ) id 1ebS4I-000566-Q0 for qemu-devel@nongnu.org; Tue, 16 Jan 2018 09:18:27 -0500 Received: by mail-wr0-x244.google.com with SMTP id z48so15341801wrz.6 for ; Tue, 16 Jan 2018 06:18:26 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=sender:from:to:cc:subject:date:message-id:in-reply-to:references; bh=2eVEPGGd0p1cc+W9ih7Iyu213y0WXBSfJ07Qj6gqueo=; b=LwSzBs3++mtfyQQLUbAXE8JoUW4iUPEC0NBCqKQphTo9BAnwRnyF9UJlR33Wj+iedb gDT2ox3hAvz09s6NAcaepyad3Wn/XdZ3MX/ZqpTeaUvwbs3yH06Wd2y7SCJ/073ADqub yyUJh4mJBAytubRilZKoYD0TIZgRZVe9lE1asMC1+tFbCfm2k08u/YwC+AwgSv6KzPS2 5yJ/pzlkh3iK4KYgYD7ea5MQHwVOaJGJx3X4zvua8/Iqhc/TcK6brJ4ZV4MQsEnFnWiV VsvWYmfE/bfwb7Jf2gWuFFnKfdJbMS0MFVKtmkaFfPx4dwcBYgMmJyD3LwZRax8Q53Yo c0ig== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:sender:from:to:cc:subject:date:message-id :in-reply-to:references; bh=2eVEPGGd0p1cc+W9ih7Iyu213y0WXBSfJ07Qj6gqueo=; b=EcLQChB3wsPDKPjGSoK+V0fnHenudSzU9HOVpVrAM62ibAaeMniNdaDfwcXcsJRKvG LSlViWzXtWOg7+1Tc41C9j4A66zn0d+TL2v+FVuAEYdo0Fj+aLZu0zBWV9bhC/Zv3DfJ 47SALbBe6u5lWXATxWz4Zm2cVOdv2p1SVE2CHnIMO2m98f1IBemX+qse5hd/UrI6uhtP Ib7y3YhWuQsM0JF+LW0k41anegMZq1rVpLHeDqBVayIMY7SyOHdJp2DSn35FWgDtDScO mmDvF3hfOZaay9TOYiTaEdoce681UNGgqEtJIUrNj0SQK+xBuW/zFrp96iSpT7h3sDNf 6FvA== X-Gm-Message-State: AKGB3mKSbVLsg2t1cbVaZ6AIehvrHENt3zH9+v3sHepDl0lQ2ZLSwhY6 di2P3TL34Wke8di72Xpqt8+BOgdj X-Google-Smtp-Source: ACJfBosWeJDWCan3acldJhphHiO79DPSCQrK1BiwQWjKGbAi3TcjumUFp7bQxH29VAqBzdYHVJ4KVA== X-Received: by 10.223.136.110 with SMTP id e43mr23760676wre.98.1516112305477; Tue, 16 Jan 2018 06:18:25 -0800 (PST) Received: from 640k.lan (dynamic-adsl-78-12-229-84.clienti.tiscali.it. [78.12.229.84]) by smtp.gmail.com with ESMTPSA id u10sm1537758wrg.6.2018.01.16.06.18.24 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Tue, 16 Jan 2018 06:18:24 -0800 (PST) From: Paolo Bonzini To: qemu-devel@nongnu.org Date: Tue, 16 Jan 2018 15:17:17 +0100 Message-Id: <1516112253-14480-36-git-send-email-pbonzini@redhat.com> X-Mailer: git-send-email 1.8.3.1 In-Reply-To: <1516112253-14480-1-git-send-email-pbonzini@redhat.com> References: <1516112253-14480-1-git-send-email-pbonzini@redhat.com> X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 2a00:1450:400c:c0c::244 Subject: [Qemu-devel] [PULL 35/51] icount: fixed saving/restoring of icount warp timers X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Pavel Dovgalyuk Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: "Qemu-devel" From: Pavel Dovgalyuk This patch adds saving and restoring of the icount warp timers in the vmstate. It is needed because there timers affect the virtual clock value. Therefore determinism of the execution in icount record/replay mode depends on determinism of the timers. Signed-off-by: Pavel Dovgalyuk Acked-by: Paolo Bonzini Signed-off-by: Paolo Bonzini Signed-off-by: Pavel Dovgalyuk --- cpus.c | 85 +++++++++++++++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 66 insertions(+), 19 deletions(-) diff --git a/cpus.c b/cpus.c index e8139de..f992537 100644 --- a/cpus.c +++ b/cpus.c @@ -120,16 +120,11 @@ static bool all_cpu_threads_idle(void) /* Protected by TimersState seqlock */ static bool icount_sleep = true; -static int64_t vm_clock_warp_start = -1; /* Conversion factor from emulated instructions to virtual clock ticks. */ static int icount_time_shift; /* Arbitrarily pick 1MIPS as the minimum allowable speed. */ #define MAX_ICOUNT_SHIFT 10 -static QEMUTimer *icount_rt_timer; -static QEMUTimer *icount_vm_timer; -static QEMUTimer *icount_warp_timer; - typedef struct TimersState { /* Protected by BQL. */ int64_t cpu_ticks_prev; @@ -147,6 +142,11 @@ typedef struct TimersState { int64_t qemu_icount_bias; /* Only written by TCG thread */ int64_t qemu_icount; + /* for adjusting icount */ + int64_t vm_clock_warp_start; + QEMUTimer *icount_rt_timer; + QEMUTimer *icount_vm_timer; + QEMUTimer *icount_warp_timer; } TimersState; static TimersState timers_state; @@ -432,14 +432,14 @@ static void icount_adjust(void) static void icount_adjust_rt(void *opaque) { - timer_mod(icount_rt_timer, + 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(icount_vm_timer, + timer_mod(timers_state.icount_vm_timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + NANOSECONDS_PER_SECOND / 10); icount_adjust(); @@ -460,7 +460,7 @@ static void icount_warp_rt(void) */ do { seq = seqlock_read_begin(&timers_state.vm_clock_seqlock); - warp_start = vm_clock_warp_start; + warp_start = timers_state.vm_clock_warp_start; } while (seqlock_read_retry(&timers_state.vm_clock_seqlock, seq)); if (warp_start == -1) { @@ -473,7 +473,7 @@ static void icount_warp_rt(void) cpu_get_clock_locked()); int64_t warp_delta; - warp_delta = clock - vm_clock_warp_start; + warp_delta = clock - timers_state.vm_clock_warp_start; if (use_icount == 2) { /* * In adaptive mode, do not let QEMU_CLOCK_VIRTUAL run too @@ -485,7 +485,7 @@ static void icount_warp_rt(void) } timers_state.qemu_icount_bias += warp_delta; } - vm_clock_warp_start = -1; + timers_state.vm_clock_warp_start = -1; seqlock_write_end(&timers_state.vm_clock_seqlock); if (qemu_clock_expired(QEMU_CLOCK_VIRTUAL)) { @@ -594,11 +594,13 @@ void qemu_start_warp_timer(void) * every 100ms. */ seqlock_write_begin(&timers_state.vm_clock_seqlock); - if (vm_clock_warp_start == -1 || vm_clock_warp_start > clock) { - vm_clock_warp_start = clock; + if (timers_state.vm_clock_warp_start == -1 + || timers_state.vm_clock_warp_start > clock) { + timers_state.vm_clock_warp_start = clock; } seqlock_write_end(&timers_state.vm_clock_seqlock); - timer_mod_anticipate(icount_warp_timer, clock + deadline); + timer_mod_anticipate(timers_state.icount_warp_timer, + clock + deadline); } } else if (deadline == 0) { qemu_clock_notify(QEMU_CLOCK_VIRTUAL); @@ -623,7 +625,7 @@ static void qemu_account_warp_timer(void) return; } - timer_del(icount_warp_timer); + timer_del(timers_state.icount_warp_timer); icount_warp_rt(); } @@ -632,6 +634,45 @@ 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; +} + +/* + * 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() + } +}; + /* * This is a subsection for icount migration. */ @@ -644,6 +685,11 @@ static const VMStateDescription icount_vmstate_timers = { 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, + NULL } }; @@ -754,7 +800,7 @@ void configure_icount(QemuOpts *opts, Error **errp) icount_sleep = qemu_opt_get_bool(opts, "sleep", true); if (icount_sleep) { - icount_warp_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL_RT, + timers_state.icount_warp_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL_RT, icount_timer_cb, NULL); } @@ -788,13 +834,14 @@ void configure_icount(QemuOpts *opts, Error **errp) the virtual time trigger catches emulated time passing too fast. Realtime triggers occur even when idle, so use them less frequently than VM triggers. */ - icount_rt_timer = timer_new_ms(QEMU_CLOCK_VIRTUAL_RT, + 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(icount_rt_timer, + timer_mod(timers_state.icount_rt_timer, qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL_RT) + 1000); - icount_vm_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, + timers_state.icount_vm_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, icount_adjust_vm, NULL); - timer_mod(icount_vm_timer, + timer_mod(timers_state.icount_vm_timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + NANOSECONDS_PER_SECOND / 10); }