i40e/i40evf: adjust interrupt throttle less frequently
The adaptive ITR (interrupt throttle rate) algorithm was adjusting the hardware's interrupt rate too frequently. This caused a lot of variation in the interrupt rate for fairly constant workloads. Change the code to have a counter and adjust only once every N number of interrupts. Change-ID: I0460f1f86571037484eca5aca36ac4d889cb8389 Signed-off-by: Jesse Brandeburg <jesse.brandeburg@intel.com> Tested-by: Andrew Bowers <andrewx.bowers@intel.com> Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
This commit is contained in:
parent
c56625d597
commit
ee2319cf17
8 changed files with 53 additions and 8 deletions
|
@ -577,6 +577,8 @@ struct i40e_q_vector {
|
|||
struct rcu_head rcu; /* to avoid race with update stats on free */
|
||||
char name[I40E_INT_NAME_STR_LEN];
|
||||
bool arm_wb_state;
|
||||
#define ITR_COUNTDOWN_START 100
|
||||
u8 itr_countdown; /* when 0 should adjust ITR */
|
||||
} ____cacheline_internodealigned_in_smp;
|
||||
|
||||
/* lan device */
|
||||
|
|
|
@ -3087,6 +3087,7 @@ static void i40e_vsi_configure_msix(struct i40e_vsi *vsi)
|
|||
for (i = 0; i < vsi->num_q_vectors; i++, vector++) {
|
||||
struct i40e_q_vector *q_vector = vsi->q_vectors[i];
|
||||
|
||||
q_vector->itr_countdown = ITR_COUNTDOWN_START;
|
||||
q_vector->rx.itr = ITR_TO_REG(vsi->rx_itr_setting);
|
||||
q_vector->rx.latency_range = I40E_LOW_LATENCY;
|
||||
wr32(hw, I40E_PFINT_ITRN(I40E_RX_ITR, vector - 1),
|
||||
|
@ -3182,6 +3183,7 @@ static void i40e_configure_msi_and_legacy(struct i40e_vsi *vsi)
|
|||
u32 val;
|
||||
|
||||
/* set the ITR configuration */
|
||||
q_vector->itr_countdown = ITR_COUNTDOWN_START;
|
||||
q_vector->rx.itr = ITR_TO_REG(vsi->rx_itr_setting);
|
||||
q_vector->rx.latency_range = I40E_LOW_LATENCY;
|
||||
wr32(hw, I40E_PFINT_ITR0(I40E_RX_ITR), q_vector->rx.itr);
|
||||
|
|
|
@ -845,10 +845,12 @@ static bool i40e_set_new_dynamic_itr(struct i40e_ring_container *rc)
|
|||
* The math works out because the divisor is in 10^(-6) which
|
||||
* turns the bytes/us input value into MB/s values, but
|
||||
* make sure to use usecs, as the register values written
|
||||
* are in 2 usec increments in the ITR registers.
|
||||
* are in 2 usec increments in the ITR registers, and make sure
|
||||
* to use the smoothed values that the countdown timer gives us.
|
||||
*/
|
||||
usecs = (rc->itr << 1);
|
||||
usecs = (rc->itr << 1) * ITR_COUNTDOWN_START;
|
||||
bytes_per_int = rc->total_bytes / usecs;
|
||||
|
||||
switch (new_latency_range) {
|
||||
case I40E_LOWEST_LATENCY:
|
||||
if (bytes_per_int > 10)
|
||||
|
@ -1806,8 +1808,17 @@ static inline void i40e_update_enable_itr(struct i40e_vsi *vsi,
|
|||
|
||||
vector = (q_vector->v_idx + vsi->base_vector);
|
||||
|
||||
/* avoid dynamic calculation if in countdown mode OR if
|
||||
* all dynamic is disabled
|
||||
*/
|
||||
rxval = txval = i40e_buildreg_itr(I40E_ITR_NONE, 0);
|
||||
|
||||
if (q_vector->itr_countdown > 0 ||
|
||||
(!ITR_IS_DYNAMIC(vsi->rx_itr_setting) &&
|
||||
!ITR_IS_DYNAMIC(vsi->tx_itr_setting))) {
|
||||
goto enable_int;
|
||||
}
|
||||
|
||||
if (ITR_IS_DYNAMIC(vsi->rx_itr_setting)) {
|
||||
rx = i40e_set_new_dynamic_itr(&q_vector->rx);
|
||||
rxval = i40e_buildreg_itr(I40E_RX_ITR, q_vector->rx.itr);
|
||||
|
@ -1845,8 +1856,15 @@ static inline void i40e_update_enable_itr(struct i40e_vsi *vsi,
|
|||
wr32(hw, INTREG(vector - 1), rxval);
|
||||
}
|
||||
|
||||
enable_int:
|
||||
if (!test_bit(__I40E_DOWN, &vsi->state))
|
||||
wr32(hw, INTREG(vector - 1), txval);
|
||||
|
||||
if (q_vector->itr_countdown)
|
||||
q_vector->itr_countdown--;
|
||||
else
|
||||
q_vector->itr_countdown = ITR_COUNTDOWN_START;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -38,8 +38,8 @@
|
|||
#define I40E_ITR_8K 0x003E
|
||||
#define I40E_ITR_4K 0x007A
|
||||
#define I40E_MAX_INTRL 0x3B /* reg uses 4 usec resolution */
|
||||
#define I40E_ITR_RX_DEF I40E_ITR_8K
|
||||
#define I40E_ITR_TX_DEF I40E_ITR_4K
|
||||
#define I40E_ITR_RX_DEF I40E_ITR_20K
|
||||
#define I40E_ITR_TX_DEF I40E_ITR_20K
|
||||
#define I40E_ITR_DYNAMIC 0x8000 /* use top bit as a flag */
|
||||
#define I40E_MIN_INT_RATE 250 /* ~= 1000000 / (I40E_MAX_ITR * 2) */
|
||||
#define I40E_MAX_INT_RATE 500000 /* == 1000000 / (I40E_MIN_ITR * 2) */
|
||||
|
|
|
@ -348,10 +348,12 @@ static bool i40e_set_new_dynamic_itr(struct i40e_ring_container *rc)
|
|||
* The math works out because the divisor is in 10^(-6) which
|
||||
* turns the bytes/us input value into MB/s values, but
|
||||
* make sure to use usecs, as the register values written
|
||||
* are in 2 usec increments in the ITR registers.
|
||||
* are in 2 usec increments in the ITR registers, and make sure
|
||||
* to use the smoothed values that the countdown timer gives us.
|
||||
*/
|
||||
usecs = (rc->itr << 1);
|
||||
usecs = (rc->itr << 1) * ITR_COUNTDOWN_START;
|
||||
bytes_per_int = rc->total_bytes / usecs;
|
||||
|
||||
switch (new_latency_range) {
|
||||
case I40E_LOWEST_LATENCY:
|
||||
if (bytes_per_int > 10)
|
||||
|
@ -1245,8 +1247,18 @@ static inline void i40e_update_enable_itr(struct i40e_vsi *vsi,
|
|||
int vector;
|
||||
|
||||
vector = (q_vector->v_idx + vsi->base_vector);
|
||||
|
||||
/* avoid dynamic calculation if in countdown mode OR if
|
||||
* all dynamic is disabled
|
||||
*/
|
||||
rxval = txval = i40e_buildreg_itr(I40E_ITR_NONE, 0);
|
||||
|
||||
if (q_vector->itr_countdown > 0 ||
|
||||
(!ITR_IS_DYNAMIC(vsi->rx_itr_setting) &&
|
||||
!ITR_IS_DYNAMIC(vsi->tx_itr_setting))) {
|
||||
goto enable_int;
|
||||
}
|
||||
|
||||
if (ITR_IS_DYNAMIC(vsi->rx_itr_setting)) {
|
||||
rx = i40e_set_new_dynamic_itr(&q_vector->rx);
|
||||
rxval = i40e_buildreg_itr(I40E_RX_ITR, q_vector->rx.itr);
|
||||
|
@ -1282,8 +1294,15 @@ static inline void i40e_update_enable_itr(struct i40e_vsi *vsi,
|
|||
wr32(hw, INTREG(vector - 1), rxval);
|
||||
}
|
||||
|
||||
enable_int:
|
||||
if (!test_bit(__I40E_DOWN, &vsi->state))
|
||||
wr32(hw, INTREG(vector - 1), txval);
|
||||
|
||||
if (q_vector->itr_countdown)
|
||||
q_vector->itr_countdown--;
|
||||
else
|
||||
q_vector->itr_countdown = ITR_COUNTDOWN_START;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -38,8 +38,8 @@
|
|||
#define I40E_ITR_8K 0x003E
|
||||
#define I40E_ITR_4K 0x007A
|
||||
#define I40E_MAX_INTRL 0x3B /* reg uses 4 usec resolution */
|
||||
#define I40E_ITR_RX_DEF I40E_ITR_8K
|
||||
#define I40E_ITR_TX_DEF I40E_ITR_4K
|
||||
#define I40E_ITR_RX_DEF I40E_ITR_20K
|
||||
#define I40E_ITR_TX_DEF I40E_ITR_20K
|
||||
#define I40E_ITR_DYNAMIC 0x8000 /* use top bit as a flag */
|
||||
#define I40E_MIN_INT_RATE 250 /* ~= 1000000 / (I40E_MAX_ITR * 2) */
|
||||
#define I40E_MAX_INT_RATE 500000 /* == 1000000 / (I40E_MIN_ITR * 2) */
|
||||
|
|
|
@ -112,6 +112,8 @@ struct i40e_q_vector {
|
|||
struct i40e_ring_container tx;
|
||||
u32 ring_mask;
|
||||
u8 num_ringpairs; /* total number of ring pairs in vector */
|
||||
#define ITR_COUNTDOWN_START 100
|
||||
u8 itr_countdown; /* when 0 or 1 update ITR */
|
||||
int v_idx; /* vector index in list */
|
||||
char name[IFNAMSIZ + 9];
|
||||
bool arm_wb_state;
|
||||
|
|
|
@ -357,6 +357,7 @@ i40evf_map_vector_to_rxq(struct i40evf_adapter *adapter, int v_idx, int r_idx)
|
|||
q_vector->rx.ring = rx_ring;
|
||||
q_vector->rx.count++;
|
||||
q_vector->rx.latency_range = I40E_LOW_LATENCY;
|
||||
q_vector->itr_countdown = ITR_COUNTDOWN_START;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -377,6 +378,7 @@ i40evf_map_vector_to_txq(struct i40evf_adapter *adapter, int v_idx, int t_idx)
|
|||
q_vector->tx.ring = tx_ring;
|
||||
q_vector->tx.count++;
|
||||
q_vector->tx.latency_range = I40E_LOW_LATENCY;
|
||||
q_vector->itr_countdown = ITR_COUNTDOWN_START;
|
||||
q_vector->num_ringpairs++;
|
||||
q_vector->ring_mask |= BIT(t_idx);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue