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.