All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v3 01/10] mac80211: enhance readability of Minstrels rc_stats output
@ 2015-03-17 17:29 Thomas Huehn
  2015-03-17 17:29 ` [PATCH v3 02/10] mac80211: enhance readability of Minstrel-HTs " Thomas Huehn
                   ` (8 more replies)
  0 siblings, 9 replies; 11+ messages in thread
From: Thomas Huehn @ 2015-03-17 17:29 UTC (permalink / raw)
  To: linux-wireless; +Cc: johannes, nbd, thomas

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 <thomas@net.t-labs.tu-berlin.de>
Signed-off-by: Stefan Venz <ikstream86@gmail.com>
---
 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.3.0


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH v3 02/10] mac80211: enhance readability of Minstrel-HTs rc_stats output
  2015-03-17 17:29 [PATCH v3 01/10] mac80211: enhance readability of Minstrels rc_stats output Thomas Huehn
@ 2015-03-17 17:29 ` Thomas Huehn
  2015-03-17 17:29 ` [PATCH v3 03/10] mac80211: add new Minstrel statistic output via csv Thomas Huehn
                   ` (7 subsequent siblings)
  8 siblings, 0 replies; 11+ messages in thread
From: Thomas Huehn @ 2015-03-17 17:29 UTC (permalink / raw)
  To: linux-wireless; +Cc: johannes, nbd, thomas

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 <thomas@net.t-labs.tu-berlin.de>
Signed-off-by: Stefan Venz <ikstream86@gmail.com>
---
 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.3.0


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH v3 03/10] mac80211: add new Minstrel statistic output via csv
  2015-03-17 17:29 [PATCH v3 01/10] mac80211: enhance readability of Minstrels rc_stats output Thomas Huehn
  2015-03-17 17:29 ` [PATCH v3 02/10] mac80211: enhance readability of Minstrel-HTs " Thomas Huehn
@ 2015-03-17 17:29 ` Thomas Huehn
  2015-03-17 17:29 ` [PATCH v3 04/10] mac80211: add new Minstrel-HT " Thomas Huehn
                   ` (6 subsequent siblings)
  8 siblings, 0 replies; 11+ messages in thread
From: Thomas Huehn @ 2015-03-17 17:29 UTC (permalink / raw)
  To: linux-wireless; +Cc: johannes, nbd, thomas

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 <thomas@net.t-labs.tu-berlin.de>
Signed-off-by: Stefan Venz <ikstream86@gmail.com>
---
 net/mac80211/rc80211_minstrel.h         |  6 +--
 net/mac80211/rc80211_minstrel_debugfs.c | 95 +++++++++++++++++++++++++++++----
 2 files changed, 87 insertions(+), 14 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..8c35402 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);
 }
+
-- 
2.3.0


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH v3 04/10] mac80211: add new Minstrel-HT statistic output via csv
  2015-03-17 17:29 [PATCH v3 01/10] mac80211: enhance readability of Minstrels rc_stats output Thomas Huehn
  2015-03-17 17:29 ` [PATCH v3 02/10] mac80211: enhance readability of Minstrel-HTs " Thomas Huehn
  2015-03-17 17:29 ` [PATCH v3 03/10] mac80211: add new Minstrel statistic output via csv Thomas Huehn
@ 2015-03-17 17:29 ` Thomas Huehn
  2015-03-17 17:29 ` [PATCH v3 05/10] mac80211: unify Minstrel & Minstrel-HTs calculation of rate statistics Thomas Huehn
                   ` (5 subsequent siblings)
  8 siblings, 0 replies; 11+ messages in thread
From: Thomas Huehn @ 2015-03-17 17:29 UTC (permalink / raw)
  To: linux-wireless; +Cc: johannes, nbd, thomas

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 <thomas@net.t-labs.tu-berlin.de>
Signed-off-by: Stefan Venz <ikstream86@gmail.com>
---
 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 7fc690f..133d7b6 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_csv_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.3.0


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH v3 05/10] mac80211: unify Minstrel & Minstrel-HTs calculation of rate statistics
  2015-03-17 17:29 [PATCH v3 01/10] mac80211: enhance readability of Minstrels rc_stats output Thomas Huehn
                   ` (2 preceding siblings ...)
  2015-03-17 17:29 ` [PATCH v3 04/10] mac80211: add new Minstrel-HT " Thomas Huehn
@ 2015-03-17 17:29 ` Thomas Huehn
  2015-03-17 17:29 ` [PATCH v3 06/10] mac80211: improve Minstrel variable & function naming Thomas Huehn
                   ` (4 subsequent siblings)
  8 siblings, 0 replies; 11+ messages in thread
From: Thomas Huehn @ 2015-03-17 17:29 UTC (permalink / raw)
  To: linux-wireless; +Cc: johannes, nbd, thomas

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 <thomas@net.t-labs.tu-berlin.de>
---
 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 60698fc..7afa562 100644
--- a/net/mac80211/rc80211_minstrel_ht.c
+++ b/net/mac80211/rc80211_minstrel_ht.c
@@ -313,32 +313,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
@@ -567,7 +541,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.3.0


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH v3 06/10] mac80211: improve Minstrel variable & function naming
  2015-03-17 17:29 [PATCH v3 01/10] mac80211: enhance readability of Minstrels rc_stats output Thomas Huehn
                   ` (3 preceding siblings ...)
  2015-03-17 17:29 ` [PATCH v3 05/10] mac80211: unify Minstrel & Minstrel-HTs calculation of rate statistics Thomas Huehn
@ 2015-03-17 17:29 ` Thomas Huehn
  2015-03-17 17:29 ` [PATCH v3 07/10] mac80211: restructure per-rate throughput calculation into function Thomas Huehn
                   ` (3 subsequent siblings)
  8 siblings, 0 replies; 11+ messages in thread
From: Thomas Huehn @ 2015-03-17 17:29 UTC (permalink / raw)
  To: linux-wireless; +Cc: johannes, nbd, thomas

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 <thomas@net.t-labs.tu-berlin.de>
---
 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 8c35402..5f219e9 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 7afa562..aca8b64 100644
--- a/net/mac80211/rc80211_minstrel_ht.c
+++ b/net/mac80211/rc80211_minstrel_ht.c
@@ -320,16 +320,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;
 	}
 
@@ -337,8 +337,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);
@@ -346,8 +346,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));
 }
 
 /*
@@ -368,13 +367,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;
@@ -396,16 +395,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 */
@@ -414,15 +413,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;
 	}
 }
@@ -467,7 +466,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;
 
@@ -477,11 +476,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;
 		}
 	}
 }
@@ -499,7 +498,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;
@@ -539,12 +538,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 */
@@ -588,7 +587,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
@@ -611,7 +610,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;
 
@@ -752,7 +751,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);
 	}
@@ -765,7 +765,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;
@@ -774,16 +774,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;
@@ -814,9 +814,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));
 }
 
 
@@ -825,22 +825,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)
@@ -898,7 +898,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;
@@ -914,12 +914,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;
 
 	/*
@@ -936,7 +936,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;
 
 	/*
@@ -951,7 +951,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)
@@ -1105,7 +1105,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 133d7b6..53db416 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.3.0


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH v3 07/10] mac80211: restructure per-rate throughput calculation into function
  2015-03-17 17:29 [PATCH v3 01/10] mac80211: enhance readability of Minstrels rc_stats output Thomas Huehn
                   ` (4 preceding siblings ...)
  2015-03-17 17:29 ` [PATCH v3 06/10] mac80211: improve Minstrel variable & function naming Thomas Huehn
@ 2015-03-17 17:29 ` Thomas Huehn
  2015-03-17 17:29 ` [PATCH v3 08/10] mac80211: add max. lossless throughput per rate to rc_stats Thomas Huehn
                   ` (2 subsequent siblings)
  8 siblings, 0 replies; 11+ messages in thread
From: Thomas Huehn @ 2015-03-17 17:29 UTC (permalink / raw)
  To: linux-wireless; +Cc: johannes, nbd, thomas

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 <thomas@net.t-labs.tu-berlin.de>
---
 net/mac80211/rc80211_minstrel.c            | 43 +++++++++++------
 net/mac80211/rc80211_minstrel.h            |  4 +-
 net/mac80211/rc80211_minstrel_debugfs.c    | 12 ++---
 net/mac80211/rc80211_minstrel_ht.c         | 77 ++++++++++++++++++------------
 net/mac80211/rc80211_minstrel_ht.h         |  1 +
 net/mac80211/rc80211_minstrel_ht_debugfs.c | 12 ++---
 6 files changed, 88 insertions(+), 61 deletions(-)

diff --git a/net/mac80211/rc80211_minstrel.c b/net/mac80211/rc80211_minstrel.c
index 89db6cf..d985227 100644
--- a/net/mac80211/rc80211_minstrel.c
+++ b/net/mac80211/rc80211_minstrel.c
@@ -69,14 +69,32 @@ 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 usecs;
+
+	usecs = mr->perfect_tx_time;
+	if (!usecs)
+		usecs = 1000000;
+
+	/* reset thr. below 10% success */
+	if (mr->stats.prob_ewma < MINSTREL_FRAC(10, 100))
+		return 0;
+	else
+		return MINSTREL_TRUNC(mr->stats.prob_ewma * (100000 / usecs));
+}
+
 /* 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));
 	if (j < MAX_THR_RATES)
@@ -158,8 +176,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 +185,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 +212,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 +685,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 5f219e9..4d6eeef 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 aca8b64..7202e34 100644
--- a/net/mac80211/rc80211_minstrel_ht.c
+++ b/net/mac80211/rc80211_minstrel_ht.c
@@ -314,11 +314,11 @@ 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;
@@ -328,10 +328,8 @@ minstrel_ht_calc_tp(struct minstrel_ht_sta *mi, int group, int 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;
-	}
+	if (mrs->prob_ewma < MINSTREL_FRAC(10, 100))
+		return 0;
 
 	/*
 	 * For the throughput calculation, limit the probability value to 90% to
@@ -346,7 +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 */
-	mrs->cur_tp = MINSTREL_TRUNC(1000000 * ((tmp_prob_ewma * 1000) / nsecs));
+	return MINSTREL_TRUNC(100000 * ((tmp_prob_ewma * 1000) / nsecs));
 }
 
 /*
@@ -360,22 +358,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);
@@ -396,14 +394,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
@@ -414,9 +417,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)
@@ -443,11 +455,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++) {
@@ -466,8 +478,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] /
@@ -476,11 +487,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);
 		}
 	}
 }
@@ -541,9 +555,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 */
@@ -1302,7 +1315,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);
@@ -1310,8 +1323,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 53db416..52ed8f5 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.3.0


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH v3 08/10] mac80211: add max. lossless throughput per rate to rc_stats
  2015-03-17 17:29 [PATCH v3 01/10] mac80211: enhance readability of Minstrels rc_stats output Thomas Huehn
                   ` (5 preceding siblings ...)
  2015-03-17 17:29 ` [PATCH v3 07/10] mac80211: restructure per-rate throughput calculation into function Thomas Huehn
@ 2015-03-17 17:29 ` Thomas Huehn
  2015-03-21 23:20   ` Felix Fietkau
  2015-03-17 17:29 ` [PATCH v3 09/10] mac80211: reduce calculation costs of EWMA Thomas Huehn
  2015-03-17 17:29 ` [PATCH v3 10/10] mac80211: add standard deviation to Minstrels throughput statistic Thomas Huehn
  8 siblings, 1 reply; 11+ messages in thread
From: Thomas Huehn @ 2015-03-17 17:29 UTC (permalink / raw)
  To: linux-wireless; +Cc: johannes, nbd, thomas

This patch adds the new statistic "maximum possible lossless
throughput" to Minstrels and Minstrel-HTs rc_stats (in debugfs). This
enables comprehensive comparison between current per-rate throughput
and max. achievable per-rate throughput.

Signed-off-by: Thomas Huehn <thomas@net.t-labs.tu-berlin.de>
---
 net/mac80211/rc80211_minstrel.c            | 10 ++++
 net/mac80211/rc80211_minstrel.h            |  1 +
 net/mac80211/rc80211_minstrel_debugfs.c    | 18 ++++---
 net/mac80211/rc80211_minstrel_ht.c         | 84 ++++++++++++++++--------------
 net/mac80211/rc80211_minstrel_ht.h         |  4 +-
 net/mac80211/rc80211_minstrel_ht_debugfs.c | 24 +++++----
 6 files changed, 83 insertions(+), 58 deletions(-)

diff --git a/net/mac80211/rc80211_minstrel.c b/net/mac80211/rc80211_minstrel.c
index d985227..c2afe51 100644
--- a/net/mac80211/rc80211_minstrel.c
+++ b/net/mac80211/rc80211_minstrel.c
@@ -85,6 +85,16 @@ int minstrel_get_tp_avg(struct minstrel_rate *mr)
 		return MINSTREL_TRUNC(mr->stats.prob_ewma * (100000 / usecs));
 }
 
+/* return max. potential lossless throughput */
+inline int
+minstrel_get_tp_max(struct minstrel_rate *mr)
+{
+	if (!mr->perfect_tx_time)
+		return 0;
+
+	return 100000 / mr->perfect_tx_time;
+}
+
 /* find & sort topmost throughput rates */
 static inline void
 minstrel_sort_best_tp_rates(struct minstrel_sta_info *mi, int i, u8 *tp_list)
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 4d6eeef..3ed69ef 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 7202e34..7430a1d 100644
--- a/net/mac80211/rc80211_minstrel_ht.c
+++ b/net/mac80211/rc80211_minstrel_ht.c
@@ -318,33 +318,30 @@ minstrel_get_ratestats(struct minstrel_ht_sta *mi, int index)
  * account the expected number of retransmissions and their expected length
  */
 int
-minstrel_ht_get_tp_avg(struct minstrel_ht_sta *mi, int group, int rate)
+minstrel_ht_get_tp_avg(struct minstrel_ht_sta *mi, int group, int rate,
+		       int prob_ewma)
 {
-	struct minstrel_rate_stats *mrs;
 	unsigned int nsecs = 0;
-	unsigned int tmp_prob_ewma;
-
-	mrs = &mi->groups[group].rates[rate];
-	tmp_prob_ewma = mrs->prob_ewma;
 
 	/* do not account throughput if sucess prob is below 10% */
-	if (mrs->prob_ewma < MINSTREL_FRAC(10, 100))
+	if (prob_ewma < MINSTREL_FRAC(10, 100))
 		return 0;
 
-	/*
-	 * For the throughput calculation, limit the probability value to 90% to
-	 * account for collision related packet error rate fluctuation
-	 */
-	if (mrs->prob_ewma > MINSTREL_FRAC(90, 100))
-		tmp_prob_ewma = MINSTREL_FRAC(90, 100);
-
 	if (group != MINSTREL_CCK_GROUP)
 		nsecs = 1000 * mi->overhead / MINSTREL_TRUNC(mi->avg_ampdu_len);
 
 	nsecs += minstrel_mcs_groups[group].duration[rate];
 
-	/* prob is scaled - see MINSTREL_FRAC above */
-	return MINSTREL_TRUNC(100000 * ((tmp_prob_ewma * 1000) / nsecs));
+	/*
+	 * For the throughput calculation, limit the probability value to 90% to
+	 * account for collision related packet error rate fluctuation
+	 * (prob is scaled - see MINSTREL_FRAC above)
+	 */
+	if (prob_ewma > MINSTREL_FRAC(90, 100))
+		return MINSTREL_TRUNC(100000 * ((MINSTREL_FRAC(90, 100) * 1000)
+								      / nsecs));
+	else
+		return MINSTREL_TRUNC(100000 * ((prob_ewma * 1000) / nsecs));
 }
 
 /*
@@ -364,14 +361,15 @@ minstrel_ht_sort_best_tp_rates(struct minstrel_ht_sta *mi, u16 index,
 
 	cur_group = index / MCS_GROUP_RATES;
 	cur_idx = index  % MCS_GROUP_RATES;
-	cur_tp_avg = minstrel_ht_get_tp_avg(mi, cur_group, cur_idx);
 	cur_prob = mi->groups[cur_group].rates[cur_idx].prob_ewma;
+	cur_tp_avg = minstrel_ht_get_tp_avg(mi, cur_group, cur_idx, cur_prob);
 
 	do {
 		tmp_group = tp_list[j - 1] / MCS_GROUP_RATES;
 		tmp_idx = tp_list[j - 1] % MCS_GROUP_RATES;
-		tmp_tp_avg = minstrel_ht_get_tp_avg(mi, tmp_group, tmp_idx);
 		tmp_prob = mi->groups[tmp_group].rates[tmp_idx].prob_ewma;
+		tmp_tp_avg = minstrel_ht_get_tp_avg(mi, tmp_group, tmp_idx,
+						    tmp_prob);
 		if (cur_tp_avg < tmp_tp_avg ||
 		    (cur_tp_avg == tmp_tp_avg && cur_prob <= tmp_prob))
 			break;
@@ -396,8 +394,8 @@ minstrel_ht_set_best_prob_rate(struct minstrel_ht_sta *mi, u16 index)
 	struct minstrel_rate_stats *mrs;
 	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;
+	int max_gpr_group, max_gpr_idx;
+	int max_gpr_tp_avg, max_gpr_prob;
 
 	cur_group = index / MCS_GROUP_RATES;
 	cur_idx = index % MCS_GROUP_RATES;
@@ -406,8 +404,8 @@ minstrel_ht_set_best_prob_rate(struct minstrel_ht_sta *mi, u16 index)
 
 	tmp_group = mi->max_prob_rate / MCS_GROUP_RATES;
 	tmp_idx = mi->max_prob_rate % MCS_GROUP_RATES;
-	tmp_tp_avg = minstrel_ht_get_tp_avg(mi, tmp_group, tmp_idx);
 	tmp_prob = mi->groups[tmp_group].rates[tmp_idx].prob_ewma;
+	tmp_tp_avg = minstrel_ht_get_tp_avg(mi, tmp_group, tmp_idx, tmp_prob);
 
 	/* if max_tp_rate[0] is from MCS_GROUP max_prob_rate get selected from
 	 * MCS_GROUP as well as CCK_GROUP rates do not allow aggregation */
@@ -417,18 +415,18 @@ minstrel_ht_set_best_prob_rate(struct minstrel_ht_sta *mi, u16 index)
 		return;
 
 	if (mrs->prob_ewma > MINSTREL_FRAC(75, 100)) {
-		cur_tp_avg = minstrel_ht_get_tp_avg(mi, cur_group, cur_idx);
+		cur_tp_avg = minstrel_ht_get_tp_avg(mi, cur_group, cur_idx,
+						    mrs->prob_ewma);
 		if (cur_tp_avg > tmp_tp_avg)
 			mi->max_prob_rate = index;
 
-		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)
+		max_gpr_group = mg->max_group_prob_rate / MCS_GROUP_RATES;
+		max_gpr_idx = mg->max_group_prob_rate %	MCS_GROUP_RATES;
+		max_gpr_prob = mi->groups[max_gpr_group].rates[max_gpr_idx].prob_ewma;
+		max_gpr_tp_avg = minstrel_ht_get_tp_avg(mi, max_gpr_group,
+							max_gpr_idx,
+							max_gpr_prob);
+		if (cur_tp_avg > max_gpr_tp_avg)
 			mg->max_group_prob_rate = index;
 	} else {
 		if (mrs->prob_ewma > tmp_prob)
@@ -450,16 +448,18 @@ minstrel_ht_assign_best_tp_rates(struct minstrel_ht_sta *mi,
 				 u16 tmp_mcs_tp_rate[MAX_THR_RATES],
 				 u16 tmp_cck_tp_rate[MAX_THR_RATES])
 {
-	unsigned int tmp_group, tmp_idx, tmp_cck_tp, tmp_mcs_tp;
+	unsigned int tmp_group, tmp_idx, tmp_cck_tp, tmp_mcs_tp, tmp_prob;
 	int i;
 
 	tmp_group = tmp_cck_tp_rate[0] / MCS_GROUP_RATES;
 	tmp_idx = tmp_cck_tp_rate[0] % MCS_GROUP_RATES;
-	tmp_cck_tp = minstrel_ht_get_tp_avg(mi, tmp_group, tmp_idx);
+	tmp_prob = mi->groups[tmp_group].rates[tmp_idx].prob_ewma;
+	tmp_cck_tp = minstrel_ht_get_tp_avg(mi, tmp_group, tmp_idx, tmp_prob);
 
 	tmp_group = tmp_mcs_tp_rate[0] / MCS_GROUP_RATES;
 	tmp_idx = tmp_mcs_tp_rate[0] % MCS_GROUP_RATES;
-	tmp_mcs_tp = minstrel_ht_get_tp_avg(mi, tmp_group, tmp_idx);
+	tmp_prob = mi->groups[tmp_group].rates[tmp_idx].prob_ewma;
+	tmp_mcs_tp = minstrel_ht_get_tp_avg(mi, tmp_group, tmp_idx, tmp_prob);
 
 	if (tmp_cck_tp > tmp_mcs_tp) {
 		for(i = 0; i < MAX_THR_RATES; i++) {
@@ -478,7 +478,7 @@ static inline void
 minstrel_ht_prob_rate_reduce_streams(struct minstrel_ht_sta *mi)
 {
 	struct minstrel_mcs_group_data *mg;
-	int tmp_max_streams, group, tmp_idx;
+	int tmp_max_streams, group, tmp_idx, tmp_prob;
 	int tmp_tp = 0;
 
 	tmp_max_streams = minstrel_mcs_groups[mi->max_tp_rate[0] /
@@ -489,12 +489,14 @@ minstrel_ht_prob_rate_reduce_streams(struct minstrel_ht_sta *mi)
 			continue;
 
 		tmp_idx = mg->max_group_prob_rate % MCS_GROUP_RATES;
+		tmp_prob = mi->groups[group].rates[tmp_idx].prob_ewma;
 
-		if (tmp_tp < minstrel_ht_get_tp_avg(mi, group, tmp_idx) &&
+		if (tmp_tp < minstrel_ht_get_tp_avg(mi, group, tmp_idx, tmp_prob) &&
 		   (minstrel_mcs_groups[group].streams < tmp_max_streams)) {
 				mi->max_prob_rate = mg->max_group_prob_rate;
 				tmp_tp = minstrel_ht_get_tp_avg(mi, group,
-								tmp_idx);
+								tmp_idx,
+								tmp_prob);
 		}
 	}
 }
@@ -513,7 +515,7 @@ minstrel_ht_update_stats(struct minstrel_priv *mp, struct minstrel_ht_sta *mi)
 {
 	struct minstrel_mcs_group_data *mg;
 	struct minstrel_rate_stats *mrs;
-	int group, i, j;
+	int group, i, j, cur_prob;
 	u16 tmp_mcs_tp_rate[MAX_THR_RATES], tmp_group_tp_rate[MAX_THR_RATES];
 	u16 tmp_cck_tp_rate[MAX_THR_RATES], index;
 
@@ -555,8 +557,9 @@ 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);
+			cur_prob = mrs->prob_ewma;
 
-			if (minstrel_ht_get_tp_avg(mi, group, i) == 0)
+			if (minstrel_ht_get_tp_avg(mi, group, i, cur_prob) == 0)
 				continue;
 
 			/* Find max throughput rate set */
@@ -1315,16 +1318,17 @@ static u32 minstrel_ht_get_expected_throughput(void *priv_sta)
 {
 	struct minstrel_ht_sta_priv *msp = priv_sta;
 	struct minstrel_ht_sta *mi = &msp->ht;
-	int i, j, tp_avg;
+	int i, j, prob, tp_avg;
 
 	if (!msp->is_ht)
 		return mac80211_minstrel.get_expected_throughput(priv_sta);
 
 	i = mi->max_tp_rate[0] / MCS_GROUP_RATES;
 	j = mi->max_tp_rate[0] % MCS_GROUP_RATES;
+	prob = mi->groups[i].rates[j].prob_ewma;
 
 	/* convert tp_avg from pkt per second in kbps */
-	tp_avg = minstrel_ht_get_tp_avg(mi, i, j) * AVG_PKT_SIZE * 8 / 1024;
+	tp_avg = minstrel_ht_get_tp_avg(mi, i, j, prob) * AVG_PKT_SIZE * 8 / 1024;
 
 	return tp_avg;
 }
diff --git a/net/mac80211/rc80211_minstrel_ht.h b/net/mac80211/rc80211_minstrel_ht.h
index 68dce4f..850d352 100644
--- a/net/mac80211/rc80211_minstrel_ht.h
+++ b/net/mac80211/rc80211_minstrel_ht.h
@@ -121,6 +121,8 @@ 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_avg(struct minstrel_ht_sta *mi, int group, int rate,
+			   int prob_ewma);
+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 52ed8f5..de034e4 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_avg = minstrel_ht_get_tp_avg(mi, i, j);
+		tp_max = minstrel_ht_get_tp_avg(mi, i, j, MINSTREL_FRAC(100, 100));
+		tp_avg = minstrel_ht_get_tp_avg(mi, i, j, mrs->prob_ewma);
 		prob = MINSTREL_TRUNC(mrs->cur_prob * 1000);
 		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_avg = minstrel_ht_get_tp_avg(mi, i, j);
+		tp_max = minstrel_ht_get_tp_avg(mi, i, j, MINSTREL_FRAC(100, 100));
+		tp_avg = minstrel_ht_get_tp_avg(mi, i, j, mrs->prob_ewma);
 		prob = MINSTREL_TRUNC(mrs->cur_prob * 1000);
 		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.3.0


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH v3 09/10] mac80211: reduce calculation costs of EWMA
  2015-03-17 17:29 [PATCH v3 01/10] mac80211: enhance readability of Minstrels rc_stats output Thomas Huehn
                   ` (6 preceding siblings ...)
  2015-03-17 17:29 ` [PATCH v3 08/10] mac80211: add max. lossless throughput per rate to rc_stats Thomas Huehn
@ 2015-03-17 17:29 ` Thomas Huehn
  2015-03-17 17:29 ` [PATCH v3 10/10] mac80211: add standard deviation to Minstrels throughput statistic Thomas Huehn
  8 siblings, 0 replies; 11+ messages in thread
From: Thomas Huehn @ 2015-03-17 17:29 UTC (permalink / raw)
  To: linux-wireless; +Cc: johannes, nbd, thomas

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 <thomas@net.t-labs.tu-berlin.de>
---
 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.3.0


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH v3 10/10] mac80211: add standard deviation to Minstrels throughput statistic
  2015-03-17 17:29 [PATCH v3 01/10] mac80211: enhance readability of Minstrels rc_stats output Thomas Huehn
                   ` (7 preceding siblings ...)
  2015-03-17 17:29 ` [PATCH v3 09/10] mac80211: reduce calculation costs of EWMA Thomas Huehn
@ 2015-03-17 17:29 ` Thomas Huehn
  8 siblings, 0 replies; 11+ messages in thread
From: Thomas Huehn @ 2015-03-17 17:29 UTC (permalink / raw)
  To: linux-wireless; +Cc: johannes, nbd, thomas

This patch adds the statistical descriptor "standard deviation"
to better describe the current properties of Minstrel and
Minstrel-HTs success probability distribution. The standard
deviation (SD) is calculated as exponential weighted moving
standard deviation (EWMSD) and its current value is added as
new column in all rc_stats (in debugfs).

Signed-off-by: Thomas Huehn <thomas@net.t-labs.tu-berlin.de>
---
 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 c2afe51..30512d0 100644
--- a/net/mac80211/rc80211_minstrel.c
+++ b/net/mac80211/rc80211_minstrel.c
@@ -156,7 +156,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)
@@ -164,11 +164,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 {
@@ -195,7 +204,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 3ed69ef..0a60bac 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 de034e4..e950059 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.3.0


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* Re: [PATCH v3 08/10] mac80211: add max. lossless throughput per rate to rc_stats
  2015-03-17 17:29 ` [PATCH v3 08/10] mac80211: add max. lossless throughput per rate to rc_stats Thomas Huehn
@ 2015-03-21 23:20   ` Felix Fietkau
  0 siblings, 0 replies; 11+ messages in thread
From: Felix Fietkau @ 2015-03-21 23:20 UTC (permalink / raw)
  To: Thomas Huehn, linux-wireless; +Cc: johannes

On 2015-03-17 18:29, 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 <thomas@net.t-labs.tu-berlin.de>
> ---
>  net/mac80211/rc80211_minstrel.c            | 10 ++++
>  net/mac80211/rc80211_minstrel.h            |  1 +
>  net/mac80211/rc80211_minstrel_debugfs.c    | 18 ++++---
>  net/mac80211/rc80211_minstrel_ht.c         | 84 ++++++++++++++++--------------
>  net/mac80211/rc80211_minstrel_ht.h         |  4 +-
>  net/mac80211/rc80211_minstrel_ht_debugfs.c | 24 +++++----
>  6 files changed, 83 insertions(+), 58 deletions(-)
> 
> diff --git a/net/mac80211/rc80211_minstrel.c b/net/mac80211/rc80211_minstrel.c
> index d985227..c2afe51 100644
> --- a/net/mac80211/rc80211_minstrel.c
> +++ b/net/mac80211/rc80211_minstrel.c
> @@ -85,6 +85,16 @@ int minstrel_get_tp_avg(struct minstrel_rate *mr)
>  		return MINSTREL_TRUNC(mr->stats.prob_ewma * (100000 / usecs));
>  }
>  
> +/* return max. potential lossless throughput */
> +inline int
> +minstrel_get_tp_max(struct minstrel_rate *mr)
> +{
> +	if (!mr->perfect_tx_time)
> +		return 0;
> +
> +	return 100000 / mr->perfect_tx_time;
> +}
> +
>  /* find & sort topmost throughput rates */
>  static inline void
>  minstrel_sort_best_tp_rates(struct minstrel_sta_info *mi, int i, u8 *tp_list)
How about merging it with the _avg function, like in minstrel_ht.

> diff --git a/net/mac80211/rc80211_minstrel_ht.h b/net/mac80211/rc80211_minstrel_ht.h
> index 68dce4f..850d352 100644
> --- a/net/mac80211/rc80211_minstrel_ht.h
> +++ b/net/mac80211/rc80211_minstrel_ht.h
> @@ -121,6 +121,8 @@ 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_avg(struct minstrel_ht_sta *mi, int group, int rate,
> +			   int prob_ewma);
> +int minstrel_ht_get_tp_max(struct minstrel_ht_sta *mi, int group, int rate);
Nonexistant function declaration, please remove it.

- Felix

^ permalink raw reply	[flat|nested] 11+ messages in thread

end of thread, other threads:[~2015-03-21 23:21 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-03-17 17:29 [PATCH v3 01/10] mac80211: enhance readability of Minstrels rc_stats output Thomas Huehn
2015-03-17 17:29 ` [PATCH v3 02/10] mac80211: enhance readability of Minstrel-HTs " Thomas Huehn
2015-03-17 17:29 ` [PATCH v3 03/10] mac80211: add new Minstrel statistic output via csv Thomas Huehn
2015-03-17 17:29 ` [PATCH v3 04/10] mac80211: add new Minstrel-HT " Thomas Huehn
2015-03-17 17:29 ` [PATCH v3 05/10] mac80211: unify Minstrel & Minstrel-HTs calculation of rate statistics Thomas Huehn
2015-03-17 17:29 ` [PATCH v3 06/10] mac80211: improve Minstrel variable & function naming Thomas Huehn
2015-03-17 17:29 ` [PATCH v3 07/10] mac80211: restructure per-rate throughput calculation into function Thomas Huehn
2015-03-17 17:29 ` [PATCH v3 08/10] mac80211: add max. lossless throughput per rate to rc_stats Thomas Huehn
2015-03-21 23:20   ` Felix Fietkau
2015-03-17 17:29 ` [PATCH v3 09/10] mac80211: reduce calculation costs of EWMA Thomas Huehn
2015-03-17 17:29 ` [PATCH v3 10/10] mac80211: add standard deviation to Minstrels throughput statistic Thomas Huehn

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.