Skip to content

Commit 2cae0b6

Browse files
thuehnjmberg-intel
authored andcommitted
mac80211: add new Minstrel-HT statistic output via csv
This patch adds a new debugfs file "rc_stats_csv" to output Minstrel-HTs statistics in a common csv format that is easy to parse. Signed-off-by: Thomas Huehn <[email protected]> Signed-off-by: Stefan Venz <[email protected]> Acked-by: Felix Fietkau <[email protected]> [remove printing current time of day] Signed-off-by: Johannes Berg <[email protected]>
1 parent 6d48851 commit 2cae0b6

File tree

2 files changed

+138
-2
lines changed

2 files changed

+138
-2
lines changed

net/mac80211/rc80211_minstrel_ht.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,7 @@ struct minstrel_ht_sta_priv {
112112
};
113113
#ifdef CONFIG_MAC80211_DEBUGFS
114114
struct dentry *dbg_stats;
115+
struct dentry *dbg_stats_csv;
115116
#endif
116117
void *ratelist;
117118
void *sample_table;

net/mac80211/rc80211_minstrel_ht_debugfs.c

Lines changed: 137 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -107,8 +107,8 @@ minstrel_ht_stats_open(struct inode *inode, struct file *file)
107107
struct minstrel_ht_sta *mi = &msp->ht;
108108
struct minstrel_debugfs_info *ms;
109109
unsigned int i;
110-
char *p;
111110
int ret;
111+
char *p;
112112

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

152151
return nonseekable_open(inode, file);
@@ -160,13 +159,148 @@ static const struct file_operations minstrel_ht_stat_fops = {
160159
.llseek = no_llseek,
161160
};
162161

162+
static char *
163+
minstrel_ht_stats_csv_dump(struct minstrel_ht_sta *mi, int i, char *p)
164+
{
165+
const struct mcs_group *mg;
166+
unsigned int j, tp, prob, eprob, tx_time;
167+
char htmode = '2';
168+
char gimode = 'L';
169+
u32 gflags;
170+
171+
if (!mi->groups[i].supported)
172+
return p;
173+
174+
mg = &minstrel_mcs_groups[i];
175+
gflags = mg->flags;
176+
177+
if (gflags & IEEE80211_TX_RC_40_MHZ_WIDTH)
178+
htmode = '4';
179+
else if (gflags & IEEE80211_TX_RC_80_MHZ_WIDTH)
180+
htmode = '8';
181+
if (gflags & IEEE80211_TX_RC_SHORT_GI)
182+
gimode = 'S';
183+
184+
for (j = 0; j < MCS_GROUP_RATES; j++) {
185+
struct minstrel_rate_stats *mr = &mi->groups[i].rates[j];
186+
static const int bitrates[4] = { 10, 20, 55, 110 };
187+
int idx = i * MCS_GROUP_RATES + j;
188+
189+
if (!(mi->groups[i].supported & BIT(j)))
190+
continue;
191+
192+
if (gflags & IEEE80211_TX_RC_MCS) {
193+
p += sprintf(p, "HT%c0,", htmode);
194+
p += sprintf(p, "%cGI,", gimode);
195+
p += sprintf(p, "%d,", mg->streams);
196+
} else if (gflags & IEEE80211_TX_RC_VHT_MCS) {
197+
p += sprintf(p, "VHT%c0,", htmode);
198+
p += sprintf(p, "%cGI,", gimode);
199+
p += sprintf(p, "%d,", mg->streams);
200+
} else {
201+
p += sprintf(p, "CCK,");
202+
p += sprintf(p, "%cP,", j < 4 ? 'L' : 'S');
203+
p += sprintf(p, "1,");
204+
}
205+
206+
p += sprintf(p, "%s" ,((idx == mi->max_tp_rate[0]) ? "A" : ""));
207+
p += sprintf(p, "%s" ,((idx == mi->max_tp_rate[1]) ? "B" : ""));
208+
p += sprintf(p, "%s" ,((idx == mi->max_tp_rate[2]) ? "C" : ""));
209+
p += sprintf(p, "%s" ,((idx == mi->max_tp_rate[3]) ? "D" : ""));
210+
p += sprintf(p, "%s" ,((idx == mi->max_prob_rate) ? "P" : ""));
211+
212+
if (gflags & IEEE80211_TX_RC_MCS) {
213+
p += sprintf(p, ",MCS%-2u,", (mg->streams - 1) * 8 + j);
214+
} else if (gflags & IEEE80211_TX_RC_VHT_MCS) {
215+
p += sprintf(p, ",MCS%-1u/%1u,", j, mg->streams);
216+
} else {
217+
int r = bitrates[j % 4];
218+
p += sprintf(p, ",%2u.%1uM,", r / 10, r % 10);
219+
}
220+
221+
p += sprintf(p, "%u,", idx);
222+
tx_time = DIV_ROUND_CLOSEST(mg->duration[j], 1000);
223+
p += sprintf(p, "%u,", tx_time);
224+
225+
tp = mr->cur_tp / 10;
226+
prob = MINSTREL_TRUNC(mr->cur_prob * 1000);
227+
eprob = MINSTREL_TRUNC(mr->probability * 1000);
228+
229+
p += sprintf(p, "%u.%u,%u.%u,%u.%u,%u,%u,%u,%llu,%llu,",
230+
tp / 10, tp % 10,
231+
eprob / 10, eprob % 10,
232+
prob / 10, prob % 10,
233+
mr->retry_count,
234+
mr->last_success,
235+
mr->last_attempts,
236+
(unsigned long long)mr->succ_hist,
237+
(unsigned long long)mr->att_hist);
238+
p += sprintf(p, "%d,%d,%d.%d\n",
239+
max(0, (int) mi->total_packets -
240+
(int) mi->sample_packets),
241+
mi->sample_packets,
242+
MINSTREL_TRUNC(mi->avg_ampdu_len),
243+
MINSTREL_TRUNC(mi->avg_ampdu_len * 10) % 10);
244+
}
245+
246+
return p;
247+
}
248+
249+
static int
250+
minstrel_ht_stats_csv_open(struct inode *inode, struct file *file)
251+
{
252+
struct minstrel_ht_sta_priv *msp = inode->i_private;
253+
struct minstrel_ht_sta *mi = &msp->ht;
254+
struct minstrel_debugfs_info *ms;
255+
unsigned int i;
256+
int ret;
257+
char *p;
258+
259+
if (!msp->is_ht) {
260+
inode->i_private = &msp->legacy;
261+
ret = minstrel_stats_csv_open(inode, file);
262+
inode->i_private = msp;
263+
return ret;
264+
}
265+
266+
ms = kmalloc(32768, GFP_KERNEL);
267+
268+
if (!ms)
269+
return -ENOMEM;
270+
271+
file->private_data = ms;
272+
273+
p = ms->buf;
274+
275+
p = minstrel_ht_stats_csv_dump(mi, MINSTREL_CCK_GROUP, p);
276+
for (i = 0; i < MINSTREL_CCK_GROUP; i++)
277+
p = minstrel_ht_stats_csv_dump(mi, i, p);
278+
for (i++; i < ARRAY_SIZE(mi->groups); i++)
279+
p = minstrel_ht_stats_csv_dump(mi, i, p);
280+
281+
ms->len = p - ms->buf;
282+
WARN_ON(ms->len + sizeof(*ms) > 32768);
283+
284+
return nonseekable_open(inode, file);
285+
}
286+
287+
static const struct file_operations minstrel_ht_stat_csv_fops = {
288+
.owner = THIS_MODULE,
289+
.open = minstrel_ht_stats_csv_open,
290+
.read = minstrel_stats_read,
291+
.release = minstrel_stats_release,
292+
.llseek = no_llseek,
293+
};
294+
163295
void
164296
minstrel_ht_add_sta_debugfs(void *priv, void *priv_sta, struct dentry *dir)
165297
{
166298
struct minstrel_ht_sta_priv *msp = priv_sta;
167299

168300
msp->dbg_stats = debugfs_create_file("rc_stats", S_IRUGO, dir, msp,
169301
&minstrel_ht_stat_fops);
302+
msp->dbg_stats_csv = debugfs_create_file("rc_stats_csv", S_IRUGO,
303+
dir, msp, &minstrel_ht_stat_csv_fops);
170304
}
171305

172306
void
@@ -175,4 +309,5 @@ minstrel_ht_remove_sta_debugfs(void *priv, void *priv_sta)
175309
struct minstrel_ht_sta_priv *msp = priv_sta;
176310

177311
debugfs_remove(msp->dbg_stats);
312+
debugfs_remove(msp->dbg_stats_csv);
178313
}

0 commit comments

Comments
 (0)