The current code is advancing qemu_icount before waiting for I/O. Instead, after the patch qemu_icount is left aside (it is a pure instruction counter) and qemu_icount_bias is changed according to the actual amount of time spent in the wait. This is more accurate, and actually works in the iothread case as well.
Signed-off-by: Paolo Bonzini <pbonz...@redhat.com> --- qemu-timer.c | 78 +++++++++++++++++++++++++++++----------------------------- 1 files changed, 39 insertions(+), 39 deletions(-) diff --git a/qemu-timer.c b/qemu-timer.c index 06fa507..163ec69 100644 --- a/qemu-timer.c +++ b/qemu-timer.c @@ -614,6 +614,39 @@ void configure_icount(const char *option) qemu_get_clock(vm_clock) + get_ticks_per_sec() / 10); } +static int64_t cpu_clock_last_read; + +int qemu_calculate_timeout(void) +{ + int64_t delta; + + /* When using icount, vm_clock timers are handled outside of the alarm + timer. So, wait for I/O in "small bits" to ensure forward progress of + vm_clock when the guest CPU is idle. When not using icount, though, we + just wait for a fixed amount of time (it might as well be infinite). */ + if (!use_icount || !vm_running) { + return 5000; + } + + delta = qemu_icount_delta(); + if (delta > 0) { + /* Virtual time is ahead of real time, wait for it to sync. Time + spent waiting for I/O will not be counted. */ + cpu_clock_last_read = -1; + } else { + /* Wait until the next virtual time event, and account the wait + as virtual time. */ + delta = qemu_next_deadline(); + cpu_clock_last_read = cpu_get_clock(); + } + + if (delta > 0) { + return (delta + 999999) / 1000000; + } else { + return 0; + } +} + void qemu_run_all_timers(void) { alarm_timer->pending = 0; @@ -626,6 +659,12 @@ void qemu_run_all_timers(void) /* vm time timers */ if (vm_running) { + if (use_icount && cpu_clock_last_read != -1) { + /* Virtual time passed without executing instructions. Increase + the bias between instruction count and virtual time. */ + qemu_icount_bias += cpu_get_clock() - cpu_clock_last_read; + cpu_clock_last_read = -1; + } qemu_run_timers(vm_clock); } @@ -1066,42 +1105,3 @@ void quit_timers(void) alarm_timer = NULL; t->stop(t); } - -int qemu_calculate_timeout(void) -{ - int timeout; - int64_t add; - int64_t delta; - - /* When using icount, making forward progress with qemu_icount when the - guest CPU is idle is critical. We only use the static io-thread timeout - for non icount runs. */ - if (!use_icount || !vm_running) { - return 5000; - } - - /* Advance virtual time to the next event. */ - delta = qemu_icount_delta(); - if (delta > 0) { - /* If virtual time is ahead of real time then just - wait for IO. */ - timeout = (delta + 999999) / 1000000; - } else { - /* Wait for either IO to occur or the next - timer event. */ - add = qemu_next_deadline(); - /* We advance the timer before checking for IO. - Limit the amount we advance so that early IO - activity won't get the guest too far ahead. */ - if (add > 10000000) - add = 10000000; - delta += add; - qemu_icount += qemu_icount_round (add); - timeout = delta / 1000000; - if (timeout < 0) - timeout = 0; - } - - return timeout; -} - -- 1.7.3.5