From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from eggs.gnu.org ([208.118.235.92]:39240) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1ScZ4D-0000Rp-9P for qemu-devel@nongnu.org; Thu, 07 Jun 2012 05:31:55 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1ScZ42-0004I8-FV for qemu-devel@nongnu.org; Thu, 07 Jun 2012 05:31:44 -0400 Received: from mx1.redhat.com ([209.132.183.28]:19535) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1ScZ42-0004Ge-7R for qemu-devel@nongnu.org; Thu, 07 Jun 2012 05:31:34 -0400 Received: from int-mx10.intmail.prod.int.phx2.redhat.com (int-mx10.intmail.prod.int.phx2.redhat.com [10.5.11.23]) by mx1.redhat.com (8.14.4/8.14.4) with ESMTP id q579VWDL021066 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK) for ; Thu, 7 Jun 2012 05:31:32 -0400 From: Gerd Hoffmann Date: Thu, 7 Jun 2012 11:31:25 +0200 Message-Id: <1339061486-28513-37-git-send-email-kraxel@redhat.com> In-Reply-To: <1339061486-28513-1-git-send-email-kraxel@redhat.com> References: <1339061486-28513-1-git-send-email-kraxel@redhat.com> Subject: [Qemu-devel] [PATCH 36/37] ehci: adaptive wakeup rate. List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: qemu-devel@nongnu.org Cc: Gerd Hoffmann Adapt the frame timer sleeps according to the actual needs. With the periodic schedule being active we'll have to wakeup 1000 times per second and go check for work. In case only the async schedule is active we can be more lazy though. When idle ehci will increate the sleep time step by step, so qemu has to wake up less frequently. When we'll see transactions on the bus or the guest fiddles with the schedule enable/disable bits we'll return to a 1000 Hz wakeup rate and full speed. With both schedules disabled we stop wakeups altogether. This patch also drops the freq property (configures wakeup rate manually) which is obsoleted by this patch. Signed-off-by: Gerd Hoffmann --- hw/usb/hcd-ehci.c | 57 ++++++++++++++++++++++++++++++++++++---------------- 1 files changed, 39 insertions(+), 18 deletions(-) diff --git a/hw/usb/hcd-ehci.c b/hw/usb/hcd-ehci.c index c15dbee..d97c539 100644 --- a/hw/usb/hcd-ehci.c +++ b/hw/usb/hcd-ehci.c @@ -386,7 +386,6 @@ struct EHCIState { int companion_count; /* properties */ - uint32_t freq; uint32_t maxframes; /* @@ -430,6 +429,7 @@ struct EHCIState { QEMUSGList isgl; uint64_t last_run_ns; + uint32_t async_stepdown; }; #define SET_LAST_RUN_CLOCK(s) \ @@ -776,6 +776,7 @@ static EHCIQueue *ehci_find_queue_by_qh(EHCIState *ehci, uint32_t addr, static void ehci_queues_rip_unused(EHCIState *ehci, int async, int flush) { EHCIQueueHead *head = async ? &ehci->aqueues : &ehci->pqueues; + uint64_t maxage = FRAME_TIMER_NS * ehci->maxframes * 4; EHCIQueue *q, *tmp; QTAILQ_FOREACH_SAFE(q, head, next, tmp) { @@ -784,8 +785,7 @@ static void ehci_queues_rip_unused(EHCIState *ehci, int async, int flush) q->ts = ehci->last_run_ns; continue; } - if (!flush && ehci->last_run_ns < q->ts + 250000000) { - /* allow 0.25 sec idle */ + if (!flush && ehci->last_run_ns < q->ts + maxage) { continue; } ehci_free_queue(q); @@ -1151,11 +1151,12 @@ static void ehci_mem_writel(void *ptr, target_phys_addr_t addr, uint32_t val) if (((USBCMD_RUNSTOP | USBCMD_PSE | USBCMD_ASE) & val) != ((USBCMD_RUNSTOP | USBCMD_PSE | USBCMD_ASE) & s->usbcmd)) { - if (!ehci_enabled(s)) { - qemu_mod_timer(s->frame_timer, qemu_get_clock_ns(vm_clock)); + if (s->pstate == EST_INACTIVE) { SET_LAST_RUN_CLOCK(s); } ehci_update_halt(s); + s->async_stepdown = 0; + qemu_mod_timer(s->frame_timer, qemu_get_clock_ns(vm_clock)); } /* not supporting dynamic frame list size at the moment */ @@ -2146,10 +2147,16 @@ static void ehci_advance_state(EHCIState *ehci, int async) case EST_EXECUTE: again = ehci_state_execute(q); + if (async) { + ehci->async_stepdown = 0; + } break; case EST_EXECUTING: assert(q != NULL); + if (async) { + ehci->async_stepdown = 0; + } again = ehci_state_executing(q); break; @@ -2305,6 +2312,7 @@ static void ehci_update_frindex(EHCIState *ehci, int frames) static void ehci_frame_timer(void *opaque) { EHCIState *ehci = opaque; + int schedules = 0; int64_t expire_time, t_now; uint64_t ns_elapsed; int frames; @@ -2312,21 +2320,32 @@ static void ehci_frame_timer(void *opaque) int skipped_frames = 0; t_now = qemu_get_clock_ns(vm_clock); - expire_time = t_now + (get_ticks_per_sec() / ehci->freq); - ns_elapsed = t_now - ehci->last_run_ns; frames = ns_elapsed / FRAME_TIMER_NS; - for (i = 0; i < frames; i++) { - ehci_update_frindex(ehci, 1); + if (ehci_periodic_enabled(ehci) || ehci->pstate != EST_INACTIVE) { + schedules++; + expire_time = t_now + (get_ticks_per_sec() / FRAME_TIMER_FREQ); - if (frames - i > ehci->maxframes) { - skipped_frames++; - } else { - ehci_advance_periodic_state(ehci); - } + for (i = 0; i < frames; i++) { + ehci_update_frindex(ehci, 1); - ehci->last_run_ns += FRAME_TIMER_NS; + if (frames - i > ehci->maxframes) { + skipped_frames++; + } else { + ehci_advance_periodic_state(ehci); + } + + ehci->last_run_ns += FRAME_TIMER_NS; + } + } else { + if (ehci->async_stepdown < ehci->maxframes / 2) { + ehci->async_stepdown++; + } + expire_time = t_now + (get_ticks_per_sec() + * ehci->async_stepdown / FRAME_TIMER_FREQ); + ehci_update_frindex(ehci, frames); + ehci->last_run_ns += FRAME_TIMER_NS * frames; } #if 0 @@ -2338,9 +2357,12 @@ static void ehci_frame_timer(void *opaque) /* Async is not inside loop since it executes everything it can once * called */ - qemu_bh_schedule(ehci->async_bh); + if (ehci_async_enabled(ehci) || ehci->astate != EST_INACTIVE) { + schedules++; + qemu_bh_schedule(ehci->async_bh); + } - if (ehci_enabled(ehci)) { + if (schedules) { qemu_mod_timer(ehci->frame_timer, expire_time); } } @@ -2379,7 +2401,6 @@ static const VMStateDescription vmstate_ehci = { }; static Property ehci_properties[] = { - DEFINE_PROP_UINT32("freq", EHCIState, freq, FRAME_TIMER_FREQ), DEFINE_PROP_UINT32("maxframes", EHCIState, maxframes, 128), DEFINE_PROP_END_OF_LIST(), }; -- 1.7.1