On Tue, Feb 26, 2019 at 03:33:23PM +0100, Stefan Sperling wrote:
> On Tue, Feb 26, 2019 at 03:04:35PM +0100, Stefan Sperling wrote:
> > This diff makes the RTS threshold dynamic in 11n mode.
> > I am looking for tests with iwn(4), iwm(4), and athn(4) drivers.
> > 
> > When there's a lot of competition for air time, RTS can do more harm than
> > good because we end up causing more RTS/CTS frames on the air than actual
> > data frames. So a fixed RTS threshold really doesn't make a lot of sense.
> > 
> > This diff implements a heuristic for setting this threshold, based on 
> > section
> > 5.2 of the MiRa paper. It should improve Tx throughput on busy channels 
> > which
> > are especially common in the 2GHz band. In my testing it helps quite a bit.
> > 
> > This diff won't change the situation in 11a/b/g modes, and it might
> > not make a difference if there are 11a/b/g networks in range.
> 
> I realized the previous diff might take some time to raise throughput,
> so please try this one instead. The difference is just that the previous
> diff starts out with RTS threshold enabled, while this one starts out with
> RTS threshold disabled. This should make results look better for people
> doing quick tests rather than looking at long-term effects.  :-)
> 
> diff f727f040295e17987bfffe9c9952e45fd6ad7859 /usr/src
> blob - 7cf96bf074b3eef4d9fbb85c9253bac7e5550fd7
> file + sys/dev/ic/ar5008.c
> --- sys/dev/ic/ar5008.c
> +++ sys/dev/ic/ar5008.c
> @@ -1514,11 +1514,16 @@ ar5008_tx(struct athn_softc *sc, struct mbuf *m, struc
>       if (!IEEE80211_IS_MULTICAST(wh->i_addr1) &&
>           (wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) ==
>           IEEE80211_FC0_TYPE_DATA) {
> +             int rtsthres = ic->ic_rtsthreshold;
>               enum ieee80211_htprot htprot;
> -             
> +
> +             if (ni->ni_flags & IEEE80211_NODE_HT)
> +                     rtsthres = ieee80211_mira_get_rts_threshold(&an->mn,
> +                         ic, ni, totlen);
>               htprot = (ic->ic_bss->ni_htop1 & IEEE80211_HTOP1_PROT_MASK);
> +
>               /* NB: Group frames are sent using CCK in 802.11b/g. */
> -             if (totlen > ic->ic_rtsthreshold) {
> +             if (totlen > rtsthres) {
>                       ds->ds_ctl0 |= AR_TXC0_RTS_ENABLE;
>               } else if (((ic->ic_flags & IEEE80211_F_USEPROT) &&
>                   athn_rates[ridx[0]].phy == IEEE80211_T_OFDM) ||
> blob - 7d7f0697a2b609f4a6e0fab09ede9a480baa7bd3
> file + sys/dev/pci/if_iwm.c
> --- sys/dev/pci/if_iwm.c
> +++ sys/dev/pci/if_iwm.c
> @@ -4216,7 +4216,7 @@ iwm_tx(struct iwm_softc *sc, struct mbuf *m, struct ie
>       bus_dma_segment_t *seg;
>       uint8_t tid, type;
>       int i, totlen, err, pad;
> -     int hdrlen2;
> +     int hdrlen2, rtsthres = ic->ic_rtsthreshold;
>  
>       wh = mtod(m, struct ieee80211_frame *);
>       hdrlen = ieee80211_get_hdrlen(wh);
> @@ -4292,9 +4292,13 @@ iwm_tx(struct iwm_softc *sc, struct mbuf *m, struct ie
>               flags |= IWM_TX_CMD_FLG_ACK;
>       }
>  
> +     if (ni->ni_flags & IEEE80211_NODE_HT)
> +             rtsthres = ieee80211_mira_get_rts_threshold(&in->in_mn, ic, ni,
> +                 totlen + IEEE80211_CRC_LEN);
> +
>       if (type == IEEE80211_FC0_TYPE_DATA &&
>           !IEEE80211_IS_MULTICAST(wh->i_addr1) &&
> -         (totlen + IEEE80211_CRC_LEN > ic->ic_rtsthreshold ||
> +         (totlen + IEEE80211_CRC_LEN > rtsthres ||
>           (ic->ic_flags & IEEE80211_F_USEPROT)))
>               flags |= IWM_TX_CMD_FLG_PROT_REQUIRE;
>  
> blob - 1dab60807c0709735799436e7a4a8e2d8d9f1ff9
> file + sys/dev/pci/if_iwn.c
> --- sys/dev/pci/if_iwn.c
> +++ sys/dev/pci/if_iwn.c
> @@ -3069,8 +3069,13 @@ iwn_tx(struct iwn_softc *sc, struct mbuf *m, struct ie
>  
>       /* Check if frame must be protected using RTS/CTS or CTS-to-self. */
>       if (!IEEE80211_IS_MULTICAST(wh->i_addr1)) {
> +             int rtsthres = ic->ic_rtsthreshold;
> +             if (ni->ni_flags & IEEE80211_NODE_HT)
> +                     rtsthres = ieee80211_mira_get_rts_threshold(&wn->mn,
> +                         ic, ni, totlen + IEEE80211_CRC_LEN);
> +
>               /* NB: Group frames are sent using CCK in 802.11b/g/n (2GHz). */
> -             if (totlen + IEEE80211_CRC_LEN > ic->ic_rtsthreshold) {
> +             if (totlen + IEEE80211_CRC_LEN > rtsthres) {
>                       flags |= IWN_TX_NEED_RTS;
>               } else if ((ic->ic_flags & IEEE80211_F_USEPROT) &&
>                   ridx >= IWN_RIDX_OFDM6) {
> blob - 4edd26a5fde82a9d9ddfd31e0bd075c0f59d2143
> file + sys/net80211/ieee80211_mira.c
> --- sys/net80211/ieee80211_mira.c
> +++ sys/net80211/ieee80211_mira.c
> @@ -85,6 +85,9 @@ int ieee80211_mira_valid_tx_mcs(struct ieee80211com *,
>  uint32_t ieee80211_mira_valid_rates(struct ieee80211com *,
>           struct ieee80211_node *);
>  uint32_t ieee80211_mira_mcs_below(struct ieee80211_mira_node *, int, int);
> +void ieee80211_mira_set_rts_threshold(struct ieee80211_mira_node *,
> +         struct ieee80211com *, struct ieee80211_node *);
> +void ieee80211_mira_reset_collision_stats(struct ieee80211_mira_node *);
>  
>  /* We use fixed point arithmetic with 64 bit integers. */
>  #define MIRA_FP_SHIFT        21
> @@ -309,7 +312,7 @@ ieee80211_mira_ack_rate(struct ieee80211_node *ni)
>  {
>       /* 
>        * Assume the ACK was sent at a mandatory ERP OFDM rate.
> -      * In the worst case, the firmware has retried at non-HT rates,
> +      * In the worst case, the driver has retried at non-HT rates,
>        * so for MCS 0 assume we didn't actually send an OFDM frame
>        * and ACKs arrived at a basic rate.
>        */
> @@ -347,11 +350,12 @@ ieee80211_mira_toverhead(struct ieee80211_mira_node *m
>               (ic->ic_htcaps & IEEE80211_HTCAP_CBW20_40))
>               rts = 1;
>       else
> -             rts = (mn->ampdu_size > ic->ic_rtsthreshold);
> +             rts = (mn->ampdu_size > ieee80211_mira_get_rts_threshold(mn,
> +                 ic, ni, mn->ampdu_size));
>  
>       if (rts) {
>               /* Assume RTS/CTS were sent at a basic rate. */
> -             rate = ieee80211_mira_best_basic_rate(ni);
> +             rate = ieee80211_min_basic_rate(ic);
>               overhead += ieee80211_mira_legacy_txtime(MIRA_RTSLEN, rate, ic);
>               overhead += ieee80211_mira_legacy_txtime(MIRA_CTSLEN, rate, ic);
>       }
> @@ -723,6 +727,7 @@ ieee80211_mira_probe_done(struct ieee80211_mira_node *
>  {
>       ieee80211_mira_cancel_timeouts(mn);
>       ieee80211_mira_reset_driver_stats(mn);
> +     ieee80211_mira_reset_collision_stats(mn);
>       mn->probing = IEEE80211_MIRA_NOT_PROBING;
>       mn->probed_rates = 0;
>       mn->candidate_rates = 0;
> @@ -1021,7 +1026,104 @@ ieee80211_mira_mcs_below(struct ieee80211_mira_node *m
>       return mcs_mask;
>  }
>  
> +/*
> + * Constants involved in detecting suspected frame collisions.
> + * See section 5.2 of MiRa paper
> + */
> +#define MIRA_COLLISION_LOSS_PERCENTAGE       10      /* from MiRA paper */
> +#define MIRA_COLLISION_DETECTED              3       /* from MiRA paper */
> +
> +/*
> + * XXX The paper's algorithm assumes aggregated frames. This is particularly
> + * important for the detection of consecutive frame collisions which indicate
> + * high competition for air time. Because we do not yet support Tx 
> aggregation,
> + * we run the algorithm over the result of several frames instead.
> + * We also aggregate retries across all frames and act upon a percentage of
> + * retried frames, rather than acting on retries seen for one aggregated 
> frame.
> + *
> + * The collision window size (number of frames sent) needs to be short to
> + * ensure our detection of consecutive collisions remains somewhat accurate.
> + * We really have no idea how much time passes between frames in the window!
> + * The good news is that users will only care about collision detection 
> during
> + * a transmit burst anyway, and we have this case more or less covered.
> + */
> +#define MIRA_COLLISION_MIN_FRAMES    6       /* XXX magic number */
> +#define MIRA_COLLISION_RETRY_PERCENTAGE      60      /* XXX magic number */
> +
> +/* Set RTS threshold based on suspected collision from other STAs. */
>  void
> +ieee80211_mira_set_rts_threshold(struct ieee80211_mira_node *mn,
> +    struct ieee80211com *ic, struct ieee80211_node *ni)
> +{
> +     uint16_t rtsthreshold = mn->rts_threshold;
> +     uint32_t loss, retry;
> +
> +     /* Update collision window stats. */
> +     mn->ifwnd_frames += mn->frames;
> +     mn->ifwnd_retries += mn->retries;
> +     mn->ifwnd_txfail += mn->txfail;
> +     if (mn->ifwnd_frames < MIRA_COLLISION_MIN_FRAMES)
> +             return; /* not enough frames yet */
> +
> +     /* Check whether the loss pattern indicates frame collisions. */
> +     loss = (mn->ifwnd_txfail * 100) / mn->ifwnd_frames;
> +     retry = (mn->ifwnd_retries * 100) / mn->ifwnd_frames;
> +     if (retry > MIRA_COLLISION_RETRY_PERCENTAGE &&
> +         loss < MIRA_COLLISION_LOSS_PERCENTAGE) {
> +             if (mn->ifwnd == 0) {
> +                     /* First frame collision confirmed. */
> +                     mn->ifwnd = MIRA_COLLISION_DETECTED;
> +             } else if (mn->ifwnd == MIRA_COLLISION_DETECTED) {
> +                     /* Successive frame collision confirmed. Use RTS. */
> +                     rtsthreshold = IEEE80211_RTS_DEFAULT;
> +             }
> +     } else {
> +             if (mn->ifwnd > 0)
> +                     mn->ifwnd--;
> +             if (mn->ifwnd == 0)
> +                     rtsthreshold = IEEE80211_RTS_MAX;
> +     }
> +
> +     mn->rts_threshold = rtsthreshold;
> +     ieee80211_mira_reset_collision_stats(mn);
> +}
> +
> +int
> +ieee80211_mira_get_rts_threshold(struct ieee80211_mira_node *mn,
> +    struct ieee80211com *ic, struct ieee80211_node *ni, size_t framelen)
> +{
> +     int rtsrate = ieee80211_min_basic_rate(ic);
> +     uint64_t txtime, rtsoverhead;
> +     /* Magic number from MiRA paper ("cost/benefit ratio"). */
> +     static const uint64_t k = MIRA_FP_1 + (MIRA_FP_1 / 2); /* 1.5 */
> +
> +     if (mn->probing || mn->rts_threshold >= IEEE80211_RTS_MAX)
> +             return IEEE80211_RTS_MAX;
> +
> +     /* Use RTS only if potential gains outweigh overhead. */
> +     txtime = ieee80211_mira_ht_txtime(framelen, ni->ni_txmcs,
> +         IEEE80211_IS_CHAN_2GHZ(ni->ni_chan),
> +         (ni->ni_flags & IEEE80211_NODE_HT_SGI20) ? 1 : 0);
> +     rtsoverhead = ieee80211_mira_legacy_txtime(MIRA_RTSLEN, rtsrate, ic);
> +     rtsoverhead += ieee80211_mira_legacy_txtime(MIRA_CTSLEN, rtsrate, ic);
> +     /* convert to fixed-point */
> +     txtime <<= MIRA_FP_SHIFT;
> +     rtsoverhead <<= MIRA_FP_SHIFT;
> +     if (txtime >= MIRA_FP_MUL(k, rtsoverhead))
> +             return mn->rts_threshold;
> +
> +     return IEEE80211_RTS_MAX;
> +}
> +
> +void
> +ieee80211_mira_reset_collision_stats(struct ieee80211_mira_node *mn)
> +{
> +     mn->ifwnd_frames = 0;
> +     mn->ifwnd_retries = 0;
> +     mn->ifwnd_txfail = 0;
> +}
> +
> +void
>  ieee80211_mira_choose(struct ieee80211_mira_node *mn, struct ieee80211com 
> *ic,
>      struct ieee80211_node *ni)
>  {
> @@ -1065,6 +1167,7 @@ ieee80211_mira_choose(struct ieee80211_mira_node *mn, 
>               splx(s);
>               return;
>       } else {
> +             ieee80211_mira_set_rts_threshold(mn, ic, ni);
>               ieee80211_mira_reset_driver_stats(mn);
>               ieee80211_mira_schedule_probe_timers(mn, ni);
>       }
> @@ -1125,7 +1228,9 @@ ieee80211_mira_node_init(struct ieee80211_mira_node *m
>  {
>       memset(mn, 0, sizeof(*mn));
>       mn->agglen = 1;
> +     mn->rts_threshold = IEEE80211_RTS_MAX;
>       ieee80211_mira_reset_goodput_stats(mn);
> +     ieee80211_mira_reset_collision_stats(mn);
>  
>       timeout_set(&mn->probe_to[IEEE80211_MIRA_PROBE_TO_UP],
>           ieee80211_mira_probe_timeout_up, mn);
> blob - 35ea4193fe71cbdf953976ce26f460699b7f41c5
> file + sys/net80211/ieee80211_mira.h
> --- sys/net80211/ieee80211_mira.h
> +++ sys/net80211/ieee80211_mira.h
> @@ -86,6 +86,15 @@ struct ieee80211_mira_node {
>  
>       /* Goodput statistics for each MCS. */
>       struct ieee80211_mira_goodput_stats g[IEEE80211_HT_RATESET_NUM_MCS];
> +
> +     /* Interference observation window (see MiRa paper section 5.2). */
> +     int ifwnd;
> +     uint32_t ifwnd_frames;
> +     uint32_t ifwnd_retries;
> +     uint32_t ifwnd_txfail;
> +
> +     /* Current RTS threshold for this node. */
> +     int rts_threshold;
>  };
>  
>  /* Initialize rate control state. */
> @@ -97,5 +106,9 @@ void       ieee80211_mira_choose(struct 
> ieee80211_mira_node 
>  
>  /* Cancel timeouts scheduled by ieee80211_mira_choose(). */
>  void ieee80211_mira_cancel_timeouts(struct ieee80211_mira_node *);
> +
> +/* Returns RTS threshold to be used for a frame about to be transmitted. */
> +int  ieee80211_mira_get_rts_threshold(struct ieee80211_mira_node *,
> +    struct ieee80211com *, struct ieee80211_node *, size_t);
>  
>  #endif /* _NET80211_IEEE80211_MIRA_H_ */
> 

Device iwm0

iwm0 at pci2 dev 0 function 0 "Intel Dual Band Wireless-AC 8265" rev 0x78, msi
iwm0: hw rev 0x230, fw ver 22.361476.0, address b4:6b:fc:f3:e4:13

Network

iwm0: flags=8943<UP,BROADCAST,RUNNING,PROMISC,SIMPLEX,MULTICAST> mtu 1500
        lladdr 8c:16:45:9b:c9:fe
        index 1 priority 4 llprio 3
        trunk: trunkdev trunk0
        groups: wlan
        media: IEEE802.11 autoselect (HT-MCS15 mode 11n)
        status: active
        ieee80211: join ZZZZZZZZZ chan 1 bssid XXXXXXXXXXXXXXXXX 83% wpakey 
wpaprotos wpa2 wpaakms psk wpaciphers ccmp wpagroupcipher ccmp


Copy a file over NFS (3 times)

Before patch: 20.51 / 19.74 / 19.74 seconds
After  patch: 14.48 / 15.03 / 14.49 seconds

It gets 25% faster!


Ping -c100 -i0.2 on local network

Before patch: 2.398/3.869/10.290/1.347 ms
After  patch: 2.470/3.245/5.608/0.492 ms


3 differents file get from NFS (once because after it in cache, not
sure if test is relevant or reliable):

Before patch: file1 11.39 / file2 12.21 / file3 6.47 seconds
After  patch: file1 12.44 / file2 12.50 / file3 7.26 seconds

This test show a small slowdown while other tests show a big
improvement.

Reply via email to