Commit 20edb50e authored by John W. Linville's avatar John W. Linville Committed by Johannes Berg

mac80211: remove PID rate control

Minstrel has long since proven its worth.
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
Signed-off-by: default avatarJohannes Berg <johannes.berg@intel.com>
parent 7171511e
......@@ -5629,16 +5629,6 @@ F: Documentation/networking/mac80211-injection.txt
F: include/net/mac80211.h
F: net/mac80211/
MAC80211 PID RATE CONTROL
M: Stefano Brivio <stefano.brivio@polimi.it>
M: Mattias Nissler <mattias.nissler@gmx.de>
L: linux-wireless@vger.kernel.org
W: http://wireless.kernel.org/en/developers/Documentation/mac80211/RateControl/PID
T: git git://git.kernel.org/pub/scm/linux/kernel/git/jberg/mac80211.git
T: git git://git.kernel.org/pub/scm/linux/kernel/git/jberg/mac80211-next.git
S: Maintained
F: net/mac80211/rc80211_pid*
MACVLAN DRIVER
M: Patrick McHardy <kaber@trash.net>
L: netdev@vger.kernel.org
......
......@@ -19,14 +19,6 @@ if MAC80211 != n
config MAC80211_HAS_RC
bool
config MAC80211_RC_PID
bool "PID controller based rate control algorithm" if EXPERT
select MAC80211_HAS_RC
---help---
This option enables a TX rate control algorithm for
mac80211 that uses a PID controller to select the TX
rate.
config MAC80211_RC_MINSTREL
bool "Minstrel" if EXPERT
select MAC80211_HAS_RC
......@@ -51,14 +43,6 @@ choice
overridden through the ieee80211_default_rc_algo module
parameter if different algorithms are available.
config MAC80211_RC_DEFAULT_PID
bool "PID controller based rate control algorithm"
depends on MAC80211_RC_PID
---help---
Select the PID controller based rate control as the
default rate control algorithm. You should choose
this unless you know what you are doing.
config MAC80211_RC_DEFAULT_MINSTREL
bool "Minstrel"
depends on MAC80211_RC_MINSTREL
......@@ -72,7 +56,6 @@ config MAC80211_RC_DEFAULT
string
default "minstrel_ht" if MAC80211_RC_DEFAULT_MINSTREL && MAC80211_RC_MINSTREL_HT
default "minstrel" if MAC80211_RC_DEFAULT_MINSTREL
default "pid" if MAC80211_RC_DEFAULT_PID
default ""
endif
......
......@@ -47,17 +47,12 @@ mac80211-$(CONFIG_PM) += pm.o
CFLAGS_trace.o := -I$(src)
# objects for PID algorithm
rc80211_pid-y := rc80211_pid_algo.o
rc80211_pid-$(CONFIG_MAC80211_DEBUGFS) += rc80211_pid_debugfs.o
rc80211_minstrel-y := rc80211_minstrel.o
rc80211_minstrel-$(CONFIG_MAC80211_DEBUGFS) += rc80211_minstrel_debugfs.o
rc80211_minstrel_ht-y := rc80211_minstrel_ht.o
rc80211_minstrel_ht-$(CONFIG_MAC80211_DEBUGFS) += rc80211_minstrel_ht_debugfs.o
mac80211-$(CONFIG_MAC80211_RC_PID) += $(rc80211_pid-y)
mac80211-$(CONFIG_MAC80211_RC_MINSTREL) += $(rc80211_minstrel-y)
mac80211-$(CONFIG_MAC80211_RC_MINSTREL_HT) += $(rc80211_minstrel_ht-y)
......
......@@ -1187,18 +1187,12 @@ static int __init ieee80211_init(void)
if (ret)
goto err_minstrel;
ret = rc80211_pid_init();
if (ret)
goto err_pid;
ret = ieee80211_iface_init();
if (ret)
goto err_netdev;
return 0;
err_netdev:
rc80211_pid_exit();
err_pid:
rc80211_minstrel_ht_exit();
err_minstrel:
rc80211_minstrel_exit();
......@@ -1208,7 +1202,6 @@ static int __init ieee80211_init(void)
static void __exit ieee80211_exit(void)
{
rc80211_pid_exit();
rc80211_minstrel_ht_exit();
rc80211_minstrel_exit();
......
......@@ -143,19 +143,6 @@ void rate_control_deinitialize(struct ieee80211_local *local);
/* Rate control algorithms */
#ifdef CONFIG_MAC80211_RC_PID
int rc80211_pid_init(void);
void rc80211_pid_exit(void);
#else
static inline int rc80211_pid_init(void)
{
return 0;
}
static inline void rc80211_pid_exit(void)
{
}
#endif
#ifdef CONFIG_MAC80211_RC_MINSTREL
int rc80211_minstrel_init(void);
void rc80211_minstrel_exit(void);
......
/*
* Copyright 2007, Mattias Nissler <mattias.nissler@gmx.de>
* Copyright 2007, Stefano Brivio <stefano.brivio@polimi.it>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#ifndef RC80211_PID_H
#define RC80211_PID_H
/* Sampling period for measuring percentage of failed frames in ms. */
#define RC_PID_INTERVAL 125
/* Exponential averaging smoothness (used for I part of PID controller) */
#define RC_PID_SMOOTHING_SHIFT 3
#define RC_PID_SMOOTHING (1 << RC_PID_SMOOTHING_SHIFT)
/* Sharpening factor (used for D part of PID controller) */
#define RC_PID_SHARPENING_FACTOR 0
#define RC_PID_SHARPENING_DURATION 0
/* Fixed point arithmetic shifting amount. */
#define RC_PID_ARITH_SHIFT 8
/* Proportional PID component coefficient. */
#define RC_PID_COEFF_P 15
/* Integral PID component coefficient. */
#define RC_PID_COEFF_I 9
/* Derivative PID component coefficient. */
#define RC_PID_COEFF_D 15
/* Target failed frames rate for the PID controller. NB: This effectively gives
* maximum failed frames percentage we're willing to accept. If the wireless
* link quality is good, the controller will fail to adjust failed frames
* percentage to the target. This is intentional.
*/
#define RC_PID_TARGET_PF 14
/* Rate behaviour normalization quantity over time. */
#define RC_PID_NORM_OFFSET 3
/* Push high rates right after loading. */
#define RC_PID_FAST_START 0
/* Arithmetic right shift for positive and negative values for ISO C. */
#define RC_PID_DO_ARITH_RIGHT_SHIFT(x, y) \
((x) < 0 ? -((-(x)) >> (y)) : (x) >> (y))
enum rc_pid_event_type {
RC_PID_EVENT_TYPE_TX_STATUS,
RC_PID_EVENT_TYPE_RATE_CHANGE,
RC_PID_EVENT_TYPE_TX_RATE,
RC_PID_EVENT_TYPE_PF_SAMPLE,
};
union rc_pid_event_data {
/* RC_PID_EVENT_TX_STATUS */
struct {
u32 flags;
struct ieee80211_tx_info tx_status;
};
/* RC_PID_EVENT_TYPE_RATE_CHANGE */
/* RC_PID_EVENT_TYPE_TX_RATE */
struct {
int index;
int rate;
};
/* RC_PID_EVENT_TYPE_PF_SAMPLE */
struct {
s32 pf_sample;
s32 prop_err;
s32 int_err;
s32 der_err;
};
};
struct rc_pid_event {
/* The time when the event occurred */
unsigned long timestamp;
/* Event ID number */
unsigned int id;
/* Type of event */
enum rc_pid_event_type type;
/* type specific data */
union rc_pid_event_data data;
};
/* Size of the event ring buffer. */
#define RC_PID_EVENT_RING_SIZE 32
struct rc_pid_event_buffer {
/* Counter that generates event IDs */
unsigned int ev_count;
/* Ring buffer of events */
struct rc_pid_event ring[RC_PID_EVENT_RING_SIZE];
/* Index to the entry in events_buf to be reused */
unsigned int next_entry;
/* Lock that guards against concurrent access to this buffer struct */
spinlock_t lock;
/* Wait queue for poll/select and blocking I/O */
wait_queue_head_t waitqueue;
};
struct rc_pid_events_file_info {
/* The event buffer we read */
struct rc_pid_event_buffer *events;
/* The entry we have should read next */
unsigned int next_entry;
};
/**
* struct rc_pid_debugfs_entries - tunable parameters
*
* Algorithm parameters, tunable via debugfs.
* @target: target percentage for failed frames
* @sampling_period: error sampling interval in milliseconds
* @coeff_p: absolute value of the proportional coefficient
* @coeff_i: absolute value of the integral coefficient
* @coeff_d: absolute value of the derivative coefficient
* @smoothing_shift: absolute value of the integral smoothing factor (i.e.
* amount of smoothing introduced by the exponential moving average)
* @sharpen_factor: absolute value of the derivative sharpening factor (i.e.
* amount of emphasis given to the derivative term after low activity
* events)
* @sharpen_duration: duration of the sharpening effect after the detected low
* activity event, relative to sampling_period
* @norm_offset: amount of normalization periodically performed on the learnt
* rate behaviour values (lower means we should trust more what we learnt
* about behaviour of rates, higher means we should trust more the natural
* ordering of rates)
*/
struct rc_pid_debugfs_entries {
struct dentry *target;
struct dentry *sampling_period;
struct dentry *coeff_p;
struct dentry *coeff_i;
struct dentry *coeff_d;
struct dentry *smoothing_shift;
struct dentry *sharpen_factor;
struct dentry *sharpen_duration;
struct dentry *norm_offset;
};
void rate_control_pid_event_tx_status(struct rc_pid_event_buffer *buf,
struct ieee80211_tx_info *stat);
void rate_control_pid_event_rate_change(struct rc_pid_event_buffer *buf,
int index, int rate);
void rate_control_pid_event_tx_rate(struct rc_pid_event_buffer *buf,
int index, int rate);
void rate_control_pid_event_pf_sample(struct rc_pid_event_buffer *buf,
s32 pf_sample, s32 prop_err,
s32 int_err, s32 der_err);
void rate_control_pid_add_sta_debugfs(void *priv, void *priv_sta,
struct dentry *dir);
void rate_control_pid_remove_sta_debugfs(void *priv, void *priv_sta);
struct rc_pid_sta_info {
unsigned long last_change;
unsigned long last_sample;
u32 tx_num_failed;
u32 tx_num_xmit;
int txrate_idx;
/* Average failed frames percentage error (i.e. actual vs. target
* percentage), scaled by RC_PID_SMOOTHING. This value is computed
* using using an exponential weighted average technique:
*
* (RC_PID_SMOOTHING - 1) * err_avg_old + err
* err_avg = ------------------------------------------
* RC_PID_SMOOTHING
*
* where err_avg is the new approximation, err_avg_old the previous one
* and err is the error w.r.t. to the current failed frames percentage
* sample. Note that the bigger RC_PID_SMOOTHING the more weight is
* given to the previous estimate, resulting in smoother behavior (i.e.
* corresponding to a longer integration window).
*
* For computation, we actually don't use the above formula, but this
* one:
*
* err_avg_scaled = err_avg_old_scaled - err_avg_old + err
*
* where:
* err_avg_scaled = err * RC_PID_SMOOTHING
* err_avg_old_scaled = err_avg_old * RC_PID_SMOOTHING
*
* This avoids floating point numbers and the per_failed_old value can
* easily be obtained by shifting per_failed_old_scaled right by
* RC_PID_SMOOTHING_SHIFT.
*/
s32 err_avg_sc;
/* Last framed failes percentage sample. */
u32 last_pf;
/* Sharpening needed. */
u8 sharp_cnt;
#ifdef CONFIG_MAC80211_DEBUGFS
/* Event buffer */
struct rc_pid_event_buffer events;
/* Events debugfs file entry */
struct dentry *events_entry;
#endif
};
/* Algorithm parameters. We keep them on a per-algorithm approach, so they can
* be tuned individually for each interface.
*/
struct rc_pid_rateinfo {
/* Map sorted rates to rates in ieee80211_hw_mode. */
int index;
/* Map rates in ieee80211_hw_mode to sorted rates. */
int rev_index;
/* Did we do any measurement on this rate? */
bool valid;
/* Comparison with the lowest rate. */
int diff;
};
struct rc_pid_info {
/* The failed frames percentage target. */
unsigned int target;
/* Rate at which failed frames percentage is sampled in 0.001s. */
unsigned int sampling_period;
/* P, I and D coefficients. */
int coeff_p;
int coeff_i;
int coeff_d;
/* Exponential averaging shift. */
unsigned int smoothing_shift;
/* Sharpening factor and duration. */
unsigned int sharpen_factor;
unsigned int sharpen_duration;
/* Normalization offset. */
unsigned int norm_offset;
/* Rates information. */
struct rc_pid_rateinfo *rinfo;
/* Index of the last used rate. */
int oldrate;
#ifdef CONFIG_MAC80211_DEBUGFS
/* Debugfs entries created for the parameters above. */
struct rc_pid_debugfs_entries dentries;
#endif
};
#endif /* RC80211_PID_H */
This diff is collapsed.
/*
* Copyright 2007, Mattias Nissler <mattias.nissler@gmx.de>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/sched.h>
#include <linux/spinlock.h>
#include <linux/poll.h>
#include <linux/netdevice.h>
#include <linux/types.h>
#include <linux/skbuff.h>
#include <linux/slab.h>
#include <linux/export.h>
#include <net/mac80211.h>
#include "rate.h"
#include "rc80211_pid.h"
static void rate_control_pid_event(struct rc_pid_event_buffer *buf,
enum rc_pid_event_type type,
union rc_pid_event_data *data)
{
struct rc_pid_event *ev;
unsigned long status;
spin_lock_irqsave(&buf->lock, status);
ev = &(buf->ring[buf->next_entry]);
buf->next_entry = (buf->next_entry + 1) % RC_PID_EVENT_RING_SIZE;
ev->timestamp = jiffies;
ev->id = buf->ev_count++;
ev->type = type;
ev->data = *data;
spin_unlock_irqrestore(&buf->lock, status);
wake_up_all(&buf->waitqueue);
}
void rate_control_pid_event_tx_status(struct rc_pid_event_buffer *buf,
struct ieee80211_tx_info *stat)
{
union rc_pid_event_data evd;
evd.flags = stat->flags;
memcpy(&evd.tx_status, stat, sizeof(struct ieee80211_tx_info));
rate_control_pid_event(buf, RC_PID_EVENT_TYPE_TX_STATUS, &evd);
}
void rate_control_pid_event_rate_change(struct rc_pid_event_buffer *buf,
int index, int rate)
{
union rc_pid_event_data evd;
evd.index = index;
evd.rate = rate;
rate_control_pid_event(buf, RC_PID_EVENT_TYPE_RATE_CHANGE, &evd);
}
void rate_control_pid_event_tx_rate(struct rc_pid_event_buffer *buf,
int index, int rate)
{
union rc_pid_event_data evd;
evd.index = index;
evd.rate = rate;
rate_control_pid_event(buf, RC_PID_EVENT_TYPE_TX_RATE, &evd);
}
void rate_control_pid_event_pf_sample(struct rc_pid_event_buffer *buf,
s32 pf_sample, s32 prop_err,
s32 int_err, s32 der_err)
{
union rc_pid_event_data evd;
evd.pf_sample = pf_sample;
evd.prop_err = prop_err;
evd.int_err = int_err;
evd.der_err = der_err;
rate_control_pid_event(buf, RC_PID_EVENT_TYPE_PF_SAMPLE, &evd);
}
static int rate_control_pid_events_open(struct inode *inode, struct file *file)
{
struct rc_pid_sta_info *sinfo = inode->i_private;
struct rc_pid_event_buffer *events = &sinfo->events;
struct rc_pid_events_file_info *file_info;
unsigned long status;
/* Allocate a state struct */
file_info = kmalloc(sizeof(*file_info), GFP_KERNEL);
if (file_info == NULL)
return -ENOMEM;
spin_lock_irqsave(&events->lock, status);
file_info->next_entry = events->next_entry;
file_info->events = events;
spin_unlock_irqrestore(&events->lock, status);
file->private_data = file_info;
return 0;
}
static int rate_control_pid_events_release(struct inode *inode,
struct file *file)
{
struct rc_pid_events_file_info *file_info = file->private_data;
kfree(file_info);
return 0;
}
static unsigned int rate_control_pid_events_poll(struct file *file,
poll_table *wait)
{
struct rc_pid_events_file_info *file_info = file->private_data;
poll_wait(file, &file_info->events->waitqueue, wait);
return POLLIN | POLLRDNORM;
}
#define RC_PID_PRINT_BUF_SIZE 64
static ssize_t rate_control_pid_events_read(struct file *file, char __user *buf,
size_t length, loff_t *offset)
{
struct rc_pid_events_file_info *file_info = file->private_data;
struct rc_pid_event_buffer *events = file_info->events;
struct rc_pid_event *ev;
char pb[RC_PID_PRINT_BUF_SIZE];
int ret;
int p;
unsigned long status;
/* Check if there is something to read. */
if (events->next_entry == file_info->next_entry) {
if (file->f_flags & O_NONBLOCK)
return -EAGAIN;
/* Wait */
ret = wait_event_interruptible(events->waitqueue,
events->next_entry != file_info->next_entry);
if (ret)
return ret;
}
/* Write out one event per call. I don't care whether it's a little
* inefficient, this is debugging code anyway. */
spin_lock_irqsave(&events->lock, status);
/* Get an event */
ev = &(events->ring[file_info->next_entry]);
file_info->next_entry = (file_info->next_entry + 1) %
RC_PID_EVENT_RING_SIZE;
/* Print information about the event. Note that userspace needs to
* provide large enough buffers. */
length = length < RC_PID_PRINT_BUF_SIZE ?
length : RC_PID_PRINT_BUF_SIZE;
p = scnprintf(pb, length, "%u %lu ", ev->id, ev->timestamp);
switch (ev->type) {
case RC_PID_EVENT_TYPE_TX_STATUS:
p += scnprintf(pb + p, length - p, "tx_status %u %u",
!(ev->data.flags & IEEE80211_TX_STAT_ACK),
ev->data.tx_status.status.rates[0].idx);
break;
case RC_PID_EVENT_TYPE_RATE_CHANGE:
p += scnprintf(pb + p, length - p, "rate_change %d %d",
ev->data.index, ev->data.rate);
break;
case RC_PID_EVENT_TYPE_TX_RATE:
p += scnprintf(pb + p, length - p, "tx_rate %d %d",
ev->data.index, ev->data.rate);
break;
case RC_PID_EVENT_TYPE_PF_SAMPLE:
p += scnprintf(pb + p, length - p,
"pf_sample %d %d %d %d",
ev->data.pf_sample, ev->data.prop_err,
ev->data.int_err, ev->data.der_err);
break;
}
p += scnprintf(pb + p, length - p, "\n");
spin_unlock_irqrestore(&events->lock, status);
if (copy_to_user(buf, pb, p))
return -EFAULT;
return p;
}
#undef RC_PID_PRINT_BUF_SIZE
static const struct file_operations rc_pid_fop_events = {
.owner = THIS_MODULE,
.read = rate_control_pid_events_read,
.poll = rate_control_pid_events_poll,
.open = rate_control_pid_events_open,
.release = rate_control_pid_events_release,
.llseek = noop_llseek,
};
void rate_control_pid_add_sta_debugfs(void *priv, void *priv_sta,
struct dentry *dir)
{
struct rc_pid_sta_info *spinfo = priv_sta;
spinfo->events_entry = debugfs_create_file("rc_pid_events", S_IRUGO,
dir, spinfo,
&rc_pid_fop_events);
}
void rate_control_pid_remove_sta_debugfs(void *priv, void *priv_sta)
{
struct rc_pid_sta_info *spinfo = priv_sta;
debugfs_remove(spinfo->events_entry);
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment