Commit 50e55a8e authored by Thomas Huehn's avatar Thomas Huehn Committed by Johannes Berg

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: default avatarThomas Huehn <thomas@net.t-labs.tu-berlin.de>
Acked-by: default avatarFelix Fietkau <nbd@openwrt.org>
Signed-off-by: default avatarJohannes Berg <johannes.berg@intel.com>
parent 6a27b2c4
...@@ -70,7 +70,7 @@ rix_to_ndx(struct minstrel_sta_info *mi, int rix) ...@@ -70,7 +70,7 @@ rix_to_ndx(struct minstrel_sta_info *mi, int rix)
} }
/* return current EMWA throughput */ /* return current EMWA throughput */
int minstrel_get_tp_avg(struct minstrel_rate *mr) int minstrel_get_tp_avg(struct minstrel_rate *mr, int prob_ewma)
{ {
int usecs; int usecs;
...@@ -81,8 +81,11 @@ int minstrel_get_tp_avg(struct minstrel_rate *mr) ...@@ -81,8 +81,11 @@ int minstrel_get_tp_avg(struct minstrel_rate *mr)
/* reset thr. below 10% success */ /* reset thr. below 10% success */
if (mr->stats.prob_ewma < MINSTREL_FRAC(10, 100)) if (mr->stats.prob_ewma < MINSTREL_FRAC(10, 100))
return 0; return 0;
if (prob_ewma > MINSTREL_FRAC(90, 100))
return MINSTREL_TRUNC(100000 * (MINSTREL_FRAC(90, 100) / usecs));
else else
return MINSTREL_TRUNC(mr->stats.prob_ewma * (100000 / usecs)); return MINSTREL_TRUNC(100000 * (prob_ewma / usecs));
} }
/* find & sort topmost throughput rates */ /* find & sort topmost throughput rates */
...@@ -90,10 +93,14 @@ static inline void ...@@ -90,10 +93,14 @@ static inline void
minstrel_sort_best_tp_rates(struct minstrel_sta_info *mi, int i, u8 *tp_list) minstrel_sort_best_tp_rates(struct minstrel_sta_info *mi, int i, u8 *tp_list)
{ {
int j = MAX_THR_RATES; int j = MAX_THR_RATES;
struct minstrel_rate_stats *tmp_mrs = &mi->r[j - 1].stats;
struct minstrel_rate_stats *cur_mrs = &mi->r[i].stats;
while (j > 0 && (minstrel_get_tp_avg(&mi->r[i]) > while (j > 0 && (minstrel_get_tp_avg(&mi->r[i], cur_mrs->prob_ewma) >
minstrel_get_tp_avg(&mi->r[tp_list[j - 1]]))) minstrel_get_tp_avg(&mi->r[tp_list[j - 1]], tmp_mrs->prob_ewma))) {
j--; j--;
tmp_mrs = &mi->r[tp_list[j - 1]].stats;
}
if (j < MAX_THR_RATES - 1) if (j < MAX_THR_RATES - 1)
memmove(&tp_list[j + 1], &tp_list[j], MAX_THR_RATES - (j + 1)); 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,6 +191,7 @@ minstrel_update_stats(struct minstrel_priv *mp, struct minstrel_sta_info *mi)
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;
struct minstrel_rate_stats *tmp_mrs = &mi->r[tmp_prob_rate].stats;
/* Update success probabilities per rate */ /* Update success probabilities per rate */
minstrel_calc_rate_stats(mrs); minstrel_calc_rate_stats(mrs);
...@@ -212,12 +220,13 @@ minstrel_update_stats(struct minstrel_priv *mp, struct minstrel_sta_info *mi) ...@@ -212,12 +220,13 @@ minstrel_update_stats(struct minstrel_priv *mp, struct minstrel_sta_info *mi)
* (2) if all success probabilities < 95%, the rate with * (2) if all success probabilities < 95%, the rate with
* highest success probability is chosen as max_prob_rate */ * highest success probability is chosen as max_prob_rate */
if (mrs->prob_ewma >= MINSTREL_FRAC(95, 100)) { if (mrs->prob_ewma >= MINSTREL_FRAC(95, 100)) {
tmp_cur_tp = minstrel_get_tp_avg(mr); tmp_cur_tp = minstrel_get_tp_avg(mr, mrs->prob_ewma);
tmp_prob_tp = minstrel_get_tp_avg(&mi->r[tmp_prob_rate]); tmp_prob_tp = minstrel_get_tp_avg(&mi->r[tmp_prob_rate],
tmp_mrs->prob_ewma);
if (tmp_cur_tp >= tmp_prob_tp) if (tmp_cur_tp >= tmp_prob_tp)
tmp_prob_rate = i; tmp_prob_rate = i;
} else { } else {
if (mrs->prob_ewma >= mi->r[tmp_prob_rate].stats.prob_ewma) if (mrs->prob_ewma >= tmp_mrs->prob_ewma)
tmp_prob_rate = i; tmp_prob_rate = i;
} }
} }
...@@ -684,13 +693,15 @@ minstrel_free(void *priv) ...@@ -684,13 +693,15 @@ minstrel_free(void *priv)
static u32 minstrel_get_expected_throughput(void *priv_sta) static u32 minstrel_get_expected_throughput(void *priv_sta)
{ {
struct minstrel_sta_info *mi = priv_sta; struct minstrel_sta_info *mi = priv_sta;
struct minstrel_rate_stats *tmp_mrs;
int idx = mi->max_tp_rate[0]; int idx = mi->max_tp_rate[0];
int tmp_cur_tp; int tmp_cur_tp;
/* convert pkt per sec in kbps (1200 is the average pkt size used for /* convert pkt per sec in kbps (1200 is the average pkt size used for
* computing cur_tp * computing cur_tp
*/ */
tmp_cur_tp = minstrel_get_tp_avg(&mi->r[idx]); tmp_mrs = &mi->r[idx].stats;
tmp_cur_tp = minstrel_get_tp_avg(&mi->r[idx], tmp_mrs->prob_ewma);
tmp_cur_tp = tmp_cur_tp * 1200 * 8 / 1024; tmp_cur_tp = tmp_cur_tp * 1200 * 8 / 1024;
return tmp_cur_tp; return tmp_cur_tp;
......
...@@ -134,7 +134,7 @@ void minstrel_remove_sta_debugfs(void *priv, void *priv_sta); ...@@ -134,7 +134,7 @@ void minstrel_remove_sta_debugfs(void *priv, void *priv_sta);
/* Recalculate success probabilities and counters for a given rate using EWMA */ /* Recalculate success probabilities and counters for a given rate using EWMA */
void minstrel_calc_rate_stats(struct minstrel_rate_stats *mrs); void minstrel_calc_rate_stats(struct minstrel_rate_stats *mrs);
int minstrel_get_tp_avg(struct minstrel_rate *mr); int minstrel_get_tp_avg(struct minstrel_rate *mr, int prob_ewma);
/* debugfs */ /* debugfs */
int minstrel_stats_open(struct inode *inode, struct file *file); int minstrel_stats_open(struct inode *inode, struct file *file);
......
...@@ -75,7 +75,7 @@ minstrel_stats_open(struct inode *inode, struct file *file) ...@@ -75,7 +75,7 @@ minstrel_stats_open(struct inode *inode, struct file *file)
{ {
struct minstrel_sta_info *mi = inode->i_private; struct minstrel_sta_info *mi = inode->i_private;
struct minstrel_debugfs_info *ms; struct minstrel_debugfs_info *ms;
unsigned int i, tp_avg, prob, eprob; unsigned int i, tp_max, tp_avg, prob, eprob;
char *p; char *p;
ms = kmalloc(2048, GFP_KERNEL); ms = kmalloc(2048, GFP_KERNEL);
...@@ -85,9 +85,9 @@ minstrel_stats_open(struct inode *inode, struct file *file) ...@@ -85,9 +85,9 @@ minstrel_stats_open(struct inode *inode, struct file *file)
file->private_data = ms; file->private_data = ms;
p = ms->buf; p = ms->buf;
p += sprintf(p, "\n"); p += sprintf(p, "\n");
p += sprintf(p, "best _______rate_____ __statistics__ " p += sprintf(p, "best __________rate_________ __statistics__ "
"________last_______ ______sum-of________\n"); "________last_______ ______sum-of________\n");
p += sprintf(p, "rate [name idx airtime] [ ø(tp) ø(prob)] " p += sprintf(p, "rate [name idx airtime max_tp] [ ø(tp) ø(prob)] "
"[prob.|retry|suc|att] [#success | #attempts]\n"); "[prob.|retry|suc|att] [#success | #attempts]\n");
for (i = 0; i < mi->n_rates; i++) { for (i = 0; i < mi->n_rates; i++) {
...@@ -103,14 +103,16 @@ minstrel_stats_open(struct inode *inode, struct file *file) ...@@ -103,14 +103,16 @@ minstrel_stats_open(struct inode *inode, struct file *file)
p += sprintf(p, " %3u%s ", mr->bitrate / 2, p += sprintf(p, " %3u%s ", mr->bitrate / 2,
(mr->bitrate & 1 ? ".5" : " ")); (mr->bitrate & 1 ? ".5" : " "));
p += sprintf(p, "%3u ", i); p += sprintf(p, "%3u ", i);
p += sprintf(p, "%6u ", mr->perfect_tx_time); p += sprintf(p, "%6u ", mr->perfect_tx_time);
tp_avg = minstrel_get_tp_avg(mr); tp_max = minstrel_get_tp_avg(mr, MINSTREL_FRAC(100,100));
tp_avg = minstrel_get_tp_avg(mr, mrs->prob_ewma);
prob = MINSTREL_TRUNC(mrs->cur_prob * 1000); prob = MINSTREL_TRUNC(mrs->cur_prob * 1000);
eprob = MINSTREL_TRUNC(mrs->prob_ewma * 1000); eprob = MINSTREL_TRUNC(mrs->prob_ewma * 1000);
p += sprintf(p, " %4u.%1u %3u.%1u %3u.%1u %3u" p += sprintf(p, "%4u.%1u %4u.%1u %3u.%1u %3u.%1u %3u"
" %3u %-3u %9llu %-9llu\n", " %3u %-3u %9llu %-9llu\n",
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,
prob / 10, prob % 10, prob / 10, prob % 10,
...@@ -144,7 +146,7 @@ minstrel_stats_csv_open(struct inode *inode, struct file *file) ...@@ -144,7 +146,7 @@ minstrel_stats_csv_open(struct inode *inode, struct file *file)
{ {
struct minstrel_sta_info *mi = inode->i_private; struct minstrel_sta_info *mi = inode->i_private;
struct minstrel_debugfs_info *ms; struct minstrel_debugfs_info *ms;
unsigned int i, tp_avg, prob, eprob; unsigned int i, tp_max, tp_avg, prob, eprob;
char *p; char *p;
ms = kmalloc(2048, GFP_KERNEL); ms = kmalloc(2048, GFP_KERNEL);
...@@ -169,12 +171,14 @@ minstrel_stats_csv_open(struct inode *inode, struct file *file) ...@@ -169,12 +171,14 @@ minstrel_stats_csv_open(struct inode *inode, struct file *file)
p += sprintf(p, "%u,", i); p += sprintf(p, "%u,", i);
p += sprintf(p, "%u,",mr->perfect_tx_time); p += sprintf(p, "%u,",mr->perfect_tx_time);
tp_avg = minstrel_get_tp_avg(mr); tp_max = minstrel_get_tp_avg(mr, MINSTREL_FRAC(100,100));
tp_avg = minstrel_get_tp_avg(mr, mrs->prob_ewma);
prob = MINSTREL_TRUNC(mrs->cur_prob * 1000); prob = MINSTREL_TRUNC(mrs->cur_prob * 1000);
eprob = MINSTREL_TRUNC(mrs->prob_ewma * 1000); eprob = MINSTREL_TRUNC(mrs->prob_ewma * 1000);
p += sprintf(p, "%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_avg / 10, tp_avg % 10, tp_avg / 10, tp_avg % 10,
eprob / 10, eprob % 10, eprob / 10, eprob % 10,
prob / 10, prob % 10, prob / 10, prob % 10,
......
...@@ -318,33 +318,30 @@ minstrel_get_ratestats(struct minstrel_ht_sta *mi, int index) ...@@ -318,33 +318,30 @@ minstrel_get_ratestats(struct minstrel_ht_sta *mi, int index)
* account the expected number of retransmissions and their expected length * account the expected number of retransmissions and their expected length
*/ */
int int
minstrel_ht_get_tp_avg(struct minstrel_ht_sta *mi, int group, int rate) minstrel_ht_get_tp_avg(struct minstrel_ht_sta *mi, int group, int rate,
int prob_ewma)
{ {
struct minstrel_rate_stats *mrs;
unsigned int nsecs = 0; unsigned int nsecs = 0;
unsigned int tmp_prob_ewma;
mrs = &mi->groups[group].rates[rate];
tmp_prob_ewma = mrs->prob_ewma;
/* do not account throughput if sucess prob is below 10% */ /* do not account throughput if sucess prob is below 10% */
if (mrs->prob_ewma < MINSTREL_FRAC(10, 100)) if (prob_ewma < MINSTREL_FRAC(10, 100))
return 0; return 0;
/*
* For the throughput calculation, limit the probability value to 90% to
* account for collision related packet error rate fluctuation
*/
if (mrs->prob_ewma > MINSTREL_FRAC(90, 100))
tmp_prob_ewma = MINSTREL_FRAC(90, 100);
if (group != MINSTREL_CCK_GROUP) if (group != MINSTREL_CCK_GROUP)
nsecs = 1000 * mi->overhead / MINSTREL_TRUNC(mi->avg_ampdu_len); nsecs = 1000 * mi->overhead / MINSTREL_TRUNC(mi->avg_ampdu_len);
nsecs += minstrel_mcs_groups[group].duration[rate]; nsecs += minstrel_mcs_groups[group].duration[rate];
/* prob is scaled - see MINSTREL_FRAC above */ /*
return MINSTREL_TRUNC(100000 * ((tmp_prob_ewma * 1000) / nsecs)); * For the throughput calculation, limit the probability value to 90% to
* account for collision related packet error rate fluctuation
* (prob is scaled - see MINSTREL_FRAC above)
*/
if (prob_ewma > MINSTREL_FRAC(90, 100))
return MINSTREL_TRUNC(100000 * ((MINSTREL_FRAC(90, 100) * 1000)
/ nsecs));
else
return MINSTREL_TRUNC(100000 * ((prob_ewma * 1000) / nsecs));
} }
/* /*
...@@ -364,14 +361,15 @@ minstrel_ht_sort_best_tp_rates(struct minstrel_ht_sta *mi, u16 index, ...@@ -364,14 +361,15 @@ minstrel_ht_sort_best_tp_rates(struct minstrel_ht_sta *mi, u16 index,
cur_group = index / MCS_GROUP_RATES; cur_group = index / MCS_GROUP_RATES;
cur_idx = index % MCS_GROUP_RATES; cur_idx = index % MCS_GROUP_RATES;
cur_tp_avg = minstrel_ht_get_tp_avg(mi, cur_group, cur_idx);
cur_prob = mi->groups[cur_group].rates[cur_idx].prob_ewma; cur_prob = mi->groups[cur_group].rates[cur_idx].prob_ewma;
cur_tp_avg = minstrel_ht_get_tp_avg(mi, cur_group, cur_idx, cur_prob);
do { do {
tmp_group = tp_list[j - 1] / MCS_GROUP_RATES; tmp_group = tp_list[j - 1] / MCS_GROUP_RATES;
tmp_idx = tp_list[j - 1] % MCS_GROUP_RATES; tmp_idx = tp_list[j - 1] % MCS_GROUP_RATES;
tmp_tp_avg = minstrel_ht_get_tp_avg(mi, tmp_group, tmp_idx);
tmp_prob = mi->groups[tmp_group].rates[tmp_idx].prob_ewma; tmp_prob = mi->groups[tmp_group].rates[tmp_idx].prob_ewma;
tmp_tp_avg = minstrel_ht_get_tp_avg(mi, tmp_group, tmp_idx,
tmp_prob);
if (cur_tp_avg < tmp_tp_avg || if (cur_tp_avg < tmp_tp_avg ||
(cur_tp_avg == tmp_tp_avg && cur_prob <= tmp_prob)) (cur_tp_avg == tmp_tp_avg && cur_prob <= tmp_prob))
break; break;
...@@ -396,8 +394,8 @@ minstrel_ht_set_best_prob_rate(struct minstrel_ht_sta *mi, u16 index) ...@@ -396,8 +394,8 @@ minstrel_ht_set_best_prob_rate(struct minstrel_ht_sta *mi, u16 index)
struct minstrel_rate_stats *mrs; struct minstrel_rate_stats *mrs;
int tmp_group, tmp_idx, tmp_tp_avg, tmp_prob; int tmp_group, tmp_idx, tmp_tp_avg, tmp_prob;
int max_tp_group, cur_tp_avg, cur_group, cur_idx; int max_tp_group, cur_tp_avg, cur_group, cur_idx;
int max_group_prob_rate_group, max_group_prob_rate_idx; int max_gpr_group, max_gpr_idx;
int max_group_prob_rate_tp_avg; int max_gpr_tp_avg, max_gpr_prob;
cur_group = index / MCS_GROUP_RATES; cur_group = index / MCS_GROUP_RATES;
cur_idx = index % MCS_GROUP_RATES; cur_idx = index % MCS_GROUP_RATES;
...@@ -406,8 +404,8 @@ minstrel_ht_set_best_prob_rate(struct minstrel_ht_sta *mi, u16 index) ...@@ -406,8 +404,8 @@ minstrel_ht_set_best_prob_rate(struct minstrel_ht_sta *mi, u16 index)
tmp_group = mi->max_prob_rate / MCS_GROUP_RATES; tmp_group = mi->max_prob_rate / MCS_GROUP_RATES;
tmp_idx = mi->max_prob_rate % MCS_GROUP_RATES; tmp_idx = mi->max_prob_rate % MCS_GROUP_RATES;
tmp_tp_avg = minstrel_ht_get_tp_avg(mi, tmp_group, tmp_idx);
tmp_prob = mi->groups[tmp_group].rates[tmp_idx].prob_ewma; tmp_prob = mi->groups[tmp_group].rates[tmp_idx].prob_ewma;
tmp_tp_avg = minstrel_ht_get_tp_avg(mi, tmp_group, tmp_idx, tmp_prob);
/* if max_tp_rate[0] is from MCS_GROUP max_prob_rate get selected from /* if max_tp_rate[0] is from MCS_GROUP max_prob_rate get selected from
* MCS_GROUP as well as CCK_GROUP rates do not allow aggregation */ * 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,18 +415,18 @@ minstrel_ht_set_best_prob_rate(struct minstrel_ht_sta *mi, u16 index)
return; return;
if (mrs->prob_ewma > MINSTREL_FRAC(75, 100)) { if (mrs->prob_ewma > MINSTREL_FRAC(75, 100)) {
cur_tp_avg = minstrel_ht_get_tp_avg(mi, cur_group, cur_idx); cur_tp_avg = minstrel_ht_get_tp_avg(mi, cur_group, cur_idx,
mrs->prob_ewma);
if (cur_tp_avg > tmp_tp_avg) if (cur_tp_avg > tmp_tp_avg)
mi->max_prob_rate = index; mi->max_prob_rate = index;
max_group_prob_rate_group = mg->max_group_prob_rate / max_gpr_group = mg->max_group_prob_rate / MCS_GROUP_RATES;
MCS_GROUP_RATES; max_gpr_idx = mg->max_group_prob_rate % MCS_GROUP_RATES;
max_group_prob_rate_idx = mg->max_group_prob_rate % max_gpr_prob = mi->groups[max_gpr_group].rates[max_gpr_idx].prob_ewma;
MCS_GROUP_RATES; max_gpr_tp_avg = minstrel_ht_get_tp_avg(mi, max_gpr_group,
max_group_prob_rate_tp_avg = minstrel_ht_get_tp_avg(mi, max_gpr_idx,
max_group_prob_rate_group, max_gpr_prob);
max_group_prob_rate_idx); if (cur_tp_avg > max_gpr_tp_avg)
if (cur_tp_avg > max_group_prob_rate_tp_avg)
mg->max_group_prob_rate = index; mg->max_group_prob_rate = index;
} else { } else {
if (mrs->prob_ewma > tmp_prob) if (mrs->prob_ewma > tmp_prob)
...@@ -450,16 +448,18 @@ minstrel_ht_assign_best_tp_rates(struct minstrel_ht_sta *mi, ...@@ -450,16 +448,18 @@ minstrel_ht_assign_best_tp_rates(struct minstrel_ht_sta *mi,
u16 tmp_mcs_tp_rate[MAX_THR_RATES], u16 tmp_mcs_tp_rate[MAX_THR_RATES],
u16 tmp_cck_tp_rate[MAX_THR_RATES]) u16 tmp_cck_tp_rate[MAX_THR_RATES])
{ {
unsigned int tmp_group, tmp_idx, tmp_cck_tp, tmp_mcs_tp; unsigned int tmp_group, tmp_idx, tmp_cck_tp, tmp_mcs_tp, tmp_prob;
int i; int i;
tmp_group = tmp_cck_tp_rate[0] / MCS_GROUP_RATES; tmp_group = tmp_cck_tp_rate[0] / MCS_GROUP_RATES;
tmp_idx = tmp_cck_tp_rate[0] % MCS_GROUP_RATES; tmp_idx = tmp_cck_tp_rate[0] % MCS_GROUP_RATES;
tmp_cck_tp = minstrel_ht_get_tp_avg(mi, tmp_group, tmp_idx); tmp_prob = mi->groups[tmp_group].rates[tmp_idx].prob_ewma;
tmp_cck_tp = minstrel_ht_get_tp_avg(mi, tmp_group, tmp_idx, tmp_prob);
tmp_group = tmp_mcs_tp_rate[0] / MCS_GROUP_RATES; tmp_group = tmp_mcs_tp_rate[0] / MCS_GROUP_RATES;
tmp_idx = tmp_mcs_tp_rate[0] % MCS_GROUP_RATES; tmp_idx = tmp_mcs_tp_rate[0] % MCS_GROUP_RATES;
tmp_mcs_tp = minstrel_ht_get_tp_avg(mi, tmp_group, tmp_idx); tmp_prob = mi->groups[tmp_group].rates[tmp_idx].prob_ewma;
tmp_mcs_tp = minstrel_ht_get_tp_avg(mi, tmp_group, tmp_idx, tmp_prob);
if (tmp_cck_tp > tmp_mcs_tp) { if (tmp_cck_tp > tmp_mcs_tp) {
for(i = 0; i < MAX_THR_RATES; i++) { for(i = 0; i < MAX_THR_RATES; i++) {
...@@ -478,7 +478,7 @@ static inline void ...@@ -478,7 +478,7 @@ static inline void
minstrel_ht_prob_rate_reduce_streams(struct minstrel_ht_sta *mi) minstrel_ht_prob_rate_reduce_streams(struct minstrel_ht_sta *mi)
{ {
struct minstrel_mcs_group_data *mg; struct minstrel_mcs_group_data *mg;
int tmp_max_streams, group, tmp_idx; int tmp_max_streams, group, tmp_idx, tmp_prob;
int tmp_tp = 0; int tmp_tp = 0;
tmp_max_streams = minstrel_mcs_groups[mi->max_tp_rate[0] / 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,12 +489,14 @@ minstrel_ht_prob_rate_reduce_streams(struct minstrel_ht_sta *mi)
continue; continue;
tmp_idx = mg->max_group_prob_rate % MCS_GROUP_RATES; tmp_idx = mg->max_group_prob_rate % MCS_GROUP_RATES;
tmp_prob = mi->groups[group].rates[tmp_idx].prob_ewma;
if (tmp_tp < minstrel_ht_get_tp_avg(mi, group, tmp_idx) && if (tmp_tp < minstrel_ht_get_tp_avg(mi, group, tmp_idx, tmp_prob) &&
(minstrel_mcs_groups[group].streams < tmp_max_streams)) { (minstrel_mcs_groups[group].streams < tmp_max_streams)) {
mi->max_prob_rate = mg->max_group_prob_rate; mi->max_prob_rate = mg->max_group_prob_rate;
tmp_tp = minstrel_ht_get_tp_avg(mi, group, tmp_tp = minstrel_ht_get_tp_avg(mi, group,
tmp_idx); tmp_idx,
tmp_prob);
} }
} }
} }
...@@ -513,7 +515,7 @@ minstrel_ht_update_stats(struct minstrel_priv *mp, struct minstrel_ht_sta *mi) ...@@ -513,7 +515,7 @@ minstrel_ht_update_stats(struct minstrel_priv *mp, struct minstrel_ht_sta *mi)
{ {
struct minstrel_mcs_group_data *mg; struct minstrel_mcs_group_data *mg;
struct minstrel_rate_stats *mrs; struct minstrel_rate_stats *mrs;
int group, i, j; int group, i, j, cur_prob;
u16 tmp_mcs_tp_rate[MAX_THR_RATES], tmp_group_tp_rate[MAX_THR_RATES]; u16 tmp_mcs_tp_rate[MAX_THR_RATES], tmp_group_tp_rate[MAX_THR_RATES];
u16 tmp_cck_tp_rate[MAX_THR_RATES], index; u16 tmp_cck_tp_rate[MAX_THR_RATES], index;
...@@ -555,8 +557,9 @@ minstrel_ht_update_stats(struct minstrel_priv *mp, struct minstrel_ht_sta *mi) ...@@ -555,8 +557,9 @@ minstrel_ht_update_stats(struct minstrel_priv *mp, struct minstrel_ht_sta *mi)
mrs = &mg->rates[i]; mrs = &mg->rates[i];
mrs->retry_updated = false; mrs->retry_updated = false;
minstrel_calc_rate_stats(mrs); minstrel_calc_rate_stats(mrs);
cur_prob = mrs->prob_ewma;
if (minstrel_ht_get_tp_avg(mi, group, i) == 0) if (minstrel_ht_get_tp_avg(mi, group, i, cur_prob) == 0)
continue; continue;
/* Find max throughput rate set */ /* Find max throughput rate set */
...@@ -1315,16 +1318,17 @@ static u32 minstrel_ht_get_expected_throughput(void *priv_sta) ...@@ -1315,16 +1318,17 @@ static u32 minstrel_ht_get_expected_throughput(void *priv_sta)
{ {
struct minstrel_ht_sta_priv *msp = priv_sta; struct minstrel_ht_sta_priv *msp = priv_sta;
struct minstrel_ht_sta *mi = &msp->ht; struct minstrel_ht_sta *mi = &msp->ht;
int i, j, tp_avg; int i, j, prob, tp_avg;
if (!msp->is_ht) if (!msp->is_ht)
return mac80211_minstrel.get_expected_throughput(priv_sta); return mac80211_minstrel.get_expected_throughput(priv_sta);
i = mi->max_tp_rate[0] / MCS_GROUP_RATES; i = mi->max_tp_rate[0] / MCS_GROUP_RATES;
j = mi->max_tp_rate[0] % MCS_GROUP_RATES; j = mi->max_tp_rate[0] % MCS_GROUP_RATES;
prob = mi->groups[i].rates[j].prob_ewma;
/* convert tp_avg from pkt per second in kbps */ /* convert tp_avg from pkt per second in kbps */
tp_avg = minstrel_ht_get_tp_avg(mi, i, j) * AVG_PKT_SIZE * 8 / 1024; tp_avg = minstrel_ht_get_tp_avg(mi, i, j, prob) * AVG_PKT_SIZE * 8 / 1024;
return tp_avg; return tp_avg;
} }
......
...@@ -121,6 +121,7 @@ struct minstrel_ht_sta_priv { ...@@ -121,6 +121,7 @@ struct minstrel_ht_sta_priv {
void minstrel_ht_add_sta_debugfs(void *priv, void *priv_sta, struct dentry *dir); void minstrel_ht_add_sta_debugfs(void *priv, void *priv_sta, struct dentry *dir);
void minstrel_ht_remove_sta_debugfs(void *priv, void *priv_sta); void minstrel_ht_remove_sta_debugfs(void *priv, void *priv_sta);
int minstrel_ht_get_tp_avg(struct minstrel_ht_sta *mi, int group, int rate); int minstrel_ht_get_tp_avg(struct minstrel_ht_sta *mi, int group, int rate,
int prob_ewma);
#endif #endif
...@@ -19,7 +19,7 @@ static char * ...@@ -19,7 +19,7 @@ static char *
minstrel_ht_stats_dump(struct minstrel_ht_sta *mi, int i, char *p) minstrel_ht_stats_dump(struct minstrel_ht_sta *mi, int i, char *p)
{ {
const struct mcs_group *mg; const struct mcs_group *mg;
unsigned int j, tp_avg, prob, eprob, tx_time; unsigned int j, tp_max, tp_avg, prob, eprob, tx_time;
char htmode = '2'; char htmode = '2';
char gimode = 'L'; char gimode = 'L';
u32 gflags; u32 gflags;
...@@ -79,14 +79,16 @@ minstrel_ht_stats_dump(struct minstrel_ht_sta *mi, int i, char *p) ...@@ -79,14 +79,16 @@ minstrel_ht_stats_dump(struct minstrel_ht_sta *mi, int i, char *p)
/* tx_time[rate(i)] in usec */ /* tx_time[rate(i)] in usec */
tx_time = DIV_ROUND_CLOSEST(mg->duration[j], 1000); tx_time = DIV_ROUND_CLOSEST(mg->duration[j], 1000);
p += sprintf(p, "%6u ", tx_time); p += sprintf(p, "%6u ", tx_time);
tp_avg = minstrel_ht_get_tp_avg(mi, i, j); 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);
prob = MINSTREL_TRUNC(mrs->cur_prob * 1000); prob = MINSTREL_TRUNC(mrs->cur_prob * 1000);
eprob = MINSTREL_TRUNC(mrs->prob_ewma * 1000); eprob = MINSTREL_TRUNC(mrs->prob_ewma * 1000);
p += sprintf(p, "%4u.%1u %3u.%1u %3u.%1u " p += sprintf(p, "%4u.%1u %4u.%1u %3u.%1u %3u.%1u "
"%3u %3u %-3u %9llu %-9llu\n", "%3u %3u %-3u %9llu %-9llu\n",
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,
prob / 10, prob % 10, prob / 10, prob % 10,
...@@ -125,11 +127,11 @@ minstrel_ht_stats_open(struct inode *inode, struct file *file) ...@@ -125,11 +127,11 @@ minstrel_ht_stats_open(struct inode *inode, struct file *file)
p = ms->buf; p = ms->buf;
p += sprintf(p, "\n"); p += sprintf(p, "\n");
p += sprintf(p, " best ________rate______ " p += sprintf(p, " best ____________rate__________ "
"__statistics__ ________last_______ " "__statistics__ ________last_______ "
"______sum-of________\n"); "______sum-of________\n");
p += sprintf(p, "mode guard # rate [name idx airtime] [ ø(tp) " p += sprintf(p, "mode guard # rate [name idx airtime max_tp] "
"ø(prob)] [prob.|retry|suc|att] [#success | " "[ ø(tp) ø(prob)] [prob.|retry|suc|att] [#success | "
"#attempts]\n"); "#attempts]\n");
p = minstrel_ht_stats_dump(mi, MINSTREL_CCK_GROUP, p); p = minstrel_ht_stats_dump(mi, MINSTREL_CCK_GROUP, p);
...@@ -163,7 +165,7 @@ static char * ...@@ -163,7 +165,7 @@ static char *
minstrel_ht_stats_csv_dump(struct minstrel_ht_sta *mi, int i, char *p) minstrel_ht_stats_csv_dump(struct minstrel_ht_sta *mi, int i, char *p)
{ {
const struct mcs_group *mg; const struct mcs_group *mg;
unsigned int j, tp_avg, prob, eprob, tx_time; unsigned int j, tp_max, tp_avg, prob, eprob, tx_time;
char htmode = '2'; char htmode = '2';
char gimode = 'L'; char gimode = 'L';
u32 gflags; u32 gflags;
...@@ -222,11 +224,13 @@ minstrel_ht_stats_csv_dump(struct minstrel_ht_sta *mi, int i, char *p) ...@@ -222,11 +224,13 @@ minstrel_ht_stats_csv_dump(struct minstrel_ht_sta *mi, int i, char *p)
tx_time = DIV_ROUND_CLOSEST(mg->duration[j], 1000); tx_time = DIV_ROUND_CLOSEST(mg->duration[j], 1000);
p += sprintf(p, "%u,", tx_time); p += sprintf(p, "%u,", tx_time);
tp_avg = minstrel_ht_get_tp_avg(mi, i, j); 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);
prob = MINSTREL_TRUNC(mrs->cur_prob * 1000); prob = MINSTREL_TRUNC(mrs->cur_prob * 1000);
eprob = MINSTREL_TRUNC(mrs->prob_ewma * 1000); eprob = MINSTREL_TRUNC(mrs->prob_ewma * 1000);
p += sprintf(p, "%u.%u,%u.%u,%u.%u,%u,%u,%u,%llu,%llu,", p += sprintf(p, "%u.%u,%u.%u,%u.%u,%u.%u,%u,%u,%u,%llu,%llu,",
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,
prob / 10, prob % 10, prob / 10, prob % 10,
......
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