Exemplo n.º 1
0
static void
update_stats(struct ath_softc *sc, struct ath_node *an, 
		  int frame_size,
		  int rix0, int tries0,
		  int rix1, int tries1,
		  int rix2, int tries2,
		  int rix3, int tries3,
		  int short_tries, int tries, int status,
		  int nframes, int nbad)
{
	struct sample_node *sn = ATH_NODE_SAMPLE(an);
	struct sample_softc *ssc = ATH_SOFTC_SAMPLE(sc);
#ifdef IEEE80211_DEBUG
	const HAL_RATE_TABLE *rt = sc->sc_currates;
#endif
	const int size_bin = size_to_bin(frame_size);
	const int size = bin_to_size(size_bin);
	int tt, tries_so_far;
	int is_ht40 = (an->an_node.ni_chw == 40);
	int pct;

	if (!IS_RATE_DEFINED(sn, rix0))
		return;
	tt = calc_usecs_unicast_packet(sc, size, rix0, short_tries,
		MIN(tries0, tries) - 1, is_ht40);
	tries_so_far = tries0;

	if (tries1 && tries_so_far < tries) {
		if (!IS_RATE_DEFINED(sn, rix1))
			return;
		tt += calc_usecs_unicast_packet(sc, size, rix1, short_tries,
			MIN(tries1 + tries_so_far, tries) - tries_so_far - 1, is_ht40);
		tries_so_far += tries1;
	}

	if (tries2 && tries_so_far < tries) {
		if (!IS_RATE_DEFINED(sn, rix2))
			return;
		tt += calc_usecs_unicast_packet(sc, size, rix2, short_tries,
			MIN(tries2 + tries_so_far, tries) - tries_so_far - 1, is_ht40);
		tries_so_far += tries2;
	}

	if (tries3 && tries_so_far < tries) {
		if (!IS_RATE_DEFINED(sn, rix3))
			return;
		tt += calc_usecs_unicast_packet(sc, size, rix3, short_tries,
			MIN(tries3 + tries_so_far, tries) - tries_so_far - 1, is_ht40);
	}

	if (sn->stats[size_bin][rix0].total_packets < ssc->smoothing_minpackets) {
		/* just average the first few packets */
		int avg_tx = sn->stats[size_bin][rix0].average_tx_time;
		int packets = sn->stats[size_bin][rix0].total_packets;
		sn->stats[size_bin][rix0].average_tx_time = (tt+(avg_tx*packets))/(packets+nframes);
	} else {
		/* use a ewma */
		sn->stats[size_bin][rix0].average_tx_time = 
			((sn->stats[size_bin][rix0].average_tx_time * ssc->smoothing_rate) + 
			 (tt * (100 - ssc->smoothing_rate))) / 100;
	}
	
	/*
	 * XXX Don't mark the higher bit rates as also having failed; as this
	 * unfortunately stops those rates from being tasted when trying to
	 * TX. This happens with 11n aggregation.
	 */
	if (nframes == nbad) {
#if 0
		int y;
#endif
		sn->stats[size_bin][rix0].successive_failures += nbad;
#if 0
		for (y = size_bin+1; y < NUM_PACKET_SIZE_BINS; y++) {
			/*
			 * Also say larger packets failed since we
			 * assume if a small packet fails at a
			 * bit-rate then a larger one will also.
			 */
			sn->stats[y][rix0].successive_failures += nbad;
			sn->stats[y][rix0].last_tx = ticks;
			sn->stats[y][rix0].tries += tries;
			sn->stats[y][rix0].total_packets += nframes;
		}
#endif
	} else {
		sn->stats[size_bin][rix0].packets_acked += (nframes - nbad);
		sn->stats[size_bin][rix0].successive_failures = 0;
	}
	sn->stats[size_bin][rix0].tries += tries;
	sn->stats[size_bin][rix0].last_tx = ticks;
	sn->stats[size_bin][rix0].total_packets += nframes;

	/* update EWMA for this rix */

	/* Calculate percentage based on current rate */
	if (nframes == 0)
		nframes = nbad = 1;
	pct = ((nframes - nbad) * 1000) / nframes;

	if (sn->stats[size_bin][rix0].total_packets <
	    ssc->smoothing_minpackets) {
		/* just average the first few packets */
		int a_pct = (sn->stats[size_bin][rix0].packets_acked * 1000) /
		    (sn->stats[size_bin][rix0].total_packets);
		sn->stats[size_bin][rix0].ewma_pct = a_pct;
	} else {
		/* use a ewma */
		sn->stats[size_bin][rix0].ewma_pct =
			((sn->stats[size_bin][rix0].ewma_pct * ssc->smoothing_rate) +
			 (pct * (100 - ssc->smoothing_rate))) / 100;
	}


	if (rix0 == sn->current_sample_rix[size_bin]) {
		IEEE80211_NOTE(an->an_node.ni_vap, IEEE80211_MSG_RATECTL,
		   &an->an_node,
"%s: size %d %s sample rate %d %s tries (%d/%d) tt %d avg_tt (%d/%d) nfrm %d nbad %d", 
		    __func__, 
		    size,
		    status ? "FAIL" : "OK",
		    dot11rate(rt, rix0),
		    dot11rate_label(rt, rix0),
		    short_tries, tries, tt, 
		    sn->stats[size_bin][rix0].average_tx_time,
		    sn->stats[size_bin][rix0].perfect_tx_time,
		    nframes, nbad);
		sn->sample_tt[size_bin] = tt;
		sn->current_sample_rix[size_bin] = -1;
	}
}
Exemplo n.º 2
0
void
ath_rate_tx_complete(struct ath_softc *sc, struct ath_node *an,
	const struct ath_rc_series *rc, const struct ath_tx_status *ts,
	int frame_size, int nframes, int nbad)
{
	struct ifnet *ifp = sc->sc_ifp;
	struct ieee80211com *ic = ifp->if_l2com;
	struct sample_node *sn = ATH_NODE_SAMPLE(an);
	int final_rix, short_tries, long_tries;
	const HAL_RATE_TABLE *rt = sc->sc_currates;
	int status = ts->ts_status;
	int mrr;

	final_rix = rt->rateCodeToIndex[ts->ts_rate];
	short_tries = ts->ts_shortretry;
	long_tries = ts->ts_longretry + 1;

	if (nframes == 0) {
		device_printf(sc->sc_dev, "%s: nframes=0?\n", __func__);
		return;
	}

	if (frame_size == 0)		    /* NB: should not happen */
		frame_size = 1500;

	if (sn->ratemask == 0) {
		IEEE80211_NOTE(an->an_node.ni_vap, IEEE80211_MSG_RATECTL,
		    &an->an_node,
		    "%s: size %d %s rate/try %d/%d no rates yet", 
		    __func__,
		    bin_to_size(size_to_bin(frame_size)),
		    status ? "FAIL" : "OK",
		    short_tries, long_tries);
		return;
	}
	mrr = sc->sc_mrretry;
	/* XXX check HT protmode too */
	if (mrr && (ic->ic_flags & IEEE80211_F_USEPROT && !sc->sc_mrrprot))
		mrr = 0;

	if (!mrr || ts->ts_finaltsi == 0) {
		if (!IS_RATE_DEFINED(sn, final_rix)) {
			device_printf(sc->sc_dev, "%s: ts_rate=%d ts_finaltsi=%d\n",
			    __func__, ts->ts_rate, ts->ts_finaltsi);
			badrate(ifp, 0, ts->ts_rate, long_tries, status);
			return;
		}
		/*
		 * Only one rate was used; optimize work.
		 */
		IEEE80211_NOTE(an->an_node.ni_vap, IEEE80211_MSG_RATECTL,
		     &an->an_node, "%s: size %d (%d bytes) %s rate/short/long %d %s/%d/%d nframes/nbad [%d/%d]",
		     __func__,
		     bin_to_size(size_to_bin(frame_size)),
		     frame_size,
		     status ? "FAIL" : "OK",
		     dot11rate(rt, final_rix), dot11rate_label(rt, final_rix),
		     short_tries, long_tries, nframes, nbad);
		update_stats(sc, an, frame_size, 
			     final_rix, long_tries,
			     0, 0,
			     0, 0,
			     0, 0,
			     short_tries, long_tries, status,
			     nframes, nbad);

	} else {
		int finalTSIdx = ts->ts_finaltsi;
		int i;

		/*
		 * Process intermediate rates that failed.
		 */

		IEEE80211_NOTE(an->an_node.ni_vap, IEEE80211_MSG_RATECTL,
		    &an->an_node,
"%s: size %d (%d bytes) finaltsidx %d short %d long %d %s rate/try [%d %s/%d %d %s/%d %d %s/%d %d %s/%d] nframes/nbad [%d/%d]", 
		     __func__,
		     bin_to_size(size_to_bin(frame_size)),
		     frame_size,
		     finalTSIdx,
		     short_tries,
		     long_tries,
		     status ? "FAIL" : "OK",
		     dot11rate(rt, rc[0].rix),
		      dot11rate_label(rt, rc[0].rix), rc[0].tries,
		     dot11rate(rt, rc[1].rix),
		      dot11rate_label(rt, rc[1].rix), rc[1].tries,
		     dot11rate(rt, rc[2].rix),
		      dot11rate_label(rt, rc[2].rix), rc[2].tries,
		     dot11rate(rt, rc[3].rix),
		      dot11rate_label(rt, rc[3].rix), rc[3].tries,
		     nframes, nbad);

		for (i = 0; i < 4; i++) {
			if (rc[i].tries && !IS_RATE_DEFINED(sn, rc[i].rix))
				badrate(ifp, 0, rc[i].ratecode, rc[i].tries,
				    status);
		}

		/*
		 * NB: series > 0 are not penalized for failure
		 * based on the try counts under the assumption
		 * that losses are often bursty and since we
		 * sample higher rates 1 try at a time doing so
		 * may unfairly penalize them.
		 */
		if (rc[0].tries) {
			update_stats(sc, an, frame_size,
				     rc[0].rix, rc[0].tries,
				     rc[1].rix, rc[1].tries,
				     rc[2].rix, rc[2].tries,
				     rc[3].rix, rc[3].tries,
				     short_tries, long_tries,
				     long_tries > rc[0].tries,
				     nframes, nbad);
			long_tries -= rc[0].tries;
		}
		
		if (rc[1].tries && finalTSIdx > 0) {
			update_stats(sc, an, frame_size,
				     rc[1].rix, rc[1].tries,
				     rc[2].rix, rc[2].tries,
				     rc[3].rix, rc[3].tries,
				     0, 0,
				     short_tries, long_tries,
				     status,
				     nframes, nbad);
			long_tries -= rc[1].tries;
		}

		if (rc[2].tries && finalTSIdx > 1) {
			update_stats(sc, an, frame_size,
				     rc[2].rix, rc[2].tries,
				     rc[3].rix, rc[3].tries,
				     0, 0,
				     0, 0,
				     short_tries, long_tries,
				     status,
				     nframes, nbad);
			long_tries -= rc[2].tries;
		}

		if (rc[3].tries && finalTSIdx > 2) {
			update_stats(sc, an, frame_size,
				     rc[3].rix, rc[3].tries,
				     0, 0,
				     0, 0,
				     0, 0,
				     short_tries, long_tries,
				     status,
				     nframes, nbad);
		}
	}
}
Exemplo n.º 3
0
void
ath_rate_tx_complete(struct ath_softc *sc, struct ath_node *an,
	const struct ath_desc *ds, const struct ath_desc *ds0)
{
	struct ieee80211com *ic = &sc->sc_ic;
	struct sample_node *sn = ATH_NODE_SAMPLE(an);
	const struct ar5212_desc *ads = (const struct ar5212_desc *)&ds->ds_ctl0;
	int final_rate, short_tries, long_tries, frame_size;
	int ndx = -1;
	int mrr;

	final_rate = sc->sc_hwmap[ds->ds_txstat.ts_rate &~ HAL_TXSTAT_ALTRATE].ieeerate;
	short_tries = ds->ds_txstat.ts_shortretry + 1;
	long_tries = ds->ds_txstat.ts_longretry + 1;
	frame_size = ds0->ds_ctl0 & 0x0fff; /* low-order 12 bits of ds_ctl0 */
	if (frame_size == 0)		    /* NB: should not happen */
		frame_size = 1500;

	if (sn->num_rates <= 0) {
		DPRINTF(sc, "%s: %s size %d status %d rate/try %d/%d "
			"no rates yet\n", 
			__func__, ether_sprintf(an->an_node.ni_macaddr),
			bin_to_size(size_to_bin(frame_size)),
			ds->ds_txstat.ts_status,
			short_tries, long_tries);
		return;
	}

	mrr = sc->sc_mrretry && !(ic->ic_flags & IEEE80211_F_USEPROT);

	if (sc->sc_mrretry && ds->ds_txstat.ts_status) {
		/* this packet failed */
		DPRINTF(sc, "%s: %s size %d rate/try %d/%d %d/%d %d/%d %d/%d status %s retries (%d/%d)\n", 
			__func__,
			ether_sprintf(an->an_node.ni_macaddr),
			bin_to_size(size_to_bin(frame_size)),
			sc->sc_hwmap[ads->xmit_rate0].ieeerate,
				ads->xmit_tries0,
			sc->sc_hwmap[ads->xmit_rate1].ieeerate,
				ads->xmit_tries1,
			sc->sc_hwmap[ads->xmit_rate2].ieeerate,
				ads->xmit_tries2,
			sc->sc_hwmap[ads->xmit_rate3].ieeerate,
				ads->xmit_tries3,
			ds->ds_txstat.ts_status ? "FAIL" : "OK",
			short_tries, 
			long_tries);
	}

	if (!mrr || !(ds->ds_txstat.ts_rate & HAL_TXSTAT_ALTRATE)) {
		/* only one rate was used */
		ndx = rate_to_ndx(sn, final_rate);
		DPRINTF(sc, "%s: %s size %d status %d rate/try %d/%d/%d\n", 
			__func__, ether_sprintf(an->an_node.ni_macaddr),
			bin_to_size(size_to_bin(frame_size)),
			ds->ds_txstat.ts_status,
			ndx, short_tries, long_tries);
		if (ndx >= 0 && ndx < sn->num_rates) {
			update_stats(sc, an, frame_size, 
				     ndx, long_tries,
				     0, 0,
				     0, 0,
				     0, 0,
				     short_tries, long_tries, ds->ds_txstat.ts_status);
		}
	} else {
		int rate0, tries0, ndx0;
		int rate1, tries1, ndx1;
		int rate2, tries2, ndx2;
		int rate3, tries3, ndx3;
		int finalTSIdx = ads->final_ts_index;

		/*
		 * Process intermediate rates that failed.
		 */

		rate0 = sc->sc_hwmap[ads->xmit_rate0].ieeerate;
		tries0 = ads->xmit_tries0;
		ndx0 = rate_to_ndx(sn, rate0);
		
		rate1 = sc->sc_hwmap[ads->xmit_rate1].ieeerate;
		tries1 = ads->xmit_tries1;
		ndx1 = rate_to_ndx(sn, rate1);
		
		rate2 = sc->sc_hwmap[ads->xmit_rate2].ieeerate;
		tries2 = ads->xmit_tries2;
		ndx2 = rate_to_ndx(sn, rate2);
		
		rate3 = sc->sc_hwmap[ads->xmit_rate3].ieeerate;
		tries3 = ads->xmit_tries3;
		ndx3 = rate_to_ndx(sn, rate3);
		
#if 1
		DPRINTF(sc, "%s: %s size %d finaltsidx %d tries %d status %d rate/try %d/%d %d/%d %d/%d %d/%d\n", 
			__func__, ether_sprintf(an->an_node.ni_macaddr),
			bin_to_size(size_to_bin(frame_size)),
			finalTSIdx,
			long_tries, 
			ds->ds_txstat.ts_status,
			rate0, tries0,
			rate1, tries1,
			rate2, tries2,
			rate3, tries3);
#endif

		if (tries0) {
			update_stats(sc, an, frame_size, 
				     ndx0, tries0, 
				     ndx1, tries1, 
				     ndx2, tries2, 
				     ndx3, tries3, 
				     short_tries, ds->ds_txstat.ts_longretry + 1, 
				     long_tries > tries0);
		}
		
		if (tries1 && finalTSIdx > 0) {
			update_stats(sc, an, frame_size, 
				     ndx1, tries1, 
				     ndx2, tries2, 
				     ndx3, tries3, 
				     0, 0, 
				     short_tries, ds->ds_txstat.ts_longretry + 1 - tries0, 
				     ds->ds_txstat.ts_status);
		}

		if (tries2 && finalTSIdx > 1) {
			update_stats(sc, an, frame_size, 
				     ndx2, tries2, 
				     ndx3, tries3, 
				     0, 0,
				     0, 0,
				     short_tries, ds->ds_txstat.ts_longretry + 1 - tries0 - tries1, 
				     ds->ds_txstat.ts_status);
		}

		if (tries3 && finalTSIdx > 2) {
			update_stats(sc, an, frame_size, 
				     ndx3, tries3, 
				     0, 0,
				     0, 0,
				     0, 0,
				     short_tries, ds->ds_txstat.ts_longretry + 1 - tries0 - tries1 - tries2, 
				     ds->ds_txstat.ts_status);
		}
	}
}
Exemplo n.º 4
0
void
ath_rate_findrate(struct ath_softc *sc, struct ath_node *an,
		  int shortPreamble, size_t frameLen,
		  u_int8_t *rix0, int *try0, u_int8_t *txrate)
{
#define	DOT11RATE(ix)	(rt->info[ix].dot11Rate & IEEE80211_RATE_VAL)
#define	MCS(ix)		(rt->info[ix].dot11Rate | IEEE80211_RATE_MCS)
#define	RATE(ix)	(DOT11RATE(ix) / 2)
	struct sample_node *sn = ATH_NODE_SAMPLE(an);
	struct sample_softc *ssc = ATH_SOFTC_SAMPLE(sc);
	struct ifnet *ifp = sc->sc_ifp;
	struct ieee80211com *ic = ifp->if_l2com;
	const HAL_RATE_TABLE *rt = sc->sc_currates;
	const int size_bin = size_to_bin(frameLen);
	int rix, mrr, best_rix, change_rates;
	unsigned average_tx_time;

	ath_rate_update_static_rix(sc, &an->an_node);

	if (sn->currates != sc->sc_currates) {
		device_printf(sc->sc_dev, "%s: currates != sc_currates!\n",
		    __func__);
		rix = 0;
		*try0 = ATH_TXMAXTRY;
		goto done;
	}

	if (sn->static_rix != -1) {
		rix = sn->static_rix;
		*try0 = ATH_TXMAXTRY;
		goto done;
	}

	mrr = sc->sc_mrretry;
	/* XXX check HT protmode too */
	if (mrr && (ic->ic_flags & IEEE80211_F_USEPROT && !sc->sc_mrrprot))
		mrr = 0;

	best_rix = pick_best_rate(an, rt, size_bin, !mrr);
	if (best_rix >= 0) {
		average_tx_time = sn->stats[size_bin][best_rix].average_tx_time;
	} else {
		average_tx_time = 0;
	}
	/*
	 * Limit the time measuring the performance of other tx
	 * rates to sample_rate% of the total transmission time.
	 */
	if (sn->sample_tt[size_bin] < average_tx_time * (sn->packets_since_sample[size_bin]*ssc->sample_rate/100)) {
		rix = pick_sample_rate(ssc, an, rt, size_bin);
		IEEE80211_NOTE(an->an_node.ni_vap, IEEE80211_MSG_RATECTL,
		     &an->an_node, "att %d sample_tt %d size %u sample rate %d %s current rate %d %s",
		     average_tx_time,
		     sn->sample_tt[size_bin],
		     bin_to_size(size_bin),
		     dot11rate(rt, rix),
		     dot11rate_label(rt, rix),
		     dot11rate(rt, sn->current_rix[size_bin]),
		     dot11rate_label(rt, sn->current_rix[size_bin]));
		if (rix != sn->current_rix[size_bin]) {
			sn->current_sample_rix[size_bin] = rix;
		} else {
			sn->current_sample_rix[size_bin] = -1;
		}
		sn->packets_since_sample[size_bin] = 0;
	} else {
		change_rates = 0;
		if (!sn->packets_sent[size_bin] || best_rix == -1) {
			/* no packet has been sent successfully yet */
			change_rates = 1;
			if (an->an_node.ni_flags & IEEE80211_NODE_HT)
				best_rix =
				    ath_rate_pick_seed_rate_ht(sc, an, frameLen);
			else
				best_rix =
				    ath_rate_pick_seed_rate_legacy(sc, an, frameLen);
		} else if (sn->packets_sent[size_bin] < 20) {
			/* let the bit-rate switch quickly during the first few packets */
			IEEE80211_NOTE(an->an_node.ni_vap,
			    IEEE80211_MSG_RATECTL, &an->an_node,
			    "%s: switching quickly..", __func__);
			change_rates = 1;
		} else if (ticks - ssc->min_switch > sn->ticks_since_switch[size_bin]) {
			/* min_switch seconds have gone by */
			IEEE80211_NOTE(an->an_node.ni_vap,
			    IEEE80211_MSG_RATECTL, &an->an_node,
			    "%s: min_switch %d > ticks_since_switch %d..",
			    __func__, ticks - ssc->min_switch, sn->ticks_since_switch[size_bin]);
			change_rates = 1;
		} else if ((! (an->an_node.ni_flags & IEEE80211_NODE_HT)) &&
		    (2*average_tx_time < sn->stats[size_bin][sn->current_rix[size_bin]].average_tx_time)) {
			/* the current bit-rate is twice as slow as the best one */
			IEEE80211_NOTE(an->an_node.ni_vap,
			    IEEE80211_MSG_RATECTL, &an->an_node,
			    "%s: 2x att (= %d) < cur_rix att %d",
			    __func__,
			    2 * average_tx_time, sn->stats[size_bin][sn->current_rix[size_bin]].average_tx_time);
			change_rates = 1;
		} else if ((an->an_node.ni_flags & IEEE80211_NODE_HT)) {
			int cur_rix = sn->current_rix[size_bin];
			int cur_att = sn->stats[size_bin][cur_rix].average_tx_time;
			/*
			 * If the node is HT, upgrade it if the MCS rate is
			 * higher and the average tx time is within 20% of
			 * the current rate. It can fail a little.
			 *
			 * This is likely not optimal!
			 */
#if 0
			printf("cur rix/att %x/%d, best rix/att %x/%d\n",
			    MCS(cur_rix), cur_att, MCS(best_rix), average_tx_time);
#endif
			if ((MCS(best_rix) > MCS(cur_rix)) &&
			    (average_tx_time * 8) <= (cur_att * 10)) {
				IEEE80211_NOTE(an->an_node.ni_vap,
				    IEEE80211_MSG_RATECTL, &an->an_node,
				    "%s: HT: best_rix 0x%d > cur_rix 0x%x, average_tx_time %d, cur_att %d",
				    __func__,
				    MCS(best_rix), MCS(cur_rix), average_tx_time, cur_att);
				change_rates = 1;
			}
		}

		sn->packets_since_sample[size_bin]++;
		
		if (change_rates) {
			if (best_rix != sn->current_rix[size_bin]) {
				IEEE80211_NOTE(an->an_node.ni_vap,
				    IEEE80211_MSG_RATECTL,
				    &an->an_node,
"%s: size %d switch rate %d (%d/%d) -> %d (%d/%d) after %d packets mrr %d",
				    __func__,
				    bin_to_size(size_bin),
				    RATE(sn->current_rix[size_bin]),
				    sn->stats[size_bin][sn->current_rix[size_bin]].average_tx_time,
				    sn->stats[size_bin][sn->current_rix[size_bin]].perfect_tx_time,
				    RATE(best_rix),
				    sn->stats[size_bin][best_rix].average_tx_time,
				    sn->stats[size_bin][best_rix].perfect_tx_time,
				    sn->packets_since_switch[size_bin],
				    mrr);
			}
			sn->packets_since_switch[size_bin] = 0;
			sn->current_rix[size_bin] = best_rix;
			sn->ticks_since_switch[size_bin] = ticks;
			/* 
			 * Set the visible txrate for this node.
			 */
			an->an_node.ni_txrate = (rt->info[best_rix].phy == IEEE80211_T_HT) ?  MCS(best_rix) : DOT11RATE(best_rix);
		}
		rix = sn->current_rix[size_bin];
		sn->packets_since_switch[size_bin]++;
	}
	*try0 = mrr ? sn->sched[rix].t0 : ATH_TXMAXTRY;
done:

	/*
	 * This bug totally sucks and should be fixed.
	 *
	 * For now though, let's not panic, so we can start to figure
	 * out how to better reproduce it.
	 */
	if (rix < 0 || rix >= rt->rateCount) {
		printf("%s: ERROR: rix %d out of bounds (rateCount=%d)\n",
		    __func__,
		    rix,
		    rt->rateCount);
		    rix = 0;	/* XXX just default for now */
	}
	KASSERT(rix >= 0 && rix < rt->rateCount, ("rix is %d", rix));

	*rix0 = rix;
	*txrate = rt->info[rix].rateCode
		| (shortPreamble ? rt->info[rix].shortPreamble : 0);
	sn->packets_sent[size_bin]++;
#undef DOT11RATE
#undef MCS
#undef RATE
}
Exemplo n.º 5
0
static void
update_stats(struct ath_softc *sc, struct ath_node *an, 
		  int frame_size,
		  int ndx0, int tries0,
		  int ndx1, int tries1,
		  int ndx2, int tries2,
		  int ndx3, int tries3,
		  int short_tries, int tries, int status)
{
	struct sample_node *sn = ATH_NODE_SAMPLE(an);
	struct sample_softc *ssc = ATH_SOFTC_SAMPLE(sc);
	int tt = 0;
	int tries_so_far = 0;
	int size_bin;
	int size;
	int rate;

	if (ndx0 == -1)
		return;

	size_bin = size_to_bin(frame_size);
	size = bin_to_size(size_bin);
	rate = sn->rates[ndx0].rate;

	tt += calc_usecs_unicast_packet(sc, size, sn->rates[ndx0].rix,
	    short_tries - 1, MIN(tries0, tries) - 1);
	tries_so_far += tries0;
	if (tries1 && tries0 < tries) {
		tt += calc_usecs_unicast_packet(sc, size,
		    ndx1 == -1 ? 0 : sn->rates[ndx1].rix, short_tries - 1, 
		    MIN(tries1 + tries_so_far, tries) - tries_so_far - 1);
	}
	tries_so_far += tries1;

	if (tries2 && tries0 + tries1 < tries) {
		tt += calc_usecs_unicast_packet(sc, size,
		    ndx2 == -1 ? 0 : sn->rates[ndx2].rix, short_tries - 1, 
		    MIN(tries2 + tries_so_far, tries) - tries_so_far - 1);
	}

	tries_so_far += tries2;

	if (tries3 && tries0 + tries1 + tries2 < tries) {
		tt += calc_usecs_unicast_packet(sc, size,
		    ndx3 == -1 ? 0 : sn->rates[ndx3].rix, short_tries - 1, 
		    MIN(tries3 + tries_so_far, tries) - tries_so_far - 1);
	}

	if (sn->stats[size_bin][ndx0].total_packets < (100 / (100 - ssc->ath_smoothing_rate))) {
		/* just average the first few packets */
		int avg_tx = sn->stats[size_bin][ndx0].average_tx_time;
		int packets = sn->stats[size_bin][ndx0].total_packets;
		sn->stats[size_bin][ndx0].average_tx_time = (tt+(avg_tx*packets))/(packets+1);
	} else {
		/* use a ewma */
		sn->stats[size_bin][ndx0].average_tx_time = 
			((sn->stats[size_bin][ndx0].average_tx_time * ssc->ath_smoothing_rate) + 
			 (tt * (100 - ssc->ath_smoothing_rate))) / 100;
	}
	
	if (status) {
		int y;
		sn->stats[size_bin][ndx0].successive_failures++;
		for (y = size_bin+1; y < NUM_PACKET_SIZE_BINS; y++) {
			/* also say larger packets failed since we
			 * assume if a small packet fails at a lower
			 * bit-rate then a larger one will also.
			 */
			sn->stats[y][ndx0].successive_failures++;
			sn->stats[y][ndx0].last_tx = ticks;
			sn->stats[y][ndx0].tries += tries;
			sn->stats[y][ndx0].total_packets++;
		}
	} else {
		sn->stats[size_bin][ndx0].packets_acked++;
		sn->stats[size_bin][ndx0].successive_failures = 0;
	}
	sn->stats[size_bin][ndx0].tries += tries;
	sn->stats[size_bin][ndx0].last_tx = ticks;
	sn->stats[size_bin][ndx0].total_packets++;


	if (ndx0 == sn->current_sample_ndx[size_bin]) {
		DPRINTF(sc, "%s: %s size %d sample rate %d tries (%d/%d) tt %d avg_tt (%d/%d) status %d\n", 
			__func__, ether_sprintf(an->an_node.ni_macaddr), 
			size, rate, short_tries, tries, tt, 
			sn->stats[size_bin][ndx0].average_tx_time,
			sn->stats[size_bin][ndx0].perfect_tx_time,
			status);
		sn->sample_tt[size_bin] = tt;
		sn->current_sample_ndx[size_bin] = -1;
	}
}
Exemplo n.º 6
0
void
ath_rate_findrate(struct ath_softc *sc, struct ath_node *an,
		  int shortPreamble, size_t frameLen,
		  u_int8_t *rix, int *try0, u_int8_t *txrate)
{
	struct sample_node *sn = ATH_NODE_SAMPLE(an);
	struct sample_softc *ssc = ATH_SOFTC_SAMPLE(sc);
	struct ieee80211com *ic = &sc->sc_ic;
	int ndx, size_bin, mrr, best_ndx, change_rates;
	unsigned average_tx_time;

	mrr = sc->sc_mrretry && !(ic->ic_flags & IEEE80211_F_USEPROT);
	size_bin = size_to_bin(frameLen);
	best_ndx = best_rate_ndx(sn, size_bin, !mrr);

	if (best_ndx >= 0) {
		average_tx_time = sn->stats[size_bin][best_ndx].average_tx_time;
	} else {
		average_tx_time = 0;
	}
	
	if (sn->static_rate_ndx != -1) {
		ndx = sn->static_rate_ndx;
		*try0 = ATH_TXMAXTRY;
	} else {
		*try0 = mrr ? 2 : ATH_TXMAXTRY;
		
		if (sn->sample_tt[size_bin] < average_tx_time * (sn->packets_since_sample[size_bin]*ssc->ath_sample_rate/100)) {
			/*
			 * we want to limit the time measuring the performance
			 * of other bit-rates to ath_sample_rate% of the
			 * total transmission time.
			 */
			ndx = pick_sample_ndx(sn, size_bin);
			if (ndx != sn->current_rate[size_bin]) {
				sn->current_sample_ndx[size_bin] = ndx;
			} else {
				sn->current_sample_ndx[size_bin] = -1;
			}
			sn->packets_since_sample[size_bin] = 0;

		} else {
			change_rates = 0;
			if (!sn->packets_sent[size_bin] || best_ndx == -1) {
				/* no packet has been sent successfully yet */
				for (ndx = sn->num_rates-1; ndx > 0; ndx--) {
					/* 
					 * pick the highest rate <= 36 Mbps
					 * that hasn't failed.
					 */
					if (sn->rates[ndx].rate <= 72 && 
					    sn->stats[size_bin][ndx].successive_failures == 0) {
						break;
					}
				}
				change_rates = 1;
				best_ndx = ndx;
			} else if (sn->packets_sent[size_bin] < 20) {
				/* let the bit-rate switch quickly during the first few packets */
				change_rates = 1;
			} else if (ticks - ((hz*MIN_SWITCH_MS)/1000) > sn->ticks_since_switch[size_bin]) {
				/* 2 seconds have gone by */
				change_rates = 1;
			} else if (average_tx_time * 2 < sn->stats[size_bin][sn->current_rate[size_bin]].average_tx_time) {
				/* the current bit-rate is twice as slow as the best one */
				change_rates = 1;
			}

			sn->packets_since_sample[size_bin]++;
			
			if (change_rates) {
				if (best_ndx != sn->current_rate[size_bin]) {
					DPRINTF(sc, "%s: %s size %d switch rate %d (%d/%d) -> %d (%d/%d) after %d packets mrr %d\n",
						__func__,
						ether_sprintf(an->an_node.ni_macaddr),
						packet_size_bins[size_bin],
						sn->rates[sn->current_rate[size_bin]].rate,
						sn->stats[size_bin][sn->current_rate[size_bin]].average_tx_time,
						sn->stats[size_bin][sn->current_rate[size_bin]].perfect_tx_time,
						sn->rates[best_ndx].rate,
						sn->stats[size_bin][best_ndx].average_tx_time,
						sn->stats[size_bin][best_ndx].perfect_tx_time,
						sn->packets_since_switch[size_bin],
						mrr);
				}
				sn->packets_since_switch[size_bin] = 0;
				sn->current_rate[size_bin] = best_ndx;
				sn->ticks_since_switch[size_bin] = ticks;
			}
			ndx = sn->current_rate[size_bin];
			sn->packets_since_switch[size_bin]++;
			if (size_bin == 0) {
	    			/* 
	    			 * set the visible txrate for this node
			         * to the rate of small packets
			         */
				an->an_node.ni_txrate = ndx;
			}
		}
	}

	KASSERTMSG(ndx >= 0 && ndx < sn->num_rates, "ndx is %d", ndx);

	*rix = sn->rates[ndx].rix;
	if (shortPreamble) {
		*txrate = sn->rates[ndx].shortPreambleRateCode;
	} else {
		*txrate = sn->rates[ndx].rateCode;
	}
	sn->packets_sent[size_bin]++;
}
Exemplo n.º 7
0
void
ath_rate_tx_complete(struct ath_softc *sc, struct ath_node *an,
                     const struct ath_buf *bf)
{
    struct ifnet *ifp = sc->sc_ifp;
    struct ieee80211com *ic = ifp->if_l2com;
    struct sample_node *sn = ATH_NODE_SAMPLE(an);
    const struct ath_tx_status *ts = &bf->bf_status.ds_txstat;
    const struct ath_desc *ds0 = &bf->bf_desc[0];
    int final_rix, short_tries, long_tries, frame_size;
    const HAL_RATE_TABLE *rt = sc->sc_currates;
    int mrr;

    final_rix = rt->rateCodeToIndex[ts->ts_rate];
    short_tries = ts->ts_shortretry;
    long_tries = ts->ts_longretry + 1;
    frame_size = ds0->ds_ctl0 & 0x0fff; /* low-order 12 bits of ds_ctl0 */
    if (frame_size == 0)		    /* NB: should not happen */
        frame_size = 1500;

    if (sn->ratemask == 0) {
        IEEE80211_NOTE(an->an_node.ni_vap, IEEE80211_MSG_RATECTL,
                       &an->an_node,
                       "%s: size %d %s rate/try %d/%d no rates yet",
                       __func__,
                       bin_to_size(size_to_bin(frame_size)),
                       ts->ts_status ? "FAIL" : "OK",
                       short_tries, long_tries);
        return;
    }
    mrr = sc->sc_mrretry && !(ic->ic_flags & IEEE80211_F_USEPROT);
    if (!mrr || ts->ts_finaltsi == 0) {
        if (!IS_RATE_DEFINED(sn, final_rix)) {
            badrate(ifp, 0, ts->ts_rate, long_tries, ts->ts_status);
            return;
        }
        /*
         * Only one rate was used; optimize work.
         */
        IEEE80211_NOTE(an->an_node.ni_vap, IEEE80211_MSG_RATECTL,
                       &an->an_node, "%s: size %d %s rate/try %d/%d/%d",
                       __func__,
                       bin_to_size(size_to_bin(frame_size)),
                       ts->ts_status ? "FAIL" : "OK",
                       final_rix, short_tries, long_tries);
        update_stats(sc, an, frame_size,
                     final_rix, long_tries,
                     0, 0,
                     0, 0,
                     0, 0,
                     short_tries, long_tries, ts->ts_status);
    } else {
        int hwrate0, rix0, tries0;
        int hwrate1, rix1, tries1;
        int hwrate2, rix2, tries2;
        int hwrate3, rix3, tries3;
        int finalTSIdx = ts->ts_finaltsi;

        /*
         * Process intermediate rates that failed.
         */
        if (sc->sc_ah->ah_magic != 0x20065416) {
            hwrate0 = MS(ds0->ds_ctl3, AR_XmitRate0);
            hwrate1 = MS(ds0->ds_ctl3, AR_XmitRate1);
            hwrate2 = MS(ds0->ds_ctl3, AR_XmitRate2);
            hwrate3 = MS(ds0->ds_ctl3, AR_XmitRate3);
        } else {
            hwrate0 = MS(ds0->ds_ctl3, AR5416_XmitRate0);
            hwrate1 = MS(ds0->ds_ctl3, AR5416_XmitRate1);
            hwrate2 = MS(ds0->ds_ctl3, AR5416_XmitRate2);
            hwrate3 = MS(ds0->ds_ctl3, AR5416_XmitRate3);
        }

        rix0 = rt->rateCodeToIndex[hwrate0];
        tries0 = MS(ds0->ds_ctl2, AR_XmitDataTries0);

        rix1 = rt->rateCodeToIndex[hwrate1];
        tries1 = MS(ds0->ds_ctl2, AR_XmitDataTries1);

        rix2 = rt->rateCodeToIndex[hwrate2];
        tries2 = MS(ds0->ds_ctl2, AR_XmitDataTries2);

        rix3 = rt->rateCodeToIndex[hwrate3];
        tries3 = MS(ds0->ds_ctl2, AR_XmitDataTries3);

        IEEE80211_NOTE(an->an_node.ni_vap, IEEE80211_MSG_RATECTL,
                       &an->an_node,
                       "%s: size %d finaltsidx %d tries %d %s rate/try [%d/%d %d/%d %d/%d %d/%d]",
                       __func__,
                       bin_to_size(size_to_bin(frame_size)),
                       finalTSIdx,
                       long_tries,
                       ts->ts_status ? "FAIL" : "OK",
                       rix0, tries0,
                       rix1, tries1,
                       rix2, tries2,
                       rix3, tries3);

        if (tries0 && !IS_RATE_DEFINED(sn, rix0))
            badrate(ifp, 0, hwrate0, tries0, ts->ts_status);
        if (tries1 && !IS_RATE_DEFINED(sn, rix1))
            badrate(ifp, 1, hwrate1, tries1, ts->ts_status);
        if (tries2 && !IS_RATE_DEFINED(sn, rix2))
            badrate(ifp, 2, hwrate2, tries2, ts->ts_status);
        if (tries3 && !IS_RATE_DEFINED(sn, rix3))
            badrate(ifp, 3, hwrate3, tries3, ts->ts_status);

        /*
         * NB: series > 0 are not penalized for failure
         * based on the try counts under the assumption
         * that losses are often bursty and since we
         * sample higher rates 1 try at a time doing so
         * may unfairly penalize them.
         */
        if (tries0) {
            update_stats(sc, an, frame_size,
                         rix0, tries0,
                         rix1, tries1,
                         rix2, tries2,
                         rix3, tries3,
                         short_tries, long_tries,
                         long_tries > tries0);
            long_tries -= tries0;
        }

        if (tries1 && finalTSIdx > 0) {
            update_stats(sc, an, frame_size,
                         rix1, tries1,
                         rix2, tries2,
                         rix3, tries3,
                         0, 0,
                         short_tries, long_tries,
                         ts->ts_status);
            long_tries -= tries1;
        }

        if (tries2 && finalTSIdx > 1) {
            update_stats(sc, an, frame_size,
                         rix2, tries2,
                         rix3, tries3,
                         0, 0,
                         0, 0,
                         short_tries, long_tries,
                         ts->ts_status);
            long_tries -= tries2;
        }

        if (tries3 && finalTSIdx > 2) {
            update_stats(sc, an, frame_size,
                         rix3, tries3,
                         0, 0,
                         0, 0,
                         0, 0,
                         short_tries, long_tries,
                         ts->ts_status);
        }
    }
}
Exemplo n.º 8
0
static void
update_stats(struct ath_softc *sc, struct ath_node *an,
             int frame_size,
             int rix0, int tries0,
             int rix1, int tries1,
             int rix2, int tries2,
             int rix3, int tries3,
             int short_tries, int tries, int status)
{
    struct sample_node *sn = ATH_NODE_SAMPLE(an);
    struct sample_softc *ssc = ATH_SOFTC_SAMPLE(sc);
    const int size_bin = size_to_bin(frame_size);
    const int size = bin_to_size(size_bin);
    int tt, tries_so_far;

    if (!IS_RATE_DEFINED(sn, rix0))
        return;
    tt = calc_usecs_unicast_packet(sc, size, rix0, short_tries,
                                   MIN(tries0, tries) - 1);
    tries_so_far = tries0;

    if (tries1 && tries_so_far < tries) {
        if (!IS_RATE_DEFINED(sn, rix1))
            return;
        tt += calc_usecs_unicast_packet(sc, size, rix1, short_tries,
                                        MIN(tries1 + tries_so_far, tries) - tries_so_far - 1);
        tries_so_far += tries1;
    }

    if (tries2 && tries_so_far < tries) {
        if (!IS_RATE_DEFINED(sn, rix2))
            return;
        tt += calc_usecs_unicast_packet(sc, size, rix2, short_tries,
                                        MIN(tries2 + tries_so_far, tries) - tries_so_far - 1);
        tries_so_far += tries2;
    }

    if (tries3 && tries_so_far < tries) {
        if (!IS_RATE_DEFINED(sn, rix3))
            return;
        tt += calc_usecs_unicast_packet(sc, size, rix3, short_tries,
                                        MIN(tries3 + tries_so_far, tries) - tries_so_far - 1);
    }

    if (sn->stats[size_bin][rix0].total_packets < ssc->smoothing_minpackets) {
        /* just average the first few packets */
        int avg_tx = sn->stats[size_bin][rix0].average_tx_time;
        int packets = sn->stats[size_bin][rix0].total_packets;
        sn->stats[size_bin][rix0].average_tx_time = (tt+(avg_tx*packets))/(packets+1);
    } else {
        /* use a ewma */
        sn->stats[size_bin][rix0].average_tx_time =
            ((sn->stats[size_bin][rix0].average_tx_time * ssc->smoothing_rate) +
             (tt * (100 - ssc->smoothing_rate))) / 100;
    }

    if (status != 0) {
        int y;
        sn->stats[size_bin][rix0].successive_failures++;
        for (y = size_bin+1; y < NUM_PACKET_SIZE_BINS; y++) {
            /*
             * Also say larger packets failed since we
             * assume if a small packet fails at a
             * bit-rate then a larger one will also.
             */
            sn->stats[y][rix0].successive_failures++;
            sn->stats[y][rix0].last_tx = ticks;
            sn->stats[y][rix0].tries += tries;
            sn->stats[y][rix0].total_packets++;
        }
    } else {
        sn->stats[size_bin][rix0].packets_acked++;
        sn->stats[size_bin][rix0].successive_failures = 0;
    }
    sn->stats[size_bin][rix0].tries += tries;
    sn->stats[size_bin][rix0].last_tx = ticks;
    sn->stats[size_bin][rix0].total_packets++;

    if (rix0 == sn->current_sample_rix[size_bin]) {
        IEEE80211_NOTE(an->an_node.ni_vap, IEEE80211_MSG_RATECTL,
                       &an->an_node,
                       "%s: size %d %s sample rate %d tries (%d/%d) tt %d avg_tt (%d/%d)",
                       __func__,
                       size,
                       status ? "FAIL" : "OK",
                       rix0, short_tries, tries, tt,
                       sn->stats[size_bin][rix0].average_tx_time,
                       sn->stats[size_bin][rix0].perfect_tx_time);
        sn->sample_tt[size_bin] = tt;
        sn->current_sample_rix[size_bin] = -1;
    }
}
Exemplo n.º 9
0
void
ath_rate_findrate(struct ath_softc *sc, struct ath_node *an,
                  int shortPreamble, size_t frameLen,
                  u_int8_t *rix0, int *try0, u_int8_t *txrate)
{
#define	DOT11RATE(ix)	(rt->info[ix].dot11Rate & IEEE80211_RATE_VAL)
#define	RATE(ix)	(DOT11RATE(ix) / 2)
    struct sample_node *sn = ATH_NODE_SAMPLE(an);
    struct sample_softc *ssc = ATH_SOFTC_SAMPLE(sc);
    struct ifnet *ifp = sc->sc_ifp;
    struct ieee80211com *ic = ifp->if_l2com;
    const HAL_RATE_TABLE *rt = sc->sc_currates;
    const int size_bin = size_to_bin(frameLen);
    int rix, mrr, best_rix, change_rates;
    unsigned average_tx_time;

    if (sn->static_rix != -1) {
        rix = sn->static_rix;
        *try0 = ATH_TXMAXTRY;
        goto done;
    }

    mrr = sc->sc_mrretry && !(ic->ic_flags & IEEE80211_F_USEPROT);

    best_rix = pick_best_rate(sn, rt, size_bin, !mrr);
    if (best_rix >= 0) {
        average_tx_time = sn->stats[size_bin][best_rix].average_tx_time;
    } else {
        average_tx_time = 0;
    }
    /*
     * Limit the time measuring the performance of other tx
     * rates to sample_rate% of the total transmission time.
     */
    if (sn->sample_tt[size_bin] < average_tx_time * (sn->packets_since_sample[size_bin]*ssc->sample_rate/100)) {
        rix = pick_sample_rate(ssc, sn, rt, size_bin);
        IEEE80211_NOTE(an->an_node.ni_vap, IEEE80211_MSG_RATECTL,
                       &an->an_node, "size %u sample rate %d current rate %d",
                       bin_to_size(size_bin), RATE(rix),
                       RATE(sn->current_rix[size_bin]));
        if (rix != sn->current_rix[size_bin]) {
            sn->current_sample_rix[size_bin] = rix;
        } else {
            sn->current_sample_rix[size_bin] = -1;
        }
        sn->packets_since_sample[size_bin] = 0;
    } else {
        change_rates = 0;
        if (!sn->packets_sent[size_bin] || best_rix == -1) {
            /* no packet has been sent successfully yet */
            for (rix = rt->rateCount-1; rix > 0; rix--) {
                if ((sn->ratemask & (1<<rix)) == 0)
                    continue;
                /*
                 * Pick the highest rate <= 36 Mbps
                 * that hasn't failed.
                 */
                if (DOT11RATE(rix) <= 72 &&
                        sn->stats[size_bin][rix].successive_failures == 0) {
                    break;
                }
            }
            change_rates = 1;
            best_rix = rix;
        } else if (sn->packets_sent[size_bin] < 20) {
            /* let the bit-rate switch quickly during the first few packets */
            change_rates = 1;
        } else if (ticks - ssc->min_switch > sn->ticks_since_switch[size_bin]) {
            /* min_switch seconds have gone by */
            change_rates = 1;
        } else if (2*average_tx_time < sn->stats[size_bin][sn->current_rix[size_bin]].average_tx_time) {
            /* the current bit-rate is twice as slow as the best one */
            change_rates = 1;
        }

        sn->packets_since_sample[size_bin]++;

        if (change_rates) {
            if (best_rix != sn->current_rix[size_bin]) {
                IEEE80211_NOTE(an->an_node.ni_vap,
                               IEEE80211_MSG_RATECTL,
                               &an->an_node,
                               "%s: size %d switch rate %d (%d/%d) -> %d (%d/%d) after %d packets mrr %d",
                               __func__,
                               bin_to_size(size_bin),
                               RATE(sn->current_rix[size_bin]),
                               sn->stats[size_bin][sn->current_rix[size_bin]].average_tx_time,
                               sn->stats[size_bin][sn->current_rix[size_bin]].perfect_tx_time,
                               RATE(best_rix),
                               sn->stats[size_bin][best_rix].average_tx_time,
                               sn->stats[size_bin][best_rix].perfect_tx_time,
                               sn->packets_since_switch[size_bin],
                               mrr);
            }
            sn->packets_since_switch[size_bin] = 0;
            sn->current_rix[size_bin] = best_rix;
            sn->ticks_since_switch[size_bin] = ticks;
            /*
             * Set the visible txrate for this node.
             */
            an->an_node.ni_txrate = DOT11RATE(best_rix);
        }
        rix = sn->current_rix[size_bin];
        sn->packets_since_switch[size_bin]++;
    }
    *try0 = mrr ? sn->sched[rix].t0 : ATH_TXMAXTRY;
done:
    KASSERT(rix >= 0 && rix < rt->rateCount, ("rix is %d", rix));

    *rix0 = rix;
    *txrate = rt->info[rix].rateCode
              | (shortPreamble ? rt->info[rix].shortPreamble : 0);
    sn->packets_sent[size_bin]++;
#undef DOT11RATE
#undef RATE
}