Commit 84b6714e authored by David S. Miller's avatar David S. Miller

Merge branch 'ewma'

Johannes Berg says:

====================
average: convert users to inline implementation

Since there's very little benefit of the out-of-line implementation
(a single byte of .text in one driver as far as I've seen), convert
all drivers to the inline implementation, saving memory, and remove
the out-of-line implementation.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 0f8f27de f4e774f5
...@@ -282,7 +282,6 @@ config VETH ...@@ -282,7 +282,6 @@ config VETH
config VIRTIO_NET config VIRTIO_NET
tristate "Virtio network driver" tristate "Virtio network driver"
depends on VIRTIO depends on VIRTIO
select AVERAGE
---help--- ---help---
This is the virtual network driver for virtio. It can be used with This is the virtual network driver for virtio. It can be used with
lguest or QEMU based VMMs (like KVM or Xen). Say Y or M. lguest or QEMU based VMMs (like KVM or Xen). Say Y or M.
......
...@@ -40,12 +40,12 @@ module_param(gso, bool, 0444); ...@@ -40,12 +40,12 @@ module_param(gso, bool, 0444);
#define GOOD_PACKET_LEN (ETH_HLEN + VLAN_HLEN + ETH_DATA_LEN) #define GOOD_PACKET_LEN (ETH_HLEN + VLAN_HLEN + ETH_DATA_LEN)
#define GOOD_COPY_LEN 128 #define GOOD_COPY_LEN 128
/* Weight used for the RX packet size EWMA. The average packet size is used to /* RX packet size EWMA. The average packet size is used to determine the packet
* determine the packet buffer size when refilling RX rings. As the entire RX * buffer size when refilling RX rings. As the entire RX ring may be refilled
* ring may be refilled at once, the weight is chosen so that the EWMA will be * at once, the weight is chosen so that the EWMA will be insensitive to short-
* insensitive to short-term, transient changes in packet size. * term, transient changes in packet size.
*/ */
#define RECEIVE_AVG_WEIGHT 64 DECLARE_EWMA(pkt_len, 1, 64)
/* Minimum alignment for mergeable packet buffers. */ /* Minimum alignment for mergeable packet buffers. */
#define MERGEABLE_BUFFER_ALIGN max(L1_CACHE_BYTES, 256) #define MERGEABLE_BUFFER_ALIGN max(L1_CACHE_BYTES, 256)
...@@ -85,7 +85,7 @@ struct receive_queue { ...@@ -85,7 +85,7 @@ struct receive_queue {
struct page *pages; struct page *pages;
/* Average packet length for mergeable receive buffers. */ /* Average packet length for mergeable receive buffers. */
struct ewma mrg_avg_pkt_len; struct ewma_pkt_len mrg_avg_pkt_len;
/* Page frag for packet buffer allocation. */ /* Page frag for packet buffer allocation. */
struct page_frag alloc_frag; struct page_frag alloc_frag;
...@@ -407,7 +407,7 @@ static struct sk_buff *receive_mergeable(struct net_device *dev, ...@@ -407,7 +407,7 @@ static struct sk_buff *receive_mergeable(struct net_device *dev,
} }
} }
ewma_add(&rq->mrg_avg_pkt_len, head_skb->len); ewma_pkt_len_add(&rq->mrg_avg_pkt_len, head_skb->len);
return head_skb; return head_skb;
err_skb: err_skb:
...@@ -600,12 +600,12 @@ static int add_recvbuf_big(struct virtnet_info *vi, struct receive_queue *rq, ...@@ -600,12 +600,12 @@ static int add_recvbuf_big(struct virtnet_info *vi, struct receive_queue *rq,
return err; return err;
} }
static unsigned int get_mergeable_buf_len(struct ewma *avg_pkt_len) static unsigned int get_mergeable_buf_len(struct ewma_pkt_len *avg_pkt_len)
{ {
const size_t hdr_len = sizeof(struct virtio_net_hdr_mrg_rxbuf); const size_t hdr_len = sizeof(struct virtio_net_hdr_mrg_rxbuf);
unsigned int len; unsigned int len;
len = hdr_len + clamp_t(unsigned int, ewma_read(avg_pkt_len), len = hdr_len + clamp_t(unsigned int, ewma_pkt_len_read(avg_pkt_len),
GOOD_PACKET_LEN, PAGE_SIZE - hdr_len); GOOD_PACKET_LEN, PAGE_SIZE - hdr_len);
return ALIGN(len, MERGEABLE_BUFFER_ALIGN); return ALIGN(len, MERGEABLE_BUFFER_ALIGN);
} }
...@@ -1615,7 +1615,7 @@ static int virtnet_alloc_queues(struct virtnet_info *vi) ...@@ -1615,7 +1615,7 @@ static int virtnet_alloc_queues(struct virtnet_info *vi)
napi_hash_add(&vi->rq[i].napi); napi_hash_add(&vi->rq[i].napi);
sg_init_table(vi->rq[i].sg, ARRAY_SIZE(vi->rq[i].sg)); sg_init_table(vi->rq[i].sg, ARRAY_SIZE(vi->rq[i].sg));
ewma_init(&vi->rq[i].mrg_avg_pkt_len, 1, RECEIVE_AVG_WEIGHT); ewma_pkt_len_init(&vi->rq[i].mrg_avg_pkt_len);
sg_init_table(vi->sq[i].sg, ARRAY_SIZE(vi->sq[i].sg)); sg_init_table(vi->sq[i].sg, ARRAY_SIZE(vi->sq[i].sg));
} }
...@@ -1658,7 +1658,7 @@ static ssize_t mergeable_rx_buffer_size_show(struct netdev_rx_queue *queue, ...@@ -1658,7 +1658,7 @@ static ssize_t mergeable_rx_buffer_size_show(struct netdev_rx_queue *queue,
{ {
struct virtnet_info *vi = netdev_priv(queue->dev); struct virtnet_info *vi = netdev_priv(queue->dev);
unsigned int queue_index = get_netdev_rx_queue_index(queue); unsigned int queue_index = get_netdev_rx_queue_index(queue);
struct ewma *avg; struct ewma_pkt_len *avg;
BUG_ON(queue_index >= vi->max_queue_pairs); BUG_ON(queue_index >= vi->max_queue_pairs);
avg = &vi->rq[queue_index].mrg_avg_pkt_len; avg = &vi->rq[queue_index].mrg_avg_pkt_len;
......
...@@ -5,7 +5,6 @@ config ATH5K ...@@ -5,7 +5,6 @@ config ATH5K
select MAC80211_LEDS select MAC80211_LEDS
select LEDS_CLASS select LEDS_CLASS
select NEW_LEDS select NEW_LEDS
select AVERAGE
select ATH5K_AHB if ATH25 select ATH5K_AHB if ATH25
select ATH5K_PCI if !ATH25 select ATH5K_PCI if !ATH25
---help--- ---help---
......
...@@ -223,7 +223,7 @@ static void ...@@ -223,7 +223,7 @@ static void
ath5k_ani_raise_immunity(struct ath5k_hw *ah, struct ath5k_ani_state *as, ath5k_ani_raise_immunity(struct ath5k_hw *ah, struct ath5k_ani_state *as,
bool ofdm_trigger) bool ofdm_trigger)
{ {
int rssi = ewma_read(&ah->ah_beacon_rssi_avg); int rssi = ewma_beacon_rssi_read(&ah->ah_beacon_rssi_avg);
ATH5K_DBG_UNLIMIT(ah, ATH5K_DEBUG_ANI, "raise immunity (%s)", ATH5K_DBG_UNLIMIT(ah, ATH5K_DEBUG_ANI, "raise immunity (%s)",
ofdm_trigger ? "ODFM" : "CCK"); ofdm_trigger ? "ODFM" : "CCK");
...@@ -309,7 +309,7 @@ ath5k_ani_raise_immunity(struct ath5k_hw *ah, struct ath5k_ani_state *as, ...@@ -309,7 +309,7 @@ ath5k_ani_raise_immunity(struct ath5k_hw *ah, struct ath5k_ani_state *as,
static void static void
ath5k_ani_lower_immunity(struct ath5k_hw *ah, struct ath5k_ani_state *as) ath5k_ani_lower_immunity(struct ath5k_hw *ah, struct ath5k_ani_state *as)
{ {
int rssi = ewma_read(&ah->ah_beacon_rssi_avg); int rssi = ewma_beacon_rssi_read(&ah->ah_beacon_rssi_avg);
ATH5K_DBG_UNLIMIT(ah, ATH5K_DEBUG_ANI, "lower immunity"); ATH5K_DBG_UNLIMIT(ah, ATH5K_DEBUG_ANI, "lower immunity");
......
...@@ -1252,6 +1252,8 @@ struct ath5k_statistics { ...@@ -1252,6 +1252,8 @@ struct ath5k_statistics {
#define ATH5K_TXQ_LEN_MAX (ATH_TXBUF / 4) /* bufs per queue */ #define ATH5K_TXQ_LEN_MAX (ATH_TXBUF / 4) /* bufs per queue */
#define ATH5K_TXQ_LEN_LOW (ATH5K_TXQ_LEN_MAX / 2) /* low mark */ #define ATH5K_TXQ_LEN_LOW (ATH5K_TXQ_LEN_MAX / 2) /* low mark */
DECLARE_EWMA(beacon_rssi, 1024, 8)
/* Driver state associated with an instance of a device */ /* Driver state associated with an instance of a device */
struct ath5k_hw { struct ath5k_hw {
struct ath_common common; struct ath_common common;
...@@ -1432,7 +1434,7 @@ struct ath5k_hw { ...@@ -1432,7 +1434,7 @@ struct ath5k_hw {
struct ath5k_nfcal_hist ah_nfcal_hist; struct ath5k_nfcal_hist ah_nfcal_hist;
/* average beacon RSSI in our BSS (used by ANI) */ /* average beacon RSSI in our BSS (used by ANI) */
struct ewma ah_beacon_rssi_avg; struct ewma_beacon_rssi ah_beacon_rssi_avg;
/* noise floor from last periodic calibration */ /* noise floor from last periodic calibration */
s32 ah_noise_floor; s32 ah_noise_floor;
......
...@@ -1430,7 +1430,7 @@ ath5k_receive_frame(struct ath5k_hw *ah, struct sk_buff *skb, ...@@ -1430,7 +1430,7 @@ ath5k_receive_frame(struct ath5k_hw *ah, struct sk_buff *skb,
trace_ath5k_rx(ah, skb); trace_ath5k_rx(ah, skb);
if (ath_is_mybeacon(common, (struct ieee80211_hdr *)skb->data)) { if (ath_is_mybeacon(common, (struct ieee80211_hdr *)skb->data)) {
ewma_add(&ah->ah_beacon_rssi_avg, rs->rs_rssi); ewma_beacon_rssi_add(&ah->ah_beacon_rssi_avg, rs->rs_rssi);
/* check beacons in IBSS mode */ /* check beacons in IBSS mode */
if (ah->opmode == NL80211_IFTYPE_ADHOC) if (ah->opmode == NL80211_IFTYPE_ADHOC)
...@@ -2936,7 +2936,7 @@ ath5k_reset(struct ath5k_hw *ah, struct ieee80211_channel *chan, ...@@ -2936,7 +2936,7 @@ ath5k_reset(struct ath5k_hw *ah, struct ieee80211_channel *chan,
ah->ah_cal_next_short = jiffies + ah->ah_cal_next_short = jiffies +
msecs_to_jiffies(ATH5K_TUNE_CALIBRATION_INTERVAL_SHORT); msecs_to_jiffies(ATH5K_TUNE_CALIBRATION_INTERVAL_SHORT);
ewma_init(&ah->ah_beacon_rssi_avg, 1024, 8); ewma_beacon_rssi_init(&ah->ah_beacon_rssi_avg);
/* clear survey data and cycle counters */ /* clear survey data and cycle counters */
memset(&ah->survey, 0, sizeof(ah->survey)); memset(&ah->survey, 0, sizeof(ah->survey));
......
...@@ -722,7 +722,7 @@ static ssize_t read_file_ani(struct file *file, char __user *user_buf, ...@@ -722,7 +722,7 @@ static ssize_t read_file_ani(struct file *file, char __user *user_buf,
st->mib_intr); st->mib_intr);
len += snprintf(buf + len, sizeof(buf) - len, len += snprintf(buf + len, sizeof(buf) - len,
"beacon RSSI average:\t%d\n", "beacon RSSI average:\t%d\n",
(int)ewma_read(&ah->ah_beacon_rssi_avg)); (int)ewma_beacon_rssi_read(&ah->ah_beacon_rssi_avg));
#define CC_PRINT(_struct, _field) \ #define CC_PRINT(_struct, _field) \
_struct._field, \ _struct._field, \
......
...@@ -240,7 +240,6 @@ config RT2X00_LIB_USB ...@@ -240,7 +240,6 @@ config RT2X00_LIB_USB
config RT2X00_LIB config RT2X00_LIB
tristate tristate
select AVERAGE
config RT2X00_LIB_FIRMWARE config RT2X00_LIB_FIRMWARE
bool bool
......
...@@ -254,6 +254,8 @@ struct link_qual { ...@@ -254,6 +254,8 @@ struct link_qual {
int tx_failed; int tx_failed;
}; };
DECLARE_EWMA(rssi, 1024, 8)
/* /*
* Antenna settings about the currently active link. * Antenna settings about the currently active link.
*/ */
...@@ -285,7 +287,7 @@ struct link_ant { ...@@ -285,7 +287,7 @@ struct link_ant {
* Similar to the avg_rssi in the link_qual structure * Similar to the avg_rssi in the link_qual structure
* this value is updated by using the walking average. * this value is updated by using the walking average.
*/ */
struct ewma rssi_ant; struct ewma_rssi rssi_ant;
}; };
/* /*
...@@ -314,7 +316,7 @@ struct link { ...@@ -314,7 +316,7 @@ struct link {
/* /*
* Currently active average RSSI value * Currently active average RSSI value
*/ */
struct ewma avg_rssi; struct ewma_rssi avg_rssi;
/* /*
* Work structure for scheduling periodic link tuning. * Work structure for scheduling periodic link tuning.
......
...@@ -33,15 +33,11 @@ ...@@ -33,15 +33,11 @@
*/ */
#define DEFAULT_RSSI -128 #define DEFAULT_RSSI -128
/* Constants for EWMA calculations. */ static inline int rt2x00link_get_avg_rssi(struct ewma_rssi *ewma)
#define RT2X00_EWMA_FACTOR 1024
#define RT2X00_EWMA_WEIGHT 8
static inline int rt2x00link_get_avg_rssi(struct ewma *ewma)
{ {
unsigned long avg; unsigned long avg;
avg = ewma_read(ewma); avg = ewma_rssi_read(ewma);
if (avg) if (avg)
return -avg; return -avg;
...@@ -76,8 +72,7 @@ static void rt2x00link_antenna_update_rssi_history(struct rt2x00_dev *rt2x00dev, ...@@ -76,8 +72,7 @@ static void rt2x00link_antenna_update_rssi_history(struct rt2x00_dev *rt2x00dev,
static void rt2x00link_antenna_reset(struct rt2x00_dev *rt2x00dev) static void rt2x00link_antenna_reset(struct rt2x00_dev *rt2x00dev)
{ {
ewma_init(&rt2x00dev->link.ant.rssi_ant, RT2X00_EWMA_FACTOR, ewma_rssi_init(&rt2x00dev->link.ant.rssi_ant);
RT2X00_EWMA_WEIGHT);
} }
static void rt2x00lib_antenna_diversity_sample(struct rt2x00_dev *rt2x00dev) static void rt2x00lib_antenna_diversity_sample(struct rt2x00_dev *rt2x00dev)
...@@ -225,12 +220,12 @@ void rt2x00link_update_stats(struct rt2x00_dev *rt2x00dev, ...@@ -225,12 +220,12 @@ void rt2x00link_update_stats(struct rt2x00_dev *rt2x00dev,
/* /*
* Update global RSSI * Update global RSSI
*/ */
ewma_add(&link->avg_rssi, -rxdesc->rssi); ewma_rssi_add(&link->avg_rssi, -rxdesc->rssi);
/* /*
* Update antenna RSSI * Update antenna RSSI
*/ */
ewma_add(&ant->rssi_ant, -rxdesc->rssi); ewma_rssi_add(&ant->rssi_ant, -rxdesc->rssi);
} }
void rt2x00link_start_tuner(struct rt2x00_dev *rt2x00dev) void rt2x00link_start_tuner(struct rt2x00_dev *rt2x00dev)
...@@ -285,8 +280,7 @@ void rt2x00link_reset_tuner(struct rt2x00_dev *rt2x00dev, bool antenna) ...@@ -285,8 +280,7 @@ void rt2x00link_reset_tuner(struct rt2x00_dev *rt2x00dev, bool antenna)
*/ */
rt2x00dev->link.count = 0; rt2x00dev->link.count = 0;
memset(qual, 0, sizeof(*qual)); memset(qual, 0, sizeof(*qual));
ewma_init(&rt2x00dev->link.avg_rssi, RT2X00_EWMA_FACTOR, ewma_rssi_init(&rt2x00dev->link.avg_rssi);
RT2X00_EWMA_WEIGHT);
/* /*
* Restore the VGC level as stored in the registers, * Restore the VGC level as stored in the registers,
......
...@@ -3,30 +3,6 @@ ...@@ -3,30 +3,6 @@
/* Exponentially weighted moving average (EWMA) */ /* Exponentially weighted moving average (EWMA) */
/* For more documentation see lib/average.c */
struct ewma {
unsigned long internal;
unsigned long factor;
unsigned long weight;
};
extern void ewma_init(struct ewma *avg, unsigned long factor,
unsigned long weight);
extern struct ewma *ewma_add(struct ewma *avg, unsigned long val);
/**
* ewma_read() - Get average value
* @avg: Average structure
*
* Returns the average value held in @avg.
*/
static inline unsigned long ewma_read(const struct ewma *avg)
{
return avg->internal >> avg->factor;
}
#define DECLARE_EWMA(name, _factor, _weight) \ #define DECLARE_EWMA(name, _factor, _weight) \
struct ewma_##name { \ struct ewma_##name { \
unsigned long internal; \ unsigned long internal; \
......
...@@ -460,16 +460,6 @@ config ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE ...@@ -460,16 +460,6 @@ config ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE
config LRU_CACHE config LRU_CACHE
tristate tristate
config AVERAGE
bool "Averaging functions"
help
This option is provided for the case where no in-kernel-tree
modules require averaging functions, but a module built outside
the kernel tree does. Such modules that use library averaging
functions require Y here.
If unsure, say N.
config CLZ_TAB config CLZ_TAB
bool bool
......
/*
* lib/average.c
*
* This source code is licensed under the GNU General Public License,
* Version 2. See the file COPYING for more details.
*/
#include <linux/export.h>
#include <linux/average.h>
#include <linux/kernel.h>
#include <linux/bug.h>
#include <linux/log2.h>
/**
* DOC: Exponentially Weighted Moving Average (EWMA)
*
* These are generic functions for calculating Exponentially Weighted Moving
* Averages (EWMA). We keep a structure with the EWMA parameters and a scaled
* up internal representation of the average value to prevent rounding errors.
* The factor for scaling up and the exponential weight (or decay rate) have to
* be specified thru the init fuction. The structure should not be accessed
* directly but only thru the helper functions.
*/
/**
* ewma_init() - Initialize EWMA parameters
* @avg: Average structure
* @factor: Factor to use for the scaled up internal value. The maximum value
* of averages can be ULONG_MAX/(factor*weight). For performance reasons
* factor has to be a power of 2.
* @weight: Exponential weight, or decay rate. This defines how fast the
* influence of older values decreases. For performance reasons weight has
* to be a power of 2.
*
* Initialize the EWMA parameters for a given struct ewma @avg.
*/
void ewma_init(struct ewma *avg, unsigned long factor, unsigned long weight)
{
WARN_ON(!is_power_of_2(weight) || !is_power_of_2(factor));
avg->weight = ilog2(weight);
avg->factor = ilog2(factor);
avg->internal = 0;
}
EXPORT_SYMBOL(ewma_init);
/**
* ewma_add() - Exponentially weighted moving average (EWMA)
* @avg: Average structure
* @val: Current value
*
* Add a sample to the average.
*/
struct ewma *ewma_add(struct ewma *avg, unsigned long val)
{
unsigned long internal = ACCESS_ONCE(avg->internal);
ACCESS_ONCE(avg->internal) = internal ?
(((internal << avg->weight) - internal) +
(val << avg->factor)) >> avg->weight :
(val << avg->factor);
return avg;
}
EXPORT_SYMBOL(ewma_add);
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