From patchwork Tue Feb 5 08:21:47 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Pavel Dovgalyuk X-Patchwork-Id: 10797037 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id A638B922 for ; Tue, 5 Feb 2019 08:39:23 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 9292A2ABCD for ; Tue, 5 Feb 2019 08:39:23 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 83A382ABE4; Tue, 5 Feb 2019 08:39:23 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-2.9 required=2.0 tests=BAYES_00,MAILING_LIST_MULTI autolearn=ham version=3.3.1 Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id D921B2ABCD for ; Tue, 5 Feb 2019 08:39:22 +0000 (UTC) Received: from localhost ([127.0.0.1]:56376 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1gqwGI-0005OP-5b for patchwork-qemu-devel@patchwork.kernel.org; Tue, 05 Feb 2019 03:39:22 -0500 Received: from eggs.gnu.org ([209.51.188.92]:52671) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1gqvzR-0000sv-EE for qemu-devel@nongnu.org; Tue, 05 Feb 2019 03:21:58 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1gqvzP-0002Mp-BN for qemu-devel@nongnu.org; Tue, 05 Feb 2019 03:21:57 -0500 Received: from mail.ispras.ru ([83.149.199.45]:33840) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1gqvzN-00020M-7M for qemu-devel@nongnu.org; Tue, 05 Feb 2019 03:21:55 -0500 Received: from [127.0.1.1] (unknown [85.142.117.226]) by mail.ispras.ru (Postfix) with ESMTPSA id 47C1054008B; Tue, 5 Feb 2019 11:21:46 +0300 (MSK) From: Pavel Dovgalyuk To: qemu-devel@nongnu.org Date: Tue, 05 Feb 2019 11:21:47 +0300 Message-ID: <154935490741.7509.7068818566955459104.stgit@pasha-VirtualBox> In-Reply-To: <154935478086.7509.4349987292919289245.stgit@pasha-VirtualBox> References: <154935478086.7509.4349987292919289245.stgit@pasha-VirtualBox> User-Agent: StGit/0.17.1-dirty MIME-Version: 1.0 X-detected-operating-system: by eggs.gnu.org: GNU/Linux 3.x X-Received-From: 83.149.199.45 Subject: [Qemu-devel] [PATCH v12 22/25] util/qemu-timer: refactor deadline calculation for external 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: kwolf@redhat.com, peter.maydell@linaro.org, war2jordan@live.com, pavel.dovgaluk@ispras.ru, pbonzini@redhat.com, crosthwaite.peter@gmail.com, ciro.santilli@gmail.com, jasowang@redhat.com, quintela@redhat.com, armbru@redhat.com, mreitz@redhat.com, alex.bennee@linaro.org, maria.klimushenkova@ispras.ru, mst@redhat.com, kraxel@redhat.com, boost.lists@gmail.com, thomas.dullien@googlemail.com, dovgaluk@ispras.ru, artem.k.pisarenko@gmail.com, dgilbert@redhat.com, rth@twiddle.net Errors-To: qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Sender: "Qemu-devel" X-Virus-Scanned: ClamAV using ClamSMTP icount-based record/replay uses qemu_clock_deadline_ns_all to measure the period until vCPU may be interrupted. This function takes in account the virtual timers, because they belong to the virtual devices that may generate interrupt request or affect the virtual machine state. However, there are a subset of virtual timers, that are marked with 'external' flag. These do not change the virtual machine state and only based on virtual clock. Calculating the deadling using the external timers breaks the determinism, because they do not belong to the replayed part of the virtual machine. This patch fixes the deadline calculation for this case. Signed-off-by: Pavel Dovgalyuk --- cpus.c | 9 ++++----- include/qemu/timer.h | 7 +++---- qtest.c | 2 +- tests/ptimer-test-stubs.c | 2 +- tests/ptimer-test.c | 4 ++-- util/qemu-timer.c | 41 +++++++++++++++++++++++++++++++++-------- 6 files changed, 44 insertions(+), 21 deletions(-) diff --git a/cpus.c b/cpus.c index 6ef0992971..fb656cefc8 100644 --- a/cpus.c +++ b/cpus.c @@ -550,7 +550,7 @@ void qtest_clock_warp(int64_t dest) assert(qtest_enabled()); aio_context = qemu_get_aio_context(); while (clock < dest) { - int64_t deadline = qemu_clock_deadline_ns_all(QEMU_CLOCK_VIRTUAL); + int64_t deadline = virtual_clock_deadline_ns(); int64_t warp = qemu_soonest_timeout(dest - clock, deadline); seqlock_write_lock(&timers_state.vm_clock_seqlock, @@ -610,7 +610,7 @@ void qemu_start_warp_timer(void) /* 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); + deadline = virtual_clock_deadline_ns(); if (deadline < 0) { static bool notified; if (!icount_sleep && !notified) { @@ -1355,7 +1355,7 @@ static int64_t tcg_get_icount_limit(void) int64_t deadline; if (replay_mode != REPLAY_MODE_PLAY) { - deadline = qemu_clock_deadline_ns_all(QEMU_CLOCK_VIRTUAL); + deadline = virtual_clock_deadline_ns(); /* Maintain prior (possibly buggy) behaviour where if no deadline * was set (as there is no QEMU_CLOCK_VIRTUAL timer) or it is more than @@ -1376,8 +1376,7 @@ static void handle_icount_deadline(void) { assert(qemu_in_vcpu_thread()); if (use_icount) { - int64_t deadline = - qemu_clock_deadline_ns_all(QEMU_CLOCK_VIRTUAL); + int64_t deadline = virtual_clock_deadline_ns(); if (deadline == 0) { /* Wake up other AioContexts. */ diff --git a/include/qemu/timer.h b/include/qemu/timer.h index a86330c987..cfc77450f2 100644 --- a/include/qemu/timer.h +++ b/include/qemu/timer.h @@ -176,16 +176,15 @@ bool qemu_clock_expired(QEMUClockType type); bool qemu_clock_use_for_deadline(QEMUClockType type); /** - * qemu_clock_deadline_ns_all: - * @type: the clock type + * virtual_clock_deadline_ns: * * Calculate the deadline across all timer lists associated - * with a clock (as opposed to just the default one) + * with virtual clock (excluding external timers) * in nanoseconds, or -1 if no timer is set to expire. * * Returns: time until expiry in nanoseconds or -1 */ -int64_t qemu_clock_deadline_ns_all(QEMUClockType type); +int64_t virtual_clock_deadline_ns(void); /** * qemu_clock_get_main_loop_timerlist: diff --git a/qtest.c b/qtest.c index 60988c8aa2..341190eb71 100644 --- a/qtest.c +++ b/qtest.c @@ -655,7 +655,7 @@ static void qtest_process_command(CharBackend *chr, gchar **words) int ret = qemu_strtoi64(words[1], NULL, 0, &ns); g_assert(ret == 0); } else { - ns = qemu_clock_deadline_ns_all(QEMU_CLOCK_VIRTUAL); + ns = virtual_clock_deadline_ns(); } qtest_clock_warp(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + ns); qtest_send_prefix(chr); diff --git a/tests/ptimer-test-stubs.c b/tests/ptimer-test-stubs.c index 54b3fd26f6..31b09c88f3 100644 --- a/tests/ptimer-test-stubs.c +++ b/tests/ptimer-test-stubs.c @@ -88,7 +88,7 @@ int64_t qemu_clock_get_ns(QEMUClockType type) return ptimer_test_time_ns; } -int64_t qemu_clock_deadline_ns_all(QEMUClockType type) +int64_t virtual_clock_deadline_ns(void) { QEMUTimerList *timer_list = main_loop_tlg.tl[type]; QEMUTimer *t = timer_list->active_timers.next; diff --git a/tests/ptimer-test.c b/tests/ptimer-test.c index b30aad0737..338a4e0c10 100644 --- a/tests/ptimer-test.c +++ b/tests/ptimer-test.c @@ -50,13 +50,13 @@ static void ptimer_test_set_qemu_time_ns(int64_t ns) static void qemu_clock_step(uint64_t ns) { - int64_t deadline = qemu_clock_deadline_ns_all(QEMU_CLOCK_VIRTUAL); + int64_t deadline = virtual_clock_deadline_ns(); int64_t advanced_time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + ns; while (deadline != -1 && deadline <= advanced_time) { ptimer_test_set_qemu_time_ns(deadline); ptimer_test_expire_qemu_timers(deadline, QEMU_CLOCK_VIRTUAL); - deadline = qemu_clock_deadline_ns_all(QEMU_CLOCK_VIRTUAL); + deadline = virtual_clock_deadline_ns(); } ptimer_test_set_qemu_time_ns(advanced_time); diff --git a/util/qemu-timer.c b/util/qemu-timer.c index 1cc1b2f2c3..88fbf04469 100644 --- a/util/qemu-timer.c +++ b/util/qemu-timer.c @@ -236,6 +236,7 @@ int64_t timerlist_deadline_ns(QEMUTimerList *timer_list) qemu_mutex_unlock(&timer_list->active_timers_lock); return -1; } + expire_time = timer_list->active_timers->expire_time; qemu_mutex_unlock(&timer_list->active_timers_lock); @@ -248,19 +249,43 @@ int64_t timerlist_deadline_ns(QEMUTimerList *timer_list) return delta; } -/* Calculate the soonest deadline across all timerlists attached - * to the clock. This is used for the icount timeout so we - * ignore whether or not the clock should be used in deadline - * calculations. +/* + * Calculate the soonest deadline across all timerlists attached + * to the virtual clock (excluding the external timers that do not affect + * the replayed guest state. */ -int64_t qemu_clock_deadline_ns_all(QEMUClockType type) +int64_t virtual_clock_deadline_ns(void) { int64_t deadline = -1; + int64_t delta; + int64_t expire_time; + QEMUTimer *ts; QEMUTimerList *timer_list; - QEMUClock *clock = qemu_clock_ptr(type); + QEMUClock *clock = qemu_clock_ptr(QEMU_CLOCK_VIRTUAL); + + if (!clock->enabled) { + return -1; + } + QLIST_FOREACH(timer_list, &clock->timerlists, list) { - deadline = qemu_soonest_timeout(deadline, - timerlist_deadline_ns(timer_list)); + qemu_mutex_lock(&timer_list->active_timers_lock); + ts = timer_list->active_timers; + /* Skip all external timers */ + while (ts && (ts->attributes & QEMU_TIMER_ATTR_EXTERNAL)) { + ts = ts->next; + } + if (!ts) { + qemu_mutex_unlock(&timer_list->active_timers_lock); + continue; + } + expire_time = ts->expire_time; + qemu_mutex_unlock(&timer_list->active_timers_lock); + + delta = expire_time - qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); + if (delta <= 0) { + delta = 0; + } + deadline = qemu_soonest_timeout(deadline, delta); } return deadline; }