> From: dev [mailto:[email protected]] On Behalf Of Leyi Rong
> Sent: Thursday, 14 January 2021 07.40
>
> Optimize Tx path by using AVX512 instructions and vectorize the
> tx free bufs process.
>
> Signed-off-by: Leyi Rong <[email protected]>
> Signed-off-by: Bruce Richardson <[email protected]>
> ---
[...]
> +static __rte_always_inline int
> +i40e_tx_free_bufs_avx512(struct i40e_tx_queue *txq)
> +{
> + struct i40e_vec_tx_entry *txep;
> + uint32_t n;
> + uint32_t i;
> + int nb_free = 0;
> + struct rte_mbuf *m, *free[RTE_I40E_TX_MAX_FREE_BUF_SZ];
> +
> + /* check DD bits on threshold descriptor */
> + if ((txq->tx_ring[txq->tx_next_dd].cmd_type_offset_bsz &
> + rte_cpu_to_le_64(I40E_TXD_QW1_DTYPE_MASK)) !=
> + rte_cpu_to_le_64(I40E_TX_DESC_DTYPE_DESC_DONE))
> + return 0;
> +
> + n = txq->tx_rs_thresh;
> +
> + /* first buffer to free from S/W ring is at index
> + * tx_next_dd - (tx_rs_thresh-1)
> + */
> + txep = (void *)txq->sw_ring;
> + txep += txq->tx_next_dd - (n - 1);
> +
> + if (txq->offloads & DEV_TX_OFFLOAD_MBUF_FAST_FREE && (n & 31) ==
> 0) {
> + struct rte_mempool *mp = txep[0].mbuf->pool;
> + void **cache_objs;
> + struct rte_mempool_cache *cache =
> rte_mempool_default_cache(mp,
> + rte_lcore_id());
> +
> + if (!cache || cache->len == 0)
> + goto normal;
> +
> + cache_objs = &cache->objs[cache->len];
> +
> + if (n > RTE_MEMPOOL_CACHE_MAX_SIZE) {
> + rte_mempool_ops_enqueue_bulk(mp, (void *)txep, n);
> + goto done;
> + }
> +
> + /* The cache follows the following algorithm
> + * 1. Add the objects to the cache
> + * 2. Anything greater than the cache min value (if it
> + * crosses the cache flush threshold) is flushed to the
> ring.
> + */
> + /* Add elements back into the cache */
> + uint32_t copied = 0;
> + /* n is multiple of 32 */
> + while (copied < n) {
> + const __m512i a = _mm512_load_si512(&txep[copied]);
> + const __m512i b = _mm512_load_si512(&txep[copied +
> 8]);
> + const __m512i c = _mm512_load_si512(&txep[copied +
> 16]);
> + const __m512i d = _mm512_load_si512(&txep[copied +
> 24]);
> +
> + _mm512_storeu_si512(&cache_objs[copied], a);
> + _mm512_storeu_si512(&cache_objs[copied + 8], b);
> + _mm512_storeu_si512(&cache_objs[copied + 16], c);
> + _mm512_storeu_si512(&cache_objs[copied + 24], d);
> + copied += 32;
> + }
Do you have any indications about how this copy loop performs, compared to e.g.
the 64-byte block copy in rte_memcpy() [1]?
[1]:
https://github.com/DPDK/dpdk/blob/v26.07-rc4/lib/eal/x86/include/rte_memcpy.h#L657
I'm wondering if it would be worth adding something similar to the mempool
library, for speeding up mbuf alloc/free.
> + cache->len += n;
> +
> + if (cache->len >= cache->flushthresh) {
> + rte_mempool_ops_enqueue_bulk
> + (mp, &cache->objs[cache->size],
> + cache->len - cache->size);
> + cache->len = cache->size;
> + }
> + goto done;
> + }
> +
> +normal: