Skip to content

Commit 50e55a8

Browse files
thuehnjmberg-intel
authored andcommitted
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 <[email protected]> Acked-by: Felix Fietkau <[email protected]> Signed-off-by: Johannes Berg <[email protected]>
1 parent 6a27b2c commit 50e55a8

File tree

6 files changed

+93
-69
lines changed

6 files changed

+93
-69
lines changed

net/mac80211/rc80211_minstrel.c

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ rix_to_ndx(struct minstrel_sta_info *mi, int rix)
7070
}
7171

7272
/* 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)
7474
{
7575
int usecs;
7676

@@ -81,19 +81,26 @@ int minstrel_get_tp_avg(struct minstrel_rate *mr)
8181
/* reset thr. below 10% success */
8282
if (mr->stats.prob_ewma < MINSTREL_FRAC(10, 100))
8383
return 0;
84+
85+
if (prob_ewma > MINSTREL_FRAC(90, 100))
86+
return MINSTREL_TRUNC(100000 * (MINSTREL_FRAC(90, 100) / usecs));
8487
else
85-
return MINSTREL_TRUNC(mr->stats.prob_ewma * (100000 / usecs));
88+
return MINSTREL_TRUNC(100000 * (prob_ewma / usecs));
8689
}
8790

8891
/* find & sort topmost throughput rates */
8992
static inline void
9093
minstrel_sort_best_tp_rates(struct minstrel_sta_info *mi, int i, u8 *tp_list)
9194
{
9295
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;
9398

94-
while (j > 0 && (minstrel_get_tp_avg(&mi->r[i]) >
95-
minstrel_get_tp_avg(&mi->r[tp_list[j - 1]])))
99+
while (j > 0 && (minstrel_get_tp_avg(&mi->r[i], cur_mrs->prob_ewma) >
100+
minstrel_get_tp_avg(&mi->r[tp_list[j - 1]], tmp_mrs->prob_ewma))) {
96101
j--;
102+
tmp_mrs = &mi->r[tp_list[j - 1]].stats;
103+
}
97104

98105
if (j < MAX_THR_RATES - 1)
99106
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)
184191
for (i = 0; i < mi->n_rates; i++) {
185192
struct minstrel_rate *mr = &mi->r[i];
186193
struct minstrel_rate_stats *mrs = &mi->r[i].stats;
194+
struct minstrel_rate_stats *tmp_mrs = &mi->r[tmp_prob_rate].stats;
187195

188196
/* Update success probabilities per rate */
189197
minstrel_calc_rate_stats(mrs);
@@ -212,12 +220,13 @@ minstrel_update_stats(struct minstrel_priv *mp, struct minstrel_sta_info *mi)
212220
* (2) if all success probabilities < 95%, the rate with
213221
* highest success probability is chosen as max_prob_rate */
214222
if (mrs->prob_ewma >= MINSTREL_FRAC(95, 100)) {
215-
tmp_cur_tp = minstrel_get_tp_avg(mr);
216-
tmp_prob_tp = minstrel_get_tp_avg(&mi->r[tmp_prob_rate]);
223+
tmp_cur_tp = minstrel_get_tp_avg(mr, mrs->prob_ewma);
224+
tmp_prob_tp = minstrel_get_tp_avg(&mi->r[tmp_prob_rate],
225+
tmp_mrs->prob_ewma);
217226
if (tmp_cur_tp >= tmp_prob_tp)
218227
tmp_prob_rate = i;
219228
} else {
220-
if (mrs->prob_ewma >= mi->r[tmp_prob_rate].stats.prob_ewma)
229+
if (mrs->prob_ewma >= tmp_mrs->prob_ewma)
221230
tmp_prob_rate = i;
222231
}
223232
}
@@ -684,13 +693,15 @@ minstrel_free(void *priv)
684693
static u32 minstrel_get_expected_throughput(void *priv_sta)
685694
{
686695
struct minstrel_sta_info *mi = priv_sta;
696+
struct minstrel_rate_stats *tmp_mrs;
687697
int idx = mi->max_tp_rate[0];
688698
int tmp_cur_tp;
689699

690700
/* convert pkt per sec in kbps (1200 is the average pkt size used for
691701
* computing cur_tp
692702
*/
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);
694705
tmp_cur_tp = tmp_cur_tp * 1200 * 8 / 1024;
695706

696707
return tmp_cur_tp;

net/mac80211/rc80211_minstrel.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,7 @@ void minstrel_remove_sta_debugfs(void *priv, void *priv_sta);
134134

135135
/* Recalculate success probabilities and counters for a given rate using EWMA */
136136
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);
138138

139139
/* debugfs */
140140
int minstrel_stats_open(struct inode *inode, struct file *file);

net/mac80211/rc80211_minstrel_debugfs.c

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ minstrel_stats_open(struct inode *inode, struct file *file)
7575
{
7676
struct minstrel_sta_info *mi = inode->i_private;
7777
struct minstrel_debugfs_info *ms;
78-
unsigned int i, tp_avg, prob, eprob;
78+
unsigned int i, tp_max, tp_avg, prob, eprob;
7979
char *p;
8080

8181
ms = kmalloc(2048, GFP_KERNEL);
@@ -85,9 +85,9 @@ minstrel_stats_open(struct inode *inode, struct file *file)
8585
file->private_data = ms;
8686
p = ms->buf;
8787
p += sprintf(p, "\n");
88-
p += sprintf(p, "best _______rate_____ __statistics__ "
88+
p += sprintf(p, "best __________rate_________ __statistics__ "
8989
"________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)] "
9191
"[prob.|retry|suc|att] [#success | #attempts]\n");
9292

9393
for (i = 0; i < mi->n_rates; i++) {
@@ -103,14 +103,16 @@ minstrel_stats_open(struct inode *inode, struct file *file)
103103
p += sprintf(p, " %3u%s ", mr->bitrate / 2,
104104
(mr->bitrate & 1 ? ".5" : " "));
105105
p += sprintf(p, "%3u ", i);
106-
p += sprintf(p, "%6u ", mr->perfect_tx_time);
106+
p += sprintf(p, "%6u ", mr->perfect_tx_time);
107107

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);
109110
prob = MINSTREL_TRUNC(mrs->cur_prob * 1000);
110111
eprob = MINSTREL_TRUNC(mrs->prob_ewma * 1000);
111112

112-
p += sprintf(p, " %4u.%1u %3u.%1u %3u.%1u %3u"
113+
p += sprintf(p, "%4u.%1u %4u.%1u %3u.%1u %3u.%1u %3u"
113114
" %3u %-3u %9llu %-9llu\n",
115+
tp_max / 10, tp_max % 10,
114116
tp_avg / 10, tp_avg % 10,
115117
eprob / 10, eprob % 10,
116118
prob / 10, prob % 10,
@@ -144,7 +146,7 @@ minstrel_stats_csv_open(struct inode *inode, struct file *file)
144146
{
145147
struct minstrel_sta_info *mi = inode->i_private;
146148
struct minstrel_debugfs_info *ms;
147-
unsigned int i, tp_avg, prob, eprob;
149+
unsigned int i, tp_max, tp_avg, prob, eprob;
148150
char *p;
149151

150152
ms = kmalloc(2048, GFP_KERNEL);
@@ -169,12 +171,14 @@ minstrel_stats_csv_open(struct inode *inode, struct file *file)
169171
p += sprintf(p, "%u,", i);
170172
p += sprintf(p, "%u,",mr->perfect_tx_time);
171173

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);
173176
prob = MINSTREL_TRUNC(mrs->cur_prob * 1000);
174177
eprob = MINSTREL_TRUNC(mrs->prob_ewma * 1000);
175178

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,"
177180
"%llu,%llu,%d,%d\n",
181+
tp_max / 10, tp_max % 10,
178182
tp_avg / 10, tp_avg % 10,
179183
eprob / 10, eprob % 10,
180184
prob / 10, prob % 10,

net/mac80211/rc80211_minstrel_ht.c

Lines changed: 44 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -318,33 +318,30 @@ minstrel_get_ratestats(struct minstrel_ht_sta *mi, int index)
318318
* account the expected number of retransmissions and their expected length
319319
*/
320320
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)
322323
{
323-
struct minstrel_rate_stats *mrs;
324324
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;
329325

330326
/* 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))
332328
return 0;
333329

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-
341330
if (group != MINSTREL_CCK_GROUP)
342331
nsecs = 1000 * mi->overhead / MINSTREL_TRUNC(mi->avg_ampdu_len);
343332

344333
nsecs += minstrel_mcs_groups[group].duration[rate];
345334

346-
/* prob is scaled - see MINSTREL_FRAC above */
347-
return MINSTREL_TRUNC(100000 * ((tmp_prob_ewma * 1000) / nsecs));
335+
/*
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));
348345
}
349346

350347
/*
@@ -364,14 +361,15 @@ minstrel_ht_sort_best_tp_rates(struct minstrel_ht_sta *mi, u16 index,
364361

365362
cur_group = index / MCS_GROUP_RATES;
366363
cur_idx = index % MCS_GROUP_RATES;
367-
cur_tp_avg = minstrel_ht_get_tp_avg(mi, cur_group, cur_idx);
368364
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);
369366

370367
do {
371368
tmp_group = tp_list[j - 1] / MCS_GROUP_RATES;
372369
tmp_idx = tp_list[j - 1] % MCS_GROUP_RATES;
373-
tmp_tp_avg = minstrel_ht_get_tp_avg(mi, tmp_group, tmp_idx);
374370
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);
375373
if (cur_tp_avg < tmp_tp_avg ||
376374
(cur_tp_avg == tmp_tp_avg && cur_prob <= tmp_prob))
377375
break;
@@ -396,8 +394,8 @@ minstrel_ht_set_best_prob_rate(struct minstrel_ht_sta *mi, u16 index)
396394
struct minstrel_rate_stats *mrs;
397395
int tmp_group, tmp_idx, tmp_tp_avg, tmp_prob;
398396
int max_tp_group, cur_tp_avg, cur_group, cur_idx;
399-
int max_group_prob_rate_group, max_group_prob_rate_idx;
400-
int max_group_prob_rate_tp_avg;
397+
int max_gpr_group, max_gpr_idx;
398+
int max_gpr_tp_avg, max_gpr_prob;
401399

402400
cur_group = index / MCS_GROUP_RATES;
403401
cur_idx = index % MCS_GROUP_RATES;
@@ -406,8 +404,8 @@ minstrel_ht_set_best_prob_rate(struct minstrel_ht_sta *mi, u16 index)
406404

407405
tmp_group = mi->max_prob_rate / MCS_GROUP_RATES;
408406
tmp_idx = mi->max_prob_rate % MCS_GROUP_RATES;
409-
tmp_tp_avg = minstrel_ht_get_tp_avg(mi, tmp_group, tmp_idx);
410407
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);
411409

412410
/* if max_tp_rate[0] is from MCS_GROUP max_prob_rate get selected from
413411
* 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)
417415
return;
418416

419417
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);
421420
if (cur_tp_avg > tmp_tp_avg)
422421
mi->max_prob_rate = index;
423422

424-
max_group_prob_rate_group = mg->max_group_prob_rate /
425-
MCS_GROUP_RATES;
426-
max_group_prob_rate_idx = mg->max_group_prob_rate %
427-
MCS_GROUP_RATES;
428-
max_group_prob_rate_tp_avg = minstrel_ht_get_tp_avg(mi,
429-
max_group_prob_rate_group,
430-
max_group_prob_rate_idx);
431-
if (cur_tp_avg > max_group_prob_rate_tp_avg)
423+
max_gpr_group = mg->max_group_prob_rate / MCS_GROUP_RATES;
424+
max_gpr_idx = mg->max_group_prob_rate % MCS_GROUP_RATES;
425+
max_gpr_prob = mi->groups[max_gpr_group].rates[max_gpr_idx].prob_ewma;
426+
max_gpr_tp_avg = minstrel_ht_get_tp_avg(mi, max_gpr_group,
427+
max_gpr_idx,
428+
max_gpr_prob);
429+
if (cur_tp_avg > max_gpr_tp_avg)
432430
mg->max_group_prob_rate = index;
433431
} else {
434432
if (mrs->prob_ewma > tmp_prob)
@@ -450,16 +448,18 @@ minstrel_ht_assign_best_tp_rates(struct minstrel_ht_sta *mi,
450448
u16 tmp_mcs_tp_rate[MAX_THR_RATES],
451449
u16 tmp_cck_tp_rate[MAX_THR_RATES])
452450
{
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;
454452
int i;
455453

456454
tmp_group = tmp_cck_tp_rate[0] / MCS_GROUP_RATES;
457455
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);
459458

460459
tmp_group = tmp_mcs_tp_rate[0] / MCS_GROUP_RATES;
461460
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);
463463

464464
if (tmp_cck_tp > tmp_mcs_tp) {
465465
for(i = 0; i < MAX_THR_RATES; i++) {
@@ -478,7 +478,7 @@ static inline void
478478
minstrel_ht_prob_rate_reduce_streams(struct minstrel_ht_sta *mi)
479479
{
480480
struct minstrel_mcs_group_data *mg;
481-
int tmp_max_streams, group, tmp_idx;
481+
int tmp_max_streams, group, tmp_idx, tmp_prob;
482482
int tmp_tp = 0;
483483

484484
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)
489489
continue;
490490

491491
tmp_idx = mg->max_group_prob_rate % MCS_GROUP_RATES;
492+
tmp_prob = mi->groups[group].rates[tmp_idx].prob_ewma;
492493

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) &&
494495
(minstrel_mcs_groups[group].streams < tmp_max_streams)) {
495496
mi->max_prob_rate = mg->max_group_prob_rate;
496497
tmp_tp = minstrel_ht_get_tp_avg(mi, group,
497-
tmp_idx);
498+
tmp_idx,
499+
tmp_prob);
498500
}
499501
}
500502
}
@@ -513,7 +515,7 @@ minstrel_ht_update_stats(struct minstrel_priv *mp, struct minstrel_ht_sta *mi)
513515
{
514516
struct minstrel_mcs_group_data *mg;
515517
struct minstrel_rate_stats *mrs;
516-
int group, i, j;
518+
int group, i, j, cur_prob;
517519
u16 tmp_mcs_tp_rate[MAX_THR_RATES], tmp_group_tp_rate[MAX_THR_RATES];
518520
u16 tmp_cck_tp_rate[MAX_THR_RATES], index;
519521

@@ -555,8 +557,9 @@ minstrel_ht_update_stats(struct minstrel_priv *mp, struct minstrel_ht_sta *mi)
555557
mrs = &mg->rates[i];
556558
mrs->retry_updated = false;
557559
minstrel_calc_rate_stats(mrs);
560+
cur_prob = mrs->prob_ewma;
558561

559-
if (minstrel_ht_get_tp_avg(mi, group, i) == 0)
562+
if (minstrel_ht_get_tp_avg(mi, group, i, cur_prob) == 0)
560563
continue;
561564

562565
/* Find max throughput rate set */
@@ -1315,16 +1318,17 @@ static u32 minstrel_ht_get_expected_throughput(void *priv_sta)
13151318
{
13161319
struct minstrel_ht_sta_priv *msp = priv_sta;
13171320
struct minstrel_ht_sta *mi = &msp->ht;
1318-
int i, j, tp_avg;
1321+
int i, j, prob, tp_avg;
13191322

13201323
if (!msp->is_ht)
13211324
return mac80211_minstrel.get_expected_throughput(priv_sta);
13221325

13231326
i = mi->max_tp_rate[0] / MCS_GROUP_RATES;
13241327
j = mi->max_tp_rate[0] % MCS_GROUP_RATES;
1328+
prob = mi->groups[i].rates[j].prob_ewma;
13251329

13261330
/* 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;
13281332

13291333
return tp_avg;
13301334
}

net/mac80211/rc80211_minstrel_ht.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,7 @@ struct minstrel_ht_sta_priv {
121121

122122
void minstrel_ht_add_sta_debugfs(void *priv, void *priv_sta, struct dentry *dir);
123123
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);
125126

126127
#endif

0 commit comments

Comments
 (0)