diff options
author | Thomas Huehn <thomas@net.t-labs.tu-berlin.de> | 2015-03-24 16:09:41 -0400 |
---|---|---|
committer | Johannes Berg <johannes.berg@intel.com> | 2015-04-01 14:44:32 -0400 |
commit | 50e55a8ea76fb593403cc09767b6371c17364ba8 (patch) | |
tree | 54362ad0fe0bf1506ee1a3cedf213108b60f4e86 /net | |
parent | 6a27b2c40b4829e625bc1dfdd0705c5ece720ab4 (diff) |
mac80211: add max lossless throughput per rate
This patch adds the new statistic "maximum possible lossless
throughput" to Minstrels and Minstrel-HTs rc_stats (in debugfs). This
enables comprehensive comparison between current per-rate throughput
and max. achievable per-rate throughput.
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>
Diffstat (limited to 'net')
-rw-r--r-- | net/mac80211/rc80211_minstrel.c | 27 | ||||
-rw-r--r-- | net/mac80211/rc80211_minstrel.h | 2 | ||||
-rw-r--r-- | net/mac80211/rc80211_minstrel_debugfs.c | 22 | ||||
-rw-r--r-- | net/mac80211/rc80211_minstrel_ht.c | 84 | ||||
-rw-r--r-- | net/mac80211/rc80211_minstrel_ht.h | 3 | ||||
-rw-r--r-- | net/mac80211/rc80211_minstrel_ht_debugfs.c | 24 |
6 files changed, 93 insertions, 69 deletions
diff --git a/net/mac80211/rc80211_minstrel.c b/net/mac80211/rc80211_minstrel.c index 61a857bca971..c4a3477812ee 100644 --- a/net/mac80211/rc80211_minstrel.c +++ b/net/mac80211/rc80211_minstrel.c | |||
@@ -70,7 +70,7 @@ rix_to_ndx(struct minstrel_sta_info *mi, int rix) | |||
70 | } | 70 | } |
71 | 71 | ||
72 | /* return current EMWA throughput */ | 72 | /* return current EMWA throughput */ |
73 | int minstrel_get_tp_avg(struct minstrel_rate *mr) | 73 | int minstrel_get_tp_avg(struct minstrel_rate *mr, int prob_ewma) |
74 | { | 74 | { |
75 | int usecs; | 75 | int usecs; |
76 | 76 | ||
@@ -81,8 +81,11 @@ int minstrel_get_tp_avg(struct minstrel_rate *mr) | |||
81 | /* reset thr. below 10% success */ | 81 | /* reset thr. below 10% success */ |
82 | if (mr->stats.prob_ewma < MINSTREL_FRAC(10, 100)) | 82 | if (mr->stats.prob_ewma < MINSTREL_FRAC(10, 100)) |
83 | return 0; | 83 | return 0; |
84 | |||
85 | if (prob_ewma > MINSTREL_FRAC(90, 100)) | ||
86 | return MINSTREL_TRUNC(100000 * (MINSTREL_FRAC(90, 100) / usecs)); | ||
84 | else | 87 | else |
85 | return MINSTREL_TRUNC(mr->stats.prob_ewma * (100000 / usecs)); | 88 | return MINSTREL_TRUNC(100000 * (prob_ewma / usecs)); |
86 | } | 89 | } |
87 | 90 | ||
88 | /* find & sort topmost throughput rates */ | 91 | /* find & sort topmost throughput rates */ |
@@ -90,10 +93,14 @@ static inline void | |||
90 | minstrel_sort_best_tp_rates(struct minstrel_sta_info *mi, int i, u8 *tp_list) | 93 | minstrel_sort_best_tp_rates(struct minstrel_sta_info *mi, int i, u8 *tp_list) |
91 | { | 94 | { |
92 | int j = MAX_THR_RATES; | 95 | int j = MAX_THR_RATES; |
96 | struct minstrel_rate_stats *tmp_mrs = &mi->r[j - 1].stats; | ||
97 | struct minstrel_rate_stats *cur_mrs = &mi->r[i].stats; | ||
93 | 98 | ||
94 | while (j > 0 && (minstrel_get_tp_avg(&mi->r[i]) > | 99 | while (j > 0 && (minstrel_get_tp_avg(&mi->r[i], cur_mrs->prob_ewma) > |
95 | minstrel_get_tp_avg(&mi->r[tp_list[j - 1]]))) | 100 | minstrel_get_tp_avg(&mi->r[tp_list[j - 1]], tmp_mrs->prob_ewma))) { |
96 | j--; | 101 | j--; |
102 | tmp_mrs = &mi->r[tp_list[j - 1]].stats; | ||
103 | } | ||
97 | 104 | ||
98 | if (j < MAX_THR_RATES - 1) | 105 | if (j < MAX_THR_RATES - 1) |
99 | memmove(&tp_list[j + 1], &tp_list[j], MAX_THR_RATES - (j + 1)); | 106 | memmove(&tp_list[j + 1], &tp_list[j], MAX_THR_RATES - (j + 1)); |
@@ -184,6 +191,7 @@ minstrel_update_stats(struct minstrel_priv *mp, struct minstrel_sta_info *mi) | |||
184 | for (i = 0; i < mi->n_rates; i++) { | 191 | for (i = 0; i < mi->n_rates; i++) { |
185 | struct minstrel_rate *mr = &mi->r[i]; | 192 | struct minstrel_rate *mr = &mi->r[i]; |
186 | struct minstrel_rate_stats *mrs = &mi->r[i].stats; | 193 | struct minstrel_rate_stats *mrs = &mi->r[i].stats; |
194 | struct minstrel_rate_stats *tmp_mrs = &mi->r[tmp_prob_rate].stats; | ||
187 | 195 | ||
188 | /* Update success probabilities per rate */ | 196 | /* Update success probabilities per rate */ |
189 | minstrel_calc_rate_stats(mrs); | 197 | minstrel_calc_rate_stats(mrs); |
@@ -212,12 +220,13 @@ minstrel_update_stats(struct minstrel_priv *mp, struct minstrel_sta_info *mi) | |||
212 | * (2) if all success probabilities < 95%, the rate with | 220 | * (2) if all success probabilities < 95%, the rate with |
213 | * highest success probability is chosen as max_prob_rate */ | 221 | * highest success probability is chosen as max_prob_rate */ |
214 | if (mrs->prob_ewma >= MINSTREL_FRAC(95, 100)) { | 222 | if (mrs->prob_ewma >= MINSTREL_FRAC(95, 100)) { |
215 | tmp_cur_tp = minstrel_get_tp_avg(mr); | 223 | tmp_cur_tp = minstrel_get_tp_avg(mr, mrs->prob_ewma); |
216 | tmp_prob_tp = minstrel_get_tp_avg(&mi->r[tmp_prob_rate]); | 224 | tmp_prob_tp = minstrel_get_tp_avg(&mi->r[tmp_prob_rate], |
225 | tmp_mrs->prob_ewma); | ||
217 | if (tmp_cur_tp >= tmp_prob_tp) | 226 | if (tmp_cur_tp >= tmp_prob_tp) |
218 | tmp_prob_rate = i; | 227 | tmp_prob_rate = i; |
219 | } else { | 228 | } else { |
220 | if (mrs->prob_ewma >= mi->r[tmp_prob_rate].stats.prob_ewma) | 229 | if (mrs->prob_ewma >= tmp_mrs->prob_ewma) |
221 | tmp_prob_rate = i; | 230 | tmp_prob_rate = i; |
222 | } | 231 | } |
223 | } | 232 | } |
@@ -684,13 +693,15 @@ minstrel_free(void *priv) | |||
684 | static u32 minstrel_get_expected_throughput(void *priv_sta) | 693 | static u32 minstrel_get_expected_throughput(void *priv_sta) |
685 | { | 694 | { |
686 | struct minstrel_sta_info *mi = priv_sta; | 695 | struct minstrel_sta_info *mi = priv_sta; |
696 | struct minstrel_rate_stats *tmp_mrs; | ||
687 | int idx = mi->max_tp_rate[0]; | 697 | int idx = mi->max_tp_rate[0]; |
688 | int tmp_cur_tp; | 698 | int tmp_cur_tp; |
689 | 699 | ||
690 | /* convert pkt per sec in kbps (1200 is the average pkt size used for | 700 | /* convert pkt per sec in kbps (1200 is the average pkt size used for |
691 | * computing cur_tp | 701 | * computing cur_tp |
692 | */ | 702 | */ |
693 | tmp_cur_tp = minstrel_get_tp_avg(&mi->r[idx]); | 703 | tmp_mrs = &mi->r[idx].stats; |
704 | tmp_cur_tp = minstrel_get_tp_avg(&mi->r[idx], tmp_mrs->prob_ewma); | ||
694 | tmp_cur_tp = tmp_cur_tp * 1200 * 8 / 1024; | 705 | tmp_cur_tp = tmp_cur_tp * 1200 * 8 / 1024; |
695 | 706 | ||
696 | return tmp_cur_tp; | 707 | return tmp_cur_tp; |
diff --git a/net/mac80211/rc80211_minstrel.h b/net/mac80211/rc80211_minstrel.h index 490df3b1f3ec..0083036161af 100644 --- a/net/mac80211/rc80211_minstrel.h +++ b/net/mac80211/rc80211_minstrel.h | |||
@@ -134,7 +134,7 @@ void minstrel_remove_sta_debugfs(void *priv, void *priv_sta); | |||
134 | 134 | ||
135 | /* Recalculate success probabilities and counters for a given rate using EWMA */ | 135 | /* Recalculate success probabilities and counters for a given rate using EWMA */ |
136 | void minstrel_calc_rate_stats(struct minstrel_rate_stats *mrs); | 136 | void minstrel_calc_rate_stats(struct minstrel_rate_stats *mrs); |
137 | int minstrel_get_tp_avg(struct minstrel_rate *mr); | 137 | int minstrel_get_tp_avg(struct minstrel_rate *mr, int prob_ewma); |
138 | 138 | ||
139 | /* debugfs */ | 139 | /* debugfs */ |
140 | int minstrel_stats_open(struct inode *inode, struct file *file); | 140 | int minstrel_stats_open(struct inode *inode, struct file *file); |
diff --git a/net/mac80211/rc80211_minstrel_debugfs.c b/net/mac80211/rc80211_minstrel_debugfs.c index 188e9858713f..617b81f72226 100644 --- a/net/mac80211/rc80211_minstrel_debugfs.c +++ b/net/mac80211/rc80211_minstrel_debugfs.c | |||
@@ -75,7 +75,7 @@ minstrel_stats_open(struct inode *inode, struct file *file) | |||
75 | { | 75 | { |
76 | struct minstrel_sta_info *mi = inode->i_private; | 76 | struct minstrel_sta_info *mi = inode->i_private; |
77 | struct minstrel_debugfs_info *ms; | 77 | struct minstrel_debugfs_info *ms; |
78 | unsigned int i, tp_avg, prob, eprob; | 78 | unsigned int i, tp_max, tp_avg, prob, eprob; |
79 | char *p; | 79 | char *p; |
80 | 80 | ||
81 | ms = kmalloc(2048, GFP_KERNEL); | 81 | ms = kmalloc(2048, GFP_KERNEL); |
@@ -85,9 +85,9 @@ minstrel_stats_open(struct inode *inode, struct file *file) | |||
85 | file->private_data = ms; | 85 | file->private_data = ms; |
86 | p = ms->buf; | 86 | p = ms->buf; |
87 | p += sprintf(p, "\n"); | 87 | p += sprintf(p, "\n"); |
88 | p += sprintf(p, "best _______rate_____ __statistics__ " | 88 | p += sprintf(p, "best __________rate_________ __statistics__ " |
89 | "________last_______ ______sum-of________\n"); | 89 | "________last_______ ______sum-of________\n"); |
90 | p += sprintf(p, "rate [name idx airtime] [ ø(tp) ø(prob)] " | 90 | p += sprintf(p, "rate [name idx airtime max_tp] [ ø(tp) ø(prob)] " |
91 | "[prob.|retry|suc|att] [#success | #attempts]\n"); | 91 | "[prob.|retry|suc|att] [#success | #attempts]\n"); |
92 | 92 | ||
93 | for (i = 0; i < mi->n_rates; i++) { | 93 | for (i = 0; i < mi->n_rates; i++) { |
@@ -103,14 +103,16 @@ minstrel_stats_open(struct inode *inode, struct file *file) | |||
103 | p += sprintf(p, " %3u%s ", mr->bitrate / 2, | 103 | p += sprintf(p, " %3u%s ", mr->bitrate / 2, |
104 | (mr->bitrate & 1 ? ".5" : " ")); | 104 | (mr->bitrate & 1 ? ".5" : " ")); |
105 | p += sprintf(p, "%3u ", i); | 105 | p += sprintf(p, "%3u ", i); |
106 | p += sprintf(p, "%6u ", mr->perfect_tx_time); | 106 | p += sprintf(p, "%6u ", mr->perfect_tx_time); |
107 | 107 | ||
108 | tp_avg = minstrel_get_tp_avg(mr); | 108 | tp_max = minstrel_get_tp_avg(mr, MINSTREL_FRAC(100,100)); |
109 | tp_avg = minstrel_get_tp_avg(mr, mrs->prob_ewma); | ||
109 | prob = MINSTREL_TRUNC(mrs->cur_prob * 1000); | 110 | prob = MINSTREL_TRUNC(mrs->cur_prob * 1000); |
110 | eprob = MINSTREL_TRUNC(mrs->prob_ewma * 1000); | 111 | eprob = MINSTREL_TRUNC(mrs->prob_ewma * 1000); |
111 | 112 | ||
112 | p += sprintf(p, " %4u.%1u %3u.%1u %3u.%1u %3u" | 113 | p += sprintf(p, "%4u.%1u %4u.%1u %3u.%1u %3u.%1u %3u" |
113 | " %3u %-3u %9llu %-9llu\n", | 114 | " %3u %-3u %9llu %-9llu\n", |
115 | tp_max / 10, tp_max % 10, | ||
114 | tp_avg / 10, tp_avg % 10, | 116 | tp_avg / 10, tp_avg % 10, |
115 | eprob / 10, eprob % 10, | 117 | eprob / 10, eprob % 10, |
116 | prob / 10, prob % 10, | 118 | prob / 10, prob % 10, |
@@ -144,7 +146,7 @@ minstrel_stats_csv_open(struct inode *inode, struct file *file) | |||
144 | { | 146 | { |
145 | struct minstrel_sta_info *mi = inode->i_private; | 147 | struct minstrel_sta_info *mi = inode->i_private; |
146 | struct minstrel_debugfs_info *ms; | 148 | struct minstrel_debugfs_info *ms; |
147 | unsigned int i, tp_avg, prob, eprob; | 149 | unsigned int i, tp_max, tp_avg, prob, eprob; |
148 | char *p; | 150 | char *p; |
149 | 151 | ||
150 | ms = kmalloc(2048, GFP_KERNEL); | 152 | ms = kmalloc(2048, GFP_KERNEL); |
@@ -169,12 +171,14 @@ minstrel_stats_csv_open(struct inode *inode, struct file *file) | |||
169 | p += sprintf(p, "%u,", i); | 171 | p += sprintf(p, "%u,", i); |
170 | p += sprintf(p, "%u,",mr->perfect_tx_time); | 172 | p += sprintf(p, "%u,",mr->perfect_tx_time); |
171 | 173 | ||
172 | tp_avg = minstrel_get_tp_avg(mr); | 174 | tp_max = minstrel_get_tp_avg(mr, MINSTREL_FRAC(100,100)); |
175 | tp_avg = minstrel_get_tp_avg(mr, mrs->prob_ewma); | ||
173 | prob = MINSTREL_TRUNC(mrs->cur_prob * 1000); | 176 | prob = MINSTREL_TRUNC(mrs->cur_prob * 1000); |
174 | eprob = MINSTREL_TRUNC(mrs->prob_ewma * 1000); | 177 | eprob = MINSTREL_TRUNC(mrs->prob_ewma * 1000); |
175 | 178 | ||
176 | p += sprintf(p, "%u.%u,%u.%u,%u.%u,%u,%u,%u," | 179 | p += sprintf(p, "%u.%u,%u.%u,%u.%u,%u.%u,%u,%u,%u," |
177 | "%llu,%llu,%d,%d\n", | 180 | "%llu,%llu,%d,%d\n", |
181 | tp_max / 10, tp_max % 10, | ||
178 | tp_avg / 10, tp_avg % 10, | 182 | tp_avg / 10, tp_avg % 10, |
179 | eprob / 10, eprob % 10, | 183 | eprob / 10, eprob % 10, |
180 | prob / 10, prob % 10, | 184 | prob / 10, prob % 10, |
diff --git a/net/mac80211/rc80211_minstrel_ht.c b/net/mac80211/rc80211_minstrel_ht.c index 7202e34ec04c..7430a1df2ab1 100644 --- a/net/mac80211/rc80211_minstrel_ht.c +++ b/net/mac80211/rc80211_minstrel_ht.c | |||
@@ -318,33 +318,30 @@ minstrel_get_ratestats(struct minstrel_ht_sta *mi, int index) | |||
318 | * account the expected number of retransmissions and their expected length | 318 | * account the expected number of retransmissions and their expected length |
319 | */ | 319 | */ |
320 | int | 320 | int |
321 | minstrel_ht_get_tp_avg(struct minstrel_ht_sta *mi, int group, int rate) | 321 | minstrel_ht_get_tp_avg(struct minstrel_ht_sta *mi, int group, int rate, |
322 | int prob_ewma) | ||
322 | { | 323 | { |
323 | struct minstrel_rate_stats *mrs; | ||
324 | unsigned int nsecs = 0; | 324 | unsigned int nsecs = 0; |
325 | unsigned int tmp_prob_ewma; | ||
326 | |||
327 | mrs = &mi->groups[group].rates[rate]; | ||
328 | tmp_prob_ewma = mrs->prob_ewma; | ||
329 | 325 | ||
330 | /* do not account throughput if sucess prob is below 10% */ | 326 | /* do not account throughput if sucess prob is below 10% */ |
331 | if (mrs->prob_ewma < MINSTREL_FRAC(10, 100)) | 327 | if (prob_ewma < MINSTREL_FRAC(10, 100)) |
332 | return 0; | 328 | return 0; |
333 | 329 | ||
334 | /* | ||
335 | * For the throughput calculation, limit the probability value to 90% to | ||
336 | * account for collision related packet error rate fluctuation | ||
337 | */ | ||
338 | if (mrs->prob_ewma > MINSTREL_FRAC(90, 100)) | ||
339 | tmp_prob_ewma = MINSTREL_FRAC(90, 100); | ||
340 | |||
341 | if (group != MINSTREL_CCK_GROUP) | 330 | if (group != MINSTREL_CCK_GROUP) |
342 | nsecs = 1000 * mi->overhead / MINSTREL_TRUNC(mi->avg_ampdu_len); | 331 | nsecs = 1000 * mi->overhead / MINSTREL_TRUNC(mi->avg_ampdu_len); |
343 | 332 | ||
344 | nsecs += minstrel_mcs_groups[group].duration[rate]; | 333 | nsecs += minstrel_mcs_groups[group].duration[rate]; |
345 | 334 | ||
346 | /* prob is scaled - see MINSTREL_FRAC above */ | 335 | /* |
347 | return MINSTREL_TRUNC(100000 * ((tmp_prob_ewma * 1000) / nsecs)); | 336 | * For the throughput calculation, limit the probability value to 90% to |
337 | * account for collision related packet error rate fluctuation | ||
338 | * (prob is scaled - see MINSTREL_FRAC above) | ||
339 | */ | ||
340 | if (prob_ewma > MINSTREL_FRAC(90, 100)) | ||
341 | return MINSTREL_TRUNC(100000 * ((MINSTREL_FRAC(90, 100) * 1000) | ||
342 | / nsecs)); | ||
343 | else | ||
344 | return MINSTREL_TRUNC(100000 * ((prob_ewma * 1000) / nsecs)); | ||
348 | } | 345 | } |
349 | 346 | ||
350 | /* | 347 | /* |
@@ -364,14 +361,15 @@ minstrel_ht_sort_best_tp_rates(struct minstrel_ht_sta *mi, u16 index, | |||
364 | 361 | ||
365 | cur_group = index / MCS_GROUP_RATES; | 362 | cur_group = index / MCS_GROUP_RATES; |
366 | cur_idx = index % MCS_GROUP_RATES; | 363 | cur_idx = index % MCS_GROUP_RATES; |
367 | cur_tp_avg = minstrel_ht_get_tp_avg(mi, cur_group, cur_idx); | ||
368 | cur_prob = mi->groups[cur_group].rates[cur_idx].prob_ewma; | 364 | cur_prob = mi->groups[cur_group].rates[cur_idx].prob_ewma; |
365 | cur_tp_avg = minstrel_ht_get_tp_avg(mi, cur_group, cur_idx, cur_prob); | ||
369 | 366 | ||
370 | do { | 367 | do { |
371 | tmp_group = tp_list[j - 1] / MCS_GROUP_RATES; | 368 | tmp_group = tp_list[j - 1] / MCS_GROUP_RATES; |
372 | tmp_idx = tp_list[j - 1] % MCS_GROUP_RATES; | 369 | tmp_idx = tp_list[j - 1] % MCS_GROUP_RATES; |
373 | tmp_tp_avg = minstrel_ht_get_tp_avg(mi, tmp_group, tmp_idx); | ||
374 | tmp_prob = mi->groups[tmp_group].rates[tmp_idx].prob_ewma; | 370 | tmp_prob = mi->groups[tmp_group].rates[tmp_idx].prob_ewma; |
371 | tmp_tp_avg = minstrel_ht_get_tp_avg(mi, tmp_group, tmp_idx, | ||
372 | tmp_prob); | ||
375 | if (cur_tp_avg < tmp_tp_avg || | 373 | if (cur_tp_avg < tmp_tp_avg || |
376 | (cur_tp_avg == tmp_tp_avg && cur_prob <= tmp_prob)) | 374 | (cur_tp_avg == tmp_tp_avg && cur_prob <= tmp_prob)) |
377 | break; | 375 | break; |
@@ -396,8 +394,8 @@ minstrel_ht_set_best_prob_rate(struct minstrel_ht_sta *mi, u16 index) | |||
396 | struct minstrel_rate_stats *mrs; | 394 | struct minstrel_rate_stats *mrs; |
397 | int tmp_group, tmp_idx, tmp_tp_avg, tmp_prob; | 395 | int tmp_group, tmp_idx, tmp_tp_avg, tmp_prob; |
398 | int max_tp_group, cur_tp_avg, cur_group, cur_idx; | 396 | int max_tp_group, cur_tp_avg, cur_group, cur_idx; |
399 | int max_group_prob_rate_group, max_group_prob_rate_idx; | 397 | int max_gpr_group, max_gpr_idx; |
400 | int max_group_prob_rate_tp_avg; | 398 | int max_gpr_tp_avg, max_gpr_prob; |
401 | 399 | ||
402 | cur_group = index / MCS_GROUP_RATES; | 400 | cur_group = index / MCS_GROUP_RATES; |
403 | cur_idx = index % MCS_GROUP_RATES; | 401 | cur_idx = index % MCS_GROUP_RATES; |
@@ -406,8 +404,8 @@ minstrel_ht_set_best_prob_rate(struct minstrel_ht_sta *mi, u16 index) | |||
406 | 404 | ||
407 | tmp_group = mi->max_prob_rate / MCS_GROUP_RATES; | 405 | tmp_group = mi->max_prob_rate / MCS_GROUP_RATES; |
408 | tmp_idx = mi->max_prob_rate % MCS_GROUP_RATES; | 406 | tmp_idx = mi->max_prob_rate % MCS_GROUP_RATES; |
409 | tmp_tp_avg = minstrel_ht_get_tp_avg(mi, tmp_group, tmp_idx); | ||
410 | tmp_prob = mi->groups[tmp_group].rates[tmp_idx].prob_ewma; | 407 | tmp_prob = mi->groups[tmp_group].rates[tmp_idx].prob_ewma; |
408 | tmp_tp_avg = minstrel_ht_get_tp_avg(mi, tmp_group, tmp_idx, tmp_prob); | ||
411 | 409 | ||
412 | /* if max_tp_rate[0] is from MCS_GROUP max_prob_rate get selected from | 410 | /* if max_tp_rate[0] is from MCS_GROUP max_prob_rate get selected from |
413 | * MCS_GROUP as well as CCK_GROUP rates do not allow aggregation */ | 411 | * MCS_GROUP as well as CCK_GROUP rates do not allow aggregation */ |
@@ -417,18 +415,18 @@ minstrel_ht_set_best_prob_rate(struct minstrel_ht_sta *mi, u16 index) | |||
417 | return; | 415 | return; |
418 | 416 | ||
419 | if (mrs->prob_ewma > MINSTREL_FRAC(75, 100)) { | 417 | if (mrs->prob_ewma > MINSTREL_FRAC(75, 100)) { |
420 | cur_tp_avg = minstrel_ht_get_tp_avg(mi, cur_group, cur_idx); | 418 | cur_tp_avg = minstrel_ht_get_tp_avg(mi, cur_group, cur_idx, |
419 | mrs->prob_ewma); | ||
421 | if (cur_tp_avg > tmp_tp_avg) | 420 | if (cur_tp_avg > tmp_tp_avg) |
422 | mi->max_prob_rate = index; | 421 | mi->max_prob_rate = index; |
423 | 422 | ||
424 | max_group_prob_rate_group = mg->max_group_prob_rate / | 423 | max_gpr_group = mg->max_group_prob_rate / MCS_GROUP_RATES; |
425 | MCS_GROUP_RATES; | 424 | max_gpr_idx = mg->max_group_prob_rate % MCS_GROUP_RATES; |
426 | max_group_prob_rate_idx = mg->max_group_prob_rate % | 425 | max_gpr_prob = mi->groups[max_gpr_group].rates[max_gpr_idx].prob_ewma; |
427 | MCS_GROUP_RATES; | 426 | max_gpr_tp_avg = minstrel_ht_get_tp_avg(mi, max_gpr_group, |
428 | max_group_prob_rate_tp_avg = minstrel_ht_get_tp_avg(mi, | 427 | max_gpr_idx, |
429 | max_group_prob_rate_group, | 428 | max_gpr_prob); |
430 | max_group_prob_rate_idx); | 429 | if (cur_tp_avg > max_gpr_tp_avg) |
431 | if (cur_tp_avg > max_group_prob_rate_tp_avg) | ||
432 | mg->max_group_prob_rate = index; | 430 | mg->max_group_prob_rate = index; |
433 | } else { | 431 | } else { |
434 | if (mrs->prob_ewma > tmp_prob) | 432 | if (mrs->prob_ewma > tmp_prob) |
@@ -450,16 +448,18 @@ minstrel_ht_assign_best_tp_rates(struct minstrel_ht_sta *mi, | |||
450 | u16 tmp_mcs_tp_rate[MAX_THR_RATES], | 448 | u16 tmp_mcs_tp_rate[MAX_THR_RATES], |
451 | u16 tmp_cck_tp_rate[MAX_THR_RATES]) | 449 | u16 tmp_cck_tp_rate[MAX_THR_RATES]) |
452 | { | 450 | { |
453 | unsigned int tmp_group, tmp_idx, tmp_cck_tp, tmp_mcs_tp; | 451 | unsigned int tmp_group, tmp_idx, tmp_cck_tp, tmp_mcs_tp, tmp_prob; |
454 | int i; | 452 | int i; |
455 | 453 | ||
456 | tmp_group = tmp_cck_tp_rate[0] / MCS_GROUP_RATES; | 454 | tmp_group = tmp_cck_tp_rate[0] / MCS_GROUP_RATES; |
457 | tmp_idx = tmp_cck_tp_rate[0] % MCS_GROUP_RATES; | 455 | tmp_idx = tmp_cck_tp_rate[0] % MCS_GROUP_RATES; |
458 | tmp_cck_tp = minstrel_ht_get_tp_avg(mi, tmp_group, tmp_idx); | 456 | tmp_prob = mi->groups[tmp_group].rates[tmp_idx].prob_ewma; |
457 | tmp_cck_tp = minstrel_ht_get_tp_avg(mi, tmp_group, tmp_idx, tmp_prob); | ||
459 | 458 | ||
460 | tmp_group = tmp_mcs_tp_rate[0] / MCS_GROUP_RATES; | 459 | tmp_group = tmp_mcs_tp_rate[0] / MCS_GROUP_RATES; |
461 | tmp_idx = tmp_mcs_tp_rate[0] % MCS_GROUP_RATES; | 460 | tmp_idx = tmp_mcs_tp_rate[0] % MCS_GROUP_RATES; |
462 | tmp_mcs_tp = minstrel_ht_get_tp_avg(mi, tmp_group, tmp_idx); | 461 | tmp_prob = mi->groups[tmp_group].rates[tmp_idx].prob_ewma; |
462 | tmp_mcs_tp = minstrel_ht_get_tp_avg(mi, tmp_group, tmp_idx, tmp_prob); | ||
463 | 463 | ||
464 | if (tmp_cck_tp > tmp_mcs_tp) { | 464 | if (tmp_cck_tp > tmp_mcs_tp) { |
465 | for(i = 0; i < MAX_THR_RATES; i++) { | 465 | for(i = 0; i < MAX_THR_RATES; i++) { |
@@ -478,7 +478,7 @@ static inline void | |||
478 | minstrel_ht_prob_rate_reduce_streams(struct minstrel_ht_sta *mi) | 478 | minstrel_ht_prob_rate_reduce_streams(struct minstrel_ht_sta *mi) |
479 | { | 479 | { |
480 | struct minstrel_mcs_group_data *mg; | 480 | struct minstrel_mcs_group_data *mg; |
481 | int tmp_max_streams, group, tmp_idx; | 481 | int tmp_max_streams, group, tmp_idx, tmp_prob; |
482 | int tmp_tp = 0; | 482 | int tmp_tp = 0; |
483 | 483 | ||
484 | tmp_max_streams = minstrel_mcs_groups[mi->max_tp_rate[0] / | 484 | tmp_max_streams = minstrel_mcs_groups[mi->max_tp_rate[0] / |
@@ -489,12 +489,14 @@ minstrel_ht_prob_rate_reduce_streams(struct minstrel_ht_sta *mi) | |||
489 | continue; | 489 | continue; |
490 | 490 | ||
491 | tmp_idx = mg->max_group_prob_rate % MCS_GROUP_RATES; | 491 | tmp_idx = mg->max_group_prob_rate % MCS_GROUP_RATES; |
492 | tmp_prob = mi->groups[group].rates[tmp_idx].prob_ewma; | ||
492 | 493 | ||
493 | if (tmp_tp < minstrel_ht_get_tp_avg(mi, group, tmp_idx) && | 494 | if (tmp_tp < minstrel_ht_get_tp_avg(mi, group, tmp_idx, tmp_prob) && |
494 | (minstrel_mcs_groups[group].streams < tmp_max_streams)) { | 495 | (minstrel_mcs_groups[group].streams < tmp_max_streams)) { |
495 | mi->max_prob_rate = mg->max_group_prob_rate; | 496 | mi->max_prob_rate = mg->max_group_prob_rate; |
496 | tmp_tp = minstrel_ht_get_tp_avg(mi, group, | 497 | tmp_tp = minstrel_ht_get_tp_avg(mi, group, |
497 | tmp_idx); | 498 | tmp_idx, |
499 | tmp_prob); | ||
498 | } | 500 | } |
499 | } | 501 | } |
500 | } | 502 | } |
@@ -513,7 +515,7 @@ minstrel_ht_update_stats(struct minstrel_priv *mp, struct minstrel_ht_sta *mi) | |||
513 | { | 515 | { |
514 | struct minstrel_mcs_group_data *mg; | 516 | struct minstrel_mcs_group_data *mg; |
515 | struct minstrel_rate_stats *mrs; | 517 | struct minstrel_rate_stats *mrs; |
516 | int group, i, j; | 518 | int group, i, j, cur_prob; |
517 | u16 tmp_mcs_tp_rate[MAX_THR_RATES], tmp_group_tp_rate[MAX_THR_RATES]; | 519 | u16 tmp_mcs_tp_rate[MAX_THR_RATES], tmp_group_tp_rate[MAX_THR_RATES]; |
518 | u16 tmp_cck_tp_rate[MAX_THR_RATES], index; | 520 | u16 tmp_cck_tp_rate[MAX_THR_RATES], index; |
519 | 521 | ||
@@ -555,8 +557,9 @@ minstrel_ht_update_stats(struct minstrel_priv *mp, struct minstrel_ht_sta *mi) | |||
555 | mrs = &mg->rates[i]; | 557 | mrs = &mg->rates[i]; |
556 | mrs->retry_updated = false; | 558 | mrs->retry_updated = false; |
557 | minstrel_calc_rate_stats(mrs); | 559 | minstrel_calc_rate_stats(mrs); |
560 | cur_prob = mrs->prob_ewma; | ||
558 | 561 | ||
559 | if (minstrel_ht_get_tp_avg(mi, group, i) == 0) | 562 | if (minstrel_ht_get_tp_avg(mi, group, i, cur_prob) == 0) |
560 | continue; | 563 | continue; |
561 | 564 | ||
562 | /* Find max throughput rate set */ | 565 | /* Find max throughput rate set */ |
@@ -1315,16 +1318,17 @@ static u32 minstrel_ht_get_expected_throughput(void *priv_sta) | |||
1315 | { | 1318 | { |
1316 | struct minstrel_ht_sta_priv *msp = priv_sta; | 1319 | struct minstrel_ht_sta_priv *msp = priv_sta; |
1317 | struct minstrel_ht_sta *mi = &msp->ht; | 1320 | struct minstrel_ht_sta *mi = &msp->ht; |
1318 | int i, j, tp_avg; | 1321 | int i, j, prob, tp_avg; |
1319 | 1322 | ||
1320 | if (!msp->is_ht) | 1323 | if (!msp->is_ht) |
1321 | return mac80211_minstrel.get_expected_throughput(priv_sta); | 1324 | return mac80211_minstrel.get_expected_throughput(priv_sta); |
1322 | 1325 | ||
1323 | i = mi->max_tp_rate[0] / MCS_GROUP_RATES; | 1326 | i = mi->max_tp_rate[0] / MCS_GROUP_RATES; |
1324 | j = mi->max_tp_rate[0] % MCS_GROUP_RATES; | 1327 | j = mi->max_tp_rate[0] % MCS_GROUP_RATES; |
1328 | prob = mi->groups[i].rates[j].prob_ewma; | ||
1325 | 1329 | ||
1326 | /* convert tp_avg from pkt per second in kbps */ | 1330 | /* convert tp_avg from pkt per second in kbps */ |
1327 | tp_avg = minstrel_ht_get_tp_avg(mi, i, j) * AVG_PKT_SIZE * 8 / 1024; | 1331 | tp_avg = minstrel_ht_get_tp_avg(mi, i, j, prob) * AVG_PKT_SIZE * 8 / 1024; |
1328 | 1332 | ||
1329 | return tp_avg; | 1333 | return tp_avg; |
1330 | } | 1334 | } |
diff --git a/net/mac80211/rc80211_minstrel_ht.h b/net/mac80211/rc80211_minstrel_ht.h index 68dce4f8641c..e8b52a94d24b 100644 --- a/net/mac80211/rc80211_minstrel_ht.h +++ b/net/mac80211/rc80211_minstrel_ht.h | |||
@@ -121,6 +121,7 @@ struct minstrel_ht_sta_priv { | |||
121 | 121 | ||
122 | void minstrel_ht_add_sta_debugfs(void *priv, void *priv_sta, struct dentry *dir); | 122 | void minstrel_ht_add_sta_debugfs(void *priv, void *priv_sta, struct dentry *dir); |
123 | void minstrel_ht_remove_sta_debugfs(void *priv, void *priv_sta); | 123 | void minstrel_ht_remove_sta_debugfs(void *priv, void *priv_sta); |
124 | int minstrel_ht_get_tp_avg(struct minstrel_ht_sta *mi, int group, int rate); | 124 | int minstrel_ht_get_tp_avg(struct minstrel_ht_sta *mi, int group, int rate, |
125 | int prob_ewma); | ||
125 | 126 | ||
126 | #endif | 127 | #endif |
diff --git a/net/mac80211/rc80211_minstrel_ht_debugfs.c b/net/mac80211/rc80211_minstrel_ht_debugfs.c index 721cf74ea9a6..135ed39790c0 100644 --- a/net/mac80211/rc80211_minstrel_ht_debugfs.c +++ b/net/mac80211/rc80211_minstrel_ht_debugfs.c | |||
@@ -19,7 +19,7 @@ static char * | |||
19 | minstrel_ht_stats_dump(struct minstrel_ht_sta *mi, int i, char *p) | 19 | minstrel_ht_stats_dump(struct minstrel_ht_sta *mi, int i, char *p) |
20 | { | 20 | { |
21 | const struct mcs_group *mg; | 21 | const struct mcs_group *mg; |
22 | unsigned int j, tp_avg, prob, eprob, tx_time; | 22 | unsigned int j, tp_max, tp_avg, prob, eprob, tx_time; |
23 | char htmode = '2'; | 23 | char htmode = '2'; |
24 | char gimode = 'L'; | 24 | char gimode = 'L'; |
25 | u32 gflags; | 25 | u32 gflags; |
@@ -79,14 +79,16 @@ minstrel_ht_stats_dump(struct minstrel_ht_sta *mi, int i, char *p) | |||
79 | 79 | ||
80 | /* tx_time[rate(i)] in usec */ | 80 | /* tx_time[rate(i)] in usec */ |
81 | tx_time = DIV_ROUND_CLOSEST(mg->duration[j], 1000); | 81 | tx_time = DIV_ROUND_CLOSEST(mg->duration[j], 1000); |
82 | p += sprintf(p, "%6u ", tx_time); | 82 | p += sprintf(p, "%6u ", tx_time); |
83 | 83 | ||
84 | tp_avg = minstrel_ht_get_tp_avg(mi, i, j); | 84 | tp_max = minstrel_ht_get_tp_avg(mi, i, j, MINSTREL_FRAC(100, 100)); |
85 | tp_avg = minstrel_ht_get_tp_avg(mi, i, j, mrs->prob_ewma); | ||
85 | prob = MINSTREL_TRUNC(mrs->cur_prob * 1000); | 86 | prob = MINSTREL_TRUNC(mrs->cur_prob * 1000); |
86 | eprob = MINSTREL_TRUNC(mrs->prob_ewma * 1000); | 87 | eprob = MINSTREL_TRUNC(mrs->prob_ewma * 1000); |
87 | 88 | ||
88 | p += sprintf(p, "%4u.%1u %3u.%1u %3u.%1u " | 89 | p += sprintf(p, "%4u.%1u %4u.%1u %3u.%1u %3u.%1u " |
89 | "%3u %3u %-3u %9llu %-9llu\n", | 90 | "%3u %3u %-3u %9llu %-9llu\n", |
91 | tp_max / 10, tp_max % 10, | ||
90 | tp_avg / 10, tp_avg % 10, | 92 | tp_avg / 10, tp_avg % 10, |
91 | eprob / 10, eprob % 10, | 93 | eprob / 10, eprob % 10, |
92 | prob / 10, prob % 10, | 94 | prob / 10, prob % 10, |
@@ -125,11 +127,11 @@ minstrel_ht_stats_open(struct inode *inode, struct file *file) | |||
125 | p = ms->buf; | 127 | p = ms->buf; |
126 | 128 | ||
127 | p += sprintf(p, "\n"); | 129 | p += sprintf(p, "\n"); |
128 | p += sprintf(p, " best ________rate______ " | 130 | p += sprintf(p, " best ____________rate__________ " |
129 | "__statistics__ ________last_______ " | 131 | "__statistics__ ________last_______ " |
130 | "______sum-of________\n"); | 132 | "______sum-of________\n"); |
131 | p += sprintf(p, "mode guard # rate [name idx airtime] [ ø(tp) " | 133 | p += sprintf(p, "mode guard # rate [name idx airtime max_tp] " |
132 | "ø(prob)] [prob.|retry|suc|att] [#success | " | 134 | "[ ø(tp) ø(prob)] [prob.|retry|suc|att] [#success | " |
133 | "#attempts]\n"); | 135 | "#attempts]\n"); |
134 | 136 | ||
135 | p = minstrel_ht_stats_dump(mi, MINSTREL_CCK_GROUP, p); | 137 | p = minstrel_ht_stats_dump(mi, MINSTREL_CCK_GROUP, p); |
@@ -163,7 +165,7 @@ static char * | |||
163 | minstrel_ht_stats_csv_dump(struct minstrel_ht_sta *mi, int i, char *p) | 165 | minstrel_ht_stats_csv_dump(struct minstrel_ht_sta *mi, int i, char *p) |
164 | { | 166 | { |
165 | const struct mcs_group *mg; | 167 | const struct mcs_group *mg; |
166 | unsigned int j, tp_avg, prob, eprob, tx_time; | 168 | unsigned int j, tp_max, tp_avg, prob, eprob, tx_time; |
167 | char htmode = '2'; | 169 | char htmode = '2'; |
168 | char gimode = 'L'; | 170 | char gimode = 'L'; |
169 | u32 gflags; | 171 | u32 gflags; |
@@ -222,11 +224,13 @@ minstrel_ht_stats_csv_dump(struct minstrel_ht_sta *mi, int i, char *p) | |||
222 | tx_time = DIV_ROUND_CLOSEST(mg->duration[j], 1000); | 224 | tx_time = DIV_ROUND_CLOSEST(mg->duration[j], 1000); |
223 | p += sprintf(p, "%u,", tx_time); | 225 | p += sprintf(p, "%u,", tx_time); |
224 | 226 | ||
225 | tp_avg = minstrel_ht_get_tp_avg(mi, i, j); | 227 | tp_max = minstrel_ht_get_tp_avg(mi, i, j, MINSTREL_FRAC(100, 100)); |
228 | tp_avg = minstrel_ht_get_tp_avg(mi, i, j, mrs->prob_ewma); | ||
226 | prob = MINSTREL_TRUNC(mrs->cur_prob * 1000); | 229 | prob = MINSTREL_TRUNC(mrs->cur_prob * 1000); |
227 | eprob = MINSTREL_TRUNC(mrs->prob_ewma * 1000); | 230 | eprob = MINSTREL_TRUNC(mrs->prob_ewma * 1000); |
228 | 231 | ||
229 | p += sprintf(p, "%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,%llu,%llu,", |
233 | tp_max / 10, tp_max % 10, | ||
230 | tp_avg / 10, tp_avg % 10, | 234 | tp_avg / 10, tp_avg % 10, |
231 | eprob / 10, eprob % 10, | 235 | eprob / 10, eprob % 10, |
232 | prob / 10, prob % 10, | 236 | prob / 10, prob % 10, |