From 5045e9d912588a7421ab899ba510025722666fd1 Mon Sep 17 00:00:00 2001 From: Victor CLEMENT Date: Fri, 29 May 2015 17:14:04 +0200 Subject: icount: implement a new icount_sleep mode toggleing real-time cpu sleep When the icount_sleep mode is disabled, the QEMU_VIRTUAL_CLOCK runs at the maximum possible speed by warping the sleep times of the virtual cpu to the soonest clock deadline. The virtual clock will be updated only according the instruction counter. Signed-off-by: Victor CLEMENT Message-Id: <1432912446-9811-2-git-send-email-victor.clement@openwide.fr> Signed-off-by: Paolo Bonzini --- cpus.c | 70 +++++++++++++++++++++++++++++++++++++++++------------------------- 1 file changed, 44 insertions(+), 26 deletions(-) (limited to 'cpus.c') diff --git a/cpus.c b/cpus.c index de6469fa8d..688eb73ec2 100644 --- a/cpus.c +++ b/cpus.c @@ -105,6 +105,7 @@ 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; @@ -393,15 +394,18 @@ void qemu_clock_warp(QEMUClockType type) return; } - /* - * If the CPUs have been sleeping, advance QEMU_CLOCK_VIRTUAL timer now. - * This ensures that the deadline for the timer is computed correctly below. - * This also makes sure that the insn counter is synchronized before the - * CPU starts running, in case the CPU is woken by an event other than - * the earliest QEMU_CLOCK_VIRTUAL timer. - */ - icount_warp_rt(NULL); - timer_del(icount_warp_timer); + if (icount_sleep) { + /* + * If the CPUs have been sleeping, advance QEMU_CLOCK_VIRTUAL timer now. + * This ensures that the deadline for the timer is computed correctly + * below. + * This also makes sure that the insn counter is synchronized before + * the CPU starts running, in case the CPU is woken by an event other + * than the earliest QEMU_CLOCK_VIRTUAL timer. + */ + icount_warp_rt(NULL); + timer_del(icount_warp_timer); + } if (!all_cpu_threads_idle()) { return; } @@ -425,23 +429,35 @@ void qemu_clock_warp(QEMUClockType type) * 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. - * - * An extreme solution for this problem would be to never let VCPUs - * sleep in icount mode if there is a pending QEMU_CLOCK_VIRTUAL - * timer; rather time could just advance to the next QEMU_CLOCK_VIRTUAL - * event. Instead, 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); - if (vm_clock_warp_start == -1 || vm_clock_warp_start > clock) { - vm_clock_warp_start = clock; + 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.qemu_icount_bias += deadline; + seqlock_write_unlock(&timers_state.vm_clock_seqlock); + 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); + if (vm_clock_warp_start == -1 || vm_clock_warp_start > clock) { + vm_clock_warp_start = clock; + } + seqlock_write_unlock(&timers_state.vm_clock_seqlock); + timer_mod_anticipate(icount_warp_timer, clock + deadline); } - seqlock_write_unlock(&timers_state.vm_clock_seqlock); - timer_mod_anticipate(icount_warp_timer, clock + deadline); } else if (deadline == 0) { qemu_clock_notify(QEMU_CLOCK_VIRTUAL); } @@ -504,9 +520,11 @@ void configure_icount(QemuOpts *opts, Error **errp) } return; } + if (icount_sleep) { + icount_warp_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL_RT, + icount_warp_rt, NULL); + } icount_align_option = qemu_opt_get_bool(opts, "align", false); - icount_warp_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL_RT, - icount_warp_rt, NULL); if (strcmp(option, "auto") != 0) { errno = 0; icount_time_shift = strtol(option, &rem_str, 0); -- cgit 1.4.1 From f1f4b57e88ff7c9cb20b074ff6106fd8f4397baa Mon Sep 17 00:00:00 2001 From: Victor CLEMENT Date: Fri, 29 May 2015 17:14:05 +0200 Subject: icount: add sleep parameter to the icount option to set icount_sleep mode The 'sleep' parameter sets the icount_sleep mode, which is enabled by default. To disable it, add the 'sleep=no' parameter (or 'nosleep') to the qemu -icount option. Signed-off-by: Victor CLEMENT Message-Id: <1432912446-9811-3-git-send-email-victor.clement@openwide.fr> Signed-off-by: Paolo Bonzini --- cpus.c | 9 +++++++++ qemu-options.hx | 12 ++++++++++-- vl.c | 3 +++ 3 files changed, 22 insertions(+), 2 deletions(-) (limited to 'cpus.c') diff --git a/cpus.c b/cpus.c index 688eb73ec2..4e90e63b43 100644 --- a/cpus.c +++ b/cpus.c @@ -520,11 +520,18 @@ void configure_icount(QemuOpts *opts, Error **errp) } return; } + + icount_sleep = qemu_opt_get_bool(opts, "sleep", true); if (icount_sleep) { icount_warp_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL_RT, icount_warp_rt, NULL); } + icount_align_option = qemu_opt_get_bool(opts, "align", false); + + if (icount_align_option && !icount_sleep) { + error_setg(errp, "align=on and sleep=no are incompatible"); + } if (strcmp(option, "auto") != 0) { errno = 0; icount_time_shift = strtol(option, &rem_str, 0); @@ -535,6 +542,8 @@ void configure_icount(QemuOpts *opts, Error **errp) return; } else if (icount_align_option) { error_setg(errp, "shift=auto and align=on are incompatible"); + } else if (!icount_sleep) { + error_setg(errp, "shift=auto and sleep=no are incompatible"); } use_icount = 2; diff --git a/qemu-options.hx b/qemu-options.hx index b3db6cbe86..85883f165a 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -3100,9 +3100,10 @@ re-inject them. ETEXI DEF("icount", HAS_ARG, QEMU_OPTION_icount, \ - "-icount [shift=N|auto][,align=on|off]\n" \ + "-icount [shift=N|auto][,align=on|off][,sleep=no]\n" \ " enable virtual instruction counter with 2^N clock ticks per\n" \ - " instruction and enable aligning the host and virtual clocks\n", QEMU_ARCH_ALL) + " instruction, enable aligning the host and virtual clocks\n" \ + " or disable real time cpu sleeping\n", QEMU_ARCH_ALL) STEXI @item -icount [shift=@var{N}|auto] @findex -icount @@ -3111,6 +3112,13 @@ instruction every 2^@var{N} ns of virtual time. If @code{auto} is specified then the virtual cpu speed will be automatically adjusted to keep virtual time within a few seconds of real time. +When the virtual cpu is sleeping, the virtual time will advance at default +speed unless @option{sleep=no} is specified. +With @option{sleep=no}, the virtual time will jump to the next timer deadline +instantly whenever the virtual cpu goes to sleep mode and will not advance +if no timer is enabled. This behavior give deterministic execution times from +the guest point of view. + Note that while this option can give deterministic behavior, it does not provide cycle accurate emulation. Modern CPUs contain superscalar out of order cores with complex cache hierarchies. The number of instructions diff --git a/vl.c b/vl.c index cdd81b4486..df5a7273c9 100644 --- a/vl.c +++ b/vl.c @@ -468,6 +468,9 @@ static QemuOptsList qemu_icount_opts = { }, { .name = "align", .type = QEMU_OPT_BOOL, + }, { + .name = "sleep", + .type = QEMU_OPT_BOOL, }, { /* end of list */ } }, -- cgit 1.4.1 From d7a0f71d9aac33e58d39fdbe4861d440af44fa8b Mon Sep 17 00:00:00 2001 From: Victor CLEMENT Date: Fri, 29 May 2015 17:14:06 +0200 Subject: icount: print a warning if there is no more deadline in sleep=no mode While qemu is running in sleep=no mode, a warning will be printed when no timer deadline is set. As this mode is intended for getting deterministic virtual time, if no timer is set on the virtual clock this determinism is broken. Signed-off-by: Victor CLEMENT Message-Id: <1432912446-9811-4-git-send-email-victor.clement@openwide.fr> Signed-off-by: Paolo Bonzini --- cpus.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'cpus.c') diff --git a/cpus.c b/cpus.c index 4e90e63b43..f38b858f9b 100644 --- a/cpus.c +++ b/cpus.c @@ -419,6 +419,11 @@ void qemu_clock_warp(QEMUClockType type) clock = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL_RT); deadline = qemu_clock_deadline_ns_all(QEMU_CLOCK_VIRTUAL); if (deadline < 0) { + static bool notified; + if (!icount_sleep && !notified) { + error_report("WARNING: icount sleep disabled and no active timers"); + notified = true; + } return; } -- cgit 1.4.1