Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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: Thomas Huehn <thomas.huehn@evernet-eg.de>
Signed-off-by: Felix Fietkau <nbd@nbd.name>
Signed-off-by: Johannes Berg <johannes.berg@intel.com>

authored by

Felix Fietkau and committed by
Johannes Berg
4f0bc9c6 0217eefa

+30 -19
+4 -4
net/mac80211/rc80211_minstrel.c
··· 168 168 mrs->prob_ewma = cur_prob; 169 169 } else { 170 170 /* update exponential weighted moving variance */ 171 - mrs->prob_ewmsd = minstrel_ewmsd(mrs->prob_ewmsd, 172 - cur_prob, 173 - mrs->prob_ewma, 174 - EWMA_LEVEL); 171 + mrs->prob_ewmv = minstrel_ewmv(mrs->prob_ewmv, 172 + cur_prob, 173 + mrs->prob_ewma, 174 + EWMA_LEVEL); 175 175 176 176 /*update exponential weighted moving avarage */ 177 177 mrs->prob_ewma = minstrel_ewma(mrs->prob_ewma,
+14 -11
net/mac80211/rc80211_minstrel.h
··· 36 36 } 37 37 38 38 /* 39 - * Perform EWMSD (Exponentially Weighted Moving Standard Deviation) calculation 39 + * Perform EWMV (Exponentially Weighted Moving Variance) calculation 40 40 */ 41 41 static inline int 42 - minstrel_ewmsd(int old_ewmsd, int cur_prob, int prob_ewma, int weight) 42 + minstrel_ewmv(int old_ewmv, int cur_prob, int prob_ewma, int weight) 43 43 { 44 - int diff, incr, tmp_var; 44 + int diff, incr; 45 45 46 - /* calculate exponential weighted moving variance */ 47 - diff = MINSTREL_TRUNC((cur_prob - prob_ewma) * 1000000); 46 + diff = cur_prob - prob_ewma; 48 47 incr = (EWMA_DIV - weight) * diff / EWMA_DIV; 49 - tmp_var = old_ewmsd * old_ewmsd; 50 - tmp_var = weight * (tmp_var + diff * incr / 1000000) / EWMA_DIV; 51 - 52 - /* return standard deviation */ 53 - return (u16) int_sqrt(tmp_var); 48 + return weight * (old_ewmv + MINSTREL_TRUNC(diff * incr)) / EWMA_DIV; 54 49 } 55 50 56 51 struct minstrel_rate_stats { ··· 60 65 * prob_ewma - exponential weighted moving average of prob 61 66 * prob_ewmsd - exp. weighted moving standard deviation of prob */ 62 67 unsigned int prob_ewma; 63 - u16 prob_ewmsd; 68 + u16 prob_ewmv; 64 69 65 70 /* maximum retry counts */ 66 71 u8 retry_count; ··· 145 150 size_t len; 146 151 char buf[]; 147 152 }; 153 + 154 + /* Get EWMSD (Exponentially Weighted Moving Standard Deviation) * 10 */ 155 + static inline int 156 + minstrel_get_ewmsd10(struct minstrel_rate_stats *mrs) 157 + { 158 + unsigned int ewmv = mrs->prob_ewmv; 159 + return int_sqrt(MINSTREL_TRUNC(ewmv * 1000 * 1000)); 160 + } 148 161 149 162 extern const struct rate_control_ops mac80211_minstrel; 150 163 void minstrel_add_sta_debugfs(void *priv, void *priv_sta, struct dentry *dir);
+6 -2
net/mac80211/rc80211_minstrel_debugfs.c
··· 93 93 for (i = 0; i < mi->n_rates; i++) { 94 94 struct minstrel_rate *mr = &mi->r[i]; 95 95 struct minstrel_rate_stats *mrs = &mi->r[i].stats; 96 + unsigned int prob_ewmsd; 96 97 97 98 *(p++) = (i == mi->max_tp_rate[0]) ? 'A' : ' '; 98 99 *(p++) = (i == mi->max_tp_rate[1]) ? 'B' : ' '; ··· 109 108 tp_max = minstrel_get_tp_avg(mr, MINSTREL_FRAC(100,100)); 110 109 tp_avg = minstrel_get_tp_avg(mr, mrs->prob_ewma); 111 110 eprob = MINSTREL_TRUNC(mrs->prob_ewma * 1000); 111 + prob_ewmsd = minstrel_get_ewmsd10(mrs); 112 112 113 113 p += sprintf(p, "%4u.%1u %4u.%1u %3u.%1u %3u.%1u" 114 114 " %3u %3u %-3u " ··· 117 115 tp_max / 10, tp_max % 10, 118 116 tp_avg / 10, tp_avg % 10, 119 117 eprob / 10, eprob % 10, 120 - mrs->prob_ewmsd / 10, mrs->prob_ewmsd % 10, 118 + prob_ewmsd / 10, prob_ewmsd % 10, 121 119 mrs->retry_count, 122 120 mrs->last_success, 123 121 mrs->last_attempts, ··· 161 159 for (i = 0; i < mi->n_rates; i++) { 162 160 struct minstrel_rate *mr = &mi->r[i]; 163 161 struct minstrel_rate_stats *mrs = &mi->r[i].stats; 162 + unsigned int prob_ewmsd; 164 163 165 164 p += sprintf(p, "%s" ,((i == mi->max_tp_rate[0]) ? "A" : "")); 166 165 p += sprintf(p, "%s" ,((i == mi->max_tp_rate[1]) ? "B" : "")); ··· 177 174 tp_max = minstrel_get_tp_avg(mr, MINSTREL_FRAC(100,100)); 178 175 tp_avg = minstrel_get_tp_avg(mr, mrs->prob_ewma); 179 176 eprob = MINSTREL_TRUNC(mrs->prob_ewma * 1000); 177 + prob_ewmsd = minstrel_get_ewmsd10(mrs); 180 178 181 179 p += sprintf(p, "%u.%u,%u.%u,%u.%u,%u.%u,%u,%u,%u," 182 180 "%llu,%llu,%d,%d\n", 183 181 tp_max / 10, tp_max % 10, 184 182 tp_avg / 10, tp_avg % 10, 185 183 eprob / 10, eprob % 10, 186 - mrs->prob_ewmsd / 10, mrs->prob_ewmsd % 10, 184 + prob_ewmsd / 10, prob_ewmsd % 10, 187 185 mrs->retry_count, 188 186 mrs->last_success, 189 187 mrs->last_attempts,
+6 -2
net/mac80211/rc80211_minstrel_ht_debugfs.c
··· 41 41 struct minstrel_rate_stats *mrs = &mi->groups[i].rates[j]; 42 42 static const int bitrates[4] = { 10, 20, 55, 110 }; 43 43 int idx = i * MCS_GROUP_RATES + j; 44 + unsigned int prob_ewmsd; 44 45 45 46 if (!(mi->supported[i] & BIT(j))) 46 47 continue; ··· 85 84 tp_max = minstrel_ht_get_tp_avg(mi, i, j, MINSTREL_FRAC(100, 100)); 86 85 tp_avg = minstrel_ht_get_tp_avg(mi, i, j, mrs->prob_ewma); 87 86 eprob = MINSTREL_TRUNC(mrs->prob_ewma * 1000); 87 + prob_ewmsd = minstrel_get_ewmsd10(mrs); 88 88 89 89 p += sprintf(p, "%4u.%1u %4u.%1u %3u.%1u %3u.%1u" 90 90 " %3u %3u %-3u " ··· 93 91 tp_max / 10, tp_max % 10, 94 92 tp_avg / 10, tp_avg % 10, 95 93 eprob / 10, eprob % 10, 96 - mrs->prob_ewmsd / 10, mrs->prob_ewmsd % 10, 94 + prob_ewmsd / 10, prob_ewmsd % 10, 97 95 mrs->retry_count, 98 96 mrs->last_success, 99 97 mrs->last_attempts, ··· 187 185 struct minstrel_rate_stats *mrs = &mi->groups[i].rates[j]; 188 186 static const int bitrates[4] = { 10, 20, 55, 110 }; 189 187 int idx = i * MCS_GROUP_RATES + j; 188 + unsigned int prob_ewmsd; 190 189 191 190 if (!(mi->supported[i] & BIT(j))) 192 191 continue; ··· 228 225 tp_max = minstrel_ht_get_tp_avg(mi, i, j, MINSTREL_FRAC(100, 100)); 229 226 tp_avg = minstrel_ht_get_tp_avg(mi, i, j, mrs->prob_ewma); 230 227 eprob = MINSTREL_TRUNC(mrs->prob_ewma * 1000); 228 + prob_ewmsd = minstrel_get_ewmsd10(mrs); 231 229 232 230 p += sprintf(p, "%u.%u,%u.%u,%u.%u,%u.%u,%u,%u," 233 231 "%u,%llu,%llu,", 234 232 tp_max / 10, tp_max % 10, 235 233 tp_avg / 10, tp_avg % 10, 236 234 eprob / 10, eprob % 10, 237 - mrs->prob_ewmsd / 10, mrs->prob_ewmsd % 10, 235 + prob_ewmsd / 10, prob_ewmsd % 10, 238 236 mrs->retry_count, 239 237 mrs->last_success, 240 238 mrs->last_attempts,