2015-02-13 14:58:04

by Thomas Huehn

[permalink] [raw]
Subject: [PATCH v2 0/10] Improve Minstrels & Minstrel-HTs common code base & statistics

This patch series adds several improvements to the readability, the
output format of rc_stats and the calculated statistics of Minstrel
and Minstrel-HT. Variable names got more consistent and functions
got unified between both rate control algorithms.

Greetings Thomas

---
Changes in v2:
- fix define MACRO from CPTCFG_* into CONFIG_*
- change standard deviation symbol sigma into "sd"

[PATCH v2 01/10] mac80211: enhance readability of Minstrels rc_stats
[PATCH v2 02/10] mac80211: enhance readability of Minstrel-HTs
[PATCH v2 03/10] mac80211: add new Minstrel statistic output via csv
[PATCH v2 04/10] mac80211: add new Minstrel-HT statistic output via
[PATCH v2 05/10] mac80211: unify Minstrel & Minstrel-HTs calculation
[PATCH v2 06/10] mac80211: improve Minstrel variable & function
[PATCH v2 07/10] mac80211: restructure per-rate throughput
[PATCH v2 08/10] mac80211: add max. lossless throughput per rate to
[PATCH v2 09/10] mac80211: reduce calculation costs of EWMA
[PATCH v2 10/10] mac80211: add standard deviation to Minstrels


2015-02-13 14:58:06

by Thomas Huehn

[permalink] [raw]
Subject: [PATCH v2 06/10] mac80211: improve Minstrel variable & function naming

This patch ensures a consistent usage of variable names for type
"minstrel_rate_stats" to be used as "mrs" and from type minstrel_rate
as "mr" across both Minstrel & Minstrel-HT. In addition some
variable and function names got changed to more meaningful ones.

Signed-off-by: Thomas Huehn <[email protected]>
---
net/mac80211/rc80211_minstrel.c | 26 +++----
net/mac80211/rc80211_minstrel.h | 13 ++--
net/mac80211/rc80211_minstrel_debugfs.c | 4 +-
net/mac80211/rc80211_minstrel_ht.c | 112 ++++++++++++++---------------
net/mac80211/rc80211_minstrel_ht.h | 2 +-
net/mac80211/rc80211_minstrel_ht_debugfs.c | 36 +++++-----
6 files changed, 98 insertions(+), 95 deletions(-)

diff --git a/net/mac80211/rc80211_minstrel.c b/net/mac80211/rc80211_minstrel.c
index 4858e67..89db6cf 100644
--- a/net/mac80211/rc80211_minstrel.c
+++ b/net/mac80211/rc80211_minstrel.c
@@ -137,9 +137,9 @@ minstrel_calc_rate_stats(struct minstrel_rate_stats *mrs)
mrs->sample_skipped = 0;
mrs->cur_prob = MINSTREL_FRAC(mrs->success, mrs->attempts);
if (unlikely(!mrs->att_hist))
- mrs->probability = mrs->cur_prob;
+ mrs->prob_ewma = mrs->cur_prob;
else
- mrs->probability = minstrel_ewma(mrs->probability,
+ mrs->prob_ewma = minstrel_ewma(mrs->prob_ewma,
mrs->cur_prob, EWMA_LEVEL);
mrs->att_hist += mrs->attempts;
mrs->succ_hist += mrs->success;
@@ -176,15 +176,15 @@ minstrel_update_stats(struct minstrel_priv *mp, struct minstrel_sta_info *mi)
minstrel_calc_rate_stats(mrs);

/* Update throughput per rate, reset thr. below 10% success */
- if (mrs->probability < MINSTREL_FRAC(10, 100))
+ if (mrs->prob_ewma < MINSTREL_FRAC(10, 100))
mrs->cur_tp = 0;
else
- mrs->cur_tp = mrs->probability * (1000000 / usecs);
+ mrs->cur_tp = mrs->prob_ewma * (1000000 / usecs);

/* Sample less often below the 10% chance of success.
* Sample less often above the 95% chance of success. */
- if (mrs->probability > MINSTREL_FRAC(95, 100) ||
- mrs->probability < MINSTREL_FRAC(10, 100)) {
+ if (mrs->prob_ewma > MINSTREL_FRAC(95, 100) ||
+ mrs->prob_ewma < MINSTREL_FRAC(10, 100)) {
mr->adjusted_retry_count = mrs->retry_count >> 1;
if (mr->adjusted_retry_count > 2)
mr->adjusted_retry_count = 2;
@@ -204,11 +204,11 @@ minstrel_update_stats(struct minstrel_priv *mp, struct minstrel_sta_info *mi)
* choose the maximum throughput rate as max_prob_rate
* (2) if all success probabilities < 95%, the rate with
* highest success probability is chosen as max_prob_rate */
- if (mrs->probability >= MINSTREL_FRAC(95, 100)) {
+ if (mrs->prob_ewma >= MINSTREL_FRAC(95, 100)) {
if (mrs->cur_tp >= mi->r[tmp_prob_rate].stats.cur_tp)
tmp_prob_rate = i;
} else {
- if (mrs->probability >= mi->r[tmp_prob_rate].stats.probability)
+ if (mrs->prob_ewma >= mi->r[tmp_prob_rate].stats.prob_ewma)
tmp_prob_rate = i;
}
}
@@ -227,7 +227,7 @@ minstrel_update_stats(struct minstrel_priv *mp, struct minstrel_sta_info *mi)
#endif

/* Reset update timer */
- mi->stats_update = jiffies;
+ mi->last_stats_update = jiffies;

minstrel_update_rates(mp, mi);
}
@@ -265,7 +265,7 @@ minstrel_tx_status(void *priv, struct ieee80211_supported_band *sband,
if (mi->sample_deferred > 0)
mi->sample_deferred--;

- if (time_after(jiffies, mi->stats_update +
+ if (time_after(jiffies, mi->last_stats_update +
(mp->update_interval * HZ) / 1000))
minstrel_update_stats(mp, mi);
}
@@ -397,7 +397,7 @@ minstrel_get_rate(void *priv, struct ieee80211_sta *sta,
* has a probability of >95%, we shouldn't be attempting
* to use it, as this only wastes precious airtime */
if (!mrr_capable &&
- (mi->r[ndx].stats.probability > MINSTREL_FRAC(95, 100)))
+ (mi->r[ndx].stats.prob_ewma > MINSTREL_FRAC(95, 100)))
return;

mi->prev_sample = true;
@@ -531,7 +531,7 @@ minstrel_rate_init(void *priv, struct ieee80211_supported_band *sband,
}

mi->n_rates = n;
- mi->stats_update = jiffies;
+ mi->last_stats_update = jiffies;

init_sample_table(mi);
minstrel_update_rates(mp, mi);
@@ -565,7 +565,7 @@ minstrel_alloc_sta(void *priv, struct ieee80211_sta *sta, gfp_t gfp)
if (!mi->sample_table)
goto error1;

- mi->stats_update = jiffies;
+ mi->last_stats_update = jiffies;
return mi;

error1:
diff --git a/net/mac80211/rc80211_minstrel.h b/net/mac80211/rc80211_minstrel.h
index 728144c..58f2870 100644
--- a/net/mac80211/rc80211_minstrel.h
+++ b/net/mac80211/rc80211_minstrel.h
@@ -38,11 +38,14 @@ struct minstrel_rate_stats {
/* total attempts/success counters */
u64 att_hist, succ_hist;

- /* current throughput */
+ /* current EWMA of rate throughput */
unsigned int cur_tp;

- /* packet delivery probabilities */
- unsigned int cur_prob, probability;
+ /* statistis of packet delivery probability
+ * cur_prob - current prob within last update intervall
+ * prob_ewma - exponential weighted moving average of prob */
+ unsigned int cur_prob;
+ unsigned int prob_ewma;

/* maximum retry counts */
u8 retry_count;
@@ -70,7 +73,7 @@ struct minstrel_rate {
struct minstrel_sta_info {
struct ieee80211_sta *sta;

- unsigned long stats_update;
+ unsigned long last_stats_update;
unsigned int sp_ack_dur;
unsigned int rate_avg;

@@ -133,7 +136,7 @@ void minstrel_add_sta_debugfs(void *priv, void *priv_sta, struct dentry *dir);
void minstrel_remove_sta_debugfs(void *priv, void *priv_sta);

/* Recalculate success probabilities and counters for a given rate using EWMA */
-void minstrel_calc_rate_stats(struct minstrel_rate_stats *mr);
+void minstrel_calc_rate_stats(struct minstrel_rate_stats *mrs);

/* debugfs */
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 ab15ca6..c0a04e1 100644
--- a/net/mac80211/rc80211_minstrel_debugfs.c
+++ b/net/mac80211/rc80211_minstrel_debugfs.c
@@ -107,7 +107,7 @@ minstrel_stats_open(struct inode *inode, struct file *file)

tp = MINSTREL_TRUNC(mrs->cur_tp / 10);
prob = MINSTREL_TRUNC(mrs->cur_prob * 1000);
- eprob = MINSTREL_TRUNC(mrs->probability * 1000);
+ eprob = MINSTREL_TRUNC(mrs->prob_ewma * 1000);

p += sprintf(p, " %4u.%1u %3u.%1u %3u.%1u %3u"
" %3u %-3u %9llu %-9llu\n",
@@ -175,7 +175,7 @@ minstrel_stats_csv_open(struct inode *inode, struct file *file)

tp = MINSTREL_TRUNC(mrs->cur_tp / 10);
prob = MINSTREL_TRUNC(mrs->cur_prob * 1000);
- eprob = MINSTREL_TRUNC(mrs->probability * 1000);
+ eprob = MINSTREL_TRUNC(mrs->prob_ewma * 1000);

p += sprintf(p, "%u.%u,%u.%u,%u.%u,%u,%u,%u,"
"%llu,%llu,%d,%d\n",
diff --git a/net/mac80211/rc80211_minstrel_ht.c b/net/mac80211/rc80211_minstrel_ht.c
index 381d089..6b07686 100644
--- a/net/mac80211/rc80211_minstrel_ht.c
+++ b/net/mac80211/rc80211_minstrel_ht.c
@@ -318,16 +318,16 @@ minstrel_get_ratestats(struct minstrel_ht_sta *mi, int index)
static void
minstrel_ht_calc_tp(struct minstrel_ht_sta *mi, int group, int rate)
{
- struct minstrel_rate_stats *mr;
+ struct minstrel_rate_stats *mrs;
unsigned int nsecs = 0;
- unsigned int tp;
- unsigned int prob;
+ unsigned int tmp_prob_ewma;

- mr = &mi->groups[group].rates[rate];
- prob = mr->probability;
+ mrs = &mi->groups[group].rates[rate];
+ tmp_prob_ewma = mrs->prob_ewma;

- if (prob < MINSTREL_FRAC(1, 10)) {
- mr->cur_tp = 0;
+ /* do not account throughput if sucess prob is below 10% */
+ if (mrs->prob_ewma < MINSTREL_FRAC(10, 100)) {
+ mrs->cur_tp = 0;
return;
}

@@ -335,8 +335,8 @@ minstrel_ht_calc_tp(struct minstrel_ht_sta *mi, int group, int rate)
* For the throughput calculation, limit the probability value to 90% to
* account for collision related packet error rate fluctuation
*/
- if (prob > MINSTREL_FRAC(9, 10))
- prob = MINSTREL_FRAC(9, 10);
+ if (mrs->prob_ewma > MINSTREL_FRAC(90, 100))
+ tmp_prob_ewma = MINSTREL_FRAC(90, 100);

if (group != MINSTREL_CCK_GROUP)
nsecs = 1000 * mi->overhead / MINSTREL_TRUNC(mi->avg_ampdu_len);
@@ -344,8 +344,7 @@ minstrel_ht_calc_tp(struct minstrel_ht_sta *mi, int group, int rate)
nsecs += minstrel_mcs_groups[group].duration[rate];

/* prob is scaled - see MINSTREL_FRAC above */
- tp = 1000000 * ((prob * 1000) / nsecs);
- mr->cur_tp = MINSTREL_TRUNC(tp);
+ mrs->cur_tp = MINSTREL_TRUNC(1000000 * ((tmp_prob_ewma * 1000) / nsecs));
}

/*
@@ -366,13 +365,13 @@ minstrel_ht_sort_best_tp_rates(struct minstrel_ht_sta *mi, u16 index,
cur_group = index / MCS_GROUP_RATES;
cur_idx = index % MCS_GROUP_RATES;
cur_thr = mi->groups[cur_group].rates[cur_idx].cur_tp;
- cur_prob = mi->groups[cur_group].rates[cur_idx].probability;
+ cur_prob = mi->groups[cur_group].rates[cur_idx].prob_ewma;

do {
tmp_group = tp_list[j - 1] / MCS_GROUP_RATES;
tmp_idx = tp_list[j - 1] % MCS_GROUP_RATES;
tmp_thr = mi->groups[tmp_group].rates[tmp_idx].cur_tp;
- tmp_prob = mi->groups[tmp_group].rates[tmp_idx].probability;
+ tmp_prob = mi->groups[tmp_group].rates[tmp_idx].prob_ewma;
if (cur_thr < tmp_thr ||
(cur_thr == tmp_thr && cur_prob <= tmp_prob))
break;
@@ -394,16 +393,16 @@ static void
minstrel_ht_set_best_prob_rate(struct minstrel_ht_sta *mi, u16 index)
{
struct minstrel_mcs_group_data *mg;
- struct minstrel_rate_stats *mr;
+ struct minstrel_rate_stats *mrs;
int tmp_group, tmp_idx, tmp_tp, tmp_prob, max_tp_group;

mg = &mi->groups[index / MCS_GROUP_RATES];
- mr = &mg->rates[index % MCS_GROUP_RATES];
+ mrs = &mg->rates[index % MCS_GROUP_RATES];

tmp_group = mi->max_prob_rate / MCS_GROUP_RATES;
tmp_idx = mi->max_prob_rate % MCS_GROUP_RATES;
tmp_tp = mi->groups[tmp_group].rates[tmp_idx].cur_tp;
- tmp_prob = mi->groups[tmp_group].rates[tmp_idx].probability;
+ tmp_prob = mi->groups[tmp_group].rates[tmp_idx].prob_ewma;

/* 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 */
@@ -412,15 +411,15 @@ minstrel_ht_set_best_prob_rate(struct minstrel_ht_sta *mi, u16 index)
(max_tp_group != MINSTREL_CCK_GROUP))
return;

- if (mr->probability > MINSTREL_FRAC(75, 100)) {
- if (mr->cur_tp > tmp_tp)
+ if (mrs->prob_ewma > MINSTREL_FRAC(75, 100)) {
+ if (mrs->cur_tp > tmp_tp)
mi->max_prob_rate = index;
- if (mr->cur_tp > mg->rates[mg->max_group_prob_rate].cur_tp)
+ if (mrs->cur_tp > mg->rates[mg->max_group_prob_rate].cur_tp)
mg->max_group_prob_rate = index;
} else {
- if (mr->probability > tmp_prob)
+ if (mrs->prob_ewma > tmp_prob)
mi->max_prob_rate = index;
- if (mr->probability > mg->rates[mg->max_group_prob_rate].probability)
+ if (mrs->prob_ewma > mg->rates[mg->max_group_prob_rate].prob_ewma)
mg->max_group_prob_rate = index;
}
}
@@ -465,7 +464,7 @@ static inline void
minstrel_ht_prob_rate_reduce_streams(struct minstrel_ht_sta *mi)
{
struct minstrel_mcs_group_data *mg;
- struct minstrel_rate_stats *mr;
+ struct minstrel_rate_stats *mrs;
int tmp_max_streams, group;
int tmp_tp = 0;

@@ -475,11 +474,11 @@ minstrel_ht_prob_rate_reduce_streams(struct minstrel_ht_sta *mi)
mg = &mi->groups[group];
if (!mg->supported || group == MINSTREL_CCK_GROUP)
continue;
- mr = minstrel_get_ratestats(mi, mg->max_group_prob_rate);
- if (tmp_tp < mr->cur_tp &&
+ mrs = minstrel_get_ratestats(mi, mg->max_group_prob_rate);
+ if (tmp_tp < mrs->cur_tp &&
(minstrel_mcs_groups[group].streams < tmp_max_streams)) {
mi->max_prob_rate = mg->max_group_prob_rate;
- tmp_tp = mr->cur_tp;
+ tmp_tp = mrs->cur_tp;
}
}
}
@@ -497,7 +496,7 @@ static void
minstrel_ht_update_stats(struct minstrel_priv *mp, struct minstrel_ht_sta *mi)
{
struct minstrel_mcs_group_data *mg;
- struct minstrel_rate_stats *mr;
+ struct minstrel_rate_stats *mrs;
int group, i, j;
u16 tmp_mcs_tp_rate[MAX_THR_RATES], tmp_group_tp_rate[MAX_THR_RATES];
u16 tmp_cck_tp_rate[MAX_THR_RATES], index;
@@ -537,12 +536,12 @@ minstrel_ht_update_stats(struct minstrel_priv *mp, struct minstrel_ht_sta *mi)

index = MCS_GROUP_RATES * group + i;

- mr = &mg->rates[i];
- mr->retry_updated = false;
- minstrel_calc_rate_stats(mr);
+ mrs = &mg->rates[i];
+ mrs->retry_updated = false;
+ minstrel_calc_rate_stats(mrs);
minstrel_ht_calc_tp(mi, group, i);

- if (!mr->cur_tp)
+ if (!mrs->cur_tp)
continue;

/* Find max throughput rate set */
@@ -586,7 +585,7 @@ minstrel_ht_update_stats(struct minstrel_priv *mp, struct minstrel_ht_sta *mi)
#endif

/* Reset update timer */
- mi->stats_update = jiffies;
+ mi->last_stats_update = jiffies;
}

static bool
@@ -609,7 +608,7 @@ minstrel_ht_txstat_valid(struct minstrel_priv *mp, struct ieee80211_tx_rate *rat
}

static void
-minstrel_next_sample_idx(struct minstrel_ht_sta *mi)
+minstrel_set_next_sample_idx(struct minstrel_ht_sta *mi)
{
struct minstrel_mcs_group_data *mg;

@@ -750,7 +749,8 @@ minstrel_ht_tx_status(void *priv, struct ieee80211_supported_band *sband,
update = true;
}

- if (time_after(jiffies, mi->stats_update + (mp->update_interval / 2 * HZ) / 1000)) {
+ if (time_after(jiffies, mi->last_stats_update +
+ (mp->update_interval / 2 * HZ) / 1000)) {
update = true;
minstrel_ht_update_stats(mp, mi);
}
@@ -763,7 +763,7 @@ static void
minstrel_calc_retransmit(struct minstrel_priv *mp, struct minstrel_ht_sta *mi,
int index)
{
- struct minstrel_rate_stats *mr;
+ struct minstrel_rate_stats *mrs;
const struct mcs_group *group;
unsigned int tx_time, tx_time_rtscts, tx_time_data;
unsigned int cw = mp->cw_min;
@@ -772,16 +772,16 @@ minstrel_calc_retransmit(struct minstrel_priv *mp, struct minstrel_ht_sta *mi,
unsigned int ampdu_len = MINSTREL_TRUNC(mi->avg_ampdu_len);
unsigned int overhead = 0, overhead_rtscts = 0;

- mr = minstrel_get_ratestats(mi, index);
- if (mr->probability < MINSTREL_FRAC(1, 10)) {
- mr->retry_count = 1;
- mr->retry_count_rtscts = 1;
+ mrs = minstrel_get_ratestats(mi, index);
+ if (mrs->prob_ewma < MINSTREL_FRAC(1, 10)) {
+ mrs->retry_count = 1;
+ mrs->retry_count_rtscts = 1;
return;
}

- mr->retry_count = 2;
- mr->retry_count_rtscts = 2;
- mr->retry_updated = true;
+ mrs->retry_count = 2;
+ mrs->retry_count_rtscts = 2;
+ mrs->retry_updated = true;

group = &minstrel_mcs_groups[index / MCS_GROUP_RATES];
tx_time_data = group->duration[index % MCS_GROUP_RATES] * ampdu_len / 1000;
@@ -812,9 +812,9 @@ minstrel_calc_retransmit(struct minstrel_priv *mp, struct minstrel_ht_sta *mi,
tx_time_rtscts += ctime + overhead_rtscts + tx_time_data;

if (tx_time_rtscts < mp->segment_size)
- mr->retry_count_rtscts++;
+ mrs->retry_count_rtscts++;
} while ((tx_time < mp->segment_size) &&
- (++mr->retry_count < mp->max_retry));
+ (++mrs->retry_count < mp->max_retry));
}


@@ -823,22 +823,22 @@ minstrel_ht_set_rate(struct minstrel_priv *mp, struct minstrel_ht_sta *mi,
struct ieee80211_sta_rates *ratetbl, int offset, int index)
{
const struct mcs_group *group = &minstrel_mcs_groups[index / MCS_GROUP_RATES];
- struct minstrel_rate_stats *mr;
+ struct minstrel_rate_stats *mrs;
u8 idx;
u16 flags = group->flags;

- mr = minstrel_get_ratestats(mi, index);
- if (!mr->retry_updated)
+ mrs = minstrel_get_ratestats(mi, index);
+ if (!mrs->retry_updated)
minstrel_calc_retransmit(mp, mi, index);

- if (mr->probability < MINSTREL_FRAC(20, 100) || !mr->retry_count) {
+ if (mrs->prob_ewma < MINSTREL_FRAC(20, 100) || !mrs->retry_count) {
ratetbl->rate[offset].count = 2;
ratetbl->rate[offset].count_rts = 2;
ratetbl->rate[offset].count_cts = 2;
} else {
- ratetbl->rate[offset].count = mr->retry_count;
- ratetbl->rate[offset].count_cts = mr->retry_count;
- ratetbl->rate[offset].count_rts = mr->retry_count_rtscts;
+ ratetbl->rate[offset].count = mrs->retry_count;
+ ratetbl->rate[offset].count_cts = mrs->retry_count;
+ ratetbl->rate[offset].count_rts = mrs->retry_count_rtscts;
}

if (index / MCS_GROUP_RATES == MINSTREL_CCK_GROUP)
@@ -896,7 +896,7 @@ minstrel_get_duration(int index)
static int
minstrel_get_sample_rate(struct minstrel_priv *mp, struct minstrel_ht_sta *mi)
{
- struct minstrel_rate_stats *mr;
+ struct minstrel_rate_stats *mrs;
struct minstrel_mcs_group_data *mg;
unsigned int sample_dur, sample_group, cur_max_tp_streams;
int sample_idx = 0;
@@ -912,12 +912,12 @@ minstrel_get_sample_rate(struct minstrel_priv *mp, struct minstrel_ht_sta *mi)
sample_group = mi->sample_group;
mg = &mi->groups[sample_group];
sample_idx = sample_table[mg->column][mg->index];
- minstrel_next_sample_idx(mi);
+ minstrel_set_next_sample_idx(mi);

if (!(mg->supported & BIT(sample_idx)))
return -1;

- mr = &mg->rates[sample_idx];
+ mrs = &mg->rates[sample_idx];
sample_idx += sample_group * MCS_GROUP_RATES;

/*
@@ -934,7 +934,7 @@ minstrel_get_sample_rate(struct minstrel_priv *mp, struct minstrel_ht_sta *mi)
* Do not sample if the probability is already higher than 95%
* to avoid wasting airtime.
*/
- if (mr->probability > MINSTREL_FRAC(95, 100))
+ if (mrs->prob_ewma > MINSTREL_FRAC(95, 100))
return -1;

/*
@@ -949,7 +949,7 @@ minstrel_get_sample_rate(struct minstrel_priv *mp, struct minstrel_ht_sta *mi)
(cur_max_tp_streams - 1 <
minstrel_mcs_groups[sample_group].streams ||
sample_dur >= minstrel_get_duration(mi->max_prob_rate))) {
- if (mr->sample_skipped < 20)
+ if (mrs->sample_skipped < 20)
return -1;

if (mi->sample_slow++ > 2)
@@ -1103,7 +1103,7 @@ minstrel_ht_update_caps(void *priv, struct ieee80211_supported_band *sband,
memset(mi, 0, sizeof(*mi));

mi->sta = sta;
- mi->stats_update = jiffies;
+ mi->last_stats_update = jiffies;

ack_dur = ieee80211_frame_duration(sband->band, 10, 60, 1, 1, 0);
mi->overhead = ieee80211_frame_duration(sband->band, 0, 60, 1, 1, 0);
diff --git a/net/mac80211/rc80211_minstrel_ht.h b/net/mac80211/rc80211_minstrel_ht.h
index 3cc30e8..fa21a82 100644
--- a/net/mac80211/rc80211_minstrel_ht.h
+++ b/net/mac80211/rc80211_minstrel_ht.h
@@ -78,7 +78,7 @@ struct minstrel_ht_sta {
u16 max_prob_rate;

/* time of last status update */
- unsigned long stats_update;
+ unsigned long last_stats_update;

/* overhead time in usec for each frame */
unsigned int overhead;
diff --git a/net/mac80211/rc80211_minstrel_ht_debugfs.c b/net/mac80211/rc80211_minstrel_ht_debugfs.c
index ae05780..5529add 100644
--- a/net/mac80211/rc80211_minstrel_ht_debugfs.c
+++ b/net/mac80211/rc80211_minstrel_ht_debugfs.c
@@ -38,7 +38,7 @@ minstrel_ht_stats_dump(struct minstrel_ht_sta *mi, int i, char *p)
gimode = 'S';

for (j = 0; j < MCS_GROUP_RATES; j++) {
- struct minstrel_rate_stats *mr = &mi->groups[i].rates[j];
+ struct minstrel_rate_stats *mrs = &mi->groups[i].rates[j];
static const int bitrates[4] = { 10, 20, 55, 110 };
int idx = i * MCS_GROUP_RATES + j;

@@ -81,20 +81,20 @@ minstrel_ht_stats_dump(struct minstrel_ht_sta *mi, int i, char *p)
tx_time = DIV_ROUND_CLOSEST(mg->duration[j], 1000);
p += sprintf(p, "%6u ", tx_time);

- tp = mr->cur_tp / 10;
- prob = MINSTREL_TRUNC(mr->cur_prob * 1000);
- eprob = MINSTREL_TRUNC(mr->probability * 1000);
+ tp = mrs->cur_tp / 10;
+ prob = MINSTREL_TRUNC(mrs->cur_prob * 1000);
+ eprob = MINSTREL_TRUNC(mrs->prob_ewma * 1000);

p += sprintf(p, "%4u.%1u %3u.%1u %3u.%1u "
"%3u %3u %-3u %9llu %-9llu\n",
tp / 10, tp % 10,
eprob / 10, eprob % 10,
prob / 10, prob % 10,
- mr->retry_count,
- mr->last_success,
- mr->last_attempts,
- (unsigned long long)mr->succ_hist,
- (unsigned long long)mr->att_hist);
+ mrs->retry_count,
+ mrs->last_success,
+ mrs->last_attempts,
+ (unsigned long long)mrs->succ_hist,
+ (unsigned long long)mrs->att_hist);
}

return p;
@@ -183,7 +183,7 @@ minstrel_ht_stats_csv_dump(struct minstrel_ht_sta *mi, int i, char *p,
gimode = 'S';

for (j = 0; j < MCS_GROUP_RATES; j++) {
- struct minstrel_rate_stats *mr = &mi->groups[i].rates[j];
+ struct minstrel_rate_stats *mrs = &mi->groups[i].rates[j];
static const int bitrates[4] = { 10, 20, 55, 110 };
int idx = i * MCS_GROUP_RATES + j;

@@ -225,19 +225,19 @@ minstrel_ht_stats_csv_dump(struct minstrel_ht_sta *mi, int i, char *p,
tx_time = DIV_ROUND_CLOSEST(mg->duration[j], 1000);
p += sprintf(p, "%u,", tx_time);

- tp = mr->cur_tp / 10;
- prob = MINSTREL_TRUNC(mr->cur_prob * 1000);
- eprob = MINSTREL_TRUNC(mr->probability * 1000);
+ tp = mrs->cur_tp / 10;
+ prob = MINSTREL_TRUNC(mrs->cur_prob * 1000);
+ eprob = MINSTREL_TRUNC(mrs->prob_ewma * 1000);

p += sprintf(p, "%u.%u,%u.%u,%u.%u,%u,%u,%u,%llu,%llu,",
tp / 10, tp % 10,
eprob / 10, eprob % 10,
prob / 10, prob % 10,
- mr->retry_count,
- mr->last_success,
- mr->last_attempts,
- (unsigned long long)mr->succ_hist,
- (unsigned long long)mr->att_hist);
+ mrs->retry_count,
+ mrs->last_success,
+ mrs->last_attempts,
+ (unsigned long long)mrs->succ_hist,
+ (unsigned long long)mrs->att_hist);
p += sprintf(p, "%d,%d,%d.%d\n",
max(0, (int) mi->total_packets -
(int) mi->sample_packets),
--
2.2.2


2015-02-13 14:58:04

by Thomas Huehn

[permalink] [raw]
Subject: [PATCH v2 01/10] mac80211: enhance readability of Minstrels rc_stats output

This patch restructures the rc_stats debugfs table of Minstrel in
order to achieve better human readability. A new layout of the
statistics and a new header is added. In addition to the old layout
there are two new columns of information added:
idx - representing the rate index of each rate in mac80211 which
can be used to set specific rates as fixed rate via debugfs
airtime - the tx-time in micro seconds that a 1200 Byte packet
takes to be transmitted over the air at the given rate

The old layout of rc_stats:

rate tpt eprob *prob ret *ok(*cum) ok( cum)
DP 1 0.9 93.5 100.0 1 0( 0) 2( 2)
2 0.4 40.0 100.0 0 0( 0) 4( 10)
5.5 0.0 0.0 0.0 0 0( 0) 0( 0)
...

is changed into this new layout:

best _______rate_____ __statistics__ ________last_______ ______sum-of________
rate [name idx tx-time] [ ø(tp) ø(prob)] [prob.|retry|suc|att] [#success | #attempts]
DP 1 0 9738 0.9 93.5 100.0 1 1 1 2 2
2 1 4922 0.4 40.0 100.0 1 0 0 4 10
5.5 2 1858 0.0 0.0 0.0 2 0 0 0 0
...

Signed-off-by: Thomas Huehn <[email protected]>
Signed-off-by: Stefan Venz <[email protected]>
---
net/mac80211/rc80211_minstrel_debugfs.c | 18 +++++++++++++-----
1 file changed, 13 insertions(+), 5 deletions(-)

diff --git a/net/mac80211/rc80211_minstrel_debugfs.c b/net/mac80211/rc80211_minstrel_debugfs.c
index 2acab1b..2d70081 100644
--- a/net/mac80211/rc80211_minstrel_debugfs.c
+++ b/net/mac80211/rc80211_minstrel_debugfs.c
@@ -68,8 +68,12 @@ minstrel_stats_open(struct inode *inode, struct file *file)

file->private_data = ms;
p = ms->buf;
- p += sprintf(p, "rate tpt eprob *prob"
- " *ok(*cum) ok( cum)\n");
+ p += sprintf(p, "\n");
+ p += sprintf(p, "best _______rate_____ __statistics__ "
+ "________last_______ ______sum-of________\n");
+ p += sprintf(p, "rate [name idx airtime] [ ø(tp) ø(prob)] "
+ "[prob.|retry|suc|att] [#success | #attempts]\n");
+
for (i = 0; i < mi->n_rates; i++) {
struct minstrel_rate *mr = &mi->r[i];
struct minstrel_rate_stats *mrs = &mi->r[i].stats;
@@ -79,18 +83,22 @@ minstrel_stats_open(struct inode *inode, struct file *file)
*(p++) = (i == mi->max_tp_rate[2]) ? 'C' : ' ';
*(p++) = (i == mi->max_tp_rate[3]) ? 'D' : ' ';
*(p++) = (i == mi->max_prob_rate) ? 'P' : ' ';
- p += sprintf(p, "%3u%s", mr->bitrate / 2,
+
+ p += sprintf(p, " %3u%s ", mr->bitrate / 2,
(mr->bitrate & 1 ? ".5" : " "));
+ p += sprintf(p, "%3u ", i);
+ p += sprintf(p, "%6u ", mr->perfect_tx_time);

tp = MINSTREL_TRUNC(mrs->cur_tp / 10);
prob = MINSTREL_TRUNC(mrs->cur_prob * 1000);
eprob = MINSTREL_TRUNC(mrs->probability * 1000);

- p += sprintf(p, " %4u.%1u %3u.%1u %3u.%1u"
- " %4u(%4u) %9llu(%9llu)\n",
+ p += sprintf(p, " %4u.%1u %3u.%1u %3u.%1u %3u"
+ " %3u %-3u %9llu %-9llu\n",
tp / 10, tp % 10,
eprob / 10, eprob % 10,
prob / 10, prob % 10,
+ mrs->retry_count,
mrs->last_success,
mrs->last_attempts,
(unsigned long long)mrs->succ_hist,
--
2.2.2


2015-02-13 14:58:06

by Thomas Huehn

[permalink] [raw]
Subject: [PATCH v2 08/10] mac80211: add max. lossless throughput per rate to rc_stats

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]>
---
net/mac80211/rc80211_minstrel.c | 12 ++++++++++++
net/mac80211/rc80211_minstrel.h | 1 +
net/mac80211/rc80211_minstrel_debugfs.c | 18 +++++++++++-------
net/mac80211/rc80211_minstrel_ht.c | 19 +++++++++++++++++++
net/mac80211/rc80211_minstrel_ht.h | 1 +
net/mac80211/rc80211_minstrel_ht_debugfs.c | 20 ++++++++++++--------
6 files changed, 56 insertions(+), 15 deletions(-)

diff --git a/net/mac80211/rc80211_minstrel.c b/net/mac80211/rc80211_minstrel.c
index 28de2f7a..42dfef8 100644
--- a/net/mac80211/rc80211_minstrel.c
+++ b/net/mac80211/rc80211_minstrel.c
@@ -87,7 +87,19 @@ int minstrel_get_tp_avg(struct minstrel_rate *mr)
return tp_avg;
}

+/* return max. potential lossless throughput */
+int minstrel_get_tp_max(struct minstrel_rate *mr)
+{
+ int tp_max, usecs;

+ usecs = mr->perfect_tx_time;
+ if (!usecs)
+ usecs = 1000000;
+
+ tp_max = 100000 / usecs;
+
+ return tp_max;
+}

/* find & sort topmost throughput rates */
static inline void
diff --git a/net/mac80211/rc80211_minstrel.h b/net/mac80211/rc80211_minstrel.h
index 490df3b..6693d8d 100644
--- a/net/mac80211/rc80211_minstrel.h
+++ b/net/mac80211/rc80211_minstrel.h
@@ -135,6 +135,7 @@ void minstrel_remove_sta_debugfs(void *priv, void *priv_sta);
/* Recalculate success probabilities and counters for a given rate using EWMA */
void minstrel_calc_rate_stats(struct minstrel_rate_stats *mrs);
int minstrel_get_tp_avg(struct minstrel_rate *mr);
+int minstrel_get_tp_max(struct minstrel_rate *mr);

/* debugfs */
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 d8ccef7..182d552 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)
{
struct minstrel_sta_info *mi = inode->i_private;
struct minstrel_debugfs_info *ms;
- unsigned int i, tp_avg, prob, eprob;
+ unsigned int i, tp_max, tp_avg, prob, eprob;
char *p;

ms = kmalloc(2048, GFP_KERNEL);
@@ -85,9 +85,9 @@ minstrel_stats_open(struct inode *inode, struct file *file)
file->private_data = ms;
p = ms->buf;
p += sprintf(p, "\n");
- p += sprintf(p, "best _______rate_____ __statistics__ "
+ p += sprintf(p, "best __________rate_________ __statistics__ "
"________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");

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

+ tp_max = minstrel_get_tp_max(mr);
tp_avg = minstrel_get_tp_avg(mr);
prob = MINSTREL_TRUNC(mrs->cur_prob * 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",
+ tp_max / 10, tp_max % 10,
tp_avg / 10, tp_avg % 10,
eprob / 10, eprob % 10,
prob / 10, prob % 10,
@@ -145,7 +147,7 @@ minstrel_stats_csv_open(struct inode *inode, struct file *file)
struct minstrel_sta_info *mi = inode->i_private;
struct minstrel_debugfs_info *ms;
struct timeval tv;
- unsigned int i, tp_avg, prob, eprob;
+ unsigned int i, tp_max, tp_avg, prob, eprob;
char *p;

ms = kmalloc(2048, GFP_KERNEL);
@@ -173,12 +175,14 @@ minstrel_stats_csv_open(struct inode *inode, struct file *file)
p += sprintf(p, "%u,", i);
p += sprintf(p, "%u,",mr->perfect_tx_time);

+ tp_max = minstrel_get_tp_max(mr);
tp_avg = minstrel_get_tp_avg(mr);
prob = MINSTREL_TRUNC(mrs->cur_prob * 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",
+ tp_max / 10, tp_max % 10,
tp_avg / 10, tp_avg % 10,
eprob / 10, eprob % 10,
prob / 10, prob % 10,
diff --git a/net/mac80211/rc80211_minstrel_ht.c b/net/mac80211/rc80211_minstrel_ht.c
index 2a55f63..b62b04e 100644
--- a/net/mac80211/rc80211_minstrel_ht.c
+++ b/net/mac80211/rc80211_minstrel_ht.c
@@ -350,6 +350,25 @@ minstrel_ht_get_tp_avg(struct minstrel_ht_sta *mi, int group, int rate)
}

/*
+ * Return max. potential lossless throughput based on the average A-MPDU
+ */
+int
+minstrel_ht_get_tp_max(struct minstrel_ht_sta *mi, int group, int rate)
+{
+ unsigned int nsecs = 0;
+ unsigned int tp_max;
+
+ if (group != MINSTREL_CCK_GROUP)
+ nsecs = 1000 * mi->overhead / MINSTREL_TRUNC(mi->avg_ampdu_len);
+
+ nsecs += minstrel_mcs_groups[group].duration[rate];
+ tp_max = 100000000 / nsecs;
+
+ return tp_max;
+}
+
+
+/*
* Find & sort topmost throughput rates
*
* If multiple rates provide equal throughput the sorting is based on their
diff --git a/net/mac80211/rc80211_minstrel_ht.h b/net/mac80211/rc80211_minstrel_ht.h
index 68dce4f..b1ea339 100644
--- a/net/mac80211/rc80211_minstrel_ht.h
+++ b/net/mac80211/rc80211_minstrel_ht.h
@@ -122,5 +122,6 @@ struct minstrel_ht_sta_priv {
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);
int minstrel_ht_get_tp_avg(struct minstrel_ht_sta *mi, int group, int rate);
+int minstrel_ht_get_tp_max(struct minstrel_ht_sta *mi, int group, int rate);

#endif
diff --git a/net/mac80211/rc80211_minstrel_ht_debugfs.c b/net/mac80211/rc80211_minstrel_ht_debugfs.c
index ce3baab..e70961f 100644
--- a/net/mac80211/rc80211_minstrel_ht_debugfs.c
+++ b/net/mac80211/rc80211_minstrel_ht_debugfs.c
@@ -19,7 +19,7 @@ static char *
minstrel_ht_stats_dump(struct minstrel_ht_sta *mi, int i, char *p)
{
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 gimode = 'L';
u32 gflags;
@@ -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 = DIV_ROUND_CLOSEST(mg->duration[j], 1000);
- p += sprintf(p, "%6u ", tx_time);
+ p += sprintf(p, "%6u ", tx_time);

+ tp_max = minstrel_ht_get_tp_max(mi, i, j);
tp_avg = minstrel_ht_get_tp_avg(mi, i, j);
prob = MINSTREL_TRUNC(mrs->cur_prob * 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",
+ tp_max / 10, tp_max % 10,
tp_avg / 10, tp_avg % 10,
eprob / 10, eprob % 10,
prob / 10, prob % 10,
@@ -125,11 +127,11 @@ minstrel_ht_stats_open(struct inode *inode, struct file *file)
p = ms->buf;

p += sprintf(p, "\n");
- p += sprintf(p, " best ________rate______ "
+ p += sprintf(p, " best ____________rate__________ "
"__statistics__ ________last_______ "
"______sum-of________\n");
- p += sprintf(p, "mode guard # rate [name idx airtime] [ ø(tp) "
- "ø(prob)] [prob.|retry|suc|att] [#success | "
+ p += sprintf(p, "mode guard # rate [name idx airtime max_tp] "
+ "[ ø(tp) ø(prob)] [prob.|retry|suc|att] [#success | "
"#attempts]\n");

p = minstrel_ht_stats_dump(mi, MINSTREL_CCK_GROUP, p);
@@ -164,7 +166,7 @@ minstrel_ht_stats_csv_dump(struct minstrel_ht_sta *mi, int i, char *p,
struct timeval tv)
{
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 gimode = 'L';
u32 gflags;
@@ -225,11 +227,13 @@ minstrel_ht_stats_csv_dump(struct minstrel_ht_sta *mi, int i, char *p,
tx_time = DIV_ROUND_CLOSEST(mg->duration[j], 1000);
p += sprintf(p, "%u,", tx_time);

+ tp_max = minstrel_ht_get_tp_max(mi, i, j);
tp_avg = minstrel_ht_get_tp_avg(mi, i, j);
prob = MINSTREL_TRUNC(mrs->cur_prob * 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,
eprob / 10, eprob % 10,
prob / 10, prob % 10,
--
2.2.2


2015-02-13 14:58:06

by Thomas Huehn

[permalink] [raw]
Subject: [PATCH v2 09/10] mac80211: reduce calculation costs of EWMA

This patch reduces the calculation costs of the EWMA macro from
"2x multiplication and 1 addition" down to "1x multiplication and
2x additions". This slightly improves performance depending on the
CPU architecture.

Signed-off-by: Thomas Huehn <[email protected]>
---
net/mac80211/rc80211_minstrel.h | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/net/mac80211/rc80211_minstrel.h b/net/mac80211/rc80211_minstrel.h
index 6693d8d..38158b0 100644
--- a/net/mac80211/rc80211_minstrel.h
+++ b/net/mac80211/rc80211_minstrel.h
@@ -27,7 +27,12 @@
static inline int
minstrel_ewma(int old, int new, int weight)
{
- return (new * (EWMA_DIV - weight) + old * weight) / EWMA_DIV;
+ int diff, incr;
+
+ diff = new - old;
+ incr = (EWMA_DIV - weight) * diff / EWMA_DIV;
+
+ return old + incr;
}

struct minstrel_rate_stats {
--
2.2.2


2015-02-25 21:11:31

by Bastian Bittorf

[permalink] [raw]
Subject: Re: [PATCH v2 0/10] Improve Minstrels & Minstrel-HTs common code base & statistics

* Job <[email protected]> [13.02.2015 16:32]:
> This patch series adds several improvements to the readability, the
> output format of rc_stats and the calculated statistics of Minstrel
> and Minstrel-HT. Variable names got more consistent and functions
> got unified between both rate control algorithms.

i did intensive testing in our small testnet (~50 routers) with all
kinds of platforms (ar71xx, x86, mpc85xx/ppc) and have no objections
for this patch-series but a big "thumbs up" for very nice, readable
and machine-parseable minstrel/rate-selector-output:

root@KuechenJukebox:~ cat /sys/kernel/debug/ieee80211/phy0/netdev:wlan0/stations/f4:ec:38:9d:81:f0/rc_stats

best ____________rate__________ ___________statistics__________ ________last_______ ______sum-of________
mode guard # rate [name idx airtime max_tp] [ ø(tp) ø-2σ(tp) ø(prob) σ(prob)] [prob.|retry|suc|att] [#success | #attempts]
CCK LP 1 1.0M 120 10548 0.9 0.0 0.0 6.4 1.6 5.2 2 0 0 74 585
CCK LP 1 2.0M 121 5476 1.8 0.0 0.0 0.0 0.0 0.0 0 0 0 0 2
CCK LP 1 5.5M 122 2411 4.1 0.0 0.0 0.0 0.0 0.0 0 0 0 0 2
CCK LP 1 11.0M 123 1535 6.5 1.2 1.1 18.7 0.7 0.0 0 0 0 1 3
HT20 LGI 1 CD MCS0 0 1480 6.5 3.3 3.2 52.7 1.2 33.3 2 0 0 320 657
HT20 LGI 1 A P MCS1 1 740 12.5 9.9 9.7 79.8 0.9 100.0 3 2 2 645 1234
HT20 LGI 1 MCS2 2 496 18.1 0.0 0.0 0.0 0.0 0.0 0 0 0 0 3
HT20 LGI 1 MCS3 3 372 23.4 1.9 1.3 8.8 1.5 0.0 5 0 0 69 281
HT20 LGI 1 MCS4 4 248 33.1 0.0 0.0 0.0 0.0 0.0 0 0 0 0 2
HT20 LGI 1 MCS5 5 188 41.3 0.0 0.0 0.0 0.0 0.0 0 0 0 0 3
HT20 LGI 1 MCS6 6 168 45.0 0.0 0.0 0.0 0.0 0.0 0 0 0 0 3
HT20 LGI 1 MCS7 7 148 49.5 0.0 0.0 0.0 0.0 0.0 0 0 0 0 3
HT20 LGI 2 MCS8 10 740 12.5 0.0 0.0 0.0 0.0 0.0 0 0 0 0 2
HT20 LGI 2 B MCS9 11 372 23.4 7.4 6.8 32.4 1.6 0.0 4 0 8 10 27
HT20 LGI 2 MCS10 12 248 33.1 0.0 0.0 0.0 0.0 0.0 0 0 0 0 2
HT20 LGI 2 MCS11 13 188 41.3 0.0 0.0 0.0 0.0 0.0 0 0 0 0 3
HT20 LGI 2 MCS12 14 124 56.1 0.0 0.0 0.0 0.0 0.0 0 0 0 0 3
HT20 LGI 2 MCS13 15 96 66.6 0.0 0.0 0.0 0.0 0.0 0 0 0 0 3
HT20 LGI 2 MCS14 16 84 72.4 0.0 0.0 0.0 0.0 0.0 0 0 0 0 3
HT20 LGI 2 MCS15 17 76 76.9 0.0 0.0 0.0 0.0 0.0 0 0 0 0 3

Total packet count:: ideal 1023 lookaround 48
Average # of aggregated frames per A-MPDU: 2.7


root@KuechenJukebox:~ cat /sys/kernel/debug/ieee80211/phy0/netdev:wlan0/stations/f4:ec:38:9d:81:f0/rc_stats_csv
1424897596.239275,CCK,LP,1,,,,,, 1.0M,120,10548,0.9,0.0,0.0,0.0,0.0,0.0,0,0,0,0,0,0,0,1.0
1424897596.239275,CCK,LP,1,,,,,, 2.0M,121,5476,1.8,0.0,0.0,0.0,0.0,0.0,0,0,0,0,0,0,0,1.0
1424897596.239275,CCK,LP,1,,,,,, 5.5M,122,2411,4.1,0.0,0.0,0.0,0.0,0.0,0,0,0,0,0,0,0,1.0
1424897596.239275,CCK,LP,1,,,,,,11.0M,123,1535,6.5,0.0,0.0,0.0,0.0,0.0,0,0,0,0,0,0,0,1.0
1424897596.239275,HT20,LGI,1,A,B,C,D,P,MCS0 ,0,1480,6.2,0.0,0.0,0.0,0.0,0.0,1,0,0,0,0,0,0,1.0
1424897596.239275,HT20,LGI,1,,,,,,MCS1 ,1,740,11.7,0.0,0.0,0.0,0.0,0.0,0,0,0,0,0,0,0,1.0
1424897596.239275,HT20,LGI,1,,,,,,MCS2 ,2,496,16.5,0.0,0.0,0.0,0.0,0.0,0,0,0,0,0,0,0,1.0
1424897596.239275,HT20,LGI,1,,,,,,MCS3 ,3,372,20.8,0.0,0.0,0.0,0.0,0.0,0,0,0,0,0,0,0,1.0
1424897596.239275,HT20,LGI,1,,,,,,MCS4 ,4,248,28.0,0.0,0.0,0.0,0.0,0.0,0,0,0,0,0,0,0,1.0
1424897596.239275,HT20,LGI,1,,,,,,MCS5 ,5,188,33.7,0.0,0.0,0.0,0.0,0.0,0,0,0,0,0,0,0,1.0
1424897596.239275,HT20,LGI,1,,,,,,MCS6 ,6,168,36.2,0.0,0.0,0.0,0.0,0.0,0,0,0,0,0,0,0,1.0
1424897596.239275,HT20,LGI,1,,,,,,MCS7 ,7,148,39.0,0.0,0.0,0.0,0.0,0.0,0,0,0,0,0,0,0,1.0
1424897596.239275,HT20,LGI,2,,,,,,MCS8 ,10,740,11.7,0.0,0.0,0.0,0.0,0.0,0,0,0,0,0,0,0,1.0
1424897596.239275,HT20,LGI,2,,,,,,MCS9 ,11,372,20.8,0.0,0.0,0.0,0.0,0.0,0,0,0,0,0,0,0,1.0
1424897596.239275,HT20,LGI,2,,,,,,MCS10,12,248,28.0,0.0,0.0,0.0,0.0,0.0,0,0,0,0,0,0,0,1.0
1424897596.239275,HT20,LGI,2,,,,,,MCS11,13,188,33.7,0.0,0.0,0.0,0.0,0.0,0,0,0,0,0,0,0,1.0
1424897596.239275,HT20,LGI,2,,,,,,MCS12,14,124,43.1,0.0,0.0,0.0,0.0,0.0,0,0,0,0,0,0,0,1.0
1424897596.239275,HT20,LGI,2,,,,,,MCS13,15,96,49.0,0.0,0.0,0.0,0.0,0.0,0,0,0,0,0,0,0,1.0
1424897596.239275,HT20,LGI,2,,,,,,MCS14,16,84,52.0,0.0,0.0,0.0,0.0,0.0,0,0,0,0,0,0,0,1.0
1424897596.239275,HT20,LGI,2,,,,,,MCS15,17,76,54.3,0.0,0.0,0.0,0.0,0.0,0,0,0,0,0,0,0,1.0



so a just want to say:

Tested-by: Bastian Bittorf

2015-02-13 14:58:04

by Thomas Huehn

[permalink] [raw]
Subject: [PATCH v2 02/10] mac80211: enhance readability of Minstrel-HTs rc_stats output

This patch restructures the rc_stats debugfs table of Minstrel-HT in
order to achieve better human readability. A new layout of the
statistics and a new header is added. In addition to the old layout
there are two new columns of information added:
idx - representing the rate index of each rate in mac80211 which
can be used to set specific rates as fixed rate via debugfs
airtime - the tx-time in micro seconds that a 1200 Byte packet
takes to be transmitted over the air at the given rate

The old layout of rc_stats:

type rate tpt eprob *prob ret *ok(*cum) ok( cum)
HT20/LGI MCS0 5.6 100.0 100.0 1 0( 0) 1( 1)
HT20/LGI B MCS1 10.5 100.0 100.0 0 0( 0) 1( 1)
HT20/LGI A MCS2 14.8 100.0 100.0 0 0( 0) 1( 1)
...

is changed into this new layout:

best ________rate______ __statistics__ ________last_______ ______sum-of________
mode guard # rate [name idx airtime] [ ø(tp) ø(prob)] [prob.|retry|suc|att] [#success | #attempts]
HT20 LGI 1 MCS0 0 1480 0.0 0.0 0.0 1 0 0 0 0
HT20 LGI 1 B MCS1 1 740 10.5 100.0 100.0 0 0 0 1 1
HT20 LGI 1 A MCS2 2 496 14.8 100.0 100.0 0 0 0 1 1
...

Signed-off-by: Thomas Huehn <[email protected]>
Signed-off-by: Stefan Venz <[email protected]>
---
net/mac80211/rc80211_minstrel_ht_debugfs.c | 49 +++++++++++++++++++++---------
1 file changed, 34 insertions(+), 15 deletions(-)

diff --git a/net/mac80211/rc80211_minstrel_ht_debugfs.c b/net/mac80211/rc80211_minstrel_ht_debugfs.c
index 20c676b..7fc690f 100644
--- a/net/mac80211/rc80211_minstrel_ht_debugfs.c
+++ b/net/mac80211/rc80211_minstrel_ht_debugfs.c
@@ -19,7 +19,7 @@ static char *
minstrel_ht_stats_dump(struct minstrel_ht_sta *mi, int i, char *p)
{
const struct mcs_group *mg;
- unsigned int j, tp, prob, eprob;
+ unsigned int j, tp, prob, eprob, tx_time;
char htmode = '2';
char gimode = 'L';
u32 gflags;
@@ -45,12 +45,19 @@ minstrel_ht_stats_dump(struct minstrel_ht_sta *mi, int i, char *p)
if (!(mi->groups[i].supported & BIT(j)))
continue;

- if (gflags & IEEE80211_TX_RC_MCS)
- p += sprintf(p, " HT%c0/%cGI ", htmode, gimode);
- else if (gflags & IEEE80211_TX_RC_VHT_MCS)
- p += sprintf(p, "VHT%c0/%cGI ", htmode, gimode);
- else
- p += sprintf(p, " CCK/%cP ", j < 4 ? 'L' : 'S');
+ if (gflags & IEEE80211_TX_RC_MCS) {
+ p += sprintf(p, "HT%c0 ", htmode);
+ p += sprintf(p, "%cGI ", gimode);
+ p += sprintf(p, "%d ", mg->streams);
+ } else if (gflags & IEEE80211_TX_RC_VHT_MCS) {
+ p += sprintf(p, "VHT%c0 ", htmode);
+ p += sprintf(p, "%cGI ", gimode);
+ p += sprintf(p, "%d ", mg->streams);
+ } else {
+ p += sprintf(p, "CCK ");
+ p += sprintf(p, "%cP ", j < 4 ? 'L' : 'S');
+ p += sprintf(p, "1 ");
+ }

*(p++) = (idx == mi->max_tp_rate[0]) ? 'A' : ' ';
*(p++) = (idx == mi->max_tp_rate[1]) ? 'B' : ' ';
@@ -59,21 +66,27 @@ minstrel_ht_stats_dump(struct minstrel_ht_sta *mi, int i, char *p)
*(p++) = (idx == mi->max_prob_rate) ? 'P' : ' ';

if (gflags & IEEE80211_TX_RC_MCS) {
- p += sprintf(p, " MCS%-2u ", (mg->streams - 1) * 8 + j);
+ p += sprintf(p, " MCS%-2u", (mg->streams - 1) * 8 + j);
} else if (gflags & IEEE80211_TX_RC_VHT_MCS) {
- p += sprintf(p, " MCS%-1u/%1u", j, mg->streams);
+ p += sprintf(p, " MCS%-1u/%1u", j, mg->streams);
} else {
int r = bitrates[j % 4];

- p += sprintf(p, " %2u.%1uM ", r / 10, r % 10);
+ p += sprintf(p, " %2u.%1uM", r / 10, r % 10);
}

+ p += sprintf(p, " %3u ", idx);
+
+ /* tx_time[rate(i)] in usec */
+ tx_time = DIV_ROUND_CLOSEST(mg->duration[j], 1000);
+ p += sprintf(p, "%6u ", tx_time);
+
tp = mr->cur_tp / 10;
prob = MINSTREL_TRUNC(mr->cur_prob * 1000);
eprob = MINSTREL_TRUNC(mr->probability * 1000);

- p += sprintf(p, " %4u.%1u %3u.%1u %3u.%1u "
- "%3u %4u(%4u) %9llu(%9llu)\n",
+ p += sprintf(p, "%4u.%1u %3u.%1u %3u.%1u "
+ "%3u %3u %-3u %9llu %-9llu\n",
tp / 10, tp % 10,
eprob / 10, eprob % 10,
prob / 10, prob % 10,
@@ -110,8 +123,14 @@ minstrel_ht_stats_open(struct inode *inode, struct file *file)

file->private_data = ms;
p = ms->buf;
- p += sprintf(p, " type rate tpt eprob *prob "
- "ret *ok(*cum) ok( cum)\n");
+
+ p += sprintf(p, "\n");
+ p += sprintf(p, " best ________rate______ "
+ "__statistics__ ________last_______ "
+ "______sum-of________\n");
+ p += sprintf(p, "mode guard # rate [name idx airtime] [ ø(tp) "
+ "ø(prob)] [prob.|retry|suc|att] [#success | "
+ "#attempts]\n");

p = minstrel_ht_stats_dump(mi, MINSTREL_CCK_GROUP, p);
for (i = 0; i < MINSTREL_CCK_GROUP; i++)
@@ -123,7 +142,7 @@ minstrel_ht_stats_open(struct inode *inode, struct file *file)
"lookaround %d\n",
max(0, (int) mi->total_packets - (int) mi->sample_packets),
mi->sample_packets);
- p += sprintf(p, "Average A-MPDU length: %d.%d\n",
+ p += sprintf(p, "Average # of aggregated frames per A-MPDU: %d.%d\n",
MINSTREL_TRUNC(mi->avg_ampdu_len),
MINSTREL_TRUNC(mi->avg_ampdu_len * 10) % 10);
ms->len = p - ms->buf;
--
2.2.2


2015-02-13 14:58:04

by Thomas Huehn

[permalink] [raw]
Subject: [PATCH v2 04/10] mac80211: add new Minstrel-HT statistic output via csv

This patch adds a new debugfs file "rc_stats_csv" to output
Minstrel-HTs statistics in a common csv format that is easy
to parse.

Signed-off-by: Thomas Huehn <[email protected]>
Signed-off-by: Stefan Venz <[email protected]>
---
net/mac80211/rc80211_minstrel_ht.h | 1 +
net/mac80211/rc80211_minstrel_ht_debugfs.c | 145 ++++++++++++++++++++++++++++-
2 files changed, 144 insertions(+), 2 deletions(-)

diff --git a/net/mac80211/rc80211_minstrel_ht.h b/net/mac80211/rc80211_minstrel_ht.h
index f2217d6..3cc30e8 100644
--- a/net/mac80211/rc80211_minstrel_ht.h
+++ b/net/mac80211/rc80211_minstrel_ht.h
@@ -112,6 +112,7 @@ struct minstrel_ht_sta_priv {
};
#ifdef CONFIG_MAC80211_DEBUGFS
struct dentry *dbg_stats;
+ struct dentry *dbg_stats_csv;
#endif
void *ratelist;
void *sample_table;
diff --git a/net/mac80211/rc80211_minstrel_ht_debugfs.c b/net/mac80211/rc80211_minstrel_ht_debugfs.c
index b300513..ae05780 100644
--- a/net/mac80211/rc80211_minstrel_ht_debugfs.c
+++ b/net/mac80211/rc80211_minstrel_ht_debugfs.c
@@ -107,8 +107,8 @@ minstrel_ht_stats_open(struct inode *inode, struct file *file)
struct minstrel_ht_sta *mi = &msp->ht;
struct minstrel_debugfs_info *ms;
unsigned int i;
- char *p;
int ret;
+ char *p;

if (!msp->is_ht) {
inode->i_private = &msp->legacy;
@@ -146,7 +146,6 @@ minstrel_ht_stats_open(struct inode *inode, struct file *file)
MINSTREL_TRUNC(mi->avg_ampdu_len),
MINSTREL_TRUNC(mi->avg_ampdu_len * 10) % 10);
ms->len = p - ms->buf;
-
WARN_ON(ms->len + sizeof(*ms) > 32768);

return nonseekable_open(inode, file);
@@ -160,6 +159,145 @@ static const struct file_operations minstrel_ht_stat_fops = {
.llseek = no_llseek,
};

+static char *
+minstrel_ht_stats_csv_dump(struct minstrel_ht_sta *mi, int i, char *p,
+ struct timeval tv)
+{
+ const struct mcs_group *mg;
+ unsigned int j, tp, prob, eprob, tx_time;
+ char htmode = '2';
+ char gimode = 'L';
+ u32 gflags;
+
+ if (!mi->groups[i].supported)
+ return p;
+
+ mg = &minstrel_mcs_groups[i];
+ gflags = mg->flags;
+
+ if (gflags & IEEE80211_TX_RC_40_MHZ_WIDTH)
+ htmode = '4';
+ else if (gflags & IEEE80211_TX_RC_80_MHZ_WIDTH)
+ htmode = '8';
+ if (gflags & IEEE80211_TX_RC_SHORT_GI)
+ gimode = 'S';
+
+ for (j = 0; j < MCS_GROUP_RATES; j++) {
+ struct minstrel_rate_stats *mr = &mi->groups[i].rates[j];
+ static const int bitrates[4] = { 10, 20, 55, 110 };
+ int idx = i * MCS_GROUP_RATES + j;
+
+ if (!(mi->groups[i].supported & BIT(j)))
+ continue;
+
+ p += sprintf(p, "%ld.%.6ld,", tv.tv_sec, tv.tv_usec);
+
+ if (gflags & IEEE80211_TX_RC_MCS) {
+ p += sprintf(p, "HT%c0,", htmode);
+ p += sprintf(p, "%cGI,", gimode);
+ p += sprintf(p, "%d,", mg->streams);
+ } else if (gflags & IEEE80211_TX_RC_VHT_MCS) {
+ p += sprintf(p, "VHT%c0,", htmode);
+ p += sprintf(p, "%cGI,", gimode);
+ p += sprintf(p, "%d,", mg->streams);
+ } else {
+ p += sprintf(p, "CCK,");
+ p += sprintf(p, "%cP,", j < 4 ? 'L' : 'S');
+ p += sprintf(p, "1,");
+ }
+
+ p += sprintf(p, "%s" ,((idx == mi->max_tp_rate[0]) ? "A," : ","));
+ p += sprintf(p, "%s" ,((idx == mi->max_tp_rate[1]) ? "B," : ","));
+ p += sprintf(p, "%s" ,((idx == mi->max_tp_rate[2]) ? "C," : ","));
+ p += sprintf(p, "%s" ,((idx == mi->max_tp_rate[3]) ? "D," : ","));
+ p += sprintf(p, "%s" ,((idx == mi->max_prob_rate) ? "P," : ","));
+
+ if (gflags & IEEE80211_TX_RC_MCS) {
+ p += sprintf(p, "MCS%-2u,", (mg->streams - 1) * 8 + j);
+ } else if (gflags & IEEE80211_TX_RC_VHT_MCS) {
+ p += sprintf(p, "MCS%-1u/%1u,", j, mg->streams);
+ } else {
+ int r = bitrates[j % 4];
+ p += sprintf(p, "%2u.%1uM,", r / 10, r % 10);
+ }
+
+ p += sprintf(p, "%u,", idx);
+ tx_time = DIV_ROUND_CLOSEST(mg->duration[j], 1000);
+ p += sprintf(p, "%u,", tx_time);
+
+ tp = mr->cur_tp / 10;
+ prob = MINSTREL_TRUNC(mr->cur_prob * 1000);
+ eprob = MINSTREL_TRUNC(mr->probability * 1000);
+
+ p += sprintf(p, "%u.%u,%u.%u,%u.%u,%u,%u,%u,%llu,%llu,",
+ tp / 10, tp % 10,
+ eprob / 10, eprob % 10,
+ prob / 10, prob % 10,
+ mr->retry_count,
+ mr->last_success,
+ mr->last_attempts,
+ (unsigned long long)mr->succ_hist,
+ (unsigned long long)mr->att_hist);
+ p += sprintf(p, "%d,%d,%d.%d\n",
+ max(0, (int) mi->total_packets -
+ (int) mi->sample_packets),
+ mi->sample_packets,
+ MINSTREL_TRUNC(mi->avg_ampdu_len),
+ MINSTREL_TRUNC(mi->avg_ampdu_len * 10) % 10);
+ }
+
+ return p;
+}
+
+static int
+minstrel_ht_stats_csv_open(struct inode *inode, struct file *file)
+{
+ struct minstrel_ht_sta_priv *msp = inode->i_private;
+ struct minstrel_ht_sta *mi = &msp->ht;
+ struct minstrel_debugfs_info *ms;
+ struct timeval tv;
+ unsigned int i;
+ int ret;
+ char *p;
+
+ do_gettimeofday(&tv);
+
+ if (!msp->is_ht) {
+ inode->i_private = &msp->legacy;
+ ret = minstrel_stats_open(inode, file);
+ inode->i_private = msp;
+ return ret;
+ }
+
+ ms = kmalloc(32768, GFP_KERNEL);
+
+ if (!ms)
+ return -ENOMEM;
+
+ file->private_data = ms;
+
+ p = ms->buf;
+
+ p = minstrel_ht_stats_csv_dump(mi, MINSTREL_CCK_GROUP, p, tv);
+ for (i = 0; i < MINSTREL_CCK_GROUP; i++)
+ p = minstrel_ht_stats_csv_dump(mi, i, p, tv);
+ for (i++; i < ARRAY_SIZE(mi->groups); i++)
+ p = minstrel_ht_stats_csv_dump(mi, i, p, tv);
+
+ ms->len = p - ms->buf;
+ WARN_ON(ms->len + sizeof(*ms) > 32768);
+
+ return nonseekable_open(inode, file);
+}
+
+static const struct file_operations minstrel_ht_stat_csv_fops = {
+ .owner = THIS_MODULE,
+ .open = minstrel_ht_stats_csv_open,
+ .read = minstrel_stats_read,
+ .release = minstrel_stats_release,
+ .llseek = no_llseek,
+};
+
void
minstrel_ht_add_sta_debugfs(void *priv, void *priv_sta, struct dentry *dir)
{
@@ -167,6 +305,8 @@ minstrel_ht_add_sta_debugfs(void *priv, void *priv_sta, struct dentry *dir)

msp->dbg_stats = debugfs_create_file("rc_stats", S_IRUGO, dir, msp,
&minstrel_ht_stat_fops);
+ msp->dbg_stats_csv = debugfs_create_file("rc_stats_csv", S_IRUGO,
+ dir, msp, &minstrel_ht_stat_csv_fops);
}

void
@@ -175,4 +315,5 @@ minstrel_ht_remove_sta_debugfs(void *priv, void *priv_sta)
struct minstrel_ht_sta_priv *msp = priv_sta;

debugfs_remove(msp->dbg_stats);
+ debugfs_remove(msp->dbg_stats_csv);
}
--
2.2.2


2015-02-13 14:58:06

by Thomas Huehn

[permalink] [raw]
Subject: [PATCH v2 07/10] mac80211: restructure per-rate throughput calculation into function

This patch moves Minstrels and Minstrel-HTs per-rate throughput
calculation (EWMA(thr)) into a dedicated function to be called.
Therefore the variable "unsigned int cur_tp" within struct
"minstrel_rate_stats" becomes obsolete. and is removed to free
up its space.

Signed-off-by: Thomas Huehn <[email protected]>
---
net/mac80211/rc80211_minstrel.c | 46 +++++++++++------
net/mac80211/rc80211_minstrel.h | 4 +-
net/mac80211/rc80211_minstrel_debugfs.c | 12 ++---
net/mac80211/rc80211_minstrel_ht.c | 79 ++++++++++++++++++------------
net/mac80211/rc80211_minstrel_ht.h | 1 +
net/mac80211/rc80211_minstrel_ht_debugfs.c | 12 ++---
6 files changed, 94 insertions(+), 60 deletions(-)

diff --git a/net/mac80211/rc80211_minstrel.c b/net/mac80211/rc80211_minstrel.c
index 89db6cf..28de2f7a 100644
--- a/net/mac80211/rc80211_minstrel.c
+++ b/net/mac80211/rc80211_minstrel.c
@@ -69,13 +69,34 @@ rix_to_ndx(struct minstrel_sta_info *mi, int rix)
return i;
}

+/* return current EMWA throughput */
+int minstrel_get_tp_avg(struct minstrel_rate *mr)
+{
+ int tp_avg, usecs;
+
+ usecs = mr->perfect_tx_time;
+ if (!usecs)
+ usecs = 1000000;
+
+ /* reset thr. below 10% success */
+ if (mr->stats.prob_ewma < MINSTREL_FRAC(10, 100))
+ tp_avg = 0;
+ else
+ tp_avg = MINSTREL_TRUNC(mr->stats.prob_ewma * (100000 / usecs));
+
+ return tp_avg;
+}
+
+
+
/* find & sort topmost throughput rates */
static inline void
minstrel_sort_best_tp_rates(struct minstrel_sta_info *mi, int i, u8 *tp_list)
{
int j = MAX_THR_RATES;

- while (j > 0 && mi->r[i].stats.cur_tp > mi->r[tp_list[j - 1]].stats.cur_tp)
+ while (j > 0 && (minstrel_get_tp_avg(&mi->r[i]) >
+ minstrel_get_tp_avg(&mi->r[tp_list[j - 1]])))
j--;
if (j < MAX_THR_RATES - 1)
memmove(&tp_list[j + 1], &tp_list[j], MAX_THR_RATES - (j + 1));
@@ -158,8 +179,7 @@ minstrel_update_stats(struct minstrel_priv *mp, struct minstrel_sta_info *mi)
{
u8 tmp_tp_rate[MAX_THR_RATES];
u8 tmp_prob_rate = 0;
- u32 usecs;
- int i;
+ int i, tmp_cur_tp, tmp_prob_tp;

for (i = 0; i < MAX_THR_RATES; i++)
tmp_tp_rate[i] = 0;
@@ -168,19 +188,9 @@ minstrel_update_stats(struct minstrel_priv *mp, struct minstrel_sta_info *mi)
struct minstrel_rate *mr = &mi->r[i];
struct minstrel_rate_stats *mrs = &mi->r[i].stats;

- usecs = mr->perfect_tx_time;
- if (!usecs)
- usecs = 1000000;
-
/* Update success probabilities per rate */
minstrel_calc_rate_stats(mrs);

- /* Update throughput per rate, reset thr. below 10% success */
- if (mrs->prob_ewma < MINSTREL_FRAC(10, 100))
- mrs->cur_tp = 0;
- else
- mrs->cur_tp = mrs->prob_ewma * (1000000 / usecs);
-
/* Sample less often below the 10% chance of success.
* Sample less often above the 95% chance of success. */
if (mrs->prob_ewma > MINSTREL_FRAC(95, 100) ||
@@ -205,7 +215,9 @@ minstrel_update_stats(struct minstrel_priv *mp, struct minstrel_sta_info *mi)
* (2) if all success probabilities < 95%, the rate with
* highest success probability is chosen as max_prob_rate */
if (mrs->prob_ewma >= MINSTREL_FRAC(95, 100)) {
- if (mrs->cur_tp >= mi->r[tmp_prob_rate].stats.cur_tp)
+ tmp_cur_tp = minstrel_get_tp_avg(mr);
+ tmp_prob_tp = minstrel_get_tp_avg(&mi->r[tmp_prob_rate]);
+ if (tmp_cur_tp >= tmp_prob_tp)
tmp_prob_rate = i;
} else {
if (mrs->prob_ewma >= mi->r[tmp_prob_rate].stats.prob_ewma)
@@ -676,11 +688,15 @@ static u32 minstrel_get_expected_throughput(void *priv_sta)
{
struct minstrel_sta_info *mi = priv_sta;
int idx = mi->max_tp_rate[0];
+ int tmp_cur_tp;

/* convert pkt per sec in kbps (1200 is the average pkt size used for
* computing cur_tp
*/
- return MINSTREL_TRUNC(mi->r[idx].stats.cur_tp) * 1200 * 8 / 1024;
+ tmp_cur_tp = minstrel_get_tp_avg(&mi->r[idx]);
+ tmp_cur_tp = tmp_cur_tp * 1200 * 8 / 1024;
+
+ return tmp_cur_tp;
}

const struct rate_control_ops mac80211_minstrel = {
diff --git a/net/mac80211/rc80211_minstrel.h b/net/mac80211/rc80211_minstrel.h
index 58f2870..490df3b 100644
--- a/net/mac80211/rc80211_minstrel.h
+++ b/net/mac80211/rc80211_minstrel.h
@@ -38,9 +38,6 @@ struct minstrel_rate_stats {
/* total attempts/success counters */
u64 att_hist, succ_hist;

- /* current EWMA of rate throughput */
- unsigned int cur_tp;
-
/* statistis of packet delivery probability
* cur_prob - current prob within last update intervall
* prob_ewma - exponential weighted moving average of prob */
@@ -137,6 +134,7 @@ void minstrel_remove_sta_debugfs(void *priv, void *priv_sta);

/* Recalculate success probabilities and counters for a given rate using EWMA */
void minstrel_calc_rate_stats(struct minstrel_rate_stats *mrs);
+int minstrel_get_tp_avg(struct minstrel_rate *mr);

/* debugfs */
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 c0a04e1..d8ccef7 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)
{
struct minstrel_sta_info *mi = inode->i_private;
struct minstrel_debugfs_info *ms;
- unsigned int i, tp, prob, eprob;
+ unsigned int i, tp_avg, prob, eprob;
char *p;

ms = kmalloc(2048, GFP_KERNEL);
@@ -105,13 +105,13 @@ minstrel_stats_open(struct inode *inode, struct file *file)
p += sprintf(p, "%3u ", i);
p += sprintf(p, "%6u ", mr->perfect_tx_time);

- tp = MINSTREL_TRUNC(mrs->cur_tp / 10);
+ tp_avg = minstrel_get_tp_avg(mr);
prob = MINSTREL_TRUNC(mrs->cur_prob * 1000);
eprob = MINSTREL_TRUNC(mrs->prob_ewma * 1000);

p += sprintf(p, " %4u.%1u %3u.%1u %3u.%1u %3u"
" %3u %-3u %9llu %-9llu\n",
- tp / 10, tp % 10,
+ tp_avg / 10, tp_avg % 10,
eprob / 10, eprob % 10,
prob / 10, prob % 10,
mrs->retry_count,
@@ -145,7 +145,7 @@ minstrel_stats_csv_open(struct inode *inode, struct file *file)
struct minstrel_sta_info *mi = inode->i_private;
struct minstrel_debugfs_info *ms;
struct timeval tv;
- unsigned int i, tp, prob, eprob;
+ unsigned int i, tp_avg, prob, eprob;
char *p;

ms = kmalloc(2048, GFP_KERNEL);
@@ -173,13 +173,13 @@ minstrel_stats_csv_open(struct inode *inode, struct file *file)
p += sprintf(p, "%u,", i);
p += sprintf(p, "%u,",mr->perfect_tx_time);

- tp = MINSTREL_TRUNC(mrs->cur_tp / 10);
+ tp_avg = minstrel_get_tp_avg(mr);
prob = MINSTREL_TRUNC(mrs->cur_prob * 1000);
eprob = MINSTREL_TRUNC(mrs->prob_ewma * 1000);

p += sprintf(p, "%u.%u,%u.%u,%u.%u,%u,%u,%u,"
"%llu,%llu,%d,%d\n",
- tp / 10, tp % 10,
+ tp_avg / 10, tp_avg % 10,
eprob / 10, eprob % 10,
prob / 10, prob % 10,
mrs->retry_count,
diff --git a/net/mac80211/rc80211_minstrel_ht.c b/net/mac80211/rc80211_minstrel_ht.c
index 6b07686..2a55f63 100644
--- a/net/mac80211/rc80211_minstrel_ht.c
+++ b/net/mac80211/rc80211_minstrel_ht.c
@@ -312,23 +312,23 @@ minstrel_get_ratestats(struct minstrel_ht_sta *mi, int index)
}

/*
- * Calculate throughput based on the average A-MPDU length, taking into account
- * the expected number of retransmissions and their expected length
+ * Return current throughput based on the average A-MPDU length, taking into
+ * account the expected number of retransmissions and their expected length
*/
-static void
-minstrel_ht_calc_tp(struct minstrel_ht_sta *mi, int group, int rate)
+int
+minstrel_ht_get_tp_avg(struct minstrel_ht_sta *mi, int group, int rate)
{
struct minstrel_rate_stats *mrs;
unsigned int nsecs = 0;
- unsigned int tmp_prob_ewma;
+ unsigned int tmp_prob_ewma, tp_avg;

mrs = &mi->groups[group].rates[rate];
tmp_prob_ewma = mrs->prob_ewma;

/* do not account throughput if sucess prob is below 10% */
if (mrs->prob_ewma < MINSTREL_FRAC(10, 100)) {
- mrs->cur_tp = 0;
- return;
+ tp_avg = 0;
+ return tp_avg;
}

/*
@@ -344,7 +344,9 @@ minstrel_ht_calc_tp(struct minstrel_ht_sta *mi, int group, int rate)
nsecs += minstrel_mcs_groups[group].duration[rate];

/* prob is scaled - see MINSTREL_FRAC above */
- mrs->cur_tp = MINSTREL_TRUNC(1000000 * ((tmp_prob_ewma * 1000) / nsecs));
+ tp_avg = MINSTREL_TRUNC(100000 * ((tmp_prob_ewma * 1000) / nsecs));
+
+ return tp_avg;
}

/*
@@ -358,22 +360,22 @@ static void
minstrel_ht_sort_best_tp_rates(struct minstrel_ht_sta *mi, u16 index,
u16 *tp_list)
{
- int cur_group, cur_idx, cur_thr, cur_prob;
- int tmp_group, tmp_idx, tmp_thr, tmp_prob;
+ int cur_group, cur_idx, cur_tp_avg, cur_prob;
+ int tmp_group, tmp_idx, tmp_tp_avg, tmp_prob;
int j = MAX_THR_RATES;

cur_group = index / MCS_GROUP_RATES;
cur_idx = index % MCS_GROUP_RATES;
- cur_thr = mi->groups[cur_group].rates[cur_idx].cur_tp;
+ cur_tp_avg = minstrel_ht_get_tp_avg(mi, cur_group, cur_idx);
cur_prob = mi->groups[cur_group].rates[cur_idx].prob_ewma;

do {
tmp_group = tp_list[j - 1] / MCS_GROUP_RATES;
tmp_idx = tp_list[j - 1] % MCS_GROUP_RATES;
- tmp_thr = mi->groups[tmp_group].rates[tmp_idx].cur_tp;
+ tmp_tp_avg = minstrel_ht_get_tp_avg(mi, tmp_group, tmp_idx);
tmp_prob = mi->groups[tmp_group].rates[tmp_idx].prob_ewma;
- if (cur_thr < tmp_thr ||
- (cur_thr == tmp_thr && cur_prob <= tmp_prob))
+ if (cur_tp_avg < tmp_tp_avg ||
+ (cur_tp_avg == tmp_tp_avg && cur_prob <= tmp_prob))
break;
j--;
} while (j > 0);
@@ -394,14 +396,19 @@ minstrel_ht_set_best_prob_rate(struct minstrel_ht_sta *mi, u16 index)
{
struct minstrel_mcs_group_data *mg;
struct minstrel_rate_stats *mrs;
- int tmp_group, tmp_idx, tmp_tp, tmp_prob, max_tp_group;
+ int tmp_group, tmp_idx, tmp_tp_avg, tmp_prob;
+ int max_tp_group, cur_tp_avg, cur_group, cur_idx;
+ int max_group_prob_rate_group, max_group_prob_rate_idx;
+ int max_group_prob_rate_tp_avg;

+ cur_group = index / MCS_GROUP_RATES;
+ cur_idx = index % MCS_GROUP_RATES;
mg = &mi->groups[index / MCS_GROUP_RATES];
mrs = &mg->rates[index % MCS_GROUP_RATES];

tmp_group = mi->max_prob_rate / MCS_GROUP_RATES;
tmp_idx = mi->max_prob_rate % MCS_GROUP_RATES;
- tmp_tp = mi->groups[tmp_group].rates[tmp_idx].cur_tp;
+ tmp_tp_avg = minstrel_ht_get_tp_avg(mi, tmp_group, tmp_idx);
tmp_prob = mi->groups[tmp_group].rates[tmp_idx].prob_ewma;

/* if max_tp_rate[0] is from MCS_GROUP max_prob_rate get selected from
@@ -412,9 +419,18 @@ minstrel_ht_set_best_prob_rate(struct minstrel_ht_sta *mi, u16 index)
return;

if (mrs->prob_ewma > MINSTREL_FRAC(75, 100)) {
- if (mrs->cur_tp > tmp_tp)
+ cur_tp_avg = minstrel_ht_get_tp_avg(mi, cur_group, cur_idx);
+ if (cur_tp_avg > tmp_tp_avg)
mi->max_prob_rate = index;
- if (mrs->cur_tp > mg->rates[mg->max_group_prob_rate].cur_tp)
+
+ max_group_prob_rate_group = mg->max_group_prob_rate /
+ MCS_GROUP_RATES;
+ max_group_prob_rate_idx = mg->max_group_prob_rate %
+ MCS_GROUP_RATES;
+ max_group_prob_rate_tp_avg = minstrel_ht_get_tp_avg(mi,
+ max_group_prob_rate_group,
+ max_group_prob_rate_idx);
+ if (cur_tp_avg > max_group_prob_rate_tp_avg)
mg->max_group_prob_rate = index;
} else {
if (mrs->prob_ewma > tmp_prob)
@@ -441,11 +457,11 @@ minstrel_ht_assign_best_tp_rates(struct minstrel_ht_sta *mi,

tmp_group = tmp_cck_tp_rate[0] / MCS_GROUP_RATES;
tmp_idx = tmp_cck_tp_rate[0] % MCS_GROUP_RATES;
- tmp_cck_tp = mi->groups[tmp_group].rates[tmp_idx].cur_tp;
+ tmp_cck_tp = minstrel_ht_get_tp_avg(mi, tmp_group, tmp_idx);

tmp_group = tmp_mcs_tp_rate[0] / MCS_GROUP_RATES;
tmp_idx = tmp_mcs_tp_rate[0] % MCS_GROUP_RATES;
- tmp_mcs_tp = mi->groups[tmp_group].rates[tmp_idx].cur_tp;
+ tmp_mcs_tp = minstrel_ht_get_tp_avg(mi, tmp_group, tmp_idx);

if (tmp_cck_tp > tmp_mcs_tp) {
for(i = 0; i < MAX_THR_RATES; i++) {
@@ -464,8 +480,7 @@ static inline void
minstrel_ht_prob_rate_reduce_streams(struct minstrel_ht_sta *mi)
{
struct minstrel_mcs_group_data *mg;
- struct minstrel_rate_stats *mrs;
- int tmp_max_streams, group;
+ int tmp_max_streams, group, tmp_idx;
int tmp_tp = 0;

tmp_max_streams = minstrel_mcs_groups[mi->max_tp_rate[0] /
@@ -474,11 +489,14 @@ minstrel_ht_prob_rate_reduce_streams(struct minstrel_ht_sta *mi)
mg = &mi->groups[group];
if (!mg->supported || group == MINSTREL_CCK_GROUP)
continue;
- mrs = minstrel_get_ratestats(mi, mg->max_group_prob_rate);
- if (tmp_tp < mrs->cur_tp &&
+
+ tmp_idx = mg->max_group_prob_rate % MCS_GROUP_RATES;
+
+ if (tmp_tp < minstrel_ht_get_tp_avg(mi, group, tmp_idx) &&
(minstrel_mcs_groups[group].streams < tmp_max_streams)) {
mi->max_prob_rate = mg->max_group_prob_rate;
- tmp_tp = mrs->cur_tp;
+ tmp_tp = minstrel_ht_get_tp_avg(mi, group,
+ tmp_idx);
}
}
}
@@ -539,9 +557,8 @@ minstrel_ht_update_stats(struct minstrel_priv *mp, struct minstrel_ht_sta *mi)
mrs = &mg->rates[i];
mrs->retry_updated = false;
minstrel_calc_rate_stats(mrs);
- minstrel_ht_calc_tp(mi, group, i);

- if (!mrs->cur_tp)
+ if (minstrel_ht_get_tp_avg(mi, group, i) == 0)
continue;

/* Find max throughput rate set */
@@ -1300,7 +1317,7 @@ static u32 minstrel_ht_get_expected_throughput(void *priv_sta)
{
struct minstrel_ht_sta_priv *msp = priv_sta;
struct minstrel_ht_sta *mi = &msp->ht;
- int i, j;
+ int i, j, tp_avg;

if (!msp->is_ht)
return mac80211_minstrel.get_expected_throughput(priv_sta);
@@ -1308,8 +1325,10 @@ static u32 minstrel_ht_get_expected_throughput(void *priv_sta)
i = mi->max_tp_rate[0] / MCS_GROUP_RATES;
j = mi->max_tp_rate[0] % MCS_GROUP_RATES;

- /* convert cur_tp from pkt per second in kbps */
- return mi->groups[i].rates[j].cur_tp * AVG_PKT_SIZE * 8 / 1024;
+ /* convert tp_avg from pkt per second in kbps */
+ tp_avg = minstrel_ht_get_tp_avg(mi, i, j) * AVG_PKT_SIZE * 8 / 1024;
+
+ return tp_avg;
}

static const struct rate_control_ops mac80211_minstrel_ht = {
diff --git a/net/mac80211/rc80211_minstrel_ht.h b/net/mac80211/rc80211_minstrel_ht.h
index fa21a82..68dce4f 100644
--- a/net/mac80211/rc80211_minstrel_ht.h
+++ b/net/mac80211/rc80211_minstrel_ht.h
@@ -121,5 +121,6 @@ struct minstrel_ht_sta_priv {

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);
+int minstrel_ht_get_tp_avg(struct minstrel_ht_sta *mi, int group, int rate);

#endif
diff --git a/net/mac80211/rc80211_minstrel_ht_debugfs.c b/net/mac80211/rc80211_minstrel_ht_debugfs.c
index 5529add..ce3baab 100644
--- a/net/mac80211/rc80211_minstrel_ht_debugfs.c
+++ b/net/mac80211/rc80211_minstrel_ht_debugfs.c
@@ -19,7 +19,7 @@ static char *
minstrel_ht_stats_dump(struct minstrel_ht_sta *mi, int i, char *p)
{
const struct mcs_group *mg;
- unsigned int j, tp, prob, eprob, tx_time;
+ unsigned int j, tp_avg, prob, eprob, tx_time;
char htmode = '2';
char gimode = 'L';
u32 gflags;
@@ -81,13 +81,13 @@ minstrel_ht_stats_dump(struct minstrel_ht_sta *mi, int i, char *p)
tx_time = DIV_ROUND_CLOSEST(mg->duration[j], 1000);
p += sprintf(p, "%6u ", tx_time);

- tp = mrs->cur_tp / 10;
+ tp_avg = minstrel_ht_get_tp_avg(mi, i, j);
prob = MINSTREL_TRUNC(mrs->cur_prob * 1000);
eprob = MINSTREL_TRUNC(mrs->prob_ewma * 1000);

p += sprintf(p, "%4u.%1u %3u.%1u %3u.%1u "
"%3u %3u %-3u %9llu %-9llu\n",
- tp / 10, tp % 10,
+ tp_avg / 10, tp_avg % 10,
eprob / 10, eprob % 10,
prob / 10, prob % 10,
mrs->retry_count,
@@ -164,7 +164,7 @@ minstrel_ht_stats_csv_dump(struct minstrel_ht_sta *mi, int i, char *p,
struct timeval tv)
{
const struct mcs_group *mg;
- unsigned int j, tp, prob, eprob, tx_time;
+ unsigned int j, tp_avg, prob, eprob, tx_time;
char htmode = '2';
char gimode = 'L';
u32 gflags;
@@ -225,12 +225,12 @@ minstrel_ht_stats_csv_dump(struct minstrel_ht_sta *mi, int i, char *p,
tx_time = DIV_ROUND_CLOSEST(mg->duration[j], 1000);
p += sprintf(p, "%u,", tx_time);

- tp = mrs->cur_tp / 10;
+ tp_avg = minstrel_ht_get_tp_avg(mi, i, j);
prob = MINSTREL_TRUNC(mrs->cur_prob * 1000);
eprob = MINSTREL_TRUNC(mrs->prob_ewma * 1000);

p += sprintf(p, "%u.%u,%u.%u,%u.%u,%u,%u,%u,%llu,%llu,",
- tp / 10, tp % 10,
+ tp_avg / 10, tp_avg % 10,
eprob / 10, eprob % 10,
prob / 10, prob % 10,
mrs->retry_count,
--
2.2.2


2015-02-13 14:58:04

by Thomas Huehn

[permalink] [raw]
Subject: [PATCH v2 03/10] mac80211: add new Minstrel statistic output via csv

This patch adds a new debugfs file "rc_stats_csv" to output Minstrels
statistics in a common csv format that is easy to parse.

Signed-off-by: Thomas Huehn <[email protected]>
Signed-off-by: Stefan Venz <[email protected]>
---
net/mac80211/rc80211_minstrel.h | 6 +-
net/mac80211/rc80211_minstrel_debugfs.c | 95 ++++++++++++++++++++++++++----
net/mac80211/rc80211_minstrel_ht_debugfs.c | 2 +-
3 files changed, 88 insertions(+), 15 deletions(-)

diff --git a/net/mac80211/rc80211_minstrel.h b/net/mac80211/rc80211_minstrel.h
index 410efe6..9613e73 100644
--- a/net/mac80211/rc80211_minstrel.h
+++ b/net/mac80211/rc80211_minstrel.h
@@ -13,7 +13,6 @@
#define EWMA_DIV 128
#define SAMPLE_COLUMNS 10 /* number of columns in sample table */

-
/* scaled fraction values */
#define MINSTREL_SCALE 16
#define MINSTREL_FRAC(val, div) (((val) << MINSTREL_SCALE) / div)
@@ -24,7 +23,7 @@

/*
* Perform EWMA (Exponentially Weighted Moving Average) calculation
- */
+ */
static inline int
minstrel_ewma(int old, int new, int weight)
{
@@ -95,6 +94,7 @@ struct minstrel_sta_info {

#ifdef CONFIG_MAC80211_DEBUGFS
struct dentry *dbg_stats;
+ struct dentry *dbg_stats_csv;
#endif
};

@@ -121,7 +121,6 @@ struct minstrel_priv {
u32 fixed_rate_idx;
struct dentry *dbg_fixed_rate;
#endif
-
};

struct minstrel_debugfs_info {
@@ -135,6 +134,7 @@ void minstrel_remove_sta_debugfs(void *priv, void *priv_sta);

/* debugfs */
int minstrel_stats_open(struct inode *inode, struct file *file);
+int minstrel_stats_csv_open(struct inode *inode, struct file *file);
ssize_t minstrel_stats_read(struct file *file, char __user *buf, size_t len, loff_t *ppos);
int minstrel_stats_release(struct inode *inode, struct file *file);

diff --git a/net/mac80211/rc80211_minstrel_debugfs.c b/net/mac80211/rc80211_minstrel_debugfs.c
index 2d70081..ab15ca6 100644
--- a/net/mac80211/rc80211_minstrel_debugfs.c
+++ b/net/mac80211/rc80211_minstrel_debugfs.c
@@ -54,6 +54,22 @@
#include <net/mac80211.h>
#include "rc80211_minstrel.h"

+ssize_t
+minstrel_stats_read(struct file *file, char __user *buf, size_t len, loff_t *ppos)
+{
+ struct minstrel_debugfs_info *ms;
+
+ ms = file->private_data;
+ return simple_read_from_buffer(buf, len, ppos, ms->buf, ms->len);
+}
+
+int
+minstrel_stats_release(struct inode *inode, struct file *file)
+{
+ kfree(file->private_data);
+ return 0;
+}
+
int
minstrel_stats_open(struct inode *inode, struct file *file)
{
@@ -115,25 +131,76 @@ minstrel_stats_open(struct inode *inode, struct file *file)
return 0;
}

-ssize_t
-minstrel_stats_read(struct file *file, char __user *buf, size_t len, loff_t *ppos)
+static const struct file_operations minstrel_stat_fops = {
+ .owner = THIS_MODULE,
+ .open = minstrel_stats_open,
+ .read = minstrel_stats_read,
+ .release = minstrel_stats_release,
+ .llseek = default_llseek,
+};
+
+int
+minstrel_stats_csv_open(struct inode *inode, struct file *file)
{
+ struct minstrel_sta_info *mi = inode->i_private;
struct minstrel_debugfs_info *ms;
+ struct timeval tv;
+ unsigned int i, tp, prob, eprob;
+ char *p;

- ms = file->private_data;
- return simple_read_from_buffer(buf, len, ppos, ms->buf, ms->len);
-}
+ ms = kmalloc(2048, GFP_KERNEL);
+ if (!ms)
+ return -ENOMEM;
+
+ file->private_data = ms;
+ p = ms->buf;
+
+ do_gettimeofday(&tv);
+
+ for (i = 0; i < mi->n_rates; i++) {
+ struct minstrel_rate *mr = &mi->r[i];
+ struct minstrel_rate_stats *mrs = &mi->r[i].stats;
+
+ p += sprintf(p, "%ld.%.6ld,", tv.tv_sec, tv.tv_usec);
+ p += sprintf(p, "%s" ,((i == mi->max_tp_rate[0]) ? "A," : ","));
+ p += sprintf(p, "%s" ,((i == mi->max_tp_rate[1]) ? "B," : ","));
+ p += sprintf(p, "%s" ,((i == mi->max_tp_rate[2]) ? "C," : ","));
+ p += sprintf(p, "%s" ,((i == mi->max_tp_rate[3]) ? "D," : ","));
+ p += sprintf(p, "%s" ,((i == mi->max_prob_rate) ? "P," : ","));
+
+ p += sprintf(p, "%u%s", mr->bitrate / 2,
+ (mr->bitrate & 1 ? ".5," : ","));
+ p += sprintf(p, "%u,", i);
+ p += sprintf(p, "%u,",mr->perfect_tx_time);
+
+ tp = MINSTREL_TRUNC(mrs->cur_tp / 10);
+ prob = MINSTREL_TRUNC(mrs->cur_prob * 1000);
+ eprob = MINSTREL_TRUNC(mrs->probability * 1000);
+
+ p += sprintf(p, "%u.%u,%u.%u,%u.%u,%u,%u,%u,"
+ "%llu,%llu,%d,%d\n",
+ tp / 10, tp % 10,
+ eprob / 10, eprob % 10,
+ prob / 10, prob % 10,
+ mrs->retry_count,
+ mrs->last_success,
+ mrs->last_attempts,
+ (unsigned long long)mrs->succ_hist,
+ (unsigned long long)mrs->att_hist,
+ mi->total_packets - mi->sample_packets,
+ mi->sample_packets);
+
+ }
+ ms->len = p - ms->buf;
+
+ WARN_ON(ms->len + sizeof(*ms) > 2048);

-int
-minstrel_stats_release(struct inode *inode, struct file *file)
-{
- kfree(file->private_data);
return 0;
}

-static const struct file_operations minstrel_stat_fops = {
+static const struct file_operations minstrel_stat_csv_fops = {
.owner = THIS_MODULE,
- .open = minstrel_stats_open,
+ .open = minstrel_stats_csv_open,
.read = minstrel_stats_read,
.release = minstrel_stats_release,
.llseek = default_llseek,
@@ -146,6 +213,9 @@ minstrel_add_sta_debugfs(void *priv, void *priv_sta, struct dentry *dir)

mi->dbg_stats = debugfs_create_file("rc_stats", S_IRUGO, dir, mi,
&minstrel_stat_fops);
+
+ mi->dbg_stats_csv = debugfs_create_file("rc_stats_csv", S_IRUGO, dir,
+ mi, &minstrel_stat_csv_fops);
}

void
@@ -154,4 +224,7 @@ minstrel_remove_sta_debugfs(void *priv, void *priv_sta)
struct minstrel_sta_info *mi = priv_sta;

debugfs_remove(mi->dbg_stats);
+
+ debugfs_remove(mi->dbg_stats_csv);
}
+
diff --git a/net/mac80211/rc80211_minstrel_ht_debugfs.c b/net/mac80211/rc80211_minstrel_ht_debugfs.c
index 7fc690f..b300513 100644
--- a/net/mac80211/rc80211_minstrel_ht_debugfs.c
+++ b/net/mac80211/rc80211_minstrel_ht_debugfs.c
@@ -112,7 +112,7 @@ minstrel_ht_stats_open(struct inode *inode, struct file *file)

if (!msp->is_ht) {
inode->i_private = &msp->legacy;
- ret = minstrel_stats_open(inode, file);
+ ret = minstrel_stats_csv_open(inode, file);
inode->i_private = msp;
return ret;
}
--
2.2.2


2015-02-25 21:12:06

by Bastian Bittorf

[permalink] [raw]
Subject: Re: [PATCH v2 0/10] Improve Minstrels & Minstrel-HTs common code base & statistics

* Job <[email protected]> [13.02.2015 16:32]:
> This patch series adds several improvements to the readability, the
> output format of rc_stats and the calculated statistics of Minstrel
> and Minstrel-HT. Variable names got more consistent and functions
> got unified between both rate control algorithms.

i did intensive testing in our small testnet (~50 routers) with all
kinds of platforms (ar71xx, x86, mpc85xx/ppc) and have no objections
for this patch-series but a big "thumbs up" for very nice, readable
and machine-parseable minstrel/rate-selector-output:

root@KuechenJukebox:~ cat /sys/kernel/debug/ieee80211/phy0/netdev:wlan0/stations/f4:ec:38:9d:81:f0/rc_stats

best ____________rate__________ ___________statistics__________ ________last_______ ______sum-of________
mode guard # rate [name idx airtime max_tp] [ ø(tp) ø-2σ(tp) ø(prob) σ(prob)] [prob.|retry|suc|att] [#success | #attempts]
CCK LP 1 1.0M 120 10548 0.9 0.0 0.0 6.4 1.6 5.2 2 0 0 74 585
CCK LP 1 2.0M 121 5476 1.8 0.0 0.0 0.0 0.0 0.0 0 0 0 0 2
CCK LP 1 5.5M 122 2411 4.1 0.0 0.0 0.0 0.0 0.0 0 0 0 0 2
CCK LP 1 11.0M 123 1535 6.5 1.2 1.1 18.7 0.7 0.0 0 0 0 1 3
HT20 LGI 1 CD MCS0 0 1480 6.5 3.3 3.2 52.7 1.2 33.3 2 0 0 320 657
HT20 LGI 1 A P MCS1 1 740 12.5 9.9 9.7 79.8 0.9 100.0 3 2 2 645 1234
HT20 LGI 1 MCS2 2 496 18.1 0.0 0.0 0.0 0.0 0.0 0 0 0 0 3
HT20 LGI 1 MCS3 3 372 23.4 1.9 1.3 8.8 1.5 0.0 5 0 0 69 281
HT20 LGI 1 MCS4 4 248 33.1 0.0 0.0 0.0 0.0 0.0 0 0 0 0 2
HT20 LGI 1 MCS5 5 188 41.3 0.0 0.0 0.0 0.0 0.0 0 0 0 0 3
HT20 LGI 1 MCS6 6 168 45.0 0.0 0.0 0.0 0.0 0.0 0 0 0 0 3
HT20 LGI 1 MCS7 7 148 49.5 0.0 0.0 0.0 0.0 0.0 0 0 0 0 3
HT20 LGI 2 MCS8 10 740 12.5 0.0 0.0 0.0 0.0 0.0 0 0 0 0 2
HT20 LGI 2 B MCS9 11 372 23.4 7.4 6.8 32.4 1.6 0.0 4 0 8 10 27
HT20 LGI 2 MCS10 12 248 33.1 0.0 0.0 0.0 0.0 0.0 0 0 0 0 2
HT20 LGI 2 MCS11 13 188 41.3 0.0 0.0 0.0 0.0 0.0 0 0 0 0 3
HT20 LGI 2 MCS12 14 124 56.1 0.0 0.0 0.0 0.0 0.0 0 0 0 0 3
HT20 LGI 2 MCS13 15 96 66.6 0.0 0.0 0.0 0.0 0.0 0 0 0 0 3
HT20 LGI 2 MCS14 16 84 72.4 0.0 0.0 0.0 0.0 0.0 0 0 0 0 3
HT20 LGI 2 MCS15 17 76 76.9 0.0 0.0 0.0 0.0 0.0 0 0 0 0 3

Total packet count:: ideal 1023 lookaround 48
Average # of aggregated frames per A-MPDU: 2.7


root@KuechenJukebox:~ cat /sys/kernel/debug/ieee80211/phy0/netdev:wlan0/stations/f4:ec:38:9d:81:f0/rc_stats_csv
1424897596.239275,CCK,LP,1,,,,,, 1.0M,120,10548,0.9,0.0,0.0,0.0,0.0,0.0,0,0,0,0,0,0,0,1.0
1424897596.239275,CCK,LP,1,,,,,, 2.0M,121,5476,1.8,0.0,0.0,0.0,0.0,0.0,0,0,0,0,0,0,0,1.0
1424897596.239275,CCK,LP,1,,,,,, 5.5M,122,2411,4.1,0.0,0.0,0.0,0.0,0.0,0,0,0,0,0,0,0,1.0
1424897596.239275,CCK,LP,1,,,,,,11.0M,123,1535,6.5,0.0,0.0,0.0,0.0,0.0,0,0,0,0,0,0,0,1.0
1424897596.239275,HT20,LGI,1,A,B,C,D,P,MCS0 ,0,1480,6.2,0.0,0.0,0.0,0.0,0.0,1,0,0,0,0,0,0,1.0
1424897596.239275,HT20,LGI,1,,,,,,MCS1 ,1,740,11.7,0.0,0.0,0.0,0.0,0.0,0,0,0,0,0,0,0,1.0
1424897596.239275,HT20,LGI,1,,,,,,MCS2 ,2,496,16.5,0.0,0.0,0.0,0.0,0.0,0,0,0,0,0,0,0,1.0
1424897596.239275,HT20,LGI,1,,,,,,MCS3 ,3,372,20.8,0.0,0.0,0.0,0.0,0.0,0,0,0,0,0,0,0,1.0
1424897596.239275,HT20,LGI,1,,,,,,MCS4 ,4,248,28.0,0.0,0.0,0.0,0.0,0.0,0,0,0,0,0,0,0,1.0
1424897596.239275,HT20,LGI,1,,,,,,MCS5 ,5,188,33.7,0.0,0.0,0.0,0.0,0.0,0,0,0,0,0,0,0,1.0
1424897596.239275,HT20,LGI,1,,,,,,MCS6 ,6,168,36.2,0.0,0.0,0.0,0.0,0.0,0,0,0,0,0,0,0,1.0
1424897596.239275,HT20,LGI,1,,,,,,MCS7 ,7,148,39.0,0.0,0.0,0.0,0.0,0.0,0,0,0,0,0,0,0,1.0
1424897596.239275,HT20,LGI,2,,,,,,MCS8 ,10,740,11.7,0.0,0.0,0.0,0.0,0.0,0,0,0,0,0,0,0,1.0
1424897596.239275,HT20,LGI,2,,,,,,MCS9 ,11,372,20.8,0.0,0.0,0.0,0.0,0.0,0,0,0,0,0,0,0,1.0
1424897596.239275,HT20,LGI,2,,,,,,MCS10,12,248,28.0,0.0,0.0,0.0,0.0,0.0,0,0,0,0,0,0,0,1.0
1424897596.239275,HT20,LGI,2,,,,,,MCS11,13,188,33.7,0.0,0.0,0.0,0.0,0.0,0,0,0,0,0,0,0,1.0
1424897596.239275,HT20,LGI,2,,,,,,MCS12,14,124,43.1,0.0,0.0,0.0,0.0,0.0,0,0,0,0,0,0,0,1.0
1424897596.239275,HT20,LGI,2,,,,,,MCS13,15,96,49.0,0.0,0.0,0.0,0.0,0.0,0,0,0,0,0,0,0,1.0
1424897596.239275,HT20,LGI,2,,,,,,MCS14,16,84,52.0,0.0,0.0,0.0,0.0,0.0,0,0,0,0,0,0,0,1.0
1424897596.239275,HT20,LGI,2,,,,,,MCS15,17,76,54.3,0.0,0.0,0.0,0.0,0.0,0,0,0,0,0,0,0,1.0



so a just want to say:

Tested-by: Bastian Bittorf

2015-02-13 14:58:07

by Thomas Huehn

[permalink] [raw]
Subject: [PATCH v2 10/10] mac80211: add standard deviation to Minstrels throughput statistic

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 <[email protected]>
---
net/mac80211/rc80211_minstrel.c | 19 ++++++++++++++-----
net/mac80211/rc80211_minstrel.h | 22 +++++++++++++++++++++-
net/mac80211/rc80211_minstrel_debugfs.c | 19 ++++++++++++-------
net/mac80211/rc80211_minstrel_ht_debugfs.c | 14 +++++++++-----
4 files changed, 56 insertions(+), 18 deletions(-)

diff --git a/net/mac80211/rc80211_minstrel.c b/net/mac80211/rc80211_minstrel.c
index 42dfef8..c108f03 100644
--- a/net/mac80211/rc80211_minstrel.c
+++ b/net/mac80211/rc80211_minstrel.c
@@ -161,7 +161,7 @@ minstrel_update_rates(struct minstrel_priv *mp, struct minstrel_sta_info *mi)
}

/*
-* Recalculate success probabilities and counters for a given rate using EWMA
+* Recalculate statistics and counters of a given rate
*/
void
minstrel_calc_rate_stats(struct minstrel_rate_stats *mrs)
@@ -169,11 +169,20 @@ minstrel_calc_rate_stats(struct minstrel_rate_stats *mrs)
if (unlikely(mrs->attempts > 0)) {
mrs->sample_skipped = 0;
mrs->cur_prob = MINSTREL_FRAC(mrs->success, mrs->attempts);
- if (unlikely(!mrs->att_hist))
+ if (unlikely(!mrs->att_hist)) {
mrs->prob_ewma = mrs->cur_prob;
- else
+ } else {
+ /* update exponential weighted moving variance */
+ mrs->prob_ewmsd = minstrel_ewmsd(mrs->prob_ewmsd,
+ mrs->cur_prob,
+ mrs->prob_ewma,
+ EWMA_LEVEL);
+
+ /*update exponential weighted moving avarage */
mrs->prob_ewma = minstrel_ewma(mrs->prob_ewma,
- mrs->cur_prob, EWMA_LEVEL);
+ mrs->cur_prob,
+ EWMA_LEVEL);
+ }
mrs->att_hist += mrs->attempts;
mrs->succ_hist += mrs->success;
} else {
@@ -200,7 +209,7 @@ minstrel_update_stats(struct minstrel_priv *mp, struct minstrel_sta_info *mi)
struct minstrel_rate *mr = &mi->r[i];
struct minstrel_rate_stats *mrs = &mi->r[i].stats;

- /* Update success probabilities per rate */
+ /* Update statistics of success probability per rate */
minstrel_calc_rate_stats(mrs);

/* Sample less often below the 10% chance of success.
diff --git a/net/mac80211/rc80211_minstrel.h b/net/mac80211/rc80211_minstrel.h
index 38158b0..713c81e 100644
--- a/net/mac80211/rc80211_minstrel.h
+++ b/net/mac80211/rc80211_minstrel.h
@@ -35,6 +35,24 @@ minstrel_ewma(int old, int new, int weight)
return old + incr;
}

+/*
+ * Perform EWMSD (Exponentially Weighted Moving Standard Deviation) calculation
+ */
+static inline int
+minstrel_ewmsd(int old_ewmsd, int cur_prob, int prob_ewma, int weight)
+{
+ int diff, incr, tmp_var;
+
+ /* calculate exponential weighted moving variance */
+ diff = MINSTREL_TRUNC((cur_prob - prob_ewma) * 1000000);
+ incr = (EWMA_DIV - weight) * diff / EWMA_DIV;
+ tmp_var = old_ewmsd * old_ewmsd;
+ tmp_var = weight * (tmp_var + diff * incr / 1000000) / EWMA_DIV;
+
+ /* return standard deviation */
+ return (u16) int_sqrt(tmp_var);
+}
+
struct minstrel_rate_stats {
/* current / last sampling period attempts/success counters */
u16 attempts, last_attempts;
@@ -45,9 +63,11 @@ struct minstrel_rate_stats {

/* statistis of packet delivery probability
* cur_prob - current prob within last update intervall
- * prob_ewma - exponential weighted moving average of prob */
+ * prob_ewma - exponential weighted moving average of prob
+ * prob_ewmsd - exp. weighted moving standard deviation of prob */
unsigned int cur_prob;
unsigned int prob_ewma;
+ u16 prob_ewmsd;

/* maximum retry counts */
u8 retry_count;
diff --git a/net/mac80211/rc80211_minstrel_debugfs.c b/net/mac80211/rc80211_minstrel_debugfs.c
index 182d552..a217a2c 100644
--- a/net/mac80211/rc80211_minstrel_debugfs.c
+++ b/net/mac80211/rc80211_minstrel_debugfs.c
@@ -85,10 +85,12 @@ minstrel_stats_open(struct inode *inode, struct file *file)
file->private_data = ms;
p = ms->buf;
p += sprintf(p, "\n");
- p += sprintf(p, "best __________rate_________ __statistics__ "
- "________last_______ ______sum-of________\n");
- p += sprintf(p, "rate [name idx airtime max_tp] [ ø(tp) ø(prob)] "
- "[prob.|retry|suc|att] [#success | #attempts]\n");
+ p += sprintf(p, "best __________rate_________ ______"
+ "statistics______ ________last_______ "
+ "______sum-of________\n");
+ p += sprintf(p, "rate [name idx airtime max_tp] [ ø(tp) ø(prob) "
+ "sd(prob)] [prob.|retry|suc|att] "
+ "[#success | #attempts]\n");

for (i = 0; i < mi->n_rates; i++) {
struct minstrel_rate *mr = &mi->r[i];
@@ -110,11 +112,13 @@ minstrel_stats_open(struct inode *inode, struct file *file)
prob = MINSTREL_TRUNC(mrs->cur_prob * 1000);
eprob = MINSTREL_TRUNC(mrs->prob_ewma * 1000);

- p += sprintf(p, "%4u.%1u %4u.%1u %3u.%1u %3u.%1u %3u"
- " %3u %-3u %9llu %-9llu\n",
+ p += sprintf(p, "%4u.%1u %4u.%1u %3u.%1u %3u.%1u"
+ " %3u.%1u %3u %3u %-3u "
+ "%9llu %-9llu\n",
tp_max / 10, tp_max % 10,
tp_avg / 10, tp_avg % 10,
eprob / 10, eprob % 10,
+ mrs->prob_ewmsd / 10, mrs->prob_ewmsd % 10,
prob / 10, prob % 10,
mrs->retry_count,
mrs->last_success,
@@ -180,11 +184,12 @@ minstrel_stats_csv_open(struct inode *inode, struct file *file)
prob = MINSTREL_TRUNC(mrs->cur_prob * 1000);
eprob = MINSTREL_TRUNC(mrs->prob_ewma * 1000);

- p += sprintf(p, "%u.%u,%u.%u,%u.%u,%u.%u,%u,%u,%u,"
+ p += sprintf(p, "%u.%u,%u.%u,%u.%u,%u.%u,%u.%u,%u,%u,%u,"
"%llu,%llu,%d,%d\n",
tp_max / 10, tp_max % 10,
tp_avg / 10, tp_avg % 10,
eprob / 10, eprob % 10,
+ mrs->prob_ewmsd / 10, mrs->prob_ewmsd % 10,
prob / 10, prob % 10,
mrs->retry_count,
mrs->last_success,
diff --git a/net/mac80211/rc80211_minstrel_ht_debugfs.c b/net/mac80211/rc80211_minstrel_ht_debugfs.c
index e70961f..892e87ab 100644
--- a/net/mac80211/rc80211_minstrel_ht_debugfs.c
+++ b/net/mac80211/rc80211_minstrel_ht_debugfs.c
@@ -86,11 +86,13 @@ minstrel_ht_stats_dump(struct minstrel_ht_sta *mi, int i, char *p)
prob = MINSTREL_TRUNC(mrs->cur_prob * 1000);
eprob = MINSTREL_TRUNC(mrs->prob_ewma * 1000);

- p += sprintf(p, "%4u.%1u %4u.%1u %3u.%1u %3u.%1u "
- "%3u %3u %-3u %9llu %-9llu\n",
+ p += sprintf(p, "%4u.%1u %4u.%1u %3u.%1u %3u.%1u"
+ " %3u.%1u %3u %3u %-3u "
+ "%9llu %-9llu\n",
tp_max / 10, tp_max % 10,
tp_avg / 10, tp_avg % 10,
eprob / 10, eprob % 10,
+ mrs->prob_ewmsd / 10, mrs->prob_ewmsd % 10,
prob / 10, prob % 10,
mrs->retry_count,
mrs->last_success,
@@ -128,10 +130,10 @@ minstrel_ht_stats_open(struct inode *inode, struct file *file)

p += sprintf(p, "\n");
p += sprintf(p, " best ____________rate__________ "
- "__statistics__ ________last_______ "
+ "______statistics______ ________last_______ "
"______sum-of________\n");
p += sprintf(p, "mode guard # rate [name idx airtime max_tp] "
- "[ ø(tp) ø(prob)] [prob.|retry|suc|att] [#success | "
+ "[ ø(tp) ø(prob) sd(prob)] [prob.|retry|suc|att] [#success | "
"#attempts]\n");

p = minstrel_ht_stats_dump(mi, MINSTREL_CCK_GROUP, p);
@@ -232,10 +234,12 @@ minstrel_ht_stats_csv_dump(struct minstrel_ht_sta *mi, int i, char *p,
prob = MINSTREL_TRUNC(mrs->cur_prob * 1000);
eprob = MINSTREL_TRUNC(mrs->prob_ewma * 1000);

- p += sprintf(p, "%u.%u,%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,%u,"
+ "%u,%llu,%llu,",
tp_max / 10, tp_max % 10,
tp_avg / 10, tp_avg % 10,
eprob / 10, eprob % 10,
+ mrs->prob_ewmsd / 10, mrs->prob_ewmsd % 10,
prob / 10, prob % 10,
mrs->retry_count,
mrs->last_success,
--
2.2.2


2015-02-13 14:58:05

by Thomas Huehn

[permalink] [raw]
Subject: [PATCH v2 05/10] mac80211: unify Minstrel & Minstrel-HTs calculation of rate statistics

This patch unifies the calculation of Minstrels and Minstrel-HTs
per-rate statistic. The new common function minstrel_calc_rate_stats()
is called when a statistic update is performed.

Signed-off-by: Thomas Huehn <[email protected]>
---
net/mac80211/rc80211_minstrel.c | 44 ++++++++++++++++++++++++--------------
net/mac80211/rc80211_minstrel.h | 3 +++
net/mac80211/rc80211_minstrel_ht.c | 28 +-----------------------
3 files changed, 32 insertions(+), 43 deletions(-)

diff --git a/net/mac80211/rc80211_minstrel.c b/net/mac80211/rc80211_minstrel.c
index 7c86a00..4858e67 100644
--- a/net/mac80211/rc80211_minstrel.c
+++ b/net/mac80211/rc80211_minstrel.c
@@ -127,6 +127,32 @@ minstrel_update_rates(struct minstrel_priv *mp, struct minstrel_sta_info *mi)
rate_control_set_rates(mp->hw, mi->sta, ratetbl);
}

+/*
+* Recalculate success probabilities and counters for a given rate using EWMA
+*/
+void
+minstrel_calc_rate_stats(struct minstrel_rate_stats *mrs)
+{
+ if (unlikely(mrs->attempts > 0)) {
+ mrs->sample_skipped = 0;
+ mrs->cur_prob = MINSTREL_FRAC(mrs->success, mrs->attempts);
+ if (unlikely(!mrs->att_hist))
+ mrs->probability = mrs->cur_prob;
+ else
+ mrs->probability = minstrel_ewma(mrs->probability,
+ mrs->cur_prob, EWMA_LEVEL);
+ mrs->att_hist += mrs->attempts;
+ mrs->succ_hist += mrs->success;
+ } else {
+ mrs->sample_skipped++;
+ }
+
+ mrs->last_success = mrs->success;
+ mrs->last_attempts = mrs->attempts;
+ mrs->success = 0;
+ mrs->attempts = 0;
+}
+
static void
minstrel_update_stats(struct minstrel_priv *mp, struct minstrel_sta_info *mi)
{
@@ -146,22 +172,8 @@ minstrel_update_stats(struct minstrel_priv *mp, struct minstrel_sta_info *mi)
if (!usecs)
usecs = 1000000;

- if (unlikely(mrs->attempts > 0)) {
- mrs->sample_skipped = 0;
- mrs->cur_prob = MINSTREL_FRAC(mrs->success,
- mrs->attempts);
- mrs->succ_hist += mrs->success;
- mrs->att_hist += mrs->attempts;
- mrs->probability = minstrel_ewma(mrs->probability,
- mrs->cur_prob,
- EWMA_LEVEL);
- } else
- mrs->sample_skipped++;
-
- mrs->last_success = mrs->success;
- mrs->last_attempts = mrs->attempts;
- mrs->success = 0;
- mrs->attempts = 0;
+ /* Update success probabilities per rate */
+ minstrel_calc_rate_stats(mrs);

/* Update throughput per rate, reset thr. below 10% success */
if (mrs->probability < MINSTREL_FRAC(10, 100))
diff --git a/net/mac80211/rc80211_minstrel.h b/net/mac80211/rc80211_minstrel.h
index 9613e73..728144c 100644
--- a/net/mac80211/rc80211_minstrel.h
+++ b/net/mac80211/rc80211_minstrel.h
@@ -132,6 +132,9 @@ extern const struct rate_control_ops mac80211_minstrel;
void minstrel_add_sta_debugfs(void *priv, void *priv_sta, struct dentry *dir);
void minstrel_remove_sta_debugfs(void *priv, void *priv_sta);

+/* Recalculate success probabilities and counters for a given rate using EWMA */
+void minstrel_calc_rate_stats(struct minstrel_rate_stats *mr);
+
/* debugfs */
int minstrel_stats_open(struct inode *inode, struct file *file);
int minstrel_stats_csv_open(struct inode *inode, struct file *file);
diff --git a/net/mac80211/rc80211_minstrel_ht.c b/net/mac80211/rc80211_minstrel_ht.c
index 80452cf..381d089 100644
--- a/net/mac80211/rc80211_minstrel_ht.c
+++ b/net/mac80211/rc80211_minstrel_ht.c
@@ -311,32 +311,6 @@ minstrel_get_ratestats(struct minstrel_ht_sta *mi, int index)
return &mi->groups[index / MCS_GROUP_RATES].rates[index % MCS_GROUP_RATES];
}

-
-/*
- * Recalculate success probabilities and counters for a rate using EWMA
- */
-static void
-minstrel_calc_rate_ewma(struct minstrel_rate_stats *mr)
-{
- if (unlikely(mr->attempts > 0)) {
- mr->sample_skipped = 0;
- mr->cur_prob = MINSTREL_FRAC(mr->success, mr->attempts);
- if (!mr->att_hist)
- mr->probability = mr->cur_prob;
- else
- mr->probability = minstrel_ewma(mr->probability,
- mr->cur_prob, EWMA_LEVEL);
- mr->att_hist += mr->attempts;
- mr->succ_hist += mr->success;
- } else {
- mr->sample_skipped++;
- }
- mr->last_success = mr->success;
- mr->last_attempts = mr->attempts;
- mr->success = 0;
- mr->attempts = 0;
-}
-
/*
* Calculate throughput based on the average A-MPDU length, taking into account
* the expected number of retransmissions and their expected length
@@ -565,7 +539,7 @@ minstrel_ht_update_stats(struct minstrel_priv *mp, struct minstrel_ht_sta *mi)

mr = &mg->rates[i];
mr->retry_updated = false;
- minstrel_calc_rate_ewma(mr);
+ minstrel_calc_rate_stats(mr);
minstrel_ht_calc_tp(mi, group, i);

if (!mr->cur_tp)
--
2.2.2


2015-03-17 08:16:45

by Felix Fietkau

[permalink] [raw]
Subject: Re: [PATCH v2 03/10] mac80211: add new Minstrel statistic output via csv

On 2015-02-13 15:57, Thomas Huehn wrote:
> This patch adds a new debugfs file "rc_stats_csv" to output Minstrels
> statistics in a common csv format that is easy to parse.
>
> Signed-off-by: Thomas Huehn <[email protected]>
> Signed-off-by: Stefan Venz <[email protected]>
> ---
> net/mac80211/rc80211_minstrel.h | 6 +-
> net/mac80211/rc80211_minstrel_debugfs.c | 95 ++++++++++++++++++++++++++----
> net/mac80211/rc80211_minstrel_ht_debugfs.c | 2 +-
> 3 files changed, 88 insertions(+), 15 deletions(-)
>

> diff --git a/net/mac80211/rc80211_minstrel_ht_debugfs.c b/net/mac80211/rc80211_minstrel_ht_debugfs.c
> index 7fc690f..b300513 100644
> --- a/net/mac80211/rc80211_minstrel_ht_debugfs.c
> +++ b/net/mac80211/rc80211_minstrel_ht_debugfs.c
> @@ -112,7 +112,7 @@ minstrel_ht_stats_open(struct inode *inode, struct file *file)
>
> if (!msp->is_ht) {
> inode->i_private = &msp->legacy;
> - ret = minstrel_stats_open(inode, file);
> + ret = minstrel_stats_csv_open(inode, file);
That does not look right to me.

- Felix

2015-03-17 08:18:45

by Felix Fietkau

[permalink] [raw]
Subject: Re: [PATCH v2 04/10] mac80211: add new Minstrel-HT statistic output via csv

On 2015-02-13 15:57, Thomas Huehn wrote:
> This patch adds a new debugfs file "rc_stats_csv" to output
> Minstrel-HTs statistics in a common csv format that is easy
> to parse.
>
> Signed-off-by: Thomas Huehn <[email protected]>
> Signed-off-by: Stefan Venz <[email protected]>
> ---
> --- a/net/mac80211/rc80211_minstrel_ht_debugfs.c
> +++ b/net/mac80211/rc80211_minstrel_ht_debugfs.c
> +static int
> +minstrel_ht_stats_csv_open(struct inode *inode, struct file *file)
> +{
> + struct minstrel_ht_sta_priv *msp = inode->i_private;
> + struct minstrel_ht_sta *mi = &msp->ht;
> + struct minstrel_debugfs_info *ms;
> + struct timeval tv;
> + unsigned int i;
> + int ret;
> + char *p;
> +
> + do_gettimeofday(&tv);
> +
> + if (!msp->is_ht) {
> + inode->i_private = &msp->legacy;
> + ret = minstrel_stats_open(inode, file);
Should be minstrel_stats_csv_open here?

- Felix

2015-03-17 08:24:07

by Felix Fietkau

[permalink] [raw]
Subject: Re: [PATCH v2 07/10] mac80211: restructure per-rate throughput calculation into function

On 2015-02-13 15:57, Thomas Huehn wrote:
> This patch moves Minstrels and Minstrel-HTs per-rate throughput
> calculation (EWMA(thr)) into a dedicated function to be called.
> Therefore the variable "unsigned int cur_tp" within struct
> "minstrel_rate_stats" becomes obsolete. and is removed to free
> up its space.
>
> Signed-off-by: Thomas Huehn <[email protected]>
> ---
> net/mac80211/rc80211_minstrel.c | 46 +++++++++++------
> net/mac80211/rc80211_minstrel.h | 4 +-
> net/mac80211/rc80211_minstrel_debugfs.c | 12 ++---
> net/mac80211/rc80211_minstrel_ht.c | 79 ++++++++++++++++++------------
> net/mac80211/rc80211_minstrel_ht.h | 1 +
> net/mac80211/rc80211_minstrel_ht_debugfs.c | 12 ++---
> 6 files changed, 94 insertions(+), 60 deletions(-)
>
> diff --git a/net/mac80211/rc80211_minstrel.c b/net/mac80211/rc80211_minstrel.c
> index 89db6cf..28de2f7a 100644
> --- a/net/mac80211/rc80211_minstrel.c
> +++ b/net/mac80211/rc80211_minstrel.c
> @@ -69,13 +69,34 @@ rix_to_ndx(struct minstrel_sta_info *mi, int rix)
> return i;
> }
>
> +/* return current EMWA throughput */
> +int minstrel_get_tp_avg(struct minstrel_rate *mr)
> +{
> + int tp_avg, usecs;
> +
> + usecs = mr->perfect_tx_time;
> + if (!usecs)
> + usecs = 1000000;
> +
> + /* reset thr. below 10% success */
> + if (mr->stats.prob_ewma < MINSTREL_FRAC(10, 100))
> + tp_avg = 0;
You don't really need a variable, you can just do return 0 here and
reduce indentation of the line below.

> + else
> + tp_avg = MINSTREL_TRUNC(mr->stats.prob_ewma * (100000 / usecs));
> +
> + return tp_avg;
> +}
> +
> +
> +
> /* find & sort topmost throughput rates */
> static inline void
> minstrel_sort_best_tp_rates(struct minstrel_sta_info *mi, int i, u8 *tp_list)
> {
> int j = MAX_THR_RATES;
>
> - while (j > 0 && mi->r[i].stats.cur_tp > mi->r[tp_list[j - 1]].stats.cur_tp)
> + while (j > 0 && (minstrel_get_tp_avg(&mi->r[i]) >
> + minstrel_get_tp_avg(&mi->r[tp_list[j - 1]])))
Indentation seems off.

> j--;
> if (j < MAX_THR_RATES - 1)
> memmove(&tp_list[j + 1], &tp_list[j], MAX_THR_RATES - (j + 1));
> @@ -158,8 +179,7 @@ minstrel_update_stats(struct minstrel_priv *mp, struct minstrel_sta_info *mi)
> {
> u8 tmp_tp_rate[MAX_THR_RATES];
> u8 tmp_prob_rate = 0;
> - u32 usecs;
> - int i;
> + int i, tmp_cur_tp, tmp_prob_tp;
>
> for (i = 0; i < MAX_THR_RATES; i++)
> tmp_tp_rate[i] = 0;
> diff --git a/net/mac80211/rc80211_minstrel_ht.c b/net/mac80211/rc80211_minstrel_ht.c
> index 6b07686..2a55f63 100644
> --- a/net/mac80211/rc80211_minstrel_ht.c
> +++ b/net/mac80211/rc80211_minstrel_ht.c
> @@ -312,23 +312,23 @@ minstrel_get_ratestats(struct minstrel_ht_sta *mi, int index)
> }
>
> /*
> - * Calculate throughput based on the average A-MPDU length, taking into account
> - * the expected number of retransmissions and their expected length
> + * Return current throughput based on the average A-MPDU length, taking into
> + * account the expected number of retransmissions and their expected length
> */
> -static void
> -minstrel_ht_calc_tp(struct minstrel_ht_sta *mi, int group, int rate)
> +int
> +minstrel_ht_get_tp_avg(struct minstrel_ht_sta *mi, int group, int rate)
> {
> struct minstrel_rate_stats *mrs;
> unsigned int nsecs = 0;
> - unsigned int tmp_prob_ewma;
> + unsigned int tmp_prob_ewma, tp_avg;
>
> mrs = &mi->groups[group].rates[rate];
> tmp_prob_ewma = mrs->prob_ewma;
>
> /* do not account throughput if sucess prob is below 10% */
> if (mrs->prob_ewma < MINSTREL_FRAC(10, 100)) {
> - mrs->cur_tp = 0;
> - return;
> + tp_avg = 0;
> + return tp_avg;
No need for the tp_avg variable.

> }
>
> /*
> @@ -344,7 +344,9 @@ minstrel_ht_calc_tp(struct minstrel_ht_sta *mi, int group, int rate)
> nsecs += minstrel_mcs_groups[group].duration[rate];
>
> /* prob is scaled - see MINSTREL_FRAC above */
> - mrs->cur_tp = MINSTREL_TRUNC(1000000 * ((tmp_prob_ewma * 1000) / nsecs));
> + tp_avg = MINSTREL_TRUNC(100000 * ((tmp_prob_ewma * 1000) / nsecs));
> +
> + return tp_avg;
> }
>
> /*

2015-03-17 08:32:32

by Felix Fietkau

[permalink] [raw]
Subject: Re: [PATCH v2 08/10] mac80211: add max. lossless throughput per rate to rc_stats

On 2015-02-13 15:57, Thomas Huehn wrote:
> 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]>
> ---
> net/mac80211/rc80211_minstrel.c | 12 ++++++++++++
> net/mac80211/rc80211_minstrel.h | 1 +
> net/mac80211/rc80211_minstrel_debugfs.c | 18 +++++++++++-------
> net/mac80211/rc80211_minstrel_ht.c | 19 +++++++++++++++++++
> net/mac80211/rc80211_minstrel_ht.h | 1 +
> net/mac80211/rc80211_minstrel_ht_debugfs.c | 20 ++++++++++++--------
> 6 files changed, 56 insertions(+), 15 deletions(-)
>
> diff --git a/net/mac80211/rc80211_minstrel.c b/net/mac80211/rc80211_minstrel.c
> index 28de2f7a..42dfef8 100644
> --- a/net/mac80211/rc80211_minstrel.c
> +++ b/net/mac80211/rc80211_minstrel.c
> @@ -87,7 +87,19 @@ int minstrel_get_tp_avg(struct minstrel_rate *mr)
> return tp_avg;
> }
>
> +/* return max. potential lossless throughput */
> +int minstrel_get_tp_max(struct minstrel_rate *mr)
> +{
> + int tp_max, usecs;
>
> + usecs = mr->perfect_tx_time;
> + if (!usecs)
> + usecs = 1000000;
> +
> + tp_max = 100000 / usecs;
> +
> + return tp_max;
> +}
This should probably be an inline function, and you can remove the
tp_max variable as well.
By the way, in the case of !usecs, the result (100000 / 1000000) will be
0, so you can simplify the logic.


> /* find & sort topmost throughput rates */
> static inline void
> diff --git a/net/mac80211/rc80211_minstrel_ht.c b/net/mac80211/rc80211_minstrel_ht.c
> index 2a55f63..b62b04e 100644
> --- a/net/mac80211/rc80211_minstrel_ht.c
> +++ b/net/mac80211/rc80211_minstrel_ht.c
> @@ -350,6 +350,25 @@ minstrel_ht_get_tp_avg(struct minstrel_ht_sta *mi, int group, int rate)
> }
>
> /*
> + * Return max. potential lossless throughput based on the average A-MPDU
> + */
> +int
> +minstrel_ht_get_tp_max(struct minstrel_ht_sta *mi, int group, int rate)
> +{
> + unsigned int nsecs = 0;
> + unsigned int tp_max;
> +
> + if (group != MINSTREL_CCK_GROUP)
> + nsecs = 1000 * mi->overhead / MINSTREL_TRUNC(mi->avg_ampdu_len);
> +
> + nsecs += minstrel_mcs_groups[group].duration[rate];
> + tp_max = 100000000 / nsecs;
> +
> + return tp_max;
> +}
I don't like duplication of the throughput metric - gets annoying if we
ever decide to tweak it. How about unifying this with
minstrel_ht_get_tp_avg by passing in the prob value as a parameter.

- Felix