Date: Sun, 14 Oct 2012 20:31:38 +0000 (UTC) From: Adrian Chadd <adrian@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r241558 - head/sys/dev/ath Message-ID: <201210142031.q9EKVcpD037119@svn.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: adrian Date: Sun Oct 14 20:31:38 2012 New Revision: 241558 URL: http://svn.freebsd.org/changeset/base/241558 Log: Break the RX processing up into smaller chunks of 128 frames each. Right now processing a full 512 frame queue takes quite a while (measured on the order of milliseconds.) Because of this, the TX processing ends up sometimes preempting the taskqueue: * userland sends a frame * it goes in through net80211 and out to ath_start() * ath_start() will end up either direct dispatching or software queuing a frame. If TX had to wait for RX to finish, it would add quite a few ms of additional latency to the packet transmission. This in the past has caused issues with TCP throughput. Now, as part of my attempt to bring sanity to the TX/RX paths, the first step is to make the RX processing happen in smaller 'parts'. That way when TX is pushed into the ath taskqueue, there won't be so much latency in the way of things. The bigger scale change (which will come much later) is to actually process the frames in the ath_intr taskqueue but process _frames_ in the ath driver taskqueue. That would reduce the latency between processing and requeuing new descriptors. But that'll come later. The actual work: * Add ATH_RX_MAX at 128 (static for now); * break out of the processing loop if npkts reaches ATH_RX_MAX; * if we processed ATH_RX_MAX or more frames during the processing loop, immediately reschedule another RX taskqueue run. This will handle the further frames in the taskqueue. This should have very minimal impact on the general throughput case, unless the scheduler is being very very strange or the ath taskqueue ends up spending a lot of time on non-RX operations (such as TX completion.) Modified: head/sys/dev/ath/if_ath_rx.c Modified: head/sys/dev/ath/if_ath_rx.c ============================================================================== --- head/sys/dev/ath/if_ath_rx.c Sun Oct 14 20:00:00 2012 (r241557) +++ head/sys/dev/ath/if_ath_rx.c Sun Oct 14 20:31:38 2012 (r241558) @@ -797,6 +797,8 @@ rx_next: return (is_good); } +#define ATH_RX_MAX 128 + static void ath_rx_proc(struct ath_softc *sc, int resched) { @@ -832,6 +834,15 @@ ath_rx_proc(struct ath_softc *sc, int re sc->sc_stats.ast_rx_noise = nf; tsf = ath_hal_gettsf64(ah); do { + /* + * Don't process too many packets at a time; give the + * TX thread time to also run - otherwise the TX + * latency can jump by quite a bit, causing throughput + * degredation. + */ + if (npkts >= ATH_RX_MAX) + break; + bf = TAILQ_FIRST(&sc->sc_rxbuf); if (sc->sc_rxslink && bf == NULL) { /* NB: shouldn't happen */ if_printf(ifp, "%s: no buffer!\n", __func__); @@ -942,11 +953,22 @@ rx_proc_next: } #undef PA2DESC + /* + * If we hit the maximum number of frames in this round, + * reschedule for another immediate pass. This gives + * the TX and TX completion routines time to run, which + * will reduce latency. + */ + if (npkts >= ATH_RX_MAX) + taskqueue_enqueue(sc->sc_tq, &sc->sc_rxtask); + ATH_PCU_LOCK(sc); sc->sc_rxproc_cnt--; ATH_PCU_UNLOCK(sc); } +#undef ATH_RX_MAX + /* * Only run the RX proc if it's not already running. * Since this may get run as part of the reset/flush path,
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201210142031.q9EKVcpD037119>