Commit 4f0bc9c6 authored by Felix Fietkau's avatar Felix Fietkau Committed by Johannes Berg

mac80211: minstrel: store probability variance instead of standard deviation

This avoids the costly int_sqrt calls in the statistics update and moves
it to the debugfs code instead.
This also fixes an overflow in the previous standard deviation
calculation.
Signed-off-by: default avatarThomas Huehn <thomas.huehn@evernet-eg.de>
Signed-off-by: default avatarFelix Fietkau <nbd@nbd.name>
Signed-off-by: default avatarJohannes Berg <johannes.berg@intel.com>
parent 0217eefa
...@@ -168,10 +168,10 @@ minstrel_calc_rate_stats(struct minstrel_rate_stats *mrs) ...@@ -168,10 +168,10 @@ minstrel_calc_rate_stats(struct minstrel_rate_stats *mrs)
mrs->prob_ewma = cur_prob; mrs->prob_ewma = cur_prob;
} else { } else {
/* update exponential weighted moving variance */ /* update exponential weighted moving variance */
mrs->prob_ewmsd = minstrel_ewmsd(mrs->prob_ewmsd, mrs->prob_ewmv = minstrel_ewmv(mrs->prob_ewmv,
cur_prob, cur_prob,
mrs->prob_ewma, mrs->prob_ewma,
EWMA_LEVEL); EWMA_LEVEL);
/*update exponential weighted moving avarage */ /*update exponential weighted moving avarage */
mrs->prob_ewma = minstrel_ewma(mrs->prob_ewma, mrs->prob_ewma = minstrel_ewma(mrs->prob_ewma,
......
...@@ -36,21 +36,16 @@ minstrel_ewma(int old, int new, int weight) ...@@ -36,21 +36,16 @@ minstrel_ewma(int old, int new, int weight)
} }
/* /*
* Perform EWMSD (Exponentially Weighted Moving Standard Deviation) calculation * Perform EWMV (Exponentially Weighted Moving Variance) calculation
*/ */
static inline int static inline int
minstrel_ewmsd(int old_ewmsd, int cur_prob, int prob_ewma, int weight) minstrel_ewmv(int old_ewmv, int cur_prob, int prob_ewma, int weight)
{ {
int diff, incr, tmp_var; int diff, incr;
/* calculate exponential weighted moving variance */ diff = cur_prob - prob_ewma;
diff = MINSTREL_TRUNC((cur_prob - prob_ewma) * 1000000);
incr = (EWMA_DIV - weight) * diff / EWMA_DIV; incr = (EWMA_DIV - weight) * diff / EWMA_DIV;
tmp_var = old_ewmsd * old_ewmsd; return weight * (old_ewmv + MINSTREL_TRUNC(diff * incr)) / EWMA_DIV;
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 {
...@@ -65,7 +60,7 @@ struct minstrel_rate_stats { ...@@ -65,7 +60,7 @@ struct minstrel_rate_stats {
* 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 */ * prob_ewmsd - exp. weighted moving standard deviation of prob */
unsigned int prob_ewma; unsigned int prob_ewma;
u16 prob_ewmsd; u16 prob_ewmv;
/* maximum retry counts */ /* maximum retry counts */
u8 retry_count; u8 retry_count;
...@@ -151,6 +146,14 @@ struct minstrel_debugfs_info { ...@@ -151,6 +146,14 @@ struct minstrel_debugfs_info {
char buf[]; char buf[];
}; };
/* Get EWMSD (Exponentially Weighted Moving Standard Deviation) * 10 */
static inline int
minstrel_get_ewmsd10(struct minstrel_rate_stats *mrs)
{
unsigned int ewmv = mrs->prob_ewmv;
return int_sqrt(MINSTREL_TRUNC(ewmv * 1000 * 1000));
}
extern const struct rate_control_ops mac80211_minstrel; extern const struct rate_control_ops mac80211_minstrel;
void minstrel_add_sta_debugfs(void *priv, void *priv_sta, struct dentry *dir); void minstrel_add_sta_debugfs(void *priv, void *priv_sta, struct dentry *dir);
void minstrel_remove_sta_debugfs(void *priv, void *priv_sta); void minstrel_remove_sta_debugfs(void *priv, void *priv_sta);
......
...@@ -93,6 +93,7 @@ minstrel_stats_open(struct inode *inode, struct file *file) ...@@ -93,6 +93,7 @@ minstrel_stats_open(struct inode *inode, struct file *file)
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];
struct minstrel_rate_stats *mrs = &mi->r[i].stats; struct minstrel_rate_stats *mrs = &mi->r[i].stats;
unsigned int prob_ewmsd;
*(p++) = (i == mi->max_tp_rate[0]) ? 'A' : ' '; *(p++) = (i == mi->max_tp_rate[0]) ? 'A' : ' ';
*(p++) = (i == mi->max_tp_rate[1]) ? 'B' : ' '; *(p++) = (i == mi->max_tp_rate[1]) ? 'B' : ' ';
...@@ -108,6 +109,7 @@ minstrel_stats_open(struct inode *inode, struct file *file) ...@@ -108,6 +109,7 @@ minstrel_stats_open(struct inode *inode, struct file *file)
tp_max = minstrel_get_tp_avg(mr, MINSTREL_FRAC(100,100)); tp_max = minstrel_get_tp_avg(mr, MINSTREL_FRAC(100,100));
tp_avg = minstrel_get_tp_avg(mr, mrs->prob_ewma); tp_avg = minstrel_get_tp_avg(mr, mrs->prob_ewma);
eprob = MINSTREL_TRUNC(mrs->prob_ewma * 1000); eprob = MINSTREL_TRUNC(mrs->prob_ewma * 1000);
prob_ewmsd = minstrel_get_ewmsd10(mrs);
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 " " %3u %3u %-3u "
...@@ -115,7 +117,7 @@ minstrel_stats_open(struct inode *inode, struct file *file) ...@@ -115,7 +117,7 @@ minstrel_stats_open(struct inode *inode, struct file *file)
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_ewmsd / 10, prob_ewmsd % 10,
mrs->retry_count, mrs->retry_count,
mrs->last_success, mrs->last_success,
mrs->last_attempts, mrs->last_attempts,
...@@ -159,6 +161,7 @@ minstrel_stats_csv_open(struct inode *inode, struct file *file) ...@@ -159,6 +161,7 @@ minstrel_stats_csv_open(struct inode *inode, struct file *file)
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];
struct minstrel_rate_stats *mrs = &mi->r[i].stats; struct minstrel_rate_stats *mrs = &mi->r[i].stats;
unsigned int prob_ewmsd;
p += sprintf(p, "%s" ,((i == mi->max_tp_rate[0]) ? "A" : "")); p += sprintf(p, "%s" ,((i == mi->max_tp_rate[0]) ? "A" : ""));
p += sprintf(p, "%s" ,((i == mi->max_tp_rate[1]) ? "B" : "")); p += sprintf(p, "%s" ,((i == mi->max_tp_rate[1]) ? "B" : ""));
...@@ -174,13 +177,14 @@ minstrel_stats_csv_open(struct inode *inode, struct file *file) ...@@ -174,13 +177,14 @@ minstrel_stats_csv_open(struct inode *inode, struct file *file)
tp_max = minstrel_get_tp_avg(mr, MINSTREL_FRAC(100,100)); tp_max = minstrel_get_tp_avg(mr, MINSTREL_FRAC(100,100));
tp_avg = minstrel_get_tp_avg(mr, mrs->prob_ewma); tp_avg = minstrel_get_tp_avg(mr, mrs->prob_ewma);
eprob = MINSTREL_TRUNC(mrs->prob_ewma * 1000); eprob = MINSTREL_TRUNC(mrs->prob_ewma * 1000);
prob_ewmsd = minstrel_get_ewmsd10(mrs);
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,"
"%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_ewmsd / 10, prob_ewmsd % 10,
mrs->retry_count, mrs->retry_count,
mrs->last_success, mrs->last_success,
mrs->last_attempts, mrs->last_attempts,
......
...@@ -41,6 +41,7 @@ minstrel_ht_stats_dump(struct minstrel_ht_sta *mi, int i, char *p) ...@@ -41,6 +41,7 @@ minstrel_ht_stats_dump(struct minstrel_ht_sta *mi, int i, char *p)
struct minstrel_rate_stats *mrs = &mi->groups[i].rates[j]; struct minstrel_rate_stats *mrs = &mi->groups[i].rates[j];
static const int bitrates[4] = { 10, 20, 55, 110 }; static const int bitrates[4] = { 10, 20, 55, 110 };
int idx = i * MCS_GROUP_RATES + j; int idx = i * MCS_GROUP_RATES + j;
unsigned int prob_ewmsd;
if (!(mi->supported[i] & BIT(j))) if (!(mi->supported[i] & BIT(j)))
continue; continue;
...@@ -84,6 +85,7 @@ minstrel_ht_stats_dump(struct minstrel_ht_sta *mi, int i, char *p) ...@@ -84,6 +85,7 @@ minstrel_ht_stats_dump(struct minstrel_ht_sta *mi, int i, char *p)
tp_max = minstrel_ht_get_tp_avg(mi, i, j, MINSTREL_FRAC(100, 100)); tp_max = minstrel_ht_get_tp_avg(mi, i, j, MINSTREL_FRAC(100, 100));
tp_avg = minstrel_ht_get_tp_avg(mi, i, j, mrs->prob_ewma); tp_avg = minstrel_ht_get_tp_avg(mi, i, j, mrs->prob_ewma);
eprob = MINSTREL_TRUNC(mrs->prob_ewma * 1000); eprob = MINSTREL_TRUNC(mrs->prob_ewma * 1000);
prob_ewmsd = minstrel_get_ewmsd10(mrs);
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 " " %3u %3u %-3u "
...@@ -91,7 +93,7 @@ minstrel_ht_stats_dump(struct minstrel_ht_sta *mi, int i, char *p) ...@@ -91,7 +93,7 @@ minstrel_ht_stats_dump(struct minstrel_ht_sta *mi, int i, char *p)
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_ewmsd / 10, prob_ewmsd % 10,
mrs->retry_count, mrs->retry_count,
mrs->last_success, mrs->last_success,
mrs->last_attempts, mrs->last_attempts,
...@@ -185,6 +187,7 @@ minstrel_ht_stats_csv_dump(struct minstrel_ht_sta *mi, int i, char *p) ...@@ -185,6 +187,7 @@ minstrel_ht_stats_csv_dump(struct minstrel_ht_sta *mi, int i, char *p)
struct minstrel_rate_stats *mrs = &mi->groups[i].rates[j]; struct minstrel_rate_stats *mrs = &mi->groups[i].rates[j];
static const int bitrates[4] = { 10, 20, 55, 110 }; static const int bitrates[4] = { 10, 20, 55, 110 };
int idx = i * MCS_GROUP_RATES + j; int idx = i * MCS_GROUP_RATES + j;
unsigned int prob_ewmsd;
if (!(mi->supported[i] & BIT(j))) if (!(mi->supported[i] & BIT(j)))
continue; continue;
...@@ -225,13 +228,14 @@ minstrel_ht_stats_csv_dump(struct minstrel_ht_sta *mi, int i, char *p) ...@@ -225,13 +228,14 @@ minstrel_ht_stats_csv_dump(struct minstrel_ht_sta *mi, int i, char *p)
tp_max = minstrel_ht_get_tp_avg(mi, i, j, MINSTREL_FRAC(100, 100)); tp_max = minstrel_ht_get_tp_avg(mi, i, j, MINSTREL_FRAC(100, 100));
tp_avg = minstrel_ht_get_tp_avg(mi, i, j, mrs->prob_ewma); tp_avg = minstrel_ht_get_tp_avg(mi, i, j, mrs->prob_ewma);
eprob = MINSTREL_TRUNC(mrs->prob_ewma * 1000); eprob = MINSTREL_TRUNC(mrs->prob_ewma * 1000);
prob_ewmsd = minstrel_get_ewmsd10(mrs);
p += sprintf(p, "%u.%u,%u.%u,%u.%u,%u.%u,%u,%u," p += sprintf(p, "%u.%u,%u.%u,%u.%u,%u.%u,%u,%u,"
"%u,%llu,%llu,", "%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_ewmsd / 10, prob_ewmsd % 10,
mrs->retry_count, mrs->retry_count,
mrs->last_success, mrs->last_success,
mrs->last_attempts, mrs->last_attempts,
......
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