Commit 5f919abc authored by Thomas Huehn's avatar Thomas Huehn Committed by Johannes Berg

mac80211: add standard deviation to Minstrel stats

This patch adds the statistical descriptor "standard deviation"
to better describe the current properties of Minstrel and
Minstrel-HTs success probability distribution. The standard
deviation (SD) is calculated as exponential weighted moving
standard deviation (EWMSD) and its current value is added as
new column in all rc_stats (in debugfs).
Signed-off-by: default avatarThomas Huehn <thomas@net.t-labs.tu-berlin.de>
Acked-by: default avatarFelix Fietkau <nbd@openwrt.org>
Signed-off-by: default avatarJohannes Berg <johannes.berg@intel.com>
parent ade6d4a2
...@@ -153,7 +153,7 @@ minstrel_update_rates(struct minstrel_priv *mp, struct minstrel_sta_info *mi) ...@@ -153,7 +153,7 @@ minstrel_update_rates(struct minstrel_priv *mp, struct minstrel_sta_info *mi)
} }
/* /*
* Recalculate success probabilities and counters for a given rate using EWMA * Recalculate statistics and counters of a given rate
*/ */
void void
minstrel_calc_rate_stats(struct minstrel_rate_stats *mrs) minstrel_calc_rate_stats(struct minstrel_rate_stats *mrs)
...@@ -161,11 +161,20 @@ minstrel_calc_rate_stats(struct minstrel_rate_stats *mrs) ...@@ -161,11 +161,20 @@ minstrel_calc_rate_stats(struct minstrel_rate_stats *mrs)
if (unlikely(mrs->attempts > 0)) { if (unlikely(mrs->attempts > 0)) {
mrs->sample_skipped = 0; mrs->sample_skipped = 0;
mrs->cur_prob = MINSTREL_FRAC(mrs->success, mrs->attempts); mrs->cur_prob = MINSTREL_FRAC(mrs->success, mrs->attempts);
if (unlikely(!mrs->att_hist)) if (unlikely(!mrs->att_hist)) {
mrs->prob_ewma = mrs->cur_prob; mrs->prob_ewma = mrs->cur_prob;
else } else {
/* update exponential weighted moving variance */
mrs->prob_ewmsd = minstrel_ewmsd(mrs->prob_ewmsd,
mrs->cur_prob,
mrs->prob_ewma,
EWMA_LEVEL);
/*update exponential weighted moving avarage */
mrs->prob_ewma = minstrel_ewma(mrs->prob_ewma, mrs->prob_ewma = minstrel_ewma(mrs->prob_ewma,
mrs->cur_prob, EWMA_LEVEL); mrs->cur_prob,
EWMA_LEVEL);
}
mrs->att_hist += mrs->attempts; mrs->att_hist += mrs->attempts;
mrs->succ_hist += mrs->success; mrs->succ_hist += mrs->success;
} else { } else {
...@@ -193,7 +202,7 @@ minstrel_update_stats(struct minstrel_priv *mp, struct minstrel_sta_info *mi) ...@@ -193,7 +202,7 @@ minstrel_update_stats(struct minstrel_priv *mp, struct minstrel_sta_info *mi)
struct minstrel_rate_stats *mrs = &mi->r[i].stats; struct minstrel_rate_stats *mrs = &mi->r[i].stats;
struct minstrel_rate_stats *tmp_mrs = &mi->r[tmp_prob_rate].stats; struct minstrel_rate_stats *tmp_mrs = &mi->r[tmp_prob_rate].stats;
/* Update success probabilities per rate */ /* Update statistics of success probability per rate */
minstrel_calc_rate_stats(mrs); minstrel_calc_rate_stats(mrs);
/* Sample less often below the 10% chance of success. /* Sample less often below the 10% chance of success.
......
...@@ -35,6 +35,24 @@ minstrel_ewma(int old, int new, int weight) ...@@ -35,6 +35,24 @@ minstrel_ewma(int old, int new, int weight)
return old + incr; return old + incr;
} }
/*
* Perform EWMSD (Exponentially Weighted Moving Standard Deviation) calculation
*/
static inline int
minstrel_ewmsd(int old_ewmsd, int cur_prob, int prob_ewma, int weight)
{
int diff, incr, tmp_var;
/* calculate exponential weighted moving variance */
diff = MINSTREL_TRUNC((cur_prob - prob_ewma) * 1000000);
incr = (EWMA_DIV - weight) * diff / EWMA_DIV;
tmp_var = old_ewmsd * old_ewmsd;
tmp_var = weight * (tmp_var + diff * incr / 1000000) / EWMA_DIV;
/* return standard deviation */
return (u16) int_sqrt(tmp_var);
}
struct minstrel_rate_stats { struct minstrel_rate_stats {
/* current / last sampling period attempts/success counters */ /* current / last sampling period attempts/success counters */
u16 attempts, last_attempts; u16 attempts, last_attempts;
...@@ -45,9 +63,11 @@ struct minstrel_rate_stats { ...@@ -45,9 +63,11 @@ struct minstrel_rate_stats {
/* statistis of packet delivery probability /* statistis of packet delivery probability
* cur_prob - current prob within last update intervall * cur_prob - current prob within last update intervall
* prob_ewma - exponential weighted moving average of prob */ * prob_ewma - exponential weighted moving average of prob
* prob_ewmsd - exp. weighted moving standard deviation of prob */
unsigned int cur_prob; unsigned int cur_prob;
unsigned int prob_ewma; unsigned int prob_ewma;
u16 prob_ewmsd;
/* maximum retry counts */ /* maximum retry counts */
u8 retry_count; u8 retry_count;
......
...@@ -85,10 +85,12 @@ minstrel_stats_open(struct inode *inode, struct file *file) ...@@ -85,10 +85,12 @@ minstrel_stats_open(struct inode *inode, struct file *file)
file->private_data = ms; file->private_data = ms;
p = ms->buf; p = ms->buf;
p += sprintf(p, "\n"); p += sprintf(p, "\n");
p += sprintf(p, "best __________rate_________ __statistics__ " p += sprintf(p, "best __________rate_________ ______"
"________last_______ ______sum-of________\n"); "statistics______ ________last_______ "
p += sprintf(p, "rate [name idx airtime max_tp] [ ø(tp) ø(prob)] " "______sum-of________\n");
"[prob.|retry|suc|att] [#success | #attempts]\n"); p += sprintf(p, "rate [name idx airtime max_tp] [ ø(tp) ø(prob) "
"sd(prob)] [prob.|retry|suc|att] "
"[#success | #attempts]\n");
for (i = 0; i < mi->n_rates; i++) { for (i = 0; i < mi->n_rates; i++) {
struct minstrel_rate *mr = &mi->r[i]; struct minstrel_rate *mr = &mi->r[i];
...@@ -110,11 +112,13 @@ minstrel_stats_open(struct inode *inode, struct file *file) ...@@ -110,11 +112,13 @@ minstrel_stats_open(struct inode *inode, struct file *file)
prob = MINSTREL_TRUNC(mrs->cur_prob * 1000); prob = MINSTREL_TRUNC(mrs->cur_prob * 1000);
eprob = MINSTREL_TRUNC(mrs->prob_ewma * 1000); eprob = MINSTREL_TRUNC(mrs->prob_ewma * 1000);
p += sprintf(p, "%4u.%1u %4u.%1u %3u.%1u %3u.%1u %3u" p += sprintf(p, "%4u.%1u %4u.%1u %3u.%1u %3u.%1u"
" %3u %-3u %9llu %-9llu\n", " %3u.%1u %3u %3u %-3u "
"%9llu %-9llu\n",
tp_max / 10, tp_max % 10, tp_max / 10, tp_max % 10,
tp_avg / 10, tp_avg % 10, tp_avg / 10, tp_avg % 10,
eprob / 10, eprob % 10, eprob / 10, eprob % 10,
mrs->prob_ewmsd / 10, mrs->prob_ewmsd % 10,
prob / 10, prob % 10, prob / 10, prob % 10,
mrs->retry_count, mrs->retry_count,
mrs->last_success, mrs->last_success,
...@@ -176,11 +180,12 @@ minstrel_stats_csv_open(struct inode *inode, struct file *file) ...@@ -176,11 +180,12 @@ minstrel_stats_csv_open(struct inode *inode, struct file *file)
prob = MINSTREL_TRUNC(mrs->cur_prob * 1000); prob = MINSTREL_TRUNC(mrs->cur_prob * 1000);
eprob = MINSTREL_TRUNC(mrs->prob_ewma * 1000); eprob = MINSTREL_TRUNC(mrs->prob_ewma * 1000);
p += sprintf(p, "%u.%u,%u.%u,%u.%u,%u.%u,%u,%u,%u," p += sprintf(p, "%u.%u,%u.%u,%u.%u,%u.%u,%u.%u,%u,%u,%u,"
"%llu,%llu,%d,%d\n", "%llu,%llu,%d,%d\n",
tp_max / 10, tp_max % 10, tp_max / 10, tp_max % 10,
tp_avg / 10, tp_avg % 10, tp_avg / 10, tp_avg % 10,
eprob / 10, eprob % 10, eprob / 10, eprob % 10,
mrs->prob_ewmsd / 10, mrs->prob_ewmsd % 10,
prob / 10, prob % 10, prob / 10, prob % 10,
mrs->retry_count, mrs->retry_count,
mrs->last_success, mrs->last_success,
......
...@@ -86,11 +86,13 @@ minstrel_ht_stats_dump(struct minstrel_ht_sta *mi, int i, char *p) ...@@ -86,11 +86,13 @@ minstrel_ht_stats_dump(struct minstrel_ht_sta *mi, int i, char *p)
prob = MINSTREL_TRUNC(mrs->cur_prob * 1000); prob = MINSTREL_TRUNC(mrs->cur_prob * 1000);
eprob = MINSTREL_TRUNC(mrs->prob_ewma * 1000); eprob = MINSTREL_TRUNC(mrs->prob_ewma * 1000);
p += sprintf(p, "%4u.%1u %4u.%1u %3u.%1u %3u.%1u " p += sprintf(p, "%4u.%1u %4u.%1u %3u.%1u %3u.%1u"
"%3u %3u %-3u %9llu %-9llu\n", " %3u.%1u %3u %3u %-3u "
"%9llu %-9llu\n",
tp_max / 10, tp_max % 10, tp_max / 10, tp_max % 10,
tp_avg / 10, tp_avg % 10, tp_avg / 10, tp_avg % 10,
eprob / 10, eprob % 10, eprob / 10, eprob % 10,
mrs->prob_ewmsd / 10, mrs->prob_ewmsd % 10,
prob / 10, prob % 10, prob / 10, prob % 10,
mrs->retry_count, mrs->retry_count,
mrs->last_success, mrs->last_success,
...@@ -128,10 +130,10 @@ minstrel_ht_stats_open(struct inode *inode, struct file *file) ...@@ -128,10 +130,10 @@ minstrel_ht_stats_open(struct inode *inode, struct file *file)
p += sprintf(p, "\n"); p += sprintf(p, "\n");
p += sprintf(p, " best ____________rate__________ " p += sprintf(p, " best ____________rate__________ "
"__statistics__ ________last_______ " "______statistics______ ________last_______ "
"______sum-of________\n"); "______sum-of________\n");
p += sprintf(p, "mode guard # rate [name idx airtime max_tp] " p += sprintf(p, "mode guard # rate [name idx airtime max_tp] "
"[ ø(tp) ø(prob)] [prob.|retry|suc|att] [#success | " "[ ø(tp) ø(prob) sd(prob)] [prob.|retry|suc|att] [#success | "
"#attempts]\n"); "#attempts]\n");
p = minstrel_ht_stats_dump(mi, MINSTREL_CCK_GROUP, p); p = minstrel_ht_stats_dump(mi, MINSTREL_CCK_GROUP, p);
...@@ -229,10 +231,12 @@ minstrel_ht_stats_csv_dump(struct minstrel_ht_sta *mi, int i, char *p) ...@@ -229,10 +231,12 @@ minstrel_ht_stats_csv_dump(struct minstrel_ht_sta *mi, int i, char *p)
prob = MINSTREL_TRUNC(mrs->cur_prob * 1000); prob = MINSTREL_TRUNC(mrs->cur_prob * 1000);
eprob = MINSTREL_TRUNC(mrs->prob_ewma * 1000); eprob = MINSTREL_TRUNC(mrs->prob_ewma * 1000);
p += sprintf(p, "%u.%u,%u.%u,%u.%u,%u.%u,%u,%u,%u,%llu,%llu,", p += sprintf(p, "%u.%u,%u.%u,%u.%u,%u.%u,%u.%u,%u,%u,"
"%u,%llu,%llu,",
tp_max / 10, tp_max % 10, tp_max / 10, tp_max % 10,
tp_avg / 10, tp_avg % 10, tp_avg / 10, tp_avg % 10,
eprob / 10, eprob % 10, eprob / 10, eprob % 10,
mrs->prob_ewmsd / 10, mrs->prob_ewmsd % 10,
prob / 10, prob % 10, prob / 10, prob % 10,
mrs->retry_count, mrs->retry_count,
mrs->last_success, mrs->last_success,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment