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