Date: Fri, 21 Nov 2008 23:02:49 GMT From: Sam Leffler <sam@FreeBSD.org> To: Perforce Change Reviews <perforce@freebsd.org> Subject: PERFORCE change 153312 for review Message-ID: <200811212302.mALN2nRb006337@repoman.freebsd.org>
next in thread | raw e-mail | index | archive | help
http://perforce.freebsd.org/chv.cgi?CH=153312 Change 153312 by sam@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)
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200811212302.mALN2nRb006337>