i40e/i40evf: Improve throughput by reducing PCIe overhead
Subsystems (2)
cover i40e/i40evf: Improve throughput by reducing PCIe overhead
This patch series is meant to address some minor performance issues and to improve the throughput for the adapter.
On my system I saw a .5Gbps improvement based on these patches.
Specific items addressed include the use of modulo division in the Tx fast-path, redundant checks against CHECKSUM_PARTIAL, and the use of only 8K of data per TXD when the maximum supported value is 16K - 1.
---
Alexander Duyck (4):
i40e/i40evf: Break up xmit_descriptor_count from maybe_stop_tx i40e/i40evf: Rewrite logic for 8 descriptor per packet check i40e/i40evf: Move Tx checksum closer to TSO
i40e/i40evf: Allow up to 12K bytes of data per Tx descriptor instead of 8K
drivers/net/ethernet/intel/i40e/i40e_fcoe.c | 20 ++- drivers/net/ethernet/intel/i40e/i40e_txrx.c | 199 +++++++++++-------------- drivers/net/ethernet/intel/i40e/i40e_txrx.h | 96 ++++++++++++ drivers/net/ethernet/intel/i40evf/i40e_txrx.c | 190 +++++++++++------------- drivers/net/ethernet/intel/i40evf/i40e_txrx.h | 94 ++++++++++++ 5 files changed, 374 insertions(+), 225 deletions(-)
--
PATCH 1/4 i40e/i40evf: Break up xmit_descriptor_count from maybe_stop_tx
In an upcoming patch I would like to have access to the descriptor count used for the data portion of the frame. For this reason I am splitting up the descriptor count function from the function that stops the ring.
Also in order to try and reduce unnecessary duplication of code I am moving the slow-path portions of the code out of being inline calls so that we can just jump to them and process them instead of having to build them into each function that calls them.
--- drivers/net/ethernet/intel/i40e/i40e_fcoe.c | 14 ++++- drivers/net/ethernet/intel/i40e/i40e_txrx.c | 71 +++++-------------------- drivers/net/ethernet/intel/i40e/i40e_txrx.h | 44 +++++++++++++++ drivers/net/ethernet/intel/i40evf/i40e_txrx.c | 64 +++++------------------ drivers/net/ethernet/intel/i40evf/i40e_txrx.h | 42 +++++++++++++++ 5 files changed, 123 insertions(+), 112 deletions(-)
drivers/net/ethernet/intel/i40e/i40e_fcoe.c +12 -2
@@ -1359,16 +1359,26 @@ static netdev_tx_t i40e_fcoe_xmit_frame(struct sk_buff *skb,struct i40e_ring *tx_ring = vsi->tx_rings[skb->queue_mapping];struct i40e_tx_buffer *first;u32 tx_flags =0 ; +int fso, count;u8 hdr_len =0 ;u8 sof =0 ;u8 eof =0 ; -int fso;if (i40e_fcoe_set_skb_header (skb)) goto out_drop; -if (!i40e_xmit_descriptor_count (skb, tx_ring)) + count =i40e_xmit_descriptor_count (skb); + +/* need: 1 descriptor per page * PAGE_SIZE/I40E_MAX_DATA_PER_TXD, +* + 1 desc for skb_head_len/I40E_MAX_DATA_PER_TXD, +* + 4 desc gap to avoid the cache line where head is, +* + 1 desc for context descriptor, +* otherwise try next time +*/ +if (i40e_maybe_stop_tx (tx_ring, count +4 +1 )) { + tx_ring->tx_stats.tx_busy++;return NETDEV_TX_BUSY ; + }/* prepare the xmit flags */ if (i40e_tx_prepare_vlan_flags (skb, tx_ring, &tx_flags))
drivers/net/ethernet/intel/i40e/i40e_txrx.c +13 -58
101 lines not on this page · raw message
drivers/net/ethernet/intel/i40e/i40e_txrx.h +42 -2
59 lines not on this page · raw message
drivers/net/ethernet/intel/i40evf/i40e_txrx.c +14 -50
99 lines not on this page · raw message
drivers/net/ethernet/intel/i40evf/i40e_txrx.h +42 -0
52 lines not on this page · raw message
Bowers
PATCH 1/4 i40e/i40evf: Break up xmit_descriptor_count from maybe_stop_tx
Quoted 17 lines
-----Original Message-----
From: Intel-wired-lan [mailto:intel-wired-lan-bounces at lists.osuosl.org] On Behalf Of Alexander Duyck
Sent: Wednesday, February 17, 2016 11:03 AM
To: intel-wired-lan at lists.osuosl.org
Subject: [Intel-wired-lan] [next PATCH 1/4] i40e/i40evf: Break upxmit_descriptor_countfrommaybe_stop_txIn an upcoming patch I would like to have access to the descriptor count used for the data portion of the frame. For this reason I am splitting up the descriptor count function from the function that stops the ring.
Also in order to try and reduce unnecessary duplication of code I am moving the slow-path portions of the code out of being inline calls so that we can just jump to them and process them instead of having to build them into each function that calls them.
Quoted 8 lines
Signed-off-by Alexander Duyck <[email protected]>--- drivers/net/ethernet/intel/i40e/i40e_fcoe.c | 14 ++++- drivers/net/ethernet/intel/i40e/i40e_txrx.c | 71 +++++-------------------- drivers/net/ethernet/intel/i40e/i40e_txrx.h | 44 +++++++++++++++ drivers/net/ethernet/intel/i40evf/i40e_txrx.c | 64 +++++------------------ drivers/net/ethernet/intel/i40evf/i40e_txrx.h | 42 +++++++++++++++ 5 files changed, 123 insertions(+), 112 deletions(-)
Patch code changes correctly applied
PATCH 2/4 i40e/i40evf: Rewrite logic for 8 descriptor per packet check
In reply to Alexander DuyckThis patch is meant to rewrite the logic for how we determine if we can transmit the frame or if it needs to be linearized.
The previous code for this function was using a mix of division and modulus division as a part of computing if we need to take the slow path. Instead I have replaced this by simply working with a sliding window which will tell us if the frame would be capable of causing a single packet to span several descriptors.
The logic for the scan is fairly simple. If any given group of 6 fragments is less than gso_size - 1 then it is possible for us to have one byte coming out of the first fragment, 6 fragments, and one or more bytes coming out of the last fragment. This gives us a total of 8 fragments which exceeds what we can allow so we send such frames to be linearized.
Arguably the use of modulus might be more exact as the approach I propose may generate some false positives. However the liklihood of us taking much of a hit for those false positives is fairly low, and I would rather not add more overhead in the case where we are receiving a frame composed of 4K pages.
--- drivers/net/ethernet/intel/i40e/i40e_fcoe.c | 6 + drivers/net/ethernet/intel/i40e/i40e_txrx.c | 105 ++++++++++++++----------- drivers/net/ethernet/intel/i40e/i40e_txrx.h | 19 +++++ drivers/net/ethernet/intel/i40evf/i40e_txrx.c | 105 ++++++++++++++----------- drivers/net/ethernet/intel/i40evf/i40e_txrx.h | 19 +++++ 5 files changed, 162 insertions(+), 92 deletions(-)
drivers/net/ethernet/intel/i40e/i40e_fcoe.c +6 -0
@@ -1368,6 +1368,12 @@ static netdev_tx_t i40e_fcoe_xmit_frame(struct sk_buff *skb, goto out_drop; count =i40e_xmit_descriptor_count (skb); +if (i40e_chk_linearize (skb, count)) { +if (__skb_linearize (skb)) + goto out_drop; + count =TXD_USE_COUNT (skb->len); + tx_ring->tx_stats.tx_linearize++; + }/* need: 1 descriptor per page * PAGE_SIZE/I40E_MAX_DATA_PER_TXD, * + 1 desc for skb_head_len/I40E_MAX_DATA_PER_TXD,
drivers/net/ethernet/intel/i40e/i40e_txrx.c +59 -46
135 lines not on this page · raw message
drivers/net/ethernet/intel/i40e/i40e_txrx.h +19 -0
@@ -337,6 +337,7 @@ int i40e_tx_prepare_vlan_flags(struct sk_buff *skb,void i40e_force_wb (struct i40e_vsi *vsi,struct i40e_q_vector *q_vector);u32 i40e_get_tx_pending (struct i40e_ring *ring,bool in_sw);int __i40e_maybe_stop_tx (struct i40e_ring *tx_ring,int size); +bool __i40e_chk_linearize (struct sk_buff *skb);/** * i40e_get_head - Retrieve head from head writeback
@@ -392,4 +393,22 @@ static inline int i40e_maybe_stop_tx(struct i40e_ring *tx_ring, int size)return 0 ; return __i40e_maybe_stop_tx(tx_ring, size); } + +/** +* i40e_chk_linearize - Check if there are more than 8 fragments per packet +* @skb: send buffer +* @count: number of buffers used +* +* Note: Our HW can't scatter-gather more than 8 fragments to build +* a packet on the wire and so we need to figure out the cases where we +* need to linearize the skb. +**/ +static inline bool i40e_chk_linearize (struct sk_buff *skb,int count) +{ +/* we can only support up to 8 data buffers for a single send */ +if (likely (count <=I40E_MAX_BUFFER_TXD )) +return false; + +return __i40e_chk_linearize (skb); +}#endif /* _I40E_TXRX_H_ */
drivers/net/ethernet/intel/i40evf/i40e_txrx.c +59 -46
135 lines not on this page · raw message
drivers/net/ethernet/intel/i40evf/i40e_txrx.h +19 -0
@@ -327,6 +327,7 @@ int i40evf_napi_poll(struct napi_struct *napi, int budget);void i40evf_force_wb (struct i40e_vsi *vsi,struct i40e_q_vector *q_vector);u32 i40evf_get_tx_pending (struct i40e_ring *ring,bool in_sw);int __i40evf_maybe_stop_tx (struct i40e_ring *tx_ring,int size); +bool __i40evf_chk_linearize (struct sk_buff *skb);/** * i40e_get_head - Retrieve head from head writeback
@@ -382,4 +383,22 @@ static inline int i40e_maybe_stop_tx(struct i40e_ring *tx_ring, int size)return 0 ; return __i40evf_maybe_stop_tx(tx_ring, size); } + +/** +* i40e_chk_linearize - Check if there are more than 8 fragments per packet +* @skb: send buffer +* @count: number of buffers used +* +* Note: Our HW can't scatter-gather more than 8 fragments to build +* a packet on the wire and so we need to figure out the cases where we +* need to linearize the skb. +**/ +static inline bool i40e_chk_linearize (struct sk_buff *skb,int count) +{ +/* we can only support up to 8 data buffers for a single send */ +if (likely (count <=I40E_MAX_BUFFER_TXD )) +return false; + +return __i40evf_chk_linearize (skb); +}#endif /* _I40E_TXRX_H_ */
PATCH 3/4 i40e/i40evf: Move Tx checksum closer to TSO
In reply to Alexander DuyckOn all of the other Intel drivers we place checksum close to TSO as they have a significant amount in common and it can help to reduce the decision tree for how to handle the frame as the first check in TSO is to see if checksumming is offloaded, and if it is not we can skip _BOTH_ TSO and Tx checksum offload based on a single check.
--- drivers/net/ethernet/intel/i40e/i40e_txrx.c | 12 ++++++------ drivers/net/ethernet/intel/i40evf/i40e_txrx.c | 10 +++++----- 2 files changed, 11 insertions(+), 11 deletions(-)
drivers/net/ethernet/intel/i40e/i40e_txrx.c +6 -6
@@ -2929,6 +2929,12 @@ static netdev_tx_t i40e_xmit_frame_ring(struct sk_buff *skb,else if (tso) tx_flags |=I40E_TX_FLAGS_TSO ; +/* Always offload the checksum, since it's in the data descriptor */ + tso =i40e_tx_enable_csum (skb, &tx_flags, &td_cmd, &td_offset, + tx_ring, &cd_tunneling); +if (tso <0 ) + goto out_drop; + tsyn =i40e_tsyn (tx_ring, skb, tx_flags, &cd_type_cmd_tso_mss);if (tsyn)
@@ -2939,12 +2945,6 @@ static netdev_tx_t i40e_xmit_frame_ring(struct sk_buff *skb,/* always enable CRC insertion offload */ td_cmd |=I40E_TX_DESC_CMD_ICRC ; -/* Always offload the checksum, since it's in the data descriptor */ - tso =i40e_tx_enable_csum (skb, &tx_flags, &td_cmd, &td_offset, - tx_ring, &cd_tunneling); -if (tso <0 ) - goto out_drop; -i40e_create_tx_ctx (tx_ring, cd_type_cmd_tso_mss, cd_tunneling, cd_l2tag2);
drivers/net/ethernet/intel/i40evf/i40e_txrx.c +5 -5
@@ -2146,17 +2146,17 @@ static netdev_tx_t i40e_xmit_frame_ring(struct sk_buff *skb,else if (tso) tx_flags |=I40E_TX_FLAGS_TSO ; -skb_tx_timestamp (skb); - -/* always enable CRC insertion offload */ - td_cmd |=I40E_TX_DESC_CMD_ICRC ; -/* Always offload the checksum, since it's in the data descriptor */ tso =i40e_tx_enable_csum (skb, &tx_flags, &td_cmd, &td_offset, tx_ring, &cd_tunneling);if (tso <0 ) goto out_drop; +skb_tx_timestamp (skb); + +/* always enable CRC insertion offload */ + td_cmd |=I40E_TX_DESC_CMD_ICRC ; +i40e_create_tx_ctx (tx_ring, cd_type_cmd_tso_mss, cd_tunneling, cd_l2tag2);
PATCH 4/4 i40e/i40evf: Allow up to 12K bytes of data per Tx descriptor instead of 8K
In reply to Alexander DuyckFrom what I can tell the practial limitation on the size of the Tx data buffer is the fact that the Tx descriptor is limited to 14 bits. As such we cannot use 16K as is typically used on the other Intel drivers. However artificially limiting ourselves to 8K can be expensive as this means that we will consume up to 10 descriptors (1 context, 1 for header, and 9 for an payload, non-8K aligned) in a single send.
I propose that we can reduce this by increasing the maximum data for a 4K aligned block to 12K. We can reduce the descriptors used for a 32K aligned block by 1 by increasing the size like this. In addition we still have the 4K - 1 of space that is still unused. We can use this as a bit of extra padding when dealing with data that is not aligned to 4K.
By aligning the descriptors after the first to 4K we can improve the effiency of PCIe accesses as we can avoid using byte enables and can fetch full TLP transactions after the first fetch of the buffer. This helps to improve PCIe efficiency. Below is the results of testing before and after with this patch:
Recv Send Send Utilization Service Demand Socket Socket Message Elapsed Send Recv Send Recv Size Size Size Time Throughput local remote local remote bytes bytes bytes secs. 10^6bits/s % S % U us/KB us/KB
Before:
87380 16384 16384 10.00 33682.24 20.27 -1.00 0.592 -1.00
After:
87380 16384 16384 10.00 34204.08 20.54 -1.00 0.590 -1.00
So the net result of this patch is that we have a small gain in throughput due to a reduction in overhead for putting together the frame.
--- drivers/net/ethernet/intel/i40e/i40e_txrx.c | 13 ++++++--- drivers/net/ethernet/intel/i40e/i40e_txrx.h | 35 +++++++++++++++++++++++-- drivers/net/ethernet/intel/i40evf/i40e_txrx.c | 13 ++++++--- drivers/net/ethernet/intel/i40evf/i40e_txrx.h | 35 +++++++++++++++++++++++-- 4 files changed, 82 insertions(+), 14 deletions(-)
drivers/net/ethernet/intel/i40e/i40e_txrx.c +9 -4
@@ -2716,6 +2716,8 @@ static inline void i40e_tx_map(struct i40e_ring *tx_ring, struct sk_buff *skb, tx_bi = first;for (frag = &skb_shinfo (skb)->frags[0 ];; frag++) { +unsigned int max_data =I40E_MAX_DATA_PER_TXD_ALIGNED ; +if (dma_mapping_error (tx_ring->dev, dma)) goto dma_error;
@@ -2723,12 +2725,14 @@ static inline void i40e_tx_map(struct i40e_ring *tx_ring, struct sk_buff *skb,dma_unmap_len_set (tx_bi, len, size);dma_unmap_addr_set (tx_bi, dma, dma); +/* align size to end of page */ + max_data += -dma & (I40E_MAX_READ_REQ_SIZE -1 ); tx_desc->buffer_addr =cpu_to_le64 (dma);while (unlikely (size >I40E_MAX_DATA_PER_TXD )) { tx_desc->cmd_type_offset_bsz =build_ctob (td_cmd, td_offset, -I40E_MAX_DATA_PER_TXD , td_tag); + max_data, td_tag); tx_desc++; i++;
@@ -2739,9 +2743,10 @@ static inline void i40e_tx_map(struct i40e_ring *tx_ring, struct sk_buff *skb, i =0 ; } - dma +=I40E_MAX_DATA_PER_TXD ; - size -=I40E_MAX_DATA_PER_TXD ; + dma += max_data; + size -= max_data; + max_data =I40E_MAX_DATA_PER_TXD_ALIGNED ; tx_desc->buffer_addr =cpu_to_le64 (dma); }
@@ -2891,7 +2896,7 @@ static netdev_tx_t i40e_xmit_frame_ring(struct sk_buff *skb,if (i40e_chk_linearize (skb, count)) {if (__skb_linearize (skb)) goto out_drop; - count =TXD_USE_COUNT (skb->len); + count =i40e_txd_use_count (skb->len); tx_ring->tx_stats.tx_linearize++; }
drivers/net/ethernet/intel/i40e/i40e_txrx.h +32 -3
@@ -146,10 +146,39 @@ enum i40e_dyn_idx_t {#define I40E_MAX_BUFFER_TXD 8#define I40E_MIN_TX_LEN 17 -#define I40E_MAX_DATA_PER_TXD 8192 + +/* The size limit for a transmit buffer in a descriptor is (16K - 1). +* In order to align with the read requests we will align the value to +* the nearest 4K which represents our maximum read request size. +*/ +#define I40E_MAX_READ_REQ_SIZE 4096 +#define I40E_MAX_DATA_PER_TXD (16 * 1024 - 1) +#define I40E_MAX_DATA_PER_TXD_ALIGNED \ + (I40E_MAX_DATA_PER_TXD & ~(I40E_MAX_READ_REQ_SIZE - 1)) + +/* This ugly bit of math is equivilent to DIV_ROUNDUP(size, X) where X is +* the value I40E_MAX_DATA_PER_TXD_ALIGNED. It is needed due to the fact +* that 12K is not a power of 2 and division is expensive. It is used to +* approximate the number of descriptors used per linear buffer. Note +* that this will overestimate in some cases as it doesn't account for the +* fact that we will add up to 4K - 1 in aligning the 12K buffer, however +* the error should not impact things much as large buffers usually mean +* we will use fewer descriptors then there are frags in an skb. +*/ +static inline unsigned int i40e_txd_use_count (unsigned int size) +{ +const unsigned int max =I40E_MAX_DATA_PER_TXD_ALIGNED ; +const unsigned int reciprocal = ((1ull <<32 ) -1 + (max /2 )) / max; +unsigned int adjust = ~(u32 )0 ; + +/* if we rounded up on the reciprprocal pull down the adjustment */ +if ((max * reciprocal) > adjust) + adjust = ~(u32)(reciprocal -1 ); + +return (u32)((((u64 )size * reciprocal) + adjust) >>32 ); +}/* Tx Descriptors needed, worst case */ -#define TXD_USE_COUNT (S ) DIV_ROUND_UP((S), I40E_MAX_DATA_PER_TXD)#define DESC_NEEDED (MAX_SKB_FRAGS + 4)#define I40E_MIN_DESC_PENDING 4
@@ -369,7 +398,7 @@ static inline int i40e_xmit_descriptor_count(struct sk_buff *skb)int count =0 , size =skb_headlen (skb);for (;;) { - count +=TXD_USE_COUNT (size); + count +=i40e_txd_use_count (size);if (!nr_frags--)break ;
drivers/net/ethernet/intel/i40evf/i40e_txrx.c +9 -4
@@ -1934,6 +1934,8 @@ static inline void i40evf_tx_map(struct i40e_ring *tx_ring, struct sk_buff *skb, tx_bi = first;for (frag = &skb_shinfo (skb)->frags[0 ];; frag++) { +unsigned int max_data =I40E_MAX_DATA_PER_TXD_ALIGNED ; +if (dma_mapping_error (tx_ring->dev, dma)) goto dma_error;
@@ -1941,12 +1943,14 @@ static inline void i40evf_tx_map(struct i40e_ring *tx_ring, struct sk_buff *skb,dma_unmap_len_set (tx_bi, len, size);dma_unmap_addr_set (tx_bi, dma, dma); +/* align size to end of page */ + max_data += -dma & (I40E_MAX_READ_REQ_SIZE -1 ); tx_desc->buffer_addr =cpu_to_le64 (dma);while (unlikely (size >I40E_MAX_DATA_PER_TXD )) { tx_desc->cmd_type_offset_bsz =build_ctob (td_cmd, td_offset, -I40E_MAX_DATA_PER_TXD , td_tag); + max_data, td_tag); tx_desc++; i++;
@@ -1957,9 +1961,10 @@ static inline void i40evf_tx_map(struct i40e_ring *tx_ring, struct sk_buff *skb, i =0 ; } - dma +=I40E_MAX_DATA_PER_TXD ; - size -=I40E_MAX_DATA_PER_TXD ; + dma += max_data; + size -= max_data; + max_data =I40E_MAX_DATA_PER_TXD_ALIGNED ; tx_desc->buffer_addr =cpu_to_le64 (dma); }
@@ -2108,7 +2113,7 @@ static netdev_tx_t i40e_xmit_frame_ring(struct sk_buff *skb,if (i40e_chk_linearize (skb, count)) {if (__skb_linearize (skb)) goto out_drop; - count =TXD_USE_COUNT (skb->len); + count =i40e_txd_use_count (skb->len); tx_ring->tx_stats.tx_linearize++; }
drivers/net/ethernet/intel/i40evf/i40e_txrx.h +32 -3
@@ -146,10 +146,39 @@ enum i40e_dyn_idx_t {#define I40E_MAX_BUFFER_TXD 8#define I40E_MIN_TX_LEN 17 -#define I40E_MAX_DATA_PER_TXD 8192 + +/* The size limit for a transmit buffer in a descriptor is (16K - 1). +* In order to align with the read requests we will align the value to +* the nearest 4K which represents our maximum read request size. +*/ +#define I40E_MAX_READ_REQ_SIZE 4096 +#define I40E_MAX_DATA_PER_TXD (16 * 1024 - 1) +#define I40E_MAX_DATA_PER_TXD_ALIGNED \ + (I40E_MAX_DATA_PER_TXD & ~(I40E_MAX_READ_REQ_SIZE - 1)) + +/* This ugly bit of math is equivilent to DIV_ROUNDUP(size, X) where X is +* the value I40E_MAX_DATA_PER_TXD_ALIGNED. It is needed due to the fact +* that 12K is not a power of 2 and division is expensive. It is used to +* approximate the number of descriptors used per linear buffer. Note +* that this will overestimate in some cases as it doesn't account for the +* fact that we will add up to 4K - 1 in aligning the 12K buffer, however +* the error should not impact things much as large buffers usually mean +* we will use fewer descriptors then there are frags in an skb. +*/ +static inline unsigned int i40e_txd_use_count (unsigned int size) +{ +const unsigned int max =I40E_MAX_DATA_PER_TXD_ALIGNED ; +const unsigned int reciprocal = ((1ull <<32 ) -1 + (max /2 )) / max; +unsigned int adjust = ~(u32 )0 ; + +/* if we rounded up on the reciprprocal pull down the adjustment */ +if ((max * reciprocal) > adjust) + adjust = ~(u32)(reciprocal -1 ); + +return (u32)((((u64 )size * reciprocal) + adjust) >>32 ); +}/* Tx Descriptors needed, worst case */ -#define TXD_USE_COUNT (S ) DIV_ROUND_UP((S), I40E_MAX_DATA_PER_TXD)#define DESC_NEEDED (MAX_SKB_FRAGS + 4)#define I40E_MIN_DESC_PENDING 4
@@ -359,7 +388,7 @@ static inline int i40e_xmit_descriptor_count(struct sk_buff *skb)int count =0 , size =skb_headlen (skb);for (;;) { - count +=TXD_USE_COUNT (size); + count +=i40e_txd_use_count (size);if (!nr_frags--)break ;
PATCH 4/4 i40e/i40evf: Allow up to 12K bytes of data per Tx descriptor instead of 8K
Quoted 51 lines · Alexander Duyck
Quoted 1 line
From what I can tell the practial limitation on the size of the Tx
data
buffer is the fact that the Tx descriptor is limited to 14 bits.? As such
we cannot use 16K as is typically used on the other Intel drivers.? However
artificially limiting ourselves to 8K can be expensive as this means that
we will consume up to 10 descriptors (1 context, 1 for header, and 9 for
an payload, non-8K aligned) in a single send.I propose that we can reduce this by increasing the maximum data for a 4K
aligned block to 12K.? We can reduce the descriptors used for a 32K aligned
block by 1 by increasing the size like this.? In addition we still have the
4K - 1 of space that is still unused.? We can use this as a bit of extra
padding when dealing with data that is not aligned to 4K.By aligning the descriptors after the first to 4K we can improve the effiency of PCIe accesses as we can avoid using byte enables and can fetch
full TLP transactions after the first fetch of the buffer.? This helps to
improve PCIe efficiency.? Below is the results of testing before and after
with this patch:Recv?? Send?? Send???????????????????????? Utilization????? Service Demand
Socket Socket Message? Elapsed???????????? Send???? Recv??? Send??? Recv
Size?? Size?? Size???? Time??? Throughput? local??? remote? local?? remote
bytes? bytes? bytes??? secs.?? 10^6bits/s? % S????? % U???? us/KB?? us/KB
Before:
87380? 16384? 16384??? 10.00???? 33682.24? 20.27??? -1.00?? 0.592?? -1.00
After:
87380? 16384? 16384??? 10.00???? 34204.08? 20.54??? -1.00?? 0.590?? -1.00So the net result of this patch is that we have a small gain in throughput
due to a reduction in overhead for putting together the frame.Signed-off-by Alexander Duyck <[email protected]>
Quoted 8 lines
---
?drivers/net/ethernet/intel/i40e/i40e_txrx.c?? |?? 13 ++++++--- ?drivers/net/ethernet/intel/i40e/i40e_txrx.h?? |?? 35
+++++++++++++++++++++++--
?drivers/net/ethernet/intel/i40evf/i40e_txrx.c |?? 13 ++++++--- ?drivers/net/ethernet/intel/i40evf/i40e_txrx.h |?? 35
+++++++++++++++++++++++--
?4 files changed, 82 insertions(+), 14 deletions(-)
Getting a compile error after applying this patch to my tree, here is what I am getting:
drivers/net/ethernet/intel/i40e/i40e_fcoe.c: In function
?i40e_fcoe_xmit_frame?:drivers/net/ethernet/intel/i40e/i40e_fcoe.c:1374:11: error: implicit
declaration of function ?TXD_USE_COUNT? [-Werror=implicit-function-
declaration]
???count = TXD_USE_COUNT(skb->len);
???????????^
cc1: some warnings being treated as errors
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: This is a digitally signed message part
URL: <http://lists.osuosl.org/pipermail/intel-wired-lan/attachments/20160217/63bd49de/attachment.asc>
PATCH 4/4 i40e/i40evf: Allow up to 12K bytes of data per Tx descriptor instead of 8K
Quoted 64 lines · Jeff Kirsher
Quoted 51 lines · Alexander Duyck
Quoted 1 line
From what I can tell the practial limitation on the size of the Tx
data
buffer is the fact that the Tx descriptor is limited to 14 bits. As such
we cannot use 16K as is typically used on the other Intel drivers. However
artificially limiting ourselves to 8K can be expensive as this means that
we will consume up to 10 descriptors (1 context, 1 for header, and 9 for
an payload, non-8K aligned) in a single send.I propose that we can reduce this by increasing the maximum data for a 4K
aligned block to 12K. We can reduce the descriptors used for a 32K aligned
block by 1 by increasing the size like this. In addition we still have the
4K - 1 of space that is still unused. We can use this as a bit of extra
padding when dealing with data that is not aligned to 4K.By aligning the descriptors after the first to 4K we can improve the effiency of PCIe accesses as we can avoid using byte enables and can fetch
full TLP transactions after the first fetch of the buffer. This helps to
improve PCIe efficiency. Below is the results of testing before and after
with this patch:Recv Send Send Utilization Service
Demand
Socket Socket Message Elapsed Send Recv Send
Recv
Size Size Size Time Throughput local remote local
remote
bytes bytes bytes secs. 10^6bits/s % S % U us/KB
us/KB
Before:
87380 16384 16384 10.00 33682.24 20.27 -1.00 0.592
-1.00
After:
87380 16384 16384 10.00 34204.08 20.54 -1.00 0.590
-1.00So the net result of this patch is that we have a small gain in throughput
due to a reduction in overhead for putting together the frame.Signed-off-by Alexander Duyck <[email protected]>Quoted 8 lines
--- drivers/net/ethernet/intel/i40e/i40e_txrx.c | 13 ++++++--- drivers/net/ethernet/intel/i40e/i40e_txrx.h | 35 +++++++++++++++++++++++-- drivers/net/ethernet/intel/i40evf/i40e_txrx.c | 13 ++++++--- drivers/net/ethernet/intel/i40evf/i40e_txrx.h | 35 +++++++++++++++++++++++-- 4 files changed, 82 insertions(+), 14 deletions(-)Getting a compile error after applying this patch to my tree, here is what I am getting:
Quoted 8 lines
drivers/net/ethernet/intel/i40e/i40e_fcoe.c: In function ?i40e_fcoe_xmit_frame?:drivers/net/ethernet/intel/i40e/i40e_fcoe.c:1374:11: error: implicit declaration of function ?TXD_USE_COUNT? [-Werror=implicit-function- declaration]count = TXD_USE_COUNT(skb->len); ^cc1: some warnings being treated as errors
Sorry about that. I don't think I was testing with FCoE enabled. I'll fix it up and resubmit.
- Alex