PERFORCE change 153312 for review

Sam Leffler sam at FreeBSD.org
Fri Nov 21 15:02:50 PST 2008


http://perforce.freebsd.org/chv.cgi?CH=153312

Change 153312 by sam at sam_ebb on 2008/11/21 23:01:52

	Another round of cleanups and improvements:
	o move max success failure count, stale failure timeout, and
	  min switch threshold to tunable variables (still need sysctl knobs)
	o fill out statistics dump attached to dev.ath.X.sample_stats
	o add sysctl knobs for smoothing rate and sample rate
	o style cleanups

Affected files ...

.. //depot/projects/vap/sys/dev/ath/ath_rate/sample/sample.c#23 edit
.. //depot/projects/vap/sys/dev/ath/ath_rate/sample/sample.h#10 edit

Differences ...

==== //depot/projects/vap/sys/dev/ath/ath_rate/sample/sample.c#23 (text+ko) ====

@@ -100,9 +100,6 @@
  * a few different packet sizes independently for each link.
  */
 
-#define STALE_FAILURE_TIMEOUT_MS 10000
-#define MIN_SWITCH_MS 1000
-
 static void	ath_rate_ctl_reset(struct ath_softc *, struct ieee80211_node *);
 
 static const int packet_size_bins[NUM_PACKET_SIZE_BINS] = { 250, 1600 };
@@ -146,7 +143,7 @@
 }
 
 /*
- * returns the rix with the lowest average_tx_time,
+ * Return the rix with the lowest average_tx_time,
  * or -1 if all the average_tx_times are 0.
  */
 static __inline int
@@ -173,7 +170,7 @@
 		if (sn->stats[size_bin][rix].successive_failures > 3)
 			continue;
 
-		if (!best_rate_tt || best_rate_tt > tt) {
+		if (best_rate_tt == 0 || tt < best_rate_tt) {
 			best_rate_tt = tt;
 			best_rate_rix = rix;
 		}
@@ -182,10 +179,11 @@
 }
 
 /*
- * pick a good "random" bit-rate to sample other than the current one
+ * Pick a good "random" bit-rate to sample other than the current one.
  */
 static __inline int
-pick_sample_rate(struct sample_node *sn, const HAL_RATE_TABLE *rt, int size_bin)
+pick_sample_rate(struct sample_softc *ssc , struct sample_node *sn,
+    const HAL_RATE_TABLE *rt, int size_bin)
 {
 #define	DOT11RATE(ix)	(rt->info[ix].dot11Rate & IEEE80211_RATE_VAL)
 	int current_rix, rix;
@@ -217,8 +215,8 @@
 		}
 
 		/* rarely sample bit-rates that fail a lot */
-		if (sn->stats[size_bin][rix].successive_failures > 3 &&
-		    ticks - sn->stats[size_bin][rix].last_tx < ((hz * STALE_FAILURE_TIMEOUT_MS)/1000)) {
+		if (sn->stats[size_bin][rix].successive_failures > ssc->max_successive_failures &&
+		    ticks - sn->stats[size_bin][rix].last_tx < ssc->stale_failure_timeout) {
 			mask &= ~(1<<rix);
 			goto nextrate;
 		}
@@ -241,7 +239,8 @@
 		  int shortPreamble, size_t frameLen,
 		  u_int8_t *rix0, int *try0, u_int8_t *txrate)
 {
-#define	RATE(ix)	(rt->info[ix].dot11Rate & IEEE80211_RATE_VAL)
+#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;
@@ -265,13 +264,16 @@
 	} else {
 		average_tx_time = 0;
 	}
-	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.
-		 */
-		rix = pick_sample_rate(sn, rt, size_bin);
+	/*
+	 * 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 {
@@ -286,10 +288,10 @@
 				if ((sn->ratemask & (1<<rix)) == 0)
 					continue;
 				/* 
-				 * pick the highest rate <= 36 Mbps
+				 * Pick the highest rate <= 36 Mbps
 				 * that hasn't failed.
 				 */
-				if (RATE(rix) <= 72 && 
+				if (DOT11RATE(rix) <= 72 && 
 				    sn->stats[size_bin][rix].successive_failures == 0) {
 					break;
 				}
@@ -299,10 +301,10 @@
 		} 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 */
+		} else if (ticks - ssc->min_switch > sn->ticks_since_switch[size_bin]) {
+			/* min_switch seconds have gone by */
 			change_rates = 1;
-		} else if (average_tx_time * 2 < sn->stats[size_bin][sn->current_rix[size_bin]].average_tx_time) {
+		} 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;
 		}
@@ -316,7 +318,7 @@
 				    &an->an_node,
 "%s: size %d switch rate %d (%d/%d) -> %d (%d/%d) after %d packets mrr %d",
 				    __func__,
-				    packet_size_bins[size_bin],
+				    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,
@@ -332,7 +334,7 @@
 			/* 
 			 * Set the visible txrate for this node.
 			 */
-			an->an_node.ni_txrate = RATE(best_rix);
+			an->an_node.ni_txrate = DOT11RATE(best_rix);
 		}
 		rix = sn->current_rix[size_bin];
 		sn->packets_since_switch[size_bin]++;
@@ -345,6 +347,7 @@
 	*txrate = rt->info[rix].rateCode
 		| (shortPreamble ? rt->info[rix].shortPreamble : 0);
 	sn->packets_sent[size_bin]++;
+#undef DOT11RATE
 #undef RATE
 }
 
@@ -459,38 +462,34 @@
 
 	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;
 
-	tt = calc_usecs_unicast_packet(sc, size, rix0, 
-					short_tries,
-					MIN(tries0, tries) - 1);
-	tries_so_far = tries0;
-	if (tries1 && tries0 < tries) {
+	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);
+		tt += calc_usecs_unicast_packet(sc, size, rix1, short_tries,
+			MIN(tries1 + tries_so_far, tries) - tries_so_far - 1);
+		tries_so_far += tries1;
 	}
-	tries_so_far += tries1;
 
-	if (tries2 && tries0 + tries1 < tries) {
+	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);
+		tt += calc_usecs_unicast_packet(sc, size, rix2, short_tries,
+			MIN(tries2 + tries_so_far, tries) - tries_so_far - 1);
+		tries_so_far += tries2;
 	}
 
-	tries_so_far += tries2;
-
-	if (tries3 && tries0 + tries1 + tries2 < tries) {
+	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);
+		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 < (100 / (100 - ssc->ath_smoothing_rate))) {
+
+	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;
@@ -498,16 +497,17 @@
 	} else {
 		/* use a ewma */
 		sn->stats[size_bin][rix0].average_tx_time = 
-			((sn->stats[size_bin][rix0].average_tx_time * ssc->ath_smoothing_rate) + 
-			 (tt * (100 - ssc->ath_smoothing_rate))) / 100;
+			((sn->stats[size_bin][rix0].average_tx_time * ssc->smoothing_rate) + 
+			 (tt * (100 - ssc->smoothing_rate))) / 100;
 	}
 	
-	if (status) {
+	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 lower
+			/*
+			 * 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++;
@@ -523,7 +523,6 @@
 	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,
@@ -734,7 +733,7 @@
 ath_rate_ctl_reset(struct ath_softc *sc, struct ieee80211_node *ni)
 {
 #define	RATE(_ix)	(ni->ni_rates.rs_rates[(_ix)] & IEEE80211_RATE_VAL)
-#define	INFORATE(_ix)	(rt->info[(_ix)].dot11Rate & IEEE80211_RATE_VAL)
+#define	DOT11RATE(_ix)	(rt->info[(_ix)].dot11Rate & IEEE80211_RATE_VAL)
 	struct ath_node *an = ATH_NODE(ni);
 	const struct ieee80211_txparam *tp = ni->ni_txparms;
 	struct sample_node *sn = ATH_NODE_SAMPLE(an);
@@ -797,7 +796,7 @@
 		for (mask = sn->ratemask, rix = 0; mask != 0; mask >>= 1, rix++) {
 			if ((mask & 1) == 0)
 				continue;
-			printf(" %d/%d", INFORATE(rix),
+			printf(" %d/%d", DOT11RATE(rix) / 2,
 			    calc_usecs_unicast_packet(sc, 1600, rix, 0,0));
 		}
 		printf("\n");
@@ -837,19 +836,19 @@
 	IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_RATECTL, ni,
 	    "%s: %d rates %d%sMbps (%dus)- %d%sMbps (%dus)", __func__, 
 	    sn->num_rates,
-	    INFORATE(0)/2, INFORATE(0) % 1 ? ".5" : "",
+	    DOT11RATE(0)/2, DOT11RATE(0) % 1 ? ".5" : "",
 	    sn->stats[1][0].perfect_tx_time,
-	    INFORATE(sn->num_rates-1)/2, INFORATE(sn->num_rates-1) % 1 ? ".5" : "",
+	    DOT11RATE(sn->num_rates-1)/2, DOT11RATE(sn->num_rates-1) % 1 ? ".5" : "",
 	    sn->stats[1][sn->num_rates-1].perfect_tx_time
 	);
 #endif
 	/* set the visible bit-rate */
 	if (sn->static_rix != -1)
-		ni->ni_txrate = INFORATE(sn->static_rix);
+		ni->ni_txrate = DOT11RATE(sn->static_rix);
 	else
 		ni->ni_txrate = RATE(0);
 #undef RATE
-#undef INFORATE
+#undef DOT11RATE
 }
 
 static void
@@ -861,15 +860,27 @@
 	uint32_t mask;
 	int rix, y;
 
-	printf("\n[%s] refcnt %d\n",
-	    ether_sprintf(ni->ni_macaddr), ieee80211_node_refcnt(ni));
+	printf("\n[%s] refcnt %d static_rix %d ratemask 0x%x\n",
+	    ether_sprintf(ni->ni_macaddr), ieee80211_node_refcnt(ni),
+	    sn->static_rix, sn->ratemask);
+	for (y = 0; y < NUM_PACKET_SIZE_BINS; y++) {
+		printf("[%4u] cur rix %d since switch: packets %d ticks %u\n",
+		    bin_to_size(y), sn->current_rix[y],
+		    sn->packets_since_switch[y], sn->ticks_since_switch[y]);
+		printf("[%4u] last sample %d cur sample %d packets sent %d\n",
+		    bin_to_size(y), sn->last_sample_rix[y],
+		    sn->current_sample_rix[y], sn->packets_sent[y]);
+		printf("[%4u] packets since sample %d sample tt %u\n",
+		    bin_to_size(y), sn->packets_since_sample[y],
+		    sn->sample_tt[y]);
+	}
 	for (mask = sn->ratemask, rix = 0; mask != 0; mask >>= 1, rix++) {
 		if ((mask & 1) == 0)
 				continue;
 		for (y = 0; y < NUM_PACKET_SIZE_BINS; y++) {
 			if (sn->stats[y][rix].total_packets == 0)
 				continue;
-			printf("[%2u:%4u] %6d:%-6d (%3d%%) T %6d F %2d avg_tx_time %u\n",
+			printf("[%2u:%4u] %8d:%-8d (%3d%%) T %8d F %4d avg %5u last %u\n",
 			    (rt->info[rix].dot11Rate & IEEE80211_RATE_VAL)/2,
 			    bin_to_size(y),
 			    sn->stats[y][rix].total_packets,
@@ -877,7 +888,8 @@
 			    (100*sn->stats[y][rix].packets_acked)/sn->stats[y][rix].total_packets,
 			    sn->stats[y][rix].tries,
 			    sn->stats[y][rix].successive_failures,
-			    sn->stats[y][rix].average_tx_time);
+			    sn->stats[y][rix].average_tx_time,
+			    sn->stats[y][rix].last_tx);
 		}
 	}
 }
@@ -898,46 +910,84 @@
 	return 0;
 }
 
+static int
+ath_rate_sysctl_smoothing_rate(SYSCTL_HANDLER_ARGS)
+{
+	struct sample_softc *ssc = arg1;
+	int rate, error;
+
+	rate = ssc->smoothing_rate;
+	error = sysctl_handle_int(oidp, &rate, 0, req);
+	if (error || !req->newptr)
+		return error;
+	if (!(0 <= rate && rate < 100))
+		return EINVAL;
+	ssc->smoothing_rate = rate;
+	ssc->smoothing_minpackets = 100 / (100 - rate);
+	return 0;
+}
+
+static int
+ath_rate_sysctl_sample_rate(SYSCTL_HANDLER_ARGS)
+{
+	struct sample_softc *ssc = arg1;
+	int rate, error;
+
+	rate = ssc->sample_rate;
+	error = sysctl_handle_int(oidp, &rate, 0, req);
+	if (error || !req->newptr)
+		return error;
+	if (!(2 <= rate && rate <= 100))
+		return EINVAL;
+	ssc->sample_rate = rate;
+	return 0;
+}
+
 static void
-ath_rate_sysctlattach(struct ath_softc *sc, struct sample_softc *osc)
+ath_rate_sysctlattach(struct ath_softc *sc, struct sample_softc *ssc)
 {
 	struct sysctl_ctx_list *ctx = device_get_sysctl_ctx(sc->sc_dev);
 	struct sysctl_oid *tree = device_get_sysctl_tree(sc->sc_dev);
 
-	/* XXX bounds check [0..100] */
-	SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
-		"smoothing_rate", CTLFLAG_RW, &osc->ath_smoothing_rate, 0,
-		"rate control: retry threshold to credit rate raise (%%)");
-	/* XXX bounds check [2..100] */
-	SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
-		"sample_rate", CTLFLAG_RW, &osc->ath_sample_rate,0,
-		"rate control: # good periods before raising rate");
+	SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
+	    "smoothing_rate", CTLTYPE_INT | CTLFLAG_RW, ssc, 0,
+	    ath_rate_sysctl_smoothing_rate, "I",
+	    "sample: smoothing rate for avg tx time (%%)");
+	SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
+	    "sample_rate", CTLTYPE_INT | CTLFLAG_RW, ssc, 0,
+	    ath_rate_sysctl_sample_rate, "I",
+	    "sample: percent air time devoted to sampling new rates (%%)");
+	/* XXX max_successive_failures, stale_failure_timeout, min_switch */
 	SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
-		"sample_stats", CTLTYPE_INT | CTLFLAG_RW, sc, 0,
-		ath_rate_sysctl_stats, "I", "print statistics");
+	    "sample_stats", CTLTYPE_INT | CTLFLAG_RW, sc, 0,
+	    ath_rate_sysctl_stats, "I", "sample: print statistics");
 }
 
 struct ath_ratectrl *
 ath_rate_attach(struct ath_softc *sc)
 {
-	struct sample_softc *osc;
+	struct sample_softc *ssc;
 	
-	osc = malloc(sizeof(struct sample_softc), M_DEVBUF, M_NOWAIT|M_ZERO);
-	if (osc == NULL)
+	ssc = malloc(sizeof(struct sample_softc), M_DEVBUF, M_NOWAIT|M_ZERO);
+	if (ssc == NULL)
 		return NULL;
-	osc->arc.arc_space = sizeof(struct sample_node);
-	osc->ath_smoothing_rate = 95;	/* ewma percentage (out of 100) */
-	osc->ath_sample_rate = 10;	/* send a different bit-rate 1/X packets */
-	ath_rate_sysctlattach(sc, osc);
-	return &osc->arc;
+	ssc->arc.arc_space = sizeof(struct sample_node);
+	ssc->smoothing_rate = 95;		/* ewma percentage ([0..99]) */
+	ssc->smoothing_minpackets = 100 / (100 - ssc->smoothing_rate);
+	ssc->sample_rate = 10;			/* %time to try diff tx rates */
+	ssc->max_successive_failures = 3;	/* threshold for rate sampling*/
+	ssc->stale_failure_timeout = 10 * hz;	/* 10 seconds */
+	ssc->min_switch = hz;			/* 1 second */
+	ath_rate_sysctlattach(sc, ssc);
+	return &ssc->arc;
 }
 
 void
 ath_rate_detach(struct ath_ratectrl *arc)
 {
-	struct sample_softc *osc = (struct sample_softc *) arc;
+	struct sample_softc *ssc = (struct sample_softc *) arc;
 	
-	free(osc, M_DEVBUF);
+	free(ssc, M_DEVBUF);
 }
 
 /*
@@ -949,7 +999,7 @@
 	switch (type) {
 	case MOD_LOAD:
 		if (bootverbose)
-			printf("ath_rate: version 1.2 <SampleRate bit-rate selection algorithm>\n");
+			printf("ath_rate: version 1.9 <SampleRate bit-rate selection algorithm>\n");
 		return 0;
 	case MOD_UNLOAD:
 		return 0;

==== //depot/projects/vap/sys/dev/ath/ath_rate/sample/sample.h#10 (text+ko) ====

@@ -44,9 +44,13 @@
 
 /* per-device state */
 struct sample_softc {
-	struct ath_ratectrl arc;	/* base state */
-	int	ath_smoothing_rate;	/* ewma percentage (out of 100) */
-	int	ath_sample_rate;	/* send a different bit-rate 1/X packets */
+	struct ath_ratectrl arc;	/* base class */
+	int	smoothing_rate;		/* ewma percentage [0..99] */
+	int	smoothing_minpackets;
+	int	sample_rate;		/* %time to try different tx rates */
+	int	max_successive_failures;
+	int	stale_failure_timeout;	/* how long to honor max_successive_failures */
+	int	min_switch;		/* min time between rate changes */
 };
 #define	ATH_SOFTC_SAMPLE(sc)	((struct sample_softc *)sc->sc_rc)
 


More information about the p4-projects mailing list