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

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: Thomas Huehn <thomas@net.t-labs.tu-berlin.de>
Acked-by: Felix Fietkau <nbd@openwrt.org>
Signed-off-by: Johannes Berg <johannes.berg@intel.com>

authored by

Thomas Huehn and committed by
Johannes Berg
5f919abc ade6d4a2

+56 -18
+14 -5
net/mac80211/rc80211_minstrel.c
··· 153 153 } 154 154 155 155 /* 156 - * Recalculate success probabilities and counters for a given rate using EWMA 156 + * Recalculate statistics and counters of a given rate 157 157 */ 158 158 void 159 159 minstrel_calc_rate_stats(struct minstrel_rate_stats *mrs) ··· 161 161 if (unlikely(mrs->attempts > 0)) { 162 162 mrs->sample_skipped = 0; 163 163 mrs->cur_prob = MINSTREL_FRAC(mrs->success, mrs->attempts); 164 - if (unlikely(!mrs->att_hist)) 164 + if (unlikely(!mrs->att_hist)) { 165 165 mrs->prob_ewma = mrs->cur_prob; 166 - else 166 + } else { 167 + /* update exponential weighted moving variance */ 168 + mrs->prob_ewmsd = minstrel_ewmsd(mrs->prob_ewmsd, 169 + mrs->cur_prob, 170 + mrs->prob_ewma, 171 + EWMA_LEVEL); 172 + 173 + /*update exponential weighted moving avarage */ 167 174 mrs->prob_ewma = minstrel_ewma(mrs->prob_ewma, 168 - mrs->cur_prob, EWMA_LEVEL); 175 + mrs->cur_prob, 176 + EWMA_LEVEL); 177 + } 169 178 mrs->att_hist += mrs->attempts; 170 179 mrs->succ_hist += mrs->success; 171 180 } else { ··· 202 193 struct minstrel_rate_stats *mrs = &mi->r[i].stats; 203 194 struct minstrel_rate_stats *tmp_mrs = &mi->r[tmp_prob_rate].stats; 204 195 205 - /* Update success probabilities per rate */ 196 + /* Update statistics of success probability per rate */ 206 197 minstrel_calc_rate_stats(mrs); 207 198 208 199 /* Sample less often below the 10% chance of success.
+21 -1
net/mac80211/rc80211_minstrel.h
··· 35 35 return old + incr; 36 36 } 37 37 38 + /* 39 + * Perform EWMSD (Exponentially Weighted Moving Standard Deviation) calculation 40 + */ 41 + static inline int 42 + minstrel_ewmsd(int old_ewmsd, int cur_prob, int prob_ewma, int weight) 43 + { 44 + int diff, incr, tmp_var; 45 + 46 + /* calculate exponential weighted moving variance */ 47 + diff = MINSTREL_TRUNC((cur_prob - prob_ewma) * 1000000); 48 + 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); 54 + } 55 + 38 56 struct minstrel_rate_stats { 39 57 /* current / last sampling period attempts/success counters */ 40 58 u16 attempts, last_attempts; ··· 63 45 64 46 /* statistis of packet delivery probability 65 47 * cur_prob - current prob within last update intervall 66 - * prob_ewma - exponential weighted moving average of prob */ 48 + * prob_ewma - exponential weighted moving average of prob 49 + * prob_ewmsd - exp. weighted moving standard deviation of prob */ 67 50 unsigned int cur_prob; 68 51 unsigned int prob_ewma; 52 + u16 prob_ewmsd; 69 53 70 54 /* maximum retry counts */ 71 55 u8 retry_count;
+12 -7
net/mac80211/rc80211_minstrel_debugfs.c
··· 85 85 file->private_data = ms; 86 86 p = ms->buf; 87 87 p += sprintf(p, "\n"); 88 - p += sprintf(p, "best __________rate_________ __statistics__ " 89 - "________last_______ ______sum-of________\n"); 90 - p += sprintf(p, "rate [name idx airtime max_tp] [ ø(tp) ø(prob)] " 91 - "[prob.|retry|suc|att] [#success | #attempts]\n"); 88 + p += sprintf(p, "best __________rate_________ ______" 89 + "statistics______ ________last_______ " 90 + "______sum-of________\n"); 91 + p += sprintf(p, "rate [name idx airtime max_tp] [ ø(tp) ø(prob) " 92 + "sd(prob)] [prob.|retry|suc|att] " 93 + "[#success | #attempts]\n"); 92 94 93 95 for (i = 0; i < mi->n_rates; i++) { 94 96 struct minstrel_rate *mr = &mi->r[i]; ··· 112 110 prob = MINSTREL_TRUNC(mrs->cur_prob * 1000); 113 111 eprob = MINSTREL_TRUNC(mrs->prob_ewma * 1000); 114 112 115 - p += sprintf(p, "%4u.%1u %4u.%1u %3u.%1u %3u.%1u %3u" 116 - " %3u %-3u %9llu %-9llu\n", 113 + p += sprintf(p, "%4u.%1u %4u.%1u %3u.%1u %3u.%1u" 114 + " %3u.%1u %3u %3u %-3u " 115 + "%9llu %-9llu\n", 117 116 tp_max / 10, tp_max % 10, 118 117 tp_avg / 10, tp_avg % 10, 119 118 eprob / 10, eprob % 10, 119 + mrs->prob_ewmsd / 10, mrs->prob_ewmsd % 10, 120 120 prob / 10, prob % 10, 121 121 mrs->retry_count, 122 122 mrs->last_success, ··· 180 176 prob = MINSTREL_TRUNC(mrs->cur_prob * 1000); 181 177 eprob = MINSTREL_TRUNC(mrs->prob_ewma * 1000); 182 178 183 - p += sprintf(p, "%u.%u,%u.%u,%u.%u,%u.%u,%u,%u,%u," 179 + p += sprintf(p, "%u.%u,%u.%u,%u.%u,%u.%u,%u.%u,%u,%u,%u," 184 180 "%llu,%llu,%d,%d\n", 185 181 tp_max / 10, tp_max % 10, 186 182 tp_avg / 10, tp_avg % 10, 187 183 eprob / 10, eprob % 10, 184 + mrs->prob_ewmsd / 10, mrs->prob_ewmsd % 10, 188 185 prob / 10, prob % 10, 189 186 mrs->retry_count, 190 187 mrs->last_success,
+9 -5
net/mac80211/rc80211_minstrel_ht_debugfs.c
··· 86 86 prob = MINSTREL_TRUNC(mrs->cur_prob * 1000); 87 87 eprob = MINSTREL_TRUNC(mrs->prob_ewma * 1000); 88 88 89 - p += sprintf(p, "%4u.%1u %4u.%1u %3u.%1u %3u.%1u " 90 - "%3u %3u %-3u %9llu %-9llu\n", 89 + p += sprintf(p, "%4u.%1u %4u.%1u %3u.%1u %3u.%1u" 90 + " %3u.%1u %3u %3u %-3u " 91 + "%9llu %-9llu\n", 91 92 tp_max / 10, tp_max % 10, 92 93 tp_avg / 10, tp_avg % 10, 93 94 eprob / 10, eprob % 10, 95 + mrs->prob_ewmsd / 10, mrs->prob_ewmsd % 10, 94 96 prob / 10, prob % 10, 95 97 mrs->retry_count, 96 98 mrs->last_success, ··· 130 128 131 129 p += sprintf(p, "\n"); 132 130 p += sprintf(p, " best ____________rate__________ " 133 - "__statistics__ ________last_______ " 131 + "______statistics______ ________last_______ " 134 132 "______sum-of________\n"); 135 133 p += sprintf(p, "mode guard # rate [name idx airtime max_tp] " 136 - "[ ø(tp) ø(prob)] [prob.|retry|suc|att] [#success | " 134 + "[ ø(tp) ø(prob) sd(prob)] [prob.|retry|suc|att] [#success | " 137 135 "#attempts]\n"); 138 136 139 137 p = minstrel_ht_stats_dump(mi, MINSTREL_CCK_GROUP, p); ··· 231 229 prob = MINSTREL_TRUNC(mrs->cur_prob * 1000); 232 230 eprob = MINSTREL_TRUNC(mrs->prob_ewma * 1000); 233 231 234 - p += sprintf(p, "%u.%u,%u.%u,%u.%u,%u.%u,%u,%u,%u,%llu,%llu,", 232 + p += sprintf(p, "%u.%u,%u.%u,%u.%u,%u.%u,%u.%u,%u,%u," 233 + "%u,%llu,%llu,", 235 234 tp_max / 10, tp_max % 10, 236 235 tp_avg / 10, tp_avg % 10, 237 236 eprob / 10, eprob % 10, 237 + mrs->prob_ewmsd / 10, mrs->prob_ewmsd % 10, 238 238 prob / 10, prob % 10, 239 239 mrs->retry_count, 240 240 mrs->last_success,