Exemple #1
0
/*
 * Update the EWMA percentage.
 *
 * This is a simple hack to track an EWMA based on the current
 * rate scenario. For the rate codes which failed, this will
 * record a 0% against it. For the rate code which succeeded,
 * EWMA will record the nbad*100/nframes percentage against it.
 */
static void
update_ewma_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);
	const int size_bin = size_to_bin(frame_size);
	int tries_so_far;
	int pct;
	int rix = rix0;

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

	/* Figure out which rate index succeeded */
	tries_so_far = tries0;

	if (tries1 && tries_so_far < tries) {
		tries_so_far += tries1;
		rix = rix1;
		/* XXX bump ewma pct */
	}

	if (tries2 && tries_so_far < tries) {
		tries_so_far += tries2;
		rix = rix2;
		/* XXX bump ewma pct */
	}

	if (tries3 && tries_so_far < tries) {
		rix = rix3;
		/* XXX bump ewma pct */
	}

	/* rix is the successful rate, update EWMA for final rix */
	if (sn->stats[size_bin][rix].total_packets <
	    ssc->smoothing_minpackets) {
		/* just average the first few packets */
		int a_pct = (sn->stats[size_bin][rix].packets_acked * 1000) /
		    (sn->stats[size_bin][rix].total_packets);
		sn->stats[size_bin][rix].ewma_pct = a_pct;
	} else {
		/* use a ewma */
		sn->stats[size_bin][rix].ewma_pct =
			((sn->stats[size_bin][rix].ewma_pct * ssc->smoothing_rate) +
			 (pct * (100 - ssc->smoothing_rate))) / 100;
	}
}
Exemple #2
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);

	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;

	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;
	}
}
Exemple #3
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->static_rix != -1) {
		rix = sn->static_rix;
		*try0 = ATH_TXMAXTRY;
		goto done;
	}

	/* XXX TODO: this doesn't know about 11gn vs 11g protection; teach it */
	mrr = sc->sc_mrretry && !(ic->ic_flags & IEEE80211_F_USEPROT);

	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:
	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
}
Exemple #4
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;
	}
}
Exemple #5
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
}
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 = 0;
	int size = 0;
	int rate = 0;

	size_bin = size_to_bin(frame_size);
	size = bin_to_size(size_bin);

	if (!(0 <= ndx0 && ndx0 < sn->num_rates)) {
		printf("%s: bogus ndx0 %d, max %u, mode %u\n",
		    __func__, ndx0, sn->num_rates, sc->sc_curmode);
		return;
	}
	rate = sn->rates[ndx0].rate;

	tt += calc_usecs_unicast_packet(sc, size, sn->rates[ndx0].rix, 
					short_tries,
					MIN(tries0, tries) - 1);
	tries_so_far += tries0;
	if (tries1 && tries0 < tries) {
		if (!(0 <= ndx1 && ndx1 < sn->num_rates)) {
			printf("%s: bogus ndx1 %d, max %u, mode %u\n",
			    __func__, ndx1, sn->num_rates, sc->sc_curmode);
			return;
		}
		tt += calc_usecs_unicast_packet(sc, size, sn->rates[ndx1].rix, 
						short_tries,
						MIN(tries1 + tries_so_far, tries) - tries_so_far - 1);
	}
	tries_so_far += tries1;

	if (tries2 && tries0 + tries1 < tries) {
		if (!(0 <= ndx2 && ndx2 < sn->num_rates)) {
			printf("%s: bogus ndx2 %d, max %u, mode %u\n",
			    __func__, ndx2, sn->num_rates, sc->sc_curmode);
			return;
		}
		tt += calc_usecs_unicast_packet(sc, size, sn->rates[ndx2].rix, 
					       short_tries,
						MIN(tries2 + tries_so_far, tries) - tries_so_far - 1);
	}

	tries_so_far += tries2;

	if (tries3 && tries0 + tries1 + tries2 < tries) {
		if (!(0 <= ndx3 && ndx3 < sn->num_rates)) {
			printf("%s: bogus ndx3 %d, max %u, mode %u\n",
			    __func__, ndx3, sn->num_rates, sc->sc_curmode);
			return;
		}
		tt += calc_usecs_unicast_packet(sc, size, sn->rates[ndx3].rix, 
						short_tries,
						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, ATH_DEBUG_RATE,
"%s: %s size %d %s sample rate %d tries (%d/%d) tt %d avg_tt (%d/%d)\n", 
		    __func__, ether_sprintf(an->an_node.ni_macaddr), 
		    size,
		    status ? "FAIL" : "OK",
		    rate, short_tries, tries, tt, 
		    sn->stats[size_bin][ndx0].average_tx_time,
		    sn->stats[size_bin][ndx0].perfect_tx_time);
		sn->sample_tt[size_bin] = tt;
		sn->current_sample_ndx[size_bin] = -1;
	}
}
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, ATH_DEBUG_RATE,
"%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;
			}
		}
	}

	KASSERT(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]++;
}