vhost: add support for packed ring in async vhost
PATCH 1/1 vhost: add support for packed ring in async vhost
For now async vhost data path only supports split ring structure. In order to make async vhost compatible with virtio 1.1 spec this patch enables packed ring in async vhost data path.
--- lib/librte_vhost/rte_vhost_async.h | 1 + lib/librte_vhost/vhost.c | 15 +- lib/librte_vhost/vhost.h | 7 +- lib/librte_vhost/virtio_net.c | 449 +++++++++++++++++++++++++++-- 4 files changed, 436 insertions(+), 36 deletions(-)
lib/librte_vhost/rte_vhost_async.h +1 -0
@@ -89,6 +89,7 @@ struct rte_vhost_async_channel_ops {struct async_inflight_info {struct rte_mbuf *mbuf;uint16_t descs;/* num of descs inflight */ +uint16_t nr_buffers;/* num of buffers inflight for packed ring*/ };/**
lib/librte_vhost/vhost.c +11 -4
@@ -1603,9 +1603,9 @@ int rte_vhost_async_channel_register(int vid, uint16_t queue_id,return -1 ;/* packed queue is not supported */ -if (unlikely (vq_is_packed (dev) || !f.async_inorder)) { +if (unlikely (!f.async_inorder)) {VHOST_LOG_CONFIG (ERR , -"async copy is not supported on packed queue or non-inorder mode " +"async copy is not supported on non-inorder mode " "(vid %d, qid: %d)\n" , vid, queue_id);return -1 ; }
@@ -1643,10 +1643,17 @@ int rte_vhost_async_channel_register(int vid, uint16_t queue_id, vq->vec_pool =rte_malloc_socket (NULL ,VHOST_MAX_ASYNC_VEC *sizeof (struct iovec ),RTE_CACHE_LINE_SIZE , node); - vq->async_descs_split =rte_malloc_socket (NULL , +if (vq_is_packed (dev)) { + vq->async_buffers_packed =rte_malloc_socket (NULL , + vq->size *sizeof (struct vring_used_elem_packed ), +RTE_CACHE_LINE_SIZE , node); + }else { + vq->async_descs_split =rte_malloc_socket (NULL , vq->size *sizeof (struct vring_used_elem ),RTE_CACHE_LINE_SIZE , node); -if (!vq->async_descs_split || !vq->async_pkts_info || + } + +if (!vq->async_pkts_info || !vq->it_pool || !vq->vec_pool) {vhost_free_async_mem (vq); VHOST_LOG_CONFIG(ERR,
lib/librte_vhost/vhost.h +6 -1
@@ -206,9 +206,14 @@ struct vhost_virtqueue {uint16_t async_pkts_idx;uint16_t async_pkts_inflight_n;uint16_t async_last_pkts_n; -struct vring_used_elem *async_descs_split; +union { +struct vring_used_elem *async_descs_split; +struct vring_used_elem_packed *async_buffers_packed; + };uint16_t async_desc_idx; +uint16_t async_packed_buffer_idx;uint16_t last_async_desc_idx; +uint16_t last_async_buffer_idx;/* vq async features */ bool async_inorder;
lib/librte_vhost/virtio_net.c +418 -31
506 lines not on this page · raw message
Signature · 1 line
2.29.2
PATCH v2 1/1 vhost: add support for packed ring in async vhost
For now async vhost data path only supports split ring structure. In order to make async vhost compatible with virtio 1.1 spec this patch enables packed ring in async vhost data path.
---
v2:
* fix wrong buffer index in rte_vhost_poll_enqueue_completed()
* add async_buffers_packed memory free in vhost_free_async_mem()
lib/librte_vhost/rte_vhost_async.h | 1 + lib/librte_vhost/vhost.c | 24 +- lib/librte_vhost/vhost.h | 7 +- lib/librte_vhost/virtio_net.c | 447 +++++++++++++++++++++++++++-- 4 files changed, 441 insertions(+), 38 deletions(-)
lib/librte_vhost/rte_vhost_async.h +1 -0
@@ -89,6 +89,7 @@ struct rte_vhost_async_channel_ops {struct async_inflight_info {struct rte_mbuf *mbuf;uint16_t descs;/* num of descs inflight */ +uint16_t nr_buffers;/* num of buffers inflight for packed ring */ };/**
lib/librte_vhost/vhost.c +18 -6
@@ -330,15 +330,20 @@ vhost_free_async_mem(struct vhost_virtqueue *vq) {if (vq->async_pkts_info)rte_free (vq->async_pkts_info); -if (vq->async_descs_split) +if (vq->async_buffers_packed) { +rte_free (vq->async_buffers_packed); + vq->async_buffers_packed =NULL ; + }else {rte_free (vq->async_descs_split); + vq->async_descs_split =NULL ; + } +if (vq->it_pool)rte_free (vq->it_pool);if (vq->vec_pool)rte_free (vq->vec_pool); vq->async_pkts_info =NULL ; - vq->async_descs_split =NULL ; vq->it_pool =NULL ; vq->vec_pool =NULL ; }
@@ -1603,9 +1608,9 @@ int rte_vhost_async_channel_register(int vid, uint16_t queue_id,return -1 ;/* packed queue is not supported */ -if (unlikely (vq_is_packed (dev) || !f.async_inorder)) { +if (unlikely (!f.async_inorder)) {VHOST_LOG_CONFIG (ERR , -"async copy is not supported on packed queue or non-inorder mode " +"async copy is not supported on non-inorder mode " "(vid %d, qid: %d)\n" , vid, queue_id);return -1 ; }
@@ -1643,10 +1648,17 @@ int rte_vhost_async_channel_register(int vid, uint16_t queue_id, vq->vec_pool =rte_malloc_socket (NULL ,VHOST_MAX_ASYNC_VEC *sizeof (struct iovec ),RTE_CACHE_LINE_SIZE , node); - vq->async_descs_split =rte_malloc_socket (NULL , +if (vq_is_packed (dev)) { + vq->async_buffers_packed =rte_malloc_socket (NULL , + vq->size *sizeof (struct vring_used_elem_packed ), +RTE_CACHE_LINE_SIZE , node); + }else { + vq->async_descs_split =rte_malloc_socket (NULL , vq->size *sizeof (struct vring_used_elem ),RTE_CACHE_LINE_SIZE , node); -if (!vq->async_descs_split || !vq->async_pkts_info || + } + +if (!vq->async_pkts_info || !vq->it_pool || !vq->vec_pool) {vhost_free_async_mem (vq); VHOST_LOG_CONFIG(ERR,
lib/librte_vhost/vhost.h +6 -1
@@ -206,9 +206,14 @@ struct vhost_virtqueue {uint16_t async_pkts_idx;uint16_t async_pkts_inflight_n;uint16_t async_last_pkts_n; -struct vring_used_elem *async_descs_split; +union { +struct vring_used_elem *async_descs_split; +struct vring_used_elem_packed *async_buffers_packed; + };uint16_t async_desc_idx; +uint16_t async_packed_buffer_idx;uint16_t last_async_desc_idx; +uint16_t last_async_buffer_idx;/* vq async features */ bool async_inorder;
lib/librte_vhost/virtio_net.c +416 -31
504 lines not on this page · raw message
--
2.29.2
Quoted 261 lines
-----Original Message-----
From: dev <[email protected]> On Behalf Of Cheng Jiang
Sent: Monday, March 22, 2021 2:15 PM
To: [email protected]; Xia, Chenbo <[email protected]>
Cc: [email protected]; Hu, Jiayu <[email protected]>; Yang, YvonneX <[email protected]>; Wang, Yinan <[email protected]>; Jiang, Cheng1 <[email protected]>
Subject: [dpdk-dev] [PATCH v2] vhost: add support for packed ring in async vhostFor now async vhost data path only supports split ring structure. In order to make async vhost compatible with virtio 1.1 spec this patch enables packed ring in async vhost data path.
Signed-off-by Cheng Jiang <[email protected]>---
v2:
* fix wrong buffer index inrte_vhost_poll_enqueue_completed()
* addasync_buffers_packedmemory free invhost_free_async_mem()lib/librte_vhost/rte_vhost_async.h | 1 + lib/librte_vhost/vhost.c | 24 +- lib/librte_vhost/vhost.h | 7 +- lib/librte_vhost/virtio_net.c | 447 +++++++++++++++++++++++++++-- 4 files changed, 441 insertions(+), 38 deletions(-)lib/librte_vhost/rte_vhost_async.h +1
-0@@ -89,6 +89,7 @@ struct rte_vhost_async_channel_ops {struct async_inflight_info {struct rte_mbuf *mbuf;uint16_t descs;/* num of descs inflight */ +uint16_t nr_buffers;/* num of buffers inflight for packed ring */ };/** lib/librte_vhost/vhost.c +7
-2@@ -330,15 +330,20 @@ vhost_free_async_mem(struct vhost_virtqueue *vq) {if (vq->async_pkts_info)rte_free (vq->async_pkts_info); -if (vq->async_descs_split) +if (vq->async_buffers_packed) { +rte_free (vq->async_buffers_packed); + vq->async_buffers_packed =NULL ; + }else {rte_free (vq->async_descs_split); + vq->async_descs_split =NULL ; + } +if (vq->it_pool)rte_free (vq->it_pool);if (vq->vec_pool)rte_free (vq->vec_pool); vq->async_pkts_info =NULL ; - vq->async_descs_split =NULL ; vq->it_pool =NULL ; vq->vec_pool =NULL ;}
lib/librte_vhost/vhost.c +1
-2@@ -1603,9 +1608,9 @@ int rte_vhost_async_channel_register(int vid,uint16_t queue_id, return -1;/* packed queue is not supported */ -if (unlikely (vq_is_packed (dev) || !f.async_inorder)) { +if (unlikely (!f.async_inorder)) { VHOST_LOG_CONFIG(ERR, - "async copy is not supported on packed queue ornon-inorder mode "
lib/librte_vhost/vhost.c +10
-2+"async copy is not supported on non-inorder mode " "(vid %d, qid: %d)\n", vid, queue_id);return -1 ; }@@ -1643,10 +1648,17 @@ int rte_vhost_async_channel_register(int vid,uint16_t queue_id, vq->vec_pool = rte_malloc_socket(NULL,VHOST_MAX_ASYNC_VEC *sizeof (struct iovec ),RTE_CACHE_LINE_SIZE , node); - vq->async_descs_split =rte_malloc_socket (NULL , +if (vq_is_packed (dev)) { + vq->async_buffers_packed =rte_malloc_socket (NULL , + vq->size *sizeof (struct vring_used_elem_packed ), +RTE_CACHE_LINE_SIZE , node); + }else { + vq->async_descs_split =rte_malloc_socket (NULL , vq->size *sizeof (struct vring_used_elem ),RTE_CACHE_LINE_SIZE , node); -if (!vq->async_descs_split || !vq->async_pkts_info || + } + +if (!vq->async_pkts_info || !vq->it_pool || !vq->vec_pool) {vhost_free_async_mem (vq);lib/librte_vhost/vhost.c +0
-0VHOST_LOG_CONFIG(ERR,lib/librte_vhost/vhost.h +6
-1@@ -206,9 +206,14 @@ struct vhost_virtqueue {uint16_t async_pkts_idx;uint16_t async_pkts_inflight_n;uint16_t async_last_pkts_n; -struct vring_used_elem *async_descs_split; +union { +struct vring_used_elem *async_descs_split; +struct vring_used_elem_packed *async_buffers_packed; + };uint16_t async_desc_idx; +uint16_t async_packed_buffer_idx;uint16_t last_async_desc_idx; +uint16_t last_async_buffer_idx;/* vq async features */ bool async_inorder;lib/librte_vhost/virtio_net.c +1
-2@@ -363,8 +363,7 @@ vhost_shadow_dequeue_single_packed_inorder(struct vhost_virtqueue *vq, } static __rte_always_inline void -vhost_shadow_enqueue_single_packed(struct virtio_net *dev, - struct vhost_virtqueue *vq, +vhost_shadow_enqueue_packed(struct vhost_virtqueue *vq, uint32_t len[], uint16_t id[],lib/librte_vhost/virtio_net.c +11
-0uint16_t count[],@@ -382,6 +381,17 @@ vhost_shadow_enqueue_single_packed(struct virtio_net *dev, vq->shadow_aligned_idx += count[i]; vq->shadow_used_idx++; } +} + +static __rte_always_inline void +vhost_shadow_enqueue_single_packed (struct virtio_net *dev, +struct vhost_virtqueue *vq, +uint32_t len[], +uint16_t id[], +uint16_t count[], +uint16_t num_buffers) +{ +vhost_shadow_enqueue_packed (vq, len, id, count, num_buffers);if (vq->shadow_aligned_idx >=PACKED_BATCH_SIZE ) {lib/librte_vhost/virtio_net.c +95
-0do_data_copy_enqueue (dev, vq);@@ -1633,12 +1643,343 @@ virtio_dev_rx_async_submit_split(structvirtio_net *dev, return pkt_idx; } +static __rte_always_inline int +vhost_enqueue_async_single_packed (struct virtio_net *dev, +struct vhost_virtqueue *vq, +struct rte_mbuf *pkt, +struct buf_vector *buf_vec, +uint16_t *nr_descs, +uint16_t *nr_buffers, +struct iovec *src_iovec,struct iovec *dst_iovec, +struct rte_vhost_iov_iter *src_it, +struct rte_vhost_iov_iter *dst_it) +{ +uint16_t nr_vec =0 ; +uint16_t avail_idx = vq->last_avail_idx; +uint16_t max_tries, tries =0 ; +uint16_t buf_id =0 ; +uint32_t len =0 ; +uint16_t desc_count; +uint32_t size = pkt->pkt_len +sizeof (struct virtio_net_hdr_mrg_rxbuf ); +uint32_t buffer_len[vq->size]; +uint16_t buffer_buf_id[vq->size]; +uint16_t buffer_desc_count[vq->size]; + *nr_buffers =0 ; + +if (rxvq_is_mergeable (dev)) + max_tries = vq->size -1 ; +else + max_tries =1 ; + +while (size >0 ) { +/* +* if we tried all available ring items, and still +* can't get enough buf, it means something abnormal +* happened. +*/ +if (unlikely (++tries > max_tries)) +return -1 ; + +if (unlikely (fill_vec_buf_packed (dev, vq, + avail_idx, &desc_count, + buf_vec, &nr_vec, + &buf_id, &len, +VHOST_ACCESS_RW ) <0 )) +return -1 ; + + len =RTE_MIN (len, size); + size -= len; + + buffer_len[*nr_buffers] = len; + buffer_buf_id[*nr_buffers] = buf_id; + buffer_desc_count[*nr_buffers] = desc_count; + *nr_buffers +=1 ; + + *nr_descs += desc_count; + avail_idx += desc_count; +if (avail_idx >= vq->size) + avail_idx -= vq->size; + } + +if (async_mbuf_to_desc (dev, vq, pkt, buf_vec, nr_vec, *nr_buffers, + src_iovec, dst_iovec, src_it, dst_it) <0 ) +return -1 ; + +vhost_shadow_enqueue_packed (vq, buffer_len, buffer_buf_id, + buffer_desc_count, *nr_buffers); + +return 0 ; +} + +static __rte_always_inline int16_t +virtio_dev_rx_async_single_packed (struct virtio_net *dev, +struct vhost_virtqueue *vq, +struct rte_mbuf *pkt, +uint16_t *nr_descs,uint16_t *nr_buffers, +struct iovec *src_iovec,struct iovec *dst_iovec, +struct rte_vhost_iov_iter *src_it, +struct rte_vhost_iov_iter *dst_it) +{ +struct buf_vector buf_vec[BUF_VECTOR_MAX ]; + *nr_descs =0 ; + *nr_buffers =0 ; + +if (unlikely (vhost_enqueue_async_single_packed (dev, vq, pkt, buf_vec, + nr_descs, + nr_buffers, + src_iovec, dst_iovec, + src_it, dst_it) <0 )) { +VHOST_LOG_DATA (DEBUG , +"(%d) failed to get enough desc from vring\n" , + dev->vid); +return -1 ; + } + + VHOST_LOG_DATA(DEBUG, "(%d) current index %d | end index %d\n", + dev->vid, vq->last_avail_idx, + vq->last_avail_idx + *nr_descs);
lib/librte_vhost/virtio_net.c virtio_dev_rx_async_submit_split(struct · line 1754
Quoted 10 lines
lib/librte_vhost/virtio_net.c +10
-0+ +return 0 ; +} + +static __rte_noinline uint32_t +virtio_dev_rx_async_submit_packed (struct virtio_net *dev, +struct vhost_virtqueue *vq,uint16_t queue_id, +struct rte_mbuf **pkts,uint32_t count, +struct rte_mbuf **comp_pkts,uint32_t *comp_count) +{
Hi Cheng,
There're some common parts in virtio_dev_rx_async_submit_packed and virtio_dev_rx_async_submit_split. We can abstract some functions for those common parts which can bring more clarity.
Also this patch may be too huge for reviewing, please separate it into few parts for better understanding.
Thanks,
Marvin
Quoted 149 lines
lib/librte_vhost/virtio_net.c +90
-0+uint32_t pkt_idx =0 , pkt_burst_idx =0 ; +uint16_t num_buffers; +uint16_t num_desc; + +struct rte_vhost_iov_iter *it_pool = vq->it_pool; +struct iovec *vec_pool = vq->vec_pool; +struct rte_vhost_async_desc tdes[MAX_PKT_BURST ]; +struct iovec *src_iovec = vec_pool; +struct iovec *dst_iovec = vec_pool + (VHOST_MAX_ASYNC_VEC >>1 ); +struct rte_vhost_iov_iter *src_it = it_pool; +struct rte_vhost_iov_iter *dst_it = it_pool +1 ; +uint16_t slot_idx =0 ; +uint16_t segs_await =0 ; +struct async_inflight_info *pkts_info = vq->async_pkts_info; +uint32_t n_pkts =0 , pkt_err =0 ; +uint32_t num_async_pkts =0 , num_done_pkts =0 ; +struct { +uint16_t pkt_idx; +uint16_t last_avail_idx; + } async_pkts_log[MAX_PKT_BURST ]; + +rte_prefetch0 (&vq->desc[vq->last_avail_idx & (vq->size -1 )]); + +for (pkt_idx =0 ; pkt_idx < count; pkt_idx++) { +if (unlikely (virtio_dev_rx_async_single_packed (dev, vq, + pkts[pkt_idx], + &num_desc, &num_buffers, + src_iovec, dst_iovec, + src_it, dst_it) <0 )) { +break ; + } + + VHOST_LOG_DATA(DEBUG, "(%d) current index %d | end index %d\n", + dev->vid, vq->last_avail_idx, + vq->last_avail_idx + num_desc); + + slot_idx = (vq->async_pkts_idx + num_async_pkts) & + (vq->size -1 ); +if (src_it->count) { +uint16_t from, to; + +async_fill_desc (&tdes[pkt_burst_idx++], src_it, dst_it); + pkts_info[slot_idx].descs = num_desc; + pkts_info[slot_idx].nr_buffers = num_buffers; + pkts_info[slot_idx].mbuf = pkts[pkt_idx]; + async_pkts_log[num_async_pkts].pkt_idx = pkt_idx; + async_pkts_log[num_async_pkts++].last_avail_idx = + vq->last_avail_idx; + src_iovec += src_it->nr_segs; + dst_iovec += dst_it->nr_segs; + src_it +=2 ; + dst_it +=2 ; + segs_await += src_it->nr_segs; + +/** +* recover shadow used ring and keep DMA-occupied +* descriptors. +*/ + from = vq->shadow_used_idx - num_buffers; + to = vq->async_packed_buffer_idx & (vq->size -1 ); +if (num_buffers + to <= vq->size) { +rte_memcpy (&vq->async_buffers_packed[to], + &vq->shadow_used_packed[from], + num_buffers * +sizeof (struct vring_used_elem_packed )); + }else { +int size = vq->size - to; + +rte_memcpy (&vq->async_buffers_packed[to], + &vq->shadow_used_packed[from], + size * +sizeof (struct vring_used_elem_packed )); +rte_memcpy (vq->async_buffers_packed, + &vq->shadow_used_packed[from + + size], (num_buffers - size) * +sizeof (struct vring_used_elem_packed )); + } + vq->async_packed_buffer_idx += num_buffers; + vq->shadow_used_idx -= num_buffers; + }else + comp_pkts[num_done_pkts++] = pkts[pkt_idx]; + +vq_inc_last_avail_packed (vq, num_desc); + +/* +* conditions to trigger async device transfer: +* - buffered packet number reaches transfer threshold +* - unused async iov number is less than max vhost vector +*/ + if (unlikely(pkt_burst_idx >=
VHOST_ASYNC_BATCH_THRESHOLD||lib/librte_vhost/virtio_net.c +6
-0+ ((VHOST_MAX_ASYNC_VEC >> 1) - segs_await < + BUF_VECTOR_MAX))) { + n_pkts = vq->async_ops.transfer_data (dev->vid, + queue_id, tdes,0 , pkt_burst_idx); + src_iovec = vec_pool; + dst_iovec = vec_pool + (VHOST_MAX_ASYNC_VEC >>1);
lib/librte_vhost/virtio_net.c +8
-0+ src_it = it_pool; + dst_it = it_pool +1 ; + segs_await =0 ; + vq->async_pkts_inflight_n += n_pkts; + +if (unlikely (n_pkts < pkt_burst_idx)) { +/* +* log error packets number here and do actual
lib/librte_vhost/virtio_net.c +37
-0+* error processing when applications poll +* completion +*/ + pkt_err = pkt_burst_idx - n_pkts; + pkt_burst_idx =0 ; +break ; + } + + pkt_burst_idx =0 ; + } + } + +if (pkt_burst_idx) { + n_pkts = vq->async_ops.transfer_data (dev->vid, + queue_id, tdes,0 , pkt_burst_idx); + vq->async_pkts_inflight_n += n_pkts; + +if (unlikely (n_pkts < pkt_burst_idx)) + pkt_err = pkt_burst_idx - n_pkts; + } + +do_data_copy_enqueue (dev, vq); + +if (unlikely (pkt_err)) { +uint16_t num_buffers =0 ; + + num_async_pkts -= pkt_err; +/* calculate the sum of descriptors of DMA-error packets. */ +while (pkt_err-- >0 ) { + num_buffers += + pkts_info[slot_idx & (vq->size -1 )].nr_buffers; + slot_idx--; + } + vq->async_packed_buffer_idx -= num_buffers; +/* recover shadow used ring and available ring */ + vq->shadow_used_idx -= (vq->last_avail_idx - +async_pkts_log[num_async_pkts].last_avail_idx -
lib/librte_vhost/virtio_net.c virtio_dev_rx_async_submit_split(struct virtio_net *dev, · line 1892
Quoted 1 line
lib/librte_vhost/virtio_net.c +1
-0+ num_buffers);
Could it possible that vq->last_avail_idx smaller than async_pkts_log[num_async_pkts].last_avail_idx when operations near the ring's boundary?
Quoted 246 lines
lib/librte_vhost/virtio_net.c +21
-0+ vq->last_avail_idx = + async_pkts_log[num_async_pkts].last_avail_idx; + pkt_idx = async_pkts_log[num_async_pkts].pkt_idx; + num_done_pkts = pkt_idx - num_async_pkts; + } + + vq->async_pkts_idx += num_async_pkts; + *comp_count = num_done_pkts; + +if (likely (vq->shadow_used_idx)) { +vhost_flush_enqueue_shadow_packed (dev, vq); +vhost_vring_call_packed (dev, vq); + } + +return pkt_idx; +} + +static __rte_always_inline void +vhost_update_used_packed (struct virtio_net *dev, +struct vhost_virtqueue *vq, + struct vring_used_elem_packed
*shadow_ring,lib/librte_vhost/virtio_net.c +127
-24+ uint16_t count) +{ +if (count ==0 ) +return ; +int i; +uint16_t used_idx = vq->last_used_idx; +uint16_t head_idx = vq->last_used_idx; +uint16_t head_flags =0 ; + +/* Split loop in two to save memory barriers */ +for (i =0 ; i < count; i++) { + vq->desc_packed[used_idx].id = shadow_ring[i].id; + vq->desc_packed[used_idx].len = shadow_ring[i].len; + + used_idx += shadow_ring[i].count; +if (used_idx >= vq->size) + used_idx -= vq->size; + } + +/* The ordering for storing desc flags needs to be enforced. */ +rte_atomic_thread_fence (__ATOMIC_RELEASE); + +for (i =0 ; i < count; i++) { +uint16_t flags; + +if (vq->shadow_used_packed[i].len) + flags =VRING_DESC_F_WRITE ; +else + flags =0 ; + +if (vq->used_wrap_counter) { + flags |=VRING_DESC_F_USED ; + flags |=VRING_DESC_F_AVAIL ; + }else { + flags &= ~VRING_DESC_F_USED ; + flags &= ~VRING_DESC_F_AVAIL ; + } + +if (i >0 ) { + vq->desc_packed[vq->last_used_idx].flags = flags; + +vhost_log_cache_used_vring (dev, vq, + vq->last_used_idx * +sizeof (struct vring_packed_desc ), +sizeof (struct vring_packed_desc )); + }else { + head_idx = vq->last_used_idx; + head_flags = flags; + } + +vq_inc_last_used_packed (vq, shadow_ring[i].count); + } + + vq->desc_packed[head_idx].flags = head_flags; + +vhost_log_cache_used_vring (dev, vq, + head_idx * +sizeof (struct vring_packed_desc ), +sizeof (struct vring_packed_desc )); + +vhost_log_cache_sync (dev, vq); +} +uint16_t rte_vhost_poll_enqueue_completed (int vid,uint16_t queue_id,struct rte_mbuf **pkts,uint16_t count) {struct virtio_net *dev =get_device (vid);struct vhost_virtqueue *vq; -uint16_t n_pkts_cpl =0 , n_pkts_put =0 , n_descs =0 ; +uint16_t n_pkts_cpl =0 , n_pkts_put =0 , n_descs =0 , n_buffers =0 ;uint16_t start_idx, pkts_idx, vq_size;struct async_inflight_info *pkts_info;uint16_t from, i;@@ -1680,53 +2021,96 @@ uint16_t rte_vhost_poll_enqueue_completed(int vid, uint16_t queue_id, goto done; } -for (i =0 ; i < n_pkts_put; i++) { - from = (start_idx + i) & (vq_size -1 ); - n_descs += pkts_info[from].descs; - pkts[i] = pkts_info[from].mbuf; +if (vq_is_packed (dev)) { +for (i =0 ; i < n_pkts_put; i++) { + from = (start_idx + i) & (vq_size -1 ); + n_buffers += pkts_info[from].nr_buffers; + pkts[i] = pkts_info[from].mbuf; + } + }else { +for (i =0 ; i < n_pkts_put; i++) { + from = (start_idx + i) & (vq_size -1 ); + n_descs += pkts_info[from].descs; + pkts[i] = pkts_info[from].mbuf; + } } + vq->async_last_pkts_n = n_pkts_cpl - n_pkts_put; vq->async_pkts_inflight_n -= n_pkts_put;if (likely (vq->enabled && vq->access_ok)) { -uint16_t nr_left = n_descs;uint16_t nr_copy;uint16_t to;/* write back completed descriptors to used ring */ -do { - from = vq->last_async_desc_idx & (vq->size -1 ); - nr_copy = nr_left + from <= vq->size ? nr_left : - vq->size - from; - to = vq->last_used_idx & (vq->size -1 ); - -if (to + nr_copy <= vq->size) { -rte_memcpy (&vq->used->ring[to], +if (vq_is_packed (dev)) { +uint16_t nr_left = n_buffers; +uint16_t to; +do { + from = vq->last_async_buffer_idx & + (vq->size -1 ); + to = (from + nr_left) & (vq->size -1 ); + +if (to > from) { +vhost_update_used_packed (dev, vq, + vq->async_buffers_packed + from, + to - from); + vq->last_async_buffer_idx += nr_left; + nr_left =0 ; + }else { +vhost_update_used_packed (dev, vq, + vq->async_buffers_packed + from, + vq->size - from); + vq->last_async_buffer_idx += + vq->size - from; + nr_left -= vq->size - from; + } + }while (nr_left >0 ); +vhost_vring_call_packed (dev, vq); + }else { +uint16_t nr_left = n_descs; +do { + from = vq->last_async_desc_idx & (vq->size -1 ); + nr_copy = nr_left + from <= vq->size ? nr_left : + vq->size - from; + to = vq->last_used_idx & (vq->size -1 ); + +if (to + nr_copy <= vq->size) { +rte_memcpy (&vq->used->ring[to], &vq- >async_descs_split[from], nr_copy *sizeof (struct vring_used_elem )); - }else { -uint16_t size = vq->size - to; + }else { +uint16_t size = vq->size - to; -rte_memcpy (&vq->used->ring[to], +rte_memcpy (&vq->used->ring[to], &vq- >async_descs_split[from], size *sizeof (struct vring_used_elem )); -rte_memcpy (vq->used->ring, +rte_memcpy (vq->used->ring, &vq->async_descs_split[from + size], (nr_copy - size) *sizeof (struct vring_used_elem )); - } + } + + vq->last_async_desc_idx += nr_copy; + vq->last_used_idx += nr_copy; + nr_left -= nr_copy; + }while (nr_left >0 ); + +__atomic_add_fetch (&vq->used->idx, n_descs, + __ATOMIC_RELEASE); +vhost_vring_call_split (dev, vq); + } - vq->last_async_desc_idx += nr_copy; - vq->last_used_idx += nr_copy; - nr_left -= nr_copy; - }while (nr_left >0 ); - __atomic_add_fetch(&vq->used->idx, n_descs,
__ATOMIC_RELEASE);lib/librte_vhost/virtio_net.c +10
-5-vhost_vring_call_split (dev, vq); - }else - vq->last_async_desc_idx += n_descs; + + }else { +if (vq_is_packed (dev)) + vq->last_async_buffer_idx += n_buffers; +else + vq->last_async_desc_idx += n_descs; + } done:rte_spinlock_unlock (&vq->access_lock);@@ -1767,9 +2151,10 @@ virtio_dev_rx_async_submit(struct virtio_net *dev, uint16_t queue_id, if (count == 0) goto out; -/* TODO: packed queue not implemented */ if (vq_is_packed (dev)) - nb_tx =0 ; + nb_tx =virtio_dev_rx_async_submit_packed (dev, + vq, queue_id, pkts, count, comp_pkts, + comp_count);else nb_tx = virtio_dev_rx_async_submit_split(dev,vq,
queue_id, pkts, count,comp_pkts,
--
2.29.2
Hi,
Quoted 256 lines
-----Original Message-----
From: Liu, Yong <[email protected]>
Sent: Wednesday, March 24, 2021 5:19 PM
To: Jiang, Cheng1 <[email protected]>; [email protected]; Xia, Chenbo <[email protected]>
Cc: [email protected]; Hu, Jiayu <[email protected]>; Yang, YvonneX <[email protected]>; Wang, Yinan <[email protected]>; Jiang, Cheng1 <[email protected]>
Subject: RE: [dpdk-dev] [PATCH v2] vhost: add support for packed ring in async vhostQuoted 68 lines
-----Original Message-----
From: dev <[email protected]> On Behalf Of Cheng Jiang
Sent: Monday, March 22, 2021 2:15 PM
To: [email protected]; Xia, Chenbo <[email protected]>
Cc: [email protected]; Hu, Jiayu <[email protected]>; Yang, YvonneX <[email protected]>; Wang, Yinan <[email protected]>; Jiang, Cheng1 <[email protected]>
Subject: [dpdk-dev] [PATCH v2] vhost: add support for packed ring in async vhostFor now async vhost data path only supports split ring structure. In order to make async vhost compatible with virtio 1.1 spec this patch enables packed ring in async vhost data path.
Signed-off-by Cheng Jiang <[email protected]>---
v2:
* fix wrong buffer index inrte_vhost_poll_enqueue_completed()
* addasync_buffers_packedmemory free invhost_free_async_mem()lib/librte_vhost/rte_vhost_async.h | 1 + lib/librte_vhost/vhost.c | 24 +- lib/librte_vhost/vhost.h | 7 +- lib/librte_vhost/virtio_net.c | 447 +++++++++++++++++++++++++++-- 4 files changed, 441 insertions(+), 38 deletions(-)lib/librte_vhost/rte_vhost_async.h +0
-0@@ -89,6 +89,7 @@ struct rte_vhost_async_channel_ops { struct
async_inflight_info{ structrte_mbuf*mbuf;uint16_tdescs; /* num of descs inflight */lib/librte_vhost/rte_vhost_async.h +1
-0+uint16_t nr_buffers;/* num of buffers inflight for packed ring */ };/** lib/librte_vhost/vhost.c index renamed from lib/librte_vhost/vhost.c +0
-0
52ab93d1e..51b44d6f2100644lib/librte_vhost/vhost.c +7
-2@@ -330,15 +330,20 @@ vhost_free_async_mem(struct vhost_virtqueue *vq) {if (vq->async_pkts_info)rte_free (vq->async_pkts_info); -if (vq->async_descs_split) +if (vq->async_buffers_packed) { +rte_free (vq->async_buffers_packed); +vq->async_buffers_packed =NULL ; +}else {rte_free (vq->async_descs_split); +vq->async_descs_split =NULL ; +} +if (vq->it_pool)rte_free (vq->it_pool);if (vq->vec_pool)rte_free (vq->vec_pool); vq->async_pkts_info =NULL ; -vq->async_descs_split =NULL ; vq->it_pool =NULL ; vq->vec_pool =NULL ;}
lib/librte_vhost/vhost.c +0
-0@@ -1603,9 +1608,9 @@ int rte_vhost_async_channel_register(int vid, uint16_t queue_id, return -1;lib/librte_vhost/vhost.c int rte_vhost_async_channel_register(int vid, · line 1616
Quoted 10 lines
lib/librte_vhost/vhost.c +3
-2/* packed queue is not supported */ -if (unlikely (vq_is_packed (dev) || !f.async_inorder)) { +if (unlikely (!f.async_inorder)) {VHOST_LOG_CONFIG (ERR , -"async copy is not supported on packed queue or non-inorder mode " +"async copy is not supported on non-inorder mode " "(vid %d, qid: %d)\n", vid, queue_id); return -1; } @@ -1643,10 +1648,17 @@ int rte_vhost_async_channel_register(int vid, uint16_t queue_id, vq->vec_pool = rte_malloc_socket(NULL,
VHOST_MAX_ASYNC_VECQuoted 38 lines
* sizeof(struct iovec),
RTE_CACHE_LINE_SIZE, node);lib/librte_vhost/vhost.c +6
-1-vq->async_descs_split = rte_malloc_socket(NULL, +if (vq_is_packed (dev)) { +vq->async_buffers_packed =rte_malloc_socket (NULL , size * +vq->sizeof(struct vring_used_elem_packed), +RTE_CACHE_LINE_SIZE , node); +}else { +vq->async_descs_split = rte_malloc_socket(NULL, vq->size * sizeof(struct vring_used_elem), RTE_CACHE_LINE_SIZE,node); -if (!vq->async_descs_split || !vq->async_pkts_info ||
lib/librte_vhost/vhost.c +3
-0+} + +if (!vq->async_pkts_info || !vq->it_pool || !vq->vec_pool) {vhost_free_async_mem (vq); VHOST_LOG_CONFIG(ERR,lib/librte_vhost/vhost.h index renamed from lib/librte_vhost/vhost.h +0
-0
658f6fc28..d6324fbf8100644lib/librte_vhost/vhost.h +0
-0@@ -206,9 +206,14 @@ struct vhost_virtqueue { uint16_tasync_pkts_idx;
uint16_tasync_pkts_inflight_n;uint16_tasync_last_pkts_n; -structvring_used_elem*async_descs_split;lib/librte_vhost/vhost.h +5
-0+union { +struct vring_used_elem *async_descs_split;struct +vring_used_elem_packed *async_buffers_packed; };uint16_t async_desc_idx; +uint16_t async_packed_buffer_idx;uint16_t last_async_desc_idx; +uint16_t last_async_buffer_idx;/* vq async features */ boolasync_inorder;(quoted diff) +0
-0
b/lib/librte_vhost/virtio_net.cindex583bf379c..fa8c4f4fe100644lib/librte_vhost/virtio_net.c +0
-0@@ -363,8 +363,7 @@Quoted 1 line
vhost_shadow_dequeue_single_packed_inorder(struct
vhost_virtqueue*vq,
Quoted 124 lines
}
static
__rte_always_inlinevoidlib/librte_vhost/virtio_net.c +12
-2-vhost_shadow_enqueue_single_packed(struct virtio_net *dev, - struct vhost_virtqueue *vq, +vhost_shadow_enqueue_packed(struct vhost_virtqueue *vq, uint32_t len[], uint16_t id[], uint16_t count[],@@ -382,6 +381,17 @@ vhost_shadow_enqueue_single_packed(struct virtio_net *dev, vq->shadow_aligned_idx += count[i]; vq->shadow_used_idx++; } +} + +static __rte_always_inline void +vhost_shadow_enqueue_single_packed (struct virtio_net *dev, +struct vhost_virtqueue *vq, +uint32_t len[], +uint16_t id[], +uint16_t count[], +uint16_t num_buffers) +{ +vhost_shadow_enqueue_packed (vq, len, id, count, num_buffers);if (vq->shadow_aligned_idx >=PACKED_BATCH_SIZE ) {
do_data_copy_enqueue(dev, vq); @@ -1633,12 +1643,343 @@ virtio_dev_rx_async_submit_split(structvirtio_net*dev,
returnpkt_idx;
}lib/librte_vhost/virtio_net.c +13
-0+static __rte_always_inline int +vhost_enqueue_async_single_packed (struct virtio_net *dev, +struct vhost_virtqueue *vq, +struct rte_mbuf *pkt, +struct buf_vector *buf_vec, +uint16_t *nr_descs, +uint16_t *nr_buffers, +struct iovec *src_iovec,struct iovec *dst_iovec, +struct rte_vhost_iov_iter *src_it, +struct rte_vhost_iov_iter *dst_it) {uint16_t nr_vec =0 ; +uint16_t avail_idx = vq->last_avail_idx;uint16_t max_tries, tries = +0 ;uint16_t buf_id =0 ;uint32_t len =0 ;uint16_t desc_count; +uint32_t size = pkt->pkt_len + sizeof(struct
virtio_net_hdr_mrg_rxbuf);lib/librte_vhost/virtio_net.c +56
-0+uint32_t buffer_len[vq->size]; +uint16_t buffer_buf_id[vq->size]; +uint16_t buffer_desc_count[vq->size]; *nr_buffers =0 ; + +if (rxvq_is_mergeable (dev)) +max_tries = vq->size -1 ; +else +max_tries =1 ; + +while (size >0 ) { +/* +* if we tried all available ring items, and still +* can't get enough buf, it means something abnormal +* happened. +*/ +if (unlikely (++tries > max_tries)) +return -1 ; + +if (unlikely (fill_vec_buf_packed (dev, vq, avail_idx, &desc_count, +buf_vec, &nr_vec, &buf_id, &len, +VHOST_ACCESS_RW ) <0 )) +return -1 ; + +len =RTE_MIN (len, size); +size -= len; + +buffer_len[*nr_buffers] = len; +buffer_buf_id[*nr_buffers] = buf_id; +buffer_desc_count[*nr_buffers] = desc_count; *nr_buffers +=1 ; + +*nr_descs += desc_count; +avail_idx += desc_count; +if (avail_idx >= vq->size) +avail_idx -= vq->size; +} + +if (async_mbuf_to_desc (dev, vq, pkt, buf_vec, nr_vec, *nr_buffers, +src_iovec, dst_iovec, src_it, dst_it) <0 )return -1 ; + +vhost_shadow_enqueue_packed (vq, buffer_len, buffer_buf_id, + buffer_desc_count, *nr_buffers); + +return 0 ; +} + +static __rte_always_inline int16_t +virtio_dev_rx_async_single_packed (struct virtio_net *dev, +struct vhost_virtqueue *vq, +struct rte_mbuf *pkt, +uint16_t *nr_descs,uint16_t *nr_buffers, +struct iovec *src_iovec,struct iovec *dst_iovec, +struct rte_vhost_iov_iter *src_it, +struct rte_vhost_iov_iter *dst_it) {struct buf_vector +buf_vec[BUF_VECTOR_MAX ]; *nr_descs =0 ; *nr_buffers =0 ; + +if (unlikely(vhost_enqueue_async_single_packed(dev, vq, pkt,
buf_vec,
+nr_descs,
+nr_buffers,
+src_iovec,dst_iovec,
+src_it,dst_it) < 0)) {lib/librte_vhost/virtio_net.c +7
-0+VHOST_LOG_DATA (DEBUG , +"(%d) failed to get enough desc from vring\n" , +dev->vid); +return -1 ; +} + +VHOST_LOG_DATA(DEBUG, "(%d) current index %d | endindex %d\n",
lib/librte_vhost/virtio_net.c +8
-0+dev->vid, vq->last_avail_idx, +vq->last_avail_idx + *nr_descs); + +return 0 ; +} + +static __rte_noinline uint32_t +virtio_dev_rx_async_submit_packed(struct virtio_net *dev, struct
Quoted 8 lines
lib/librte_vhost/virtio_net.c
Quoted 2 lines
lib/librte_vhost/virtio_net.c +2
-0+vhost_virtqueue *vq, uint16_t queue_id, struct rte_mbuf **pkts, +uint32_t count, struct rte_mbuf **comp_pkts, uint32_t *comp_count) {Hi Cheng,
There're some common parts invirtio_dev_rx_async_submit_packedandvirtio_dev_rx_async_submit_split.
We can abstract some functions for those common parts which can bring more clarity.
Sure, but the structure or variable used by packed ring and split ring are different, it may not be very suitable for abstraction, I will consider it again, thank you.
Quoted 3 lines
Also this patch may be too huge for reviewing, please separate it into few parts for better understanding.
I'll make it better in the next version.
Quoted 130 lines
Thanks,
MarvinQuoted 126 lines
lib/librte_vhost/virtio_net.c +22
-0+uint32_t pkt_idx =0 , pkt_burst_idx =0 ;uint16_t num_buffers; +uint16_t num_desc; + +struct rte_vhost_iov_iter *it_pool = vq->it_pool;struct iovec +*vec_pool = vq->vec_pool;struct rte_vhost_async_desc +tdes[MAX_PKT_BURST ];struct iovec *src_iovec = vec_pool;struct iovec +*dst_iovec = vec_pool + (VHOST_MAX_ASYNC_VEC >>1 );struct +rte_vhost_iov_iter *src_it = it_pool;struct rte_vhost_iov_iter +*dst_it = it_pool +1 ;uint16_t slot_idx =0 ;uint16_t segs_await = +0 ;struct async_inflight_info *pkts_info = vq->async_pkts_info; +uint32_t n_pkts =0 , pkt_err =0 ;uint32_t num_async_pkts =0 , +num_done_pkts =0 ;struct {uint16_t pkt_idx;uint16_t +last_avail_idx; } async_pkts_log[MAX_PKT_BURST ]; + +rte_prefetch0 (&vq->desc[vq->last_avail_idx & (vq->size -1 )]); + +for (pkt_idx =0 ; pkt_idx < count; pkt_idx++) {if +(unlikely (virtio_dev_rx_async_single_packed (dev, vq, pkts[pkt_idx], +&num_desc, &num_buffers, src_iovec, dst_iovec, src_it, dst_it) <0 )) +{break ; } + +VHOST_LOG_DATA(DEBUG, "(%d) current index %d | endindex %d\n",
lib/librte_vhost/virtio_net.c +28
-0+dev->vid, vq->last_avail_idx, +vq->last_avail_idx + num_desc); + +slot_idx = (vq->async_pkts_idx + num_async_pkts) & (vq->size -1 );if +(src_it->count) {uint16_t from, to; + +async_fill_desc (&tdes[pkt_burst_idx++], src_it, dst_it); +pkts_info[slot_idx].descs = num_desc; pkts_info[slot_idx].nr_buffers += num_buffers; pkts_info[slot_idx].mbuf = pkts[pkt_idx]; +async_pkts_log[num_async_pkts].pkt_idx = pkt_idx; +async_pkts_log[num_async_pkts++].last_avail_idx = +vq->last_avail_idx; +src_iovec += src_it->nr_segs; +dst_iovec += dst_it->nr_segs; +src_it +=2 ; +dst_it +=2 ; +segs_await += src_it->nr_segs; + +/** +* recover shadow used ring and keep DMA-occupied +* descriptors. +*/ +from = vq->shadow_used_idx - num_buffers; to = +vq->async_packed_buffer_idx & (vq->size -1 );if (num_buffers + to <= +vq->size) { rte_memcpy(&vq->async_buffers_packed[to], +&vq->shadow_used_packed[from], +num_buffers * +sizeof(struct
vring_used_elem_packed));lib/librte_vhost/virtio_net.c +7
-0+}else { +int size = vq->size - to; + +rte_memcpy(&vq->async_buffers_packed[to], +&vq->shadow_used_packed[from], +size * +sizeof(struct
vring_used_elem_packed));lib/librte_vhost/virtio_net.c +4
-0+rte_memcpy(vq->async_buffers_packed, +&vq->shadow_used_packed[from + +size], (num_buffers - size) * +sizeof(struct
vring_used_elem_packed));lib/librte_vhost/virtio_net.c +13
-0+} +vq->async_packed_buffer_idx += num_buffers; shadow_used_idx -= +vq->num_buffers; +}else +comp_pkts[num_done_pkts++] = pkts[pkt_idx]; + +vq_inc_last_avail_packed (vq, num_desc); + +/* +* conditions to trigger async device transfer: +* - buffered packet number reaches transfer threshold + * - unused async iov number is less than max vhost vector */ if +(unlikely(pkt_burst_idx >=
VHOST_ASYNC_BATCH_THRESHOLD||lib/librte_vhost/virtio_net.c +6
-0+((VHOST_MAX_ASYNC_VEC >> 1) - segs_await < +BUF_VECTOR_MAX))) { +n_pkts = vq->async_ops.transfer_data (dev->vid, +queue_id, tdes,0 , pkt_burst_idx); +src_iovec = vec_pool; +dst_iovec = vec_pool + (VHOST_MAX_ASYNC_VEC >>1);
lib/librte_vhost/virtio_net.c +8
-0+src_it = it_pool; +dst_it = it_pool +1 ; +segs_await =0 ; +vq->async_pkts_inflight_n += n_pkts; + +if (unlikely (n_pkts < pkt_burst_idx)) { +/* +* log error packets number here and do actual
+ * error processing when applications poll
+ * completion
+ */lib/librte_vhost/virtio_net.c +28
-0+pkt_err = pkt_burst_idx - n_pkts; +pkt_burst_idx =0 ; +break ; +} + +pkt_burst_idx =0 ; +} +} + +if (pkt_burst_idx) { +n_pkts = vq->async_ops.transfer_data (dev->vid, +queue_id, tdes,0 , pkt_burst_idx); +vq->async_pkts_inflight_n += n_pkts; + +if (unlikely (n_pkts < pkt_burst_idx)) pkt_err = pkt_burst_idx - +n_pkts; } + +do_data_copy_enqueue (dev, vq); + +if (unlikely (pkt_err)) { +uint16_t num_buffers =0 ; + +num_async_pkts -= pkt_err; +/* calculate the sum of descriptors of DMA-error packets. */ while +(pkt_err-- >0 ) { num_buffers += pkts_info[slot_idx & (vq->size - +1 )].nr_buffers; slot_idx--; } +vq->async_packed_buffer_idx -= num_buffers; +/* recover shadow used ring and available ring */
Quoted 8 lines
Quoted 4 lines
lib/librte_vhost/virtio_net.c +2
-0+vq->shadow_used_idx -= (vq->last_avail_idx - +async_pkts_log[num_async_pkts].last_avail_idx -
+num_buffers);Could it possible that
vq->last_avail_idxsmaller than async_pkts_log[num_async_pkts].last_avail_idx when operations near the ring's boundary?
Yes, you are right. Will be fixed, thanks.
Cheng
Quoted 222 lines
Quoted 221 lines
lib/librte_vhost/virtio_net.c +19
-0+vq->last_avail_idx = +async_pkts_log[num_async_pkts].last_avail_idx; +pkt_idx = async_pkts_log[num_async_pkts].pkt_idx; +num_done_pkts = pkt_idx - num_async_pkts; } + +vq->async_pkts_idx += num_async_pkts; +*comp_count = num_done_pkts; + +if (likely (vq->shadow_used_idx)) { +vhost_flush_enqueue_shadow_packed (dev, vq); +vhost_vring_call_packed (dev, vq); } + +return pkt_idx; +} + +static __rte_always_inline void +vhost_update_used_packed (struct virtio_net *dev, +struct vhost_virtqueue *vq, + struct vring_used_elem_packed
*shadow_ring,lib/librte_vhost/virtio_net.c +61
-0+ uint16_t count) +{ +if (count ==0 ) +return ; +int i; +uint16_t used_idx = vq->last_used_idx;uint16_t head_idx = +vq->last_used_idx;uint16_t head_flags =0 ; + +/* Split loop in two to save memory barriers */ for (i =0 ; i < +count; i++) { +vq->desc_packed[used_idx].id = shadow_ring[i].id; +vq->desc_packed[used_idx].len = shadow_ring[i].len; + +used_idx += shadow_ring[i].count; +if (used_idx >= vq->size) +used_idx -= vq->size; +} + +/* The ordering for storing desc flags needs to be enforced. */ +rte_atomic_thread_fence (__ATOMIC_RELEASE); + +for (i =0 ; i < count; i++) { +uint16_t flags; + +if (vq->shadow_used_packed[i].len) +flags =VRING_DESC_F_WRITE ; +else +flags =0 ; + +if (vq->used_wrap_counter) { +flags |=VRING_DESC_F_USED ; +flags |=VRING_DESC_F_AVAIL ; +}else { +flags &= ~VRING_DESC_F_USED ; +flags &= ~VRING_DESC_F_AVAIL ; +} + +if (i >0 ) { +vq->desc_packed[vq->last_used_idx].flags = flags; + +vhost_log_cache_used_vring (dev, vq, +vq->last_used_idx * +sizeof (struct vring_packed_desc ), +sizeof (struct vring_packed_desc )); +}else { +head_idx = vq->last_used_idx; +head_flags = flags; +} + +vq_inc_last_used_packed (vq, shadow_ring[i].count); } + +vq->desc_packed[head_idx].flags = head_flags; + +vhost_log_cache_used_vring (dev, vq, +head_idx * +sizeof (struct vring_packed_desc ), +sizeof (struct vring_packed_desc )); + +vhost_log_cache_sync (dev, vq); +} + uint16_t rte_vhost_poll_enqueue_completed(int vid, uint16_t queue_id,struct
rte_mbuf**pkts,uint16_tcount) { structvirtio_net*dev =get_device(vid); structvhost_virtqueue*vq; -uint16_tn_pkts_cpl= 0,n_pkts_put= 0,n_descs= 0;
+uint16_tn_pkts_cpl= 0,n_pkts_put= 0,n_descs= 0,n_buffers= 0;
uint16_tstart_idx,pkts_idx,vq_size; structasync_inflight_info*pkts_info;uint16_tfrom, i; @@ -1680,53 +2021,96 @@uint16_trte_vhost_poll_enqueue_completed(int vid,uint16_tqueue_id, goto done; }lib/librte_vhost/virtio_net.c +0
-2-for (i =0 ; i < n_pkts_put; i++) { -from = (start_idx + i) & (vq_size - 1); -n_descs +=pkts_info[from].descs; -pkts[i] = pkts_info[from].mbuf;
lib/librte_vhost/virtio_net.c +8
-0+if (vq_is_packed (dev)) { +for (i =0 ; i < n_pkts_put; i++) { +from = (start_idx + i) & (vq_size -1 ); n_buffers += +pkts_info[from].nr_buffers; pkts[i] = pkts_info[from].mbuf; } }else +{for (i =0 ; i < n_pkts_put; i++) { from = (start_idx + i) & +(vq_size -1 ); n_descs += pkts_info[from].descs; pkts[i] = +pkts_info[from].mbuf; } } + vq->async_last_pkts_n = n_pkts_cpl - n_pkts_put;
vq->async_pkts_inflight_n-=n_pkts_put;if (
likely(vq->enabled && vq->access_ok)) { -uint16_tnr_left=n_descs;uint16_tnr_copy;uint16_tto;/* write back completed descriptors to used ring */ -do { -from =
vq->last_async_desc_idx& (vq->size- 1); -nr_copy =nr_left+ from <=vq->size?nr_left:lib/librte_vhost/virtio_net.c +11
-5-vq->size - from; -to = vq->last_used_idx & (vq->size -1 ); - -if (to + nr_copy <= vq->size) { -rte_memcpy(&vq->used->ring[to], +if (vq_is_packed(dev)) { +uint16_t nr_left = n_buffers; +uint16_t to; +do { +from = vq->last_async_buffer_idx & +(vq->size - 1); +to = (from + nr_left) & (vq->size - 1); + +if (to > from) { +vhost_update_used_packed(dev, vq, +vq->async_buffers_packed +from,
lib/librte_vhost/virtio_net.c +6
-0+to - from); +vq->last_async_buffer_idx += nr_left; +nr_left =0 ; +}else { +vhost_update_used_packed(dev, vq, +vq->async_buffers_packed +from,
lib/librte_vhost/virtio_net.c +3
-0+vq->size - from); +vq->last_async_buffer_idx += +vq->size -from;
lib/librte_vhost/virtio_net.c +8
-0+nr_left -= vq->size - from; +} +}while (nr_left >0 ); +vhost_vring_call_packed (dev, vq); +} else { +uint16_t nr_left = n_descs; +do { +from = vq->last_async_desc_idx & (vq->size -1);
lib/librte_vhost/virtio_net.c +6
-0+nr_copy = nr_left + from <= vq->size ? nr_left : +vq->size - from; +to = vq->last_used_idx & (vq->size -1 ); + +if (to + nr_copy <= vq->size) { +rte_memcpy(&vq->used->ring[to], &vq-Quoted 1 line
async_descs_split[from],
nr_copy*
sizeof(structvring_used_elem));lib/librte_vhost/virtio_net.c +3
-3-}else { -uint16_t size = vq->size - to; +}else { +uint16_t size = vq->size - to; -rte_memcpy(&vq->used->ring[to], +rte_memcpy(&vq->used->ring[to], &vq-Quoted 1 line
async_descs_split[from],
size *
sizeof(structvring_used_elem));lib/librte_vhost/virtio_net.c +2
-1-rte_memcpy(vq->used->ring, +rte_memcpy(vq->used->ring, &vq->async_descs_split[from + size], (nr_copy - size) * sizeof(struct
vring_used_elem));lib/librte_vhost/virtio_net.c +18
-11-} +} + +vq->last_async_desc_idx += nr_copy; +vq->last_used_idx += nr_copy; +nr_left -= nr_copy; +}while (nr_left >0 ); + +__atomic_add_fetch (&vq->used->idx, n_descs, __ATOMIC_RELEASE); +vhost_vring_call_split (dev, vq); } -vq->last_async_desc_idx += nr_copy; -vq->last_used_idx += nr_copy; -nr_left -= nr_copy; -}while (nr_left >0 ); -__atomic_add_fetch (&vq->used->idx, n_descs, __ATOMIC_RELEASE); -vhost_vring_call_split(dev, vq); -} else -vq->last_async_desc_idx += n_descs; + +}else { +if (vq_is_packed (dev)) +vq->last_async_buffer_idx += n_buffers; +else +vq->last_async_desc_idx += n_descs; +} done:rte_spinlock_unlock (&vq->access_lock);@@ -1767,9 +2151,10 @@ virtio_dev_rx_async_submit(struct virtio_net *dev, uint16_t queue_id, if (count == 0) goto out; -/* TODO: packed queue not implemented */ if (vq_is_packed (dev)) -nb_tx =0 ; +nb_tx =virtio_dev_rx_async_submit_packed (dev, +vq, queue_id, pkts, count, comp_pkts, comp_count); else nb_tx = virtio_dev_rx_async_submit_split(dev, vq, queue_id, pkts, count, comp_pkts, --2.29.2
PATCH v3 1/1 vhost: add support for packed ring in async vhost
In reply to Cheng JiangFor now async vhost data path only supports split ring structure. In order to make async vhost compatible with virtio 1.1 spec this patch enables packed ring in async vhost data path.
---
v3:
* fix error handler for DMA-copy packet
* remove variables that are no longer needed
v2:
* fix wrong buffer index in rte_vhost_poll_enqueue_completed()
* add async_buffers_packed memory free in vhost_free_async_mem()
lib/librte_vhost/rte_vhost_async.h | 1 + lib/librte_vhost/vhost.c | 24 +- lib/librte_vhost/vhost.h | 7 +- lib/librte_vhost/virtio_net.c | 463 +++++++++++++++++++++++++++-- 4 files changed, 457 insertions(+), 38 deletions(-)
lib/librte_vhost/rte_vhost_async.h +1 -0
@@ -89,6 +89,7 @@ struct rte_vhost_async_channel_ops {struct async_inflight_info {struct rte_mbuf *mbuf;uint16_t descs;/* num of descs inflight */ +uint16_t nr_buffers;/* num of buffers inflight for packed ring */ };/**
lib/librte_vhost/vhost.c +18 -6
@@ -330,15 +330,20 @@ vhost_free_async_mem(struct vhost_virtqueue *vq) {if (vq->async_pkts_info)rte_free (vq->async_pkts_info); -if (vq->async_descs_split) +if (vq->async_buffers_packed) { +rte_free (vq->async_buffers_packed); + vq->async_buffers_packed =NULL ; + }else {rte_free (vq->async_descs_split); + vq->async_descs_split =NULL ; + } +if (vq->it_pool)rte_free (vq->it_pool);if (vq->vec_pool)rte_free (vq->vec_pool); vq->async_pkts_info =NULL ; - vq->async_descs_split =NULL ; vq->it_pool =NULL ; vq->vec_pool =NULL ; }
@@ -1603,9 +1608,9 @@ int rte_vhost_async_channel_register(int vid, uint16_t queue_id,return -1 ;/* packed queue is not supported */ -if (unlikely (vq_is_packed (dev) || !f.async_inorder)) { +if (unlikely (!f.async_inorder)) {VHOST_LOG_CONFIG (ERR , -"async copy is not supported on packed queue or non-inorder mode " +"async copy is not supported on non-inorder mode " "(vid %d, qid: %d)\n" , vid, queue_id);return -1 ; }
@@ -1643,10 +1648,17 @@ int rte_vhost_async_channel_register(int vid, uint16_t queue_id, vq->vec_pool =rte_malloc_socket (NULL ,VHOST_MAX_ASYNC_VEC *sizeof (struct iovec ),RTE_CACHE_LINE_SIZE , node); - vq->async_descs_split =rte_malloc_socket (NULL , +if (vq_is_packed (dev)) { + vq->async_buffers_packed =rte_malloc_socket (NULL , + vq->size *sizeof (struct vring_used_elem_packed ), +RTE_CACHE_LINE_SIZE , node); + }else { + vq->async_descs_split =rte_malloc_socket (NULL , vq->size *sizeof (struct vring_used_elem ),RTE_CACHE_LINE_SIZE , node); -if (!vq->async_descs_split || !vq->async_pkts_info || + } + +if (!vq->async_pkts_info || !vq->it_pool || !vq->vec_pool) {vhost_free_async_mem (vq); VHOST_LOG_CONFIG(ERR,
lib/librte_vhost/vhost.h +6 -1
@@ -206,9 +206,14 @@ struct vhost_virtqueue {uint16_t async_pkts_idx;uint16_t async_pkts_inflight_n;uint16_t async_last_pkts_n; -struct vring_used_elem *async_descs_split; +union { +struct vring_used_elem *async_descs_split; +struct vring_used_elem_packed *async_buffers_packed; + };uint16_t async_desc_idx; +uint16_t async_packed_buffer_idx;uint16_t last_async_desc_idx; +uint16_t last_async_buffer_idx;/* vq async features */ bool async_inorder;
lib/librte_vhost/virtio_net.c +432 -31
526 lines not on this page · raw message
--
2.29.2
Hi Cheng,
Some comments are inline.
Quoted 91 lines
-----Original Message-----
From: Jiang, Cheng1 <[email protected]>
Sent: Wednesday, March 31, 2021 10:06 PM
To: [email protected]; Xia, Chenbo <[email protected]>
Cc: [email protected]; Hu, Jiayu <[email protected]>; Yang, YvonneX <[email protected]>; Wang, Yinan <[email protected]>; Jiang, Cheng1 <[email protected]>
Subject: [PATCH v3] vhost: add support for packed ring in async vhostFor now async vhost data path only supports split ring structure. In order to make async vhost compatible with virtio 1.1 spec this patch enables packed ring in async vhost data path.
Signed-off-by Cheng Jiang <[email protected]>---
v3:
* fix error handler for DMA-copy packet
* remove variables that are no longer needed
v2:
* fix wrong buffer index inrte_vhost_poll_enqueue_completed()
* addasync_buffers_packedmemory free invhost_free_async_mem()lib/librte_vhost/rte_vhost_async.h | 1 + lib/librte_vhost/vhost.c | 24 +- lib/librte_vhost/vhost.h | 7 +- lib/librte_vhost/virtio_net.c | 463 +++++++++++++++++++++++++++-- 4 files changed, 457 insertions(+), 38 deletions(-)lib/librte_vhost/rte_vhost_async.h +1
-0@@ -89,6 +89,7 @@ struct rte_vhost_async_channel_ops {struct async_inflight_info {struct rte_mbuf *mbuf;uint16_t descs;/* num of descs inflight */ +uint16_t nr_buffers;/* num of buffers inflight for packed ring */ };/** lib/librte_vhost/vhost.c +7
-2@@ -330,15 +330,20 @@ vhost_free_async_mem(struct vhost_virtqueue *vq) {if (vq->async_pkts_info)rte_free (vq->async_pkts_info); -if (vq->async_descs_split) +if (vq->async_buffers_packed) { +rte_free (vq->async_buffers_packed); + vq->async_buffers_packed =NULL ; + }else {rte_free (vq->async_descs_split); + vq->async_descs_split =NULL ; + } +if (vq->it_pool)rte_free (vq->it_pool);if (vq->vec_pool)rte_free (vq->vec_pool); vq->async_pkts_info =NULL ; - vq->async_descs_split =NULL ; vq->it_pool =NULL ; vq->vec_pool =NULL ;}
lib/librte_vhost/vhost.c +1
-2@@ -1603,9 +1608,9 @@ int rte_vhost_async_channel_register(int vid,uint16_t queue_id, return -1;/* packed queue is not supported */ -if (unlikely (vq_is_packed (dev) || !f.async_inorder)) { +if (unlikely (!f.async_inorder)) { VHOST_LOG_CONFIG(ERR, - "async copy is not supported on packed queue ornon-inorder mode "
lib/librte_vhost/vhost.c +3
-1+"async copy is not supported on non-inorder mode " "(vid %d, qid: %d)\n", vid, queue_id);return -1 ; }@@ -1643,10 +1648,17 @@ int rte_vhost_async_channel_register(int vid,uint16_t queue_id, vq->vec_pool = rte_malloc_socket(NULL,VHOST_MAX_ASYNC_VEC *sizeof (struct iovec ),RTE_CACHE_LINE_SIZE , node); - vq->async_descs_split = rte_malloc_socket(NULL, +if (vq_is_packed (dev)) { + vq->async_buffers_packed = rte_malloc_socket(NULL,
lib/librte_vhost/vhost.c int rte_vhost_async_channel_register(int vid, · line 1662
Quoted 10 lines
lib/librte_vhost/vhost.c +7
-1+ vq->size *sizeof (struct vring_used_elem_packed ), + RTE_CACHE_LINE_SIZE, node); + }else { + vq->async_descs_split =rte_malloc_socket (NULL , vq->size *sizeof (struct vring_used_elem ),RTE_CACHE_LINE_SIZE , node); - if (!vq->async_descs_split || !vq->async_pkts_info || + } + + if (!vq->async_pkts_info ||
Need to check if malloc fails for async_buffers_packed.
Quoted 118 lines
lib/librte_vhost/vhost.c +0
-0!vq->it_pool || !vq->vec_pool) {vhost_free_async_mem (vq);lib/librte_vhost/vhost.c +0
-0VHOST_LOG_CONFIG(ERR,lib/librte_vhost/vhost.h +6
-1@@ -206,9 +206,14 @@ struct vhost_virtqueue {uint16_t async_pkts_idx;uint16_t async_pkts_inflight_n;uint16_t async_last_pkts_n; -struct vring_used_elem *async_descs_split; +union { +struct vring_used_elem *async_descs_split; +struct vring_used_elem_packed *async_buffers_packed; + };uint16_t async_desc_idx; +uint16_t async_packed_buffer_idx;uint16_t last_async_desc_idx; +uint16_t last_async_buffer_idx;/* vq async features */ bool async_inorder;lib/librte_vhost/virtio_net.c +1
-2@@ -363,8 +363,7 @@ vhost_shadow_dequeue_single_packed_inorder(struct vhost_virtqueue *vq, } static __rte_always_inline void -vhost_shadow_enqueue_single_packed(struct virtio_net *dev, - struct vhost_virtqueue *vq, +vhost_shadow_enqueue_packed(struct vhost_virtqueue *vq, uint32_t len[], uint16_t id[],lib/librte_vhost/virtio_net.c +11
-0uint16_t count[],@@ -382,6 +381,17 @@ vhost_shadow_enqueue_single_packed(struct virtio_net *dev, vq->shadow_aligned_idx += count[i]; vq->shadow_used_idx++; } +} + +static __rte_always_inline void +vhost_shadow_enqueue_single_packed (struct virtio_net *dev, +struct vhost_virtqueue *vq, +uint32_t len[], +uint16_t id[], +uint16_t count[], +uint16_t num_buffers) +{ +vhost_shadow_enqueue_packed (vq, len, id, count, num_buffers);if (vq->shadow_aligned_idx >=PACKED_BATCH_SIZE ) {lib/librte_vhost/virtio_net.c +55
-0do_data_copy_enqueue (dev, vq);@@ -1452,6 +1462,73 @@ virtio_dev_rx_async_get_info_idx(uint16_t pkts_idx, (vq_size - n_inflight + pkts_idx) & (vq_size -1 ); } +static __rte_always_inline void +vhost_update_used_packed (struct virtio_net *dev, +struct vhost_virtqueue *vq, +struct vring_used_elem_packed *shadow_ring, +uint16_t count) +{ +if (count ==0 ) +return ; +int i; +uint16_t used_idx = vq->last_used_idx; +uint16_t head_idx = vq->last_used_idx; +uint16_t head_flags =0 ; + +/* Split loop in two to save memory barriers */ +for (i =0 ; i < count; i++) { + vq->desc_packed[used_idx].id = shadow_ring[i].id; + vq->desc_packed[used_idx].len = shadow_ring[i].len; + + used_idx += shadow_ring[i].count; +if (used_idx >= vq->size) + used_idx -= vq->size; + } + +/* The ordering for storing desc flags needs to be enforced. */ +rte_atomic_thread_fence (__ATOMIC_RELEASE); + +for (i =0 ; i < count; i++) { +uint16_t flags; + +if (vq->shadow_used_packed[i].len) + flags =VRING_DESC_F_WRITE ; +else + flags =0 ; + +if (vq->used_wrap_counter) { + flags |=VRING_DESC_F_USED ; + flags |=VRING_DESC_F_AVAIL ; + }else { + flags &= ~VRING_DESC_F_USED ; + flags &= ~VRING_DESC_F_AVAIL ; + } + +if (i >0 ) { + vq->desc_packed[vq->last_used_idx].flags = flags; + +vhost_log_cache_used_vring (dev, vq, + vq->last_used_idx * +sizeof (struct vring_packed_desc ), +sizeof (struct vring_packed_desc )); + }else { + head_idx = vq->last_used_idx; + head_flags = flags; + } + +vq_inc_last_used_packed (vq, shadow_ring[i].count);
lib/librte_vhost/virtio_net.c virtio_dev_rx_async_get_info_idx(uint16_t · line 1531
Quoted 10 lines
lib/librte_vhost/virtio_net.c +10
-0+ } + + vq->desc_packed[head_idx].flags = head_flags; + +vhost_log_cache_used_vring (dev, vq, + head_idx * +sizeof (struct vring_packed_desc ), +sizeof (struct vring_packed_desc )); + +vhost_log_cache_sync (dev, vq);
Async enqueue of packed ring has no support of live migration. The above code is not needed.
Quoted 276 lines
lib/librte_vhost/virtio_net.c +2
-0+} +static __rte_noinline uint32_tvirtio_dev_rx_async_submit_split(struct
virtio_net*dev,lib/librte_vhost/virtio_net.c +189
-0struct vhost_virtqueue *vq, uint16_t queue_id,@@ -1633,12 +1710,292 @@ virtio_dev_rx_async_submit_split(structvirtio_net *dev, return pkt_idx; } +static __rte_always_inline int +vhost_enqueue_async_single_packed (struct virtio_net *dev, +struct vhost_virtqueue *vq, +struct rte_mbuf *pkt, +struct buf_vector *buf_vec, +uint16_t *nr_descs, +uint16_t *nr_buffers, +struct iovec *src_iovec,struct iovec *dst_iovec, +struct rte_vhost_iov_iter *src_it, +struct rte_vhost_iov_iter *dst_it) +{ +uint16_t nr_vec =0 ; +uint16_t avail_idx = vq->last_avail_idx; +uint16_t max_tries, tries =0 ; +uint16_t buf_id =0 ; +uint32_t len =0 ; +uint16_t desc_count; +uint32_t size = pkt->pkt_len +sizeof (struct virtio_net_hdr_mrg_rxbuf ); +uint32_t buffer_len[vq->size]; +uint16_t buffer_buf_id[vq->size]; +uint16_t buffer_desc_count[vq->size]; + *nr_buffers =0 ; + +if (rxvq_is_mergeable (dev)) + max_tries = vq->size -1 ; +else + max_tries =1 ; + +while (size >0 ) { +/* +* if we tried all available ring items, and still +* can't get enough buf, it means something abnormal +* happened. +*/ +if (unlikely (++tries > max_tries)) +return -1 ; + +if (unlikely (fill_vec_buf_packed (dev, vq, + avail_idx, &desc_count, + buf_vec, &nr_vec, + &buf_id, &len, +VHOST_ACCESS_RW ) <0 )) +return -1 ; + + len =RTE_MIN (len, size); + size -= len; + + buffer_len[*nr_buffers] = len; + buffer_buf_id[*nr_buffers] = buf_id; + buffer_desc_count[*nr_buffers] = desc_count; + *nr_buffers +=1 ; + + *nr_descs += desc_count; + avail_idx += desc_count; +if (avail_idx >= vq->size) + avail_idx -= vq->size; + } + +if (async_mbuf_to_desc (dev, vq, pkt, buf_vec, nr_vec, *nr_buffers, + src_iovec, dst_iovec, src_it, dst_it) <0 ) +return -1 ; + +vhost_shadow_enqueue_packed (vq, buffer_len, buffer_buf_id, + buffer_desc_count, *nr_buffers); + +return 0 ; +} + +static __rte_always_inline int16_t +virtio_dev_rx_async_single_packed (struct virtio_net *dev, +struct vhost_virtqueue *vq, +struct rte_mbuf *pkt, +uint16_t *nr_descs,uint16_t *nr_buffers, +struct iovec *src_iovec,struct iovec *dst_iovec, +struct rte_vhost_iov_iter *src_it, +struct rte_vhost_iov_iter *dst_it) +{ +struct buf_vector buf_vec[BUF_VECTOR_MAX ]; + *nr_descs =0 ; + *nr_buffers =0 ; + +if (unlikely (vhost_enqueue_async_single_packed (dev, vq, pkt, buf_vec, + nr_descs, + nr_buffers, + src_iovec, dst_iovec, + src_it, dst_it) <0 )) { +VHOST_LOG_DATA (DEBUG , +"(%d) failed to get enough desc from vring\n" , + dev->vid); +return -1 ; + } + + VHOST_LOG_DATA(DEBUG, "(%d) current index %d | end index %d\n", + dev->vid, vq->last_avail_idx, + vq->last_avail_idx + *nr_descs); + +return 0 ; +} + +static __rte_noinline uint32_t +virtio_dev_rx_async_submit_packed (struct virtio_net *dev, +struct vhost_virtqueue *vq,uint16_t queue_id, +struct rte_mbuf **pkts,uint32_t count, +struct rte_mbuf **comp_pkts,uint32_t *comp_count) +{ +uint32_t pkt_idx =0 , pkt_burst_idx =0 ; +uint16_t num_buffers; +uint16_t num_desc; + +struct rte_vhost_iov_iter *it_pool = vq->it_pool; +struct iovec *vec_pool = vq->vec_pool; +struct rte_vhost_async_desc tdes[MAX_PKT_BURST ]; +struct iovec *src_iovec = vec_pool; +struct iovec *dst_iovec = vec_pool + (VHOST_MAX_ASYNC_VEC >>1 ); +struct rte_vhost_iov_iter *src_it = it_pool; +struct rte_vhost_iov_iter *dst_it = it_pool +1 ; +uint16_t slot_idx =0 ; +uint16_t segs_await =0 ; +struct async_inflight_info *pkts_info = vq->async_pkts_info; +uint32_t n_pkts =0 , pkt_err =0 ; +uint32_t num_async_pkts =0 , num_done_pkts =0 ; + +rte_prefetch0 (&vq->desc[vq->last_avail_idx & (vq->size -1 )]); + +for (pkt_idx =0 ; pkt_idx < count; pkt_idx++) { +if (unlikely (virtio_dev_rx_async_single_packed (dev, vq, + pkts[pkt_idx], + &num_desc, &num_buffers, + src_iovec, dst_iovec, + src_it, dst_it) <0 )) { +break ; + } + + VHOST_LOG_DATA(DEBUG, "(%d) current index %d | end index %d\n", + dev->vid, vq->last_avail_idx, + vq->last_avail_idx + num_desc); + + slot_idx = (vq->async_pkts_idx + num_async_pkts) & + (vq->size -1 ); +if (src_it->count) { +uint16_t from, to; + +async_fill_desc (&tdes[pkt_burst_idx++], src_it, dst_it); + pkts_info[slot_idx].descs = num_desc; + pkts_info[slot_idx].nr_buffers = num_buffers; + pkts_info[slot_idx].mbuf = pkts[pkt_idx]; + num_async_pkts++; + src_iovec += src_it->nr_segs; + dst_iovec += dst_it->nr_segs; + src_it +=2 ; + dst_it +=2 ; + segs_await += src_it->nr_segs; + +/** +* recover shadow used ring and keep DMA-occupied +* descriptors. +*/ + from = vq->shadow_used_idx - num_buffers; + to = vq->async_packed_buffer_idx & (vq->size -1 ); +if (num_buffers + to <= vq->size) { +rte_memcpy (&vq->async_buffers_packed[to], + &vq->shadow_used_packed[from], + num_buffers * +sizeof (struct vring_used_elem_packed )); + }else { +int size = vq->size - to; + +rte_memcpy (&vq->async_buffers_packed[to], + &vq->shadow_used_packed[from], + size * +sizeof (struct vring_used_elem_packed )); +rte_memcpy (vq->async_buffers_packed, + &vq->shadow_used_packed[from + + size], (num_buffers - size) * +sizeof (struct vring_used_elem_packed )); + } + vq->async_packed_buffer_idx += num_buffers; + vq->shadow_used_idx -= num_buffers; + }else + comp_pkts[num_done_pkts++] = pkts[pkt_idx]; + +vq_inc_last_avail_packed (vq, num_desc); + +/* +* conditions to trigger async device transfer: +* - buffered packet number reaches transfer threshold +* - unused async iov number is less than max vhost vector +*/ + if (unlikely(pkt_burst_idx >=
VHOST_ASYNC_BATCH_THRESHOLD||lib/librte_vhost/virtio_net.c +6
-0+ ((VHOST_MAX_ASYNC_VEC >> 1) - segs_await < + BUF_VECTOR_MAX))) { + n_pkts = vq->async_ops.transfer_data (dev->vid, + queue_id, tdes,0 , pkt_burst_idx); + src_iovec = vec_pool; + dst_iovec = vec_pool + (VHOST_MAX_ASYNC_VEC >>1);
lib/librte_vhost/virtio_net.c +8
-0+ src_it = it_pool; + dst_it = it_pool +1 ; + segs_await =0 ; + vq->async_pkts_inflight_n += n_pkts; + +if (unlikely (n_pkts < pkt_burst_idx)) { +/* +* log error packets number here and do actual
lib/librte_vhost/virtio_net.c +53
-0+* error processing when applications poll +* completion +*/ + pkt_err = pkt_burst_idx - n_pkts; + pkt_burst_idx =0 ; + pkt_idx++; +break ; + } + + pkt_burst_idx =0 ; + } + } + +if (pkt_burst_idx) { + n_pkts = vq->async_ops.transfer_data (dev->vid, + queue_id, tdes,0 , pkt_burst_idx); + vq->async_pkts_inflight_n += n_pkts; + +if (unlikely (n_pkts < pkt_burst_idx)) + pkt_err = pkt_burst_idx - n_pkts; + } + +do_data_copy_enqueue (dev, vq); + + if (unlikely(pkt_err)) { + uint16_t buffers_err = 0; + uint16_t async_buffer_idx; + uint16_t i; + + num_async_pkts -= pkt_err; + pkt_idx -= pkt_err; + /* calculate the sum of buffers of DMA-error packets. */ + while (pkt_err-- > 0) { + buffers_err += + pkts_info[slot_idx & (vq->size - 1)].nr_buffers; + slot_idx--; + } + + vq->async_packed_buffer_idx -= buffers_err; + async_buffer_idx = vq->async_packed_buffer_idx; + /* set 0 to the length of descriptors of DMA-error packets */ + for (i = 0; i < buffers_err; i++) { + vq->async_buffers_packed[(async_buffer_idx + i) + & (vq->size - 1)].len = 0; + } + /* write back DMA-error descriptors to used ring */ + do { + uint16_t from = async_buffer_idx & (vq->size - 1); + uint16_t to = (from + buffers_err) & (vq->size - 1); + + if (to > from) { + vhost_update_used_packed(dev, vq, + vq->async_buffers_packed + from,
lib/librte_vhost/virtio_net.c virtio_dev_rx_async_submit_split(struct virtio_net *dev, · line 1978
Quoted 10 lines
lib/librte_vhost/virtio_net.c +10
-0+ to - from); + buffers_err =0 ; + }else { +vhost_update_used_packed (dev, vq, + vq->async_buffers_packed + from, + vq->size - from); + buffers_err -= vq->size - from; + } + }while (buffers_err >0 ); +vhost_vring_call_packed (dev, vq);
Why notify front-end here?
lib/librte_vhost/virtio_net.c virtio_dev_rx_async_submit_split(struct virtio_net *dev, · line 1991
Quoted 13 lines
lib/librte_vhost/virtio_net.c +13
-0+ num_done_pkts = pkt_idx - num_async_pkts; + } + + vq->async_pkts_idx += num_async_pkts; + *comp_count = num_done_pkts; + +if (likely (vq->shadow_used_idx)) { +vhost_flush_enqueue_shadow_packed (dev, vq); +vhost_vring_call_packed (dev, vq); + } + +return pkt_idx; +}
virtio_dev_rx_async_submit_packed is too long and it has several parts are similar with split ring. I think you need to abstract common parts into inline functions to make the code easier to read.
Quoted 133 lines
lib/librte_vhost/virtio_net.c +65
-24+uint16_t rte_vhost_poll_enqueue_completed (int vid,uint16_t queue_id,struct rte_mbuf **pkts,uint16_t count) {struct virtio_net *dev =get_device (vid);struct vhost_virtqueue *vq; -uint16_t n_pkts_cpl =0 , n_pkts_put =0 , n_descs =0 ; +uint16_t n_pkts_cpl =0 , n_pkts_put =0 , n_descs =0 , n_buffers =0 ;uint16_t start_idx, pkts_idx, vq_size;struct async_inflight_info *pkts_info;uint16_t from, i;@@ -1680,53 +2037,96 @@ uint16_t rte_vhost_poll_enqueue_completed(int vid, uint16_t queue_id, goto done; } -for (i =0 ; i < n_pkts_put; i++) { - from = (start_idx + i) & (vq_size -1 ); - n_descs += pkts_info[from].descs; - pkts[i] = pkts_info[from].mbuf; +if (vq_is_packed (dev)) { +for (i =0 ; i < n_pkts_put; i++) { + from = (start_idx + i) & (vq_size -1 ); + n_buffers += pkts_info[from].nr_buffers; + pkts[i] = pkts_info[from].mbuf; + } + }else { +for (i =0 ; i < n_pkts_put; i++) { + from = (start_idx + i) & (vq_size -1 ); + n_descs += pkts_info[from].descs; + pkts[i] = pkts_info[from].mbuf; + } } + vq->async_last_pkts_n = n_pkts_cpl - n_pkts_put; vq->async_pkts_inflight_n -= n_pkts_put;if (likely (vq->enabled && vq->access_ok)) { -uint16_t nr_left = n_descs;uint16_t nr_copy;uint16_t to;/* write back completed descriptors to used ring */ -do { - from = vq->last_async_desc_idx & (vq->size -1 ); - nr_copy = nr_left + from <= vq->size ? nr_left : - vq->size - from; - to = vq->last_used_idx & (vq->size -1 ); - -if (to + nr_copy <= vq->size) { -rte_memcpy (&vq->used->ring[to], +if (vq_is_packed (dev)) { +uint16_t nr_left = n_buffers; +uint16_t to; +do { + from = vq->last_async_buffer_idx & + (vq->size -1 ); + to = (from + nr_left) & (vq->size -1 ); + +if (to > from) { +vhost_update_used_packed (dev, vq, + vq->async_buffers_packed + from, + to - from); + vq->last_async_buffer_idx += nr_left; + nr_left =0 ; + }else { +vhost_update_used_packed (dev, vq, + vq->async_buffers_packed + from, + vq->size - from); + vq->last_async_buffer_idx += + vq->size - from; + nr_left -= vq->size - from; + } + }while (nr_left >0 ); +vhost_vring_call_packed (dev, vq); + }else { +uint16_t nr_left = n_descs; +do { + from = vq->last_async_desc_idx & (vq->size -1 ); + nr_copy = nr_left + from <= vq->size ? nr_left : + vq->size - from; + to = vq->last_used_idx & (vq->size -1 ); + +if (to + nr_copy <= vq->size) { +rte_memcpy (&vq->used->ring[to], &vq- >async_descs_split[from], nr_copy *sizeof (struct vring_used_elem )); - }else { -uint16_t size = vq->size - to; + }else { +uint16_t size = vq->size - to; -rte_memcpy (&vq->used->ring[to], +rte_memcpy (&vq->used->ring[to], &vq- >async_descs_split[from], size *sizeof (struct vring_used_elem )); -rte_memcpy (vq->used->ring, +rte_memcpy (vq->used->ring, &vq->async_descs_split[from + size], (nr_copy - size) *sizeof (struct vring_used_elem )); - } + } + + vq->last_async_desc_idx += nr_copy; + vq->last_used_idx += nr_copy; + nr_left -= nr_copy; + }while (nr_left >0 ); + +__atomic_add_fetch (&vq->used->idx, n_descs, + __ATOMIC_RELEASE); +vhost_vring_call_split (dev, vq); + } - vq->last_async_desc_idx += nr_copy; - vq->last_used_idx += nr_copy; - nr_left -= nr_copy; - }while (nr_left >0 ); - __atomic_add_fetch(&vq->used->idx, n_descs,
__ATOMIC_RELEASE);
lib/librte_vhost/virtio_net.c uint16_t rte_vhost_poll_enqueue_completed(int vid, uint16_t queue_id, · line 2129
Quoted 10 lines
lib/librte_vhost/virtio_net.c +7
-3-vhost_vring_call_split (dev, vq); - }else - vq->last_async_desc_idx += n_descs; + + }else { +if (vq_is_packed (dev)) + vq->last_async_buffer_idx += n_buffers; +else + vq->last_async_desc_idx += n_descs; + }
rte_vhost_poll_enqueue_completed is too long and not easy to read. Save suggestion as above.
Thanks,
Jiayu
Quoted 19 lines
done:
lib/librte_vhost/virtio_net.c +3
-2rte_spinlock_unlock (&vq->access_lock);@@ -1767,9 +2167,10 @@ virtio_dev_rx_async_submit(struct virtio_net *dev, uint16_t queue_id, if (count == 0) goto out; -/* TODO: packed queue not implemented */ if (vq_is_packed (dev)) - nb_tx =0 ; + nb_tx =virtio_dev_rx_async_submit_packed (dev, + vq, queue_id, pkts, count, comp_pkts, + comp_count);else nb_tx = virtio_dev_rx_async_submit_split(dev,vq,
queue_id, pkts, count,comp_pkts,
--
2.29.2
Hi Jiayu,
Quoted 94 lines
-----Original Message-----
From: Hu, Jiayu <[email protected]>
Sent: Wednesday, April 7, 2021 2:27 PM
To: Jiang, Cheng1 <[email protected]>; [email protected]; Xia, Chenbo <[email protected]>
Cc: [email protected]; Yang, YvonneX <[email protected]>; Wang, Yinan <[email protected]>
Subject: RE: [PATCH v3] vhost: add support for packed ring in async vhostHi Cheng,
Some comments are inline.
Quoted 70 lines
-----Original Message-----
From: Jiang, Cheng1 <[email protected]>
Sent: Wednesday, March 31, 2021 10:06 PM
To: [email protected]; Xia, Chenbo <[email protected]>
Cc: [email protected]; Hu, Jiayu <[email protected]>; Yang, YvonneX <[email protected]>; Wang, Yinan <[email protected]>; Jiang, Cheng1 <[email protected]>
Subject: [PATCH v3] vhost: add support for packed ring in async vhostFor now async vhost data path only supports split ring structure. In order to make async vhost compatible with virtio 1.1 spec this patch enables packed ring in async vhost data path.
Signed-off-by Cheng Jiang <[email protected]>---
v3:
* fix error handler for DMA-copy packet
* remove variables that are no longer needed
v2:
* fix wrong buffer index inrte_vhost_poll_enqueue_completed()
* addasync_buffers_packedmemory free invhost_free_async_mem()lib/librte_vhost/rte_vhost_async.h | 1 + lib/librte_vhost/vhost.c | 24 +- lib/librte_vhost/vhost.h | 7 +- lib/librte_vhost/virtio_net.c | 463 +++++++++++++++++++++++++++-- 4 files changed, 457 insertions(+), 38 deletions(-)lib/librte_vhost/rte_vhost_async.h +0
-0@@ -89,6 +89,7 @@ struct rte_vhost_async_channel_ops { struct
async_inflight_info{ structrte_mbuf*mbuf;uint16_tdescs; /* num of descs inflight */lib/librte_vhost/rte_vhost_async.h +1
-0+uint16_t nr_buffers;/* num of buffers inflight for packed ring */ };/** lib/librte_vhost/vhost.c index renamed from lib/librte_vhost/vhost.c +0
-0
52ab93d1e..51b44d6f2100644lib/librte_vhost/vhost.c +7
-2@@ -330,15 +330,20 @@ vhost_free_async_mem(struct vhost_virtqueue *vq) {if (vq->async_pkts_info)rte_free (vq->async_pkts_info); -if (vq->async_descs_split) +if (vq->async_buffers_packed) { +rte_free (vq->async_buffers_packed); +vq->async_buffers_packed =NULL ; +}else {rte_free (vq->async_descs_split); +vq->async_descs_split =NULL ; +} +if (vq->it_pool)rte_free (vq->it_pool);if (vq->vec_pool)rte_free (vq->vec_pool); vq->async_pkts_info =NULL ; -vq->async_descs_split =NULL ; vq->it_pool =NULL ; vq->vec_pool =NULL ;}
lib/librte_vhost/vhost.c +0
-0@@ -1603,9 +1608,9 @@ int rte_vhost_async_channel_register(int vid, uint16_t queue_id, return -1;lib/librte_vhost/vhost.c int rte_vhost_async_channel_register(int vid, · line 1616
Quoted 10 lines
lib/librte_vhost/vhost.c +3
-2/* packed queue is not supported */ -if (unlikely (vq_is_packed (dev) || !f.async_inorder)) { +if (unlikely (!f.async_inorder)) {VHOST_LOG_CONFIG (ERR , -"async copy is not supported on packed queue or non-inorder mode " +"async copy is not supported on non-inorder mode " "(vid %d, qid: %d)\n", vid, queue_id); return -1; } @@ -1643,10 +1648,17 @@ int rte_vhost_async_channel_register(int vid, uint16_t queue_id, vq->vec_pool = rte_malloc_socket(NULL,
VHOST_MAX_ASYNC_VEC
Quoted 15 lines
lib/librte_vhost/vhost.c int rte_vhost_async_channel_register(int vid, uint16_t queue_id, · line 1661
Quoted 13 lines
* sizeof(struct iovec),
RTE_CACHE_LINE_SIZE, node);lib/librte_vhost/vhost.c +6
-1-vq->async_descs_split = rte_malloc_socket(NULL, +if (vq_is_packed (dev)) { +vq->async_buffers_packed =rte_malloc_socket (NULL , size * +vq->sizeof(struct vring_used_elem_packed), +RTE_CACHE_LINE_SIZE , node); +}else { +vq->async_descs_split = rte_malloc_socket(NULL, vq->size * sizeof(struct vring_used_elem), RTE_CACHE_LINE_SIZE,node); -if (!vq->async_descs_split || !vq->async_pkts_info ||
lib/librte_vhost/vhost.c +3
-0+} + +if (!vq->async_pkts_info ||Need to check if malloc fails for
async_buffers_packed.
Sure, It will be fixed in the next version.
Quoted 119 lines
Quoted 26 lines
!vq->it_pool || !vq->vec_pool) {
vhost_free_async_mem(vq);
VHOST_LOG_CONFIG(ERR,lib/librte_vhost/vhost.h index renamed from lib/librte_vhost/vhost.h +0
-0
658f6fc28..d6324fbf8100644lib/librte_vhost/vhost.h +0
-0@@ -206,9 +206,14 @@ struct vhost_virtqueue { uint16_tasync_pkts_idx;
uint16_tasync_pkts_inflight_n;uint16_tasync_last_pkts_n; -structvring_used_elem*async_descs_split;lib/librte_vhost/vhost.h +5
-0+union { +struct vring_used_elem *async_descs_split;struct +vring_used_elem_packed *async_buffers_packed; };uint16_t async_desc_idx; +uint16_t async_packed_buffer_idx;uint16_t last_async_desc_idx; +uint16_t last_async_buffer_idx;/* vq async features */ boolasync_inorder;(quoted diff) +0
-0
b/lib/librte_vhost/virtio_net.cindex583bf379c..fa2dfde02100644lib/librte_vhost/virtio_net.c +0
-0@@ -363,8 +363,7 @@Quoted 1 line
vhost_shadow_dequeue_single_packed_inorder(struct
vhost_virtqueue*vq,
Quoted 91 lines
}
static
__rte_always_inlinevoidlib/librte_vhost/virtio_net.c +12
-2-vhost_shadow_enqueue_single_packed(struct virtio_net *dev, - struct vhost_virtqueue *vq, +vhost_shadow_enqueue_packed(struct vhost_virtqueue *vq, uint32_t len[], uint16_t id[], uint16_t count[],@@ -382,6 +381,17 @@ vhost_shadow_enqueue_single_packed(struct virtio_net *dev, vq->shadow_aligned_idx += count[i]; vq->shadow_used_idx++; } +} + +static __rte_always_inline void +vhost_shadow_enqueue_single_packed (struct virtio_net *dev, +struct vhost_virtqueue *vq, +uint32_t len[], +uint16_t id[], +uint16_t count[], +uint16_t num_buffers) +{ +vhost_shadow_enqueue_packed (vq, len, id, count, num_buffers);if (vq->shadow_aligned_idx >=PACKED_BATCH_SIZE ) {
do_data_copy_enqueue(dev, vq); @@ -1452,6 +1462,73 @@ virtio_dev_rx_async_get_info_idx(uint16_tpkts_idx,
(vq_size-n_inflight+pkts_idx) & (vq_size- 1); }lib/librte_vhost/virtio_net.c +4
-0+static __rte_always_inline void +vhost_update_used_packed (struct virtio_net *dev, +struct vhost_virtqueue *vq, + struct vring_used_elem_packed
*shadow_ring,lib/librte_vhost/virtio_net.c +54
-0+ uint16_t count) +{ +if (count ==0 ) +return ; +int i; +uint16_t used_idx = vq->last_used_idx;uint16_t head_idx = +vq->last_used_idx;uint16_t head_flags =0 ; + +/* Split loop in two to save memory barriers */ for (i =0 ; i < +count; i++) { +vq->desc_packed[used_idx].id = shadow_ring[i].id; +vq->desc_packed[used_idx].len = shadow_ring[i].len; + +used_idx += shadow_ring[i].count; +if (used_idx >= vq->size) +used_idx -= vq->size; +} + +/* The ordering for storing desc flags needs to be enforced. */ +rte_atomic_thread_fence (__ATOMIC_RELEASE); + +for (i =0 ; i < count; i++) { +uint16_t flags; + +if (vq->shadow_used_packed[i].len) +flags =VRING_DESC_F_WRITE ; +else +flags =0 ; + +if (vq->used_wrap_counter) { +flags |=VRING_DESC_F_USED ; +flags |=VRING_DESC_F_AVAIL ; +}else { +flags &= ~VRING_DESC_F_USED ; +flags &= ~VRING_DESC_F_AVAIL ; +} + +if (i >0 ) { +vq->desc_packed[vq->last_used_idx].flags = flags; + +vhost_log_cache_used_vring (dev, vq, +vq->last_used_idx * +sizeof (struct vring_packed_desc ), +sizeof (struct vring_packed_desc )); +}else { +head_idx = vq->last_used_idx; +head_flags = flags; +} + +vq_inc_last_used_packed (vq, shadow_ring[i].count); } + +vq->desc_packed[head_idx].flags = head_flags; + +vhost_log_cache_used_vring(dev, vq,
Quoted 8 lines
lib/librte_vhost/virtio_net.c virtio_dev_rx_async_get_info_idx(uint16_t pkts_idx, · line 1529
Quoted 5 lines
lib/librte_vhost/virtio_net.c +5
-0+head_idx * +sizeof(struct vring_packed_desc), +sizeof(struct vring_packed_desc)); + +vhost_log_cache_sync (dev, vq);Async enqueue of packed ring has no support of live migration. The above code is not needed.
It will be removed.
Quoted 252 lines
Quoted 252 lines
lib/librte_vhost/virtio_net.c +2
-0+} + static __rte_noinline uint32_t virtio_dev_rx_async_submit_split(struct virtio_net *dev, struct
vhost_virtqueue*vq,uint16_tqueue_id, @@ -1633,12 +1710,292 @@ virtio_dev_rx_async_submit_split(structvirtio_net*dev,
returnpkt_idx;
}lib/librte_vhost/virtio_net.c +13
-0+static __rte_always_inline int +vhost_enqueue_async_single_packed (struct virtio_net *dev, +struct vhost_virtqueue *vq, +struct rte_mbuf *pkt, +struct buf_vector *buf_vec, +uint16_t *nr_descs, +uint16_t *nr_buffers, +struct iovec *src_iovec,struct iovec *dst_iovec, +struct rte_vhost_iov_iter *src_it, +struct rte_vhost_iov_iter *dst_it) {uint16_t nr_vec =0 ; +uint16_t avail_idx = vq->last_avail_idx;uint16_t max_tries, tries = +0 ;uint16_t buf_id =0 ;uint32_t len =0 ;uint16_t desc_count; +uint32_t size = pkt->pkt_len + sizeof(struct
virtio_net_hdr_mrg_rxbuf);lib/librte_vhost/virtio_net.c +56
-0+uint32_t buffer_len[vq->size]; +uint16_t buffer_buf_id[vq->size]; +uint16_t buffer_desc_count[vq->size]; *nr_buffers =0 ; + +if (rxvq_is_mergeable (dev)) +max_tries = vq->size -1 ; +else +max_tries =1 ; + +while (size >0 ) { +/* +* if we tried all available ring items, and still +* can't get enough buf, it means something abnormal +* happened. +*/ +if (unlikely (++tries > max_tries)) +return -1 ; + +if (unlikely (fill_vec_buf_packed (dev, vq, avail_idx, &desc_count, +buf_vec, &nr_vec, &buf_id, &len, +VHOST_ACCESS_RW ) <0 )) +return -1 ; + +len =RTE_MIN (len, size); +size -= len; + +buffer_len[*nr_buffers] = len; +buffer_buf_id[*nr_buffers] = buf_id; +buffer_desc_count[*nr_buffers] = desc_count; *nr_buffers +=1 ; + +*nr_descs += desc_count; +avail_idx += desc_count; +if (avail_idx >= vq->size) +avail_idx -= vq->size; +} + +if (async_mbuf_to_desc (dev, vq, pkt, buf_vec, nr_vec, *nr_buffers, +src_iovec, dst_iovec, src_it, dst_it) <0 )return -1 ; + +vhost_shadow_enqueue_packed (vq, buffer_len, buffer_buf_id, + buffer_desc_count, *nr_buffers); + +return 0 ; +} + +static __rte_always_inline int16_t +virtio_dev_rx_async_single_packed (struct virtio_net *dev, +struct vhost_virtqueue *vq, +struct rte_mbuf *pkt, +uint16_t *nr_descs,uint16_t *nr_buffers, +struct iovec *src_iovec,struct iovec *dst_iovec, +struct rte_vhost_iov_iter *src_it, +struct rte_vhost_iov_iter *dst_it) {struct buf_vector +buf_vec[BUF_VECTOR_MAX ]; *nr_descs =0 ; *nr_buffers =0 ; + +if (unlikely(vhost_enqueue_async_single_packed(dev, vq, pkt,
buf_vec,
+nr_descs,
+nr_buffers,
+src_iovec,dst_iovec,
+src_it,dst_it) < 0)) {lib/librte_vhost/virtio_net.c +7
-0+VHOST_LOG_DATA (DEBUG , +"(%d) failed to get enough desc from vring\n" , +dev->vid); +return -1 ; +} + +VHOST_LOG_DATA(DEBUG, "(%d) current index %d | endindex %d\n",
lib/librte_vhost/virtio_net.c +31
-0+dev->vid, vq->last_avail_idx, +vq->last_avail_idx + *nr_descs); + +return 0 ; +} + +static __rte_noinline uint32_t +virtio_dev_rx_async_submit_packed (struct virtio_net *dev,struct +vhost_virtqueue *vq,uint16_t queue_id,struct rte_mbuf **pkts, +uint32_t count,struct rte_mbuf **comp_pkts,uint32_t *comp_count) { +uint32_t pkt_idx =0 , pkt_burst_idx =0 ;uint16_t num_buffers; +uint16_t num_desc; + +struct rte_vhost_iov_iter *it_pool = vq->it_pool;struct iovec +*vec_pool = vq->vec_pool;struct rte_vhost_async_desc +tdes[MAX_PKT_BURST ];struct iovec *src_iovec = vec_pool;struct iovec +*dst_iovec = vec_pool + (VHOST_MAX_ASYNC_VEC >>1 );struct +rte_vhost_iov_iter *src_it = it_pool;struct rte_vhost_iov_iter +*dst_it = it_pool +1 ;uint16_t slot_idx =0 ;uint16_t segs_await = +0 ;struct async_inflight_info *pkts_info = vq->async_pkts_info; +uint32_t n_pkts =0 , pkt_err =0 ;uint32_t num_async_pkts =0 , +num_done_pkts =0 ; + +rte_prefetch0 (&vq->desc[vq->last_avail_idx & (vq->size -1 )]); + +for (pkt_idx =0 ; pkt_idx < count; pkt_idx++) {if +(unlikely (virtio_dev_rx_async_single_packed (dev, vq, pkts[pkt_idx], +&num_desc, &num_buffers, src_iovec, dst_iovec, src_it, dst_it) <0 )) +{break ; } + +VHOST_LOG_DATA(DEBUG, "(%d) current index %d | endindex %d\n",
lib/librte_vhost/virtio_net.c +24
-0+dev->vid, vq->last_avail_idx, +vq->last_avail_idx + num_desc); + +slot_idx = (vq->async_pkts_idx + num_async_pkts) & (vq->size -1 );if +(src_it->count) {uint16_t from, to; + +async_fill_desc (&tdes[pkt_burst_idx++], src_it, dst_it); +pkts_info[slot_idx].descs = num_desc; pkts_info[slot_idx].nr_buffers += num_buffers; pkts_info[slot_idx].mbuf = pkts[pkt_idx]; +num_async_pkts++; src_iovec += src_it->nr_segs; dst_iovec += +dst_it->nr_segs; src_it +=2 ; dst_it +=2 ; segs_await += +src_it->nr_segs; + +/** +* recover shadow used ring and keep DMA-occupied +* descriptors. +*/ +from = vq->shadow_used_idx - num_buffers; +to = vq->async_packed_buffer_idx & (vq->size -1 ); +if (num_buffers + to <= vq->size) { +rte_memcpy(&vq->async_buffers_packed[to], +&vq->shadow_used_packed[from], +num_buffers * +sizeof(struct
vring_used_elem_packed));lib/librte_vhost/virtio_net.c +7
-0+}else { +int size = vq->size - to; + +rte_memcpy(&vq->async_buffers_packed[to], +&vq->shadow_used_packed[from], +size * +sizeof(struct
vring_used_elem_packed));lib/librte_vhost/virtio_net.c +4
-0+rte_memcpy(vq->async_buffers_packed, +&vq->shadow_used_packed[from + +size], (num_buffers - size) * +sizeof(struct
vring_used_elem_packed));lib/librte_vhost/virtio_net.c +14
-0+} +vq->async_packed_buffer_idx += num_buffers; +vq->shadow_used_idx -= num_buffers; +}else +comp_pkts[num_done_pkts++] = pkts[pkt_idx]; + +vq_inc_last_avail_packed (vq, num_desc); + +/* +* conditions to trigger async device transfer: +* - buffered packet number reaches transfer threshold +* - unused async iov number is less than max vhost vector +*/ +if (unlikely(pkt_burst_idx >=
VHOST_ASYNC_BATCH_THRESHOLD||lib/librte_vhost/virtio_net.c +6
-0+((VHOST_MAX_ASYNC_VEC >> 1) - segs_await < +BUF_VECTOR_MAX))) { +n_pkts = vq->async_ops.transfer_data (dev->vid, +queue_id, tdes,0 , pkt_burst_idx); +src_iovec = vec_pool; +dst_iovec = vec_pool + (VHOST_MAX_ASYNC_VEC >>1);
lib/librte_vhost/virtio_net.c +8
-0+src_it = it_pool; +dst_it = it_pool +1 ; +segs_await =0 ; +vq->async_pkts_inflight_n += n_pkts; + +if (unlikely (n_pkts < pkt_burst_idx)) { +/* +* log error packets number here and do actual
+ * error processing when applications poll
+ * completion
+ */lib/librte_vhost/virtio_net.c +54
-0+pkt_err = pkt_burst_idx - n_pkts; +pkt_burst_idx =0 ; +pkt_idx++; +break ; +} + +pkt_burst_idx =0 ; +} +} + +if (pkt_burst_idx) { +n_pkts = vq->async_ops.transfer_data (dev->vid, +queue_id, tdes,0 , pkt_burst_idx); +vq->async_pkts_inflight_n += n_pkts; + +if (unlikely (n_pkts < pkt_burst_idx)) +pkt_err = pkt_burst_idx - n_pkts; +} + +do_data_copy_enqueue (dev, vq); + +if (unlikely(pkt_err)) { +uint16_t buffers_err = 0; +uint16_t async_buffer_idx; +uint16_t i; + +num_async_pkts -= pkt_err; +pkt_idx -= pkt_err; +/* calculate the sum of buffers of DMA-error packets. */ +while (pkt_err-- > 0) { +buffers_err += +pkts_info[slot_idx & (vq->size - 1)].nr_buffers; +slot_idx--; +} + +vq->async_packed_buffer_idx -= buffers_err; +async_buffer_idx = vq->async_packed_buffer_idx; +/* set 0 to the length of descriptors of DMA-error packets */ +for (i = 0; i < buffers_err; i++) { +vq->async_buffers_packed[(async_buffer_idx + i) +& (vq->size - 1)].len = 0; +} +/* write back DMA-error descriptors to used ring */ +do { +uint16_t from = async_buffer_idx & (vq->size - 1); +uint16_t to = (from + buffers_err) & (vq->size - 1); + +if (to > from) { +vhost_update_used_packed(dev, vq, +vq->async_buffers_packed + from, +to - from); +buffers_err = 0; +} else { +vhost_update_used_packed(dev, vq,
Quoted 8 lines
lib/librte_vhost/virtio_net.c virtio_dev_rx_async_submit_split(struct virtio_net *dev, · line 1978
Quoted 6 lines
lib/librte_vhost/virtio_net.c +6
-0+vq->async_buffers_packed + from, +vq->size - from); +buffers_err -= vq->size - from; +} +}while (buffers_err >0 ); +vhost_vring_call_packed (dev, vq);Why notify front-end here?
The error handling method will be changed in the next version, so this notification will be removed.
Quoted 10 lines
Quoted 10 lines
lib/librte_vhost/virtio_net.c +9
-0+num_done_pkts = pkt_idx - num_async_pkts; +} + +vq->async_pkts_idx += num_async_pkts; +*comp_count = num_done_pkts; + +if (likely (vq->shadow_used_idx)) { +vhost_flush_enqueue_shadow_packed (dev, vq); +vhost_vring_call_packed (dev, vq);
Quoted 8 lines
lib/librte_vhost/virtio_net.c virtio_dev_rx_async_submit_split(struct virtio_net *dev, · line 1991
Quoted 4 lines
lib/librte_vhost/virtio_net.c +4
-0+} + +return pkt_idx; +}
virtio_dev_rx_async_submit_packedis too long and it has several parts are similar with split ring. I think you need to abstract common parts into inline functions to make the code easier to read.
I'm not sure which parts can be easily processed into functions. Maybe we can have a discussion offline.
Quoted 132 lines
Quoted 132 lines
lib/librte_vhost/virtio_net.c +65
-23+uint16_t rte_vhost_poll_enqueue_completed (int vid,uint16_t queue_id,struct rte_mbuf **pkts,uint16_t count) {struct virtio_net *dev =get_device (vid);struct vhost_virtqueue *vq; -uint16_t n_pkts_cpl =0 , n_pkts_put =0 , n_descs =0 ; +uint16_t n_pkts_cpl =0 , n_pkts_put =0 , n_descs =0 , n_buffers =0 ;uint16_t start_idx, pkts_idx, vq_size;struct async_inflight_info *pkts_info;uint16_t from, i;@@ -1680,53 +2037,96 @@ uint16_t rte_vhost_poll_enqueue_completed(int vid, uint16_t queue_id, goto done; } -for (i =0 ; i < n_pkts_put; i++) { -from = (start_idx + i) & (vq_size -1 ); -n_descs += pkts_info[from].descs; -pkts[i] = pkts_info[from].mbuf; +if (vq_is_packed (dev)) { +for (i =0 ; i < n_pkts_put; i++) { +from = (start_idx + i) & (vq_size -1 ); +n_buffers += pkts_info[from].nr_buffers; +pkts[i] = pkts_info[from].mbuf; +} +}else { +for (i =0 ; i < n_pkts_put; i++) { +from = (start_idx + i) & (vq_size -1 ); +n_descs += pkts_info[from].descs; +pkts[i] = pkts_info[from].mbuf; +} } + vq->async_last_pkts_n = n_pkts_cpl - n_pkts_put; vq->async_pkts_inflight_n -= n_pkts_put;if (likely (vq->enabled && vq->access_ok)) { -uint16_t nr_left = n_descs;uint16_t nr_copy;uint16_t to;/* write back completed descriptors to used ring */ -do { -from = vq->last_async_desc_idx & (vq->size -1 ); -nr_copy = nr_left + from <= vq->size ? nr_left : -vq->size - from; -to = vq->last_used_idx & (vq->size -1 ); - -if (to + nr_copy <= vq->size) { -rte_memcpy (&vq->used->ring[to], +if (vq_is_packed (dev)) { +uint16_t nr_left = n_buffers; +uint16_t to; +do { +from = vq->last_async_buffer_idx & +(vq->size -1 ); +to = (from + nr_left) & (vq->size -1 ); + +if (to > from) { +vhost_update_used_packed (dev, vq, +vq->async_buffers_packed + from, +to - from); +vq->last_async_buffer_idx += nr_left; +nr_left =0 ; +}else { +vhost_update_used_packed (dev, vq, +vq->async_buffers_packed + from, +vq->size - from); +vq->last_async_buffer_idx += +vq->size - from; +nr_left -= vq->size - from; +} +}while (nr_left >0 ); +vhost_vring_call_packed (dev, vq); +}else { +uint16_t nr_left = n_descs; +do { +from = vq->last_async_desc_idx & (vq->size -1 ); +nr_copy = nr_left + from <= vq->size ? nr_left : +vq->size - from; +to = vq->last_used_idx & (vq->size -1 ); + +if (to + nr_copy <= vq->size) { +rte_memcpy (&vq->used->ring[to], &vq- >async_descs_split[from], nr_copy *sizeof (struct vring_used_elem )); -}else { -uint16_t size = vq->size - to; +}else { +uint16_t size = vq->size - to; -rte_memcpy (&vq->used->ring[to], +rte_memcpy (&vq->used->ring[to], &vq- >async_descs_split[from], size *sizeof (struct vring_used_elem )); -rte_memcpy (vq->used->ring, +rte_memcpy (vq->used->ring, &vq->async_descs_split[from + size], (nr_copy - size) *sizeof (struct vring_used_elem )); -} +} + +vq->last_async_desc_idx += nr_copy; +vq->last_used_idx += nr_copy; +nr_left -= nr_copy; +}while (nr_left >0 ); + +__atomic_add_fetch (&vq->used->idx, n_descs, +__ATOMIC_RELEASE); +vhost_vring_call_split (dev, vq); +} -vq->last_async_desc_idx += nr_copy; -vq->last_used_idx += nr_copy; -nr_left -= nr_copy; -}while (nr_left >0 );
Quoted 17 lines
lib/librte_vhost/virtio_net.c uint16_t rte_vhost_poll_enqueue_completed(int vid, uint16_t queue_id, · line 2129
Quoted 12 lines
-__atomic_add_fetch(&vq->used->idx,
n_descs,__ATOMIC_RELEASE);lib/librte_vhost/virtio_net.c +7
-3-vhost_vring_call_split (dev, vq); -}else -vq->last_async_desc_idx += n_descs; + +}else { +if (vq_is_packed (dev)) +vq->last_async_buffer_idx += n_buffers; +else +vq->last_async_desc_idx += n_descs; +}
rte_vhost_poll_enqueue_completedis too long and not easy to read. Save suggestion
as above.
I can try to process some code into functions, but I'm not sure if this is necessary, I will discuss it with you later.
Thanks,
Cheng
Quoted 23 lines
Thanks,
JiayuQuoted 19 lines
done:
rte_spinlock_unlock(&vq->access_lock);lib/librte_vhost/virtio_net.c +3
-2@@ -1767,9 +2167,10 @@ virtio_dev_rx_async_submit(struct virtio_net *dev, uint16_t queue_id, if (count == 0) goto out; -/* TODO: packed queue not implemented */ if (vq_is_packed (dev)) -nb_tx =0 ; +nb_tx =virtio_dev_rx_async_submit_packed (dev, +vq, queue_id, pkts, count, comp_pkts, +comp_count);else nb_tx = virtio_dev_rx_async_submit_split(dev,vq,
queue_id, pkts, count,comp_pkts,
--
2.29.2
v4 cover add support for packed ring in async vhost
In reply to Cheng JiangFor now async vhost data path only supports split ring structure. In order to make async vhost compatible with virtio 1.1 spec this patch set cleans async split ring codes and enables packed ring in async vhost data path. Batch datapath is also enabled in packed ring.
v4:
* change the patch structure
* clean code for async split ring
* reuse some code from split ring
* change the error handler for DMA-copy packet
* add check for malloc
* remove useless code
* add doc update
v3:
* fix error handler for DMA-copy packet
v2:
* fix wrong buffer index in rte_vhost_poll_enqueue_completed()
* add async_buffers_packed memory free in vhost_free_async_mem()
Cheng Jiang (4):
vhost: abstract and reorganize async split ring code
vhost: add support for packed ring in async vhost
vhost: add batch datapath for async vhost packed ring
doc: add release note for vhost async packed ring
doc/guides/rel_notes/release_21_05.rst | 4 + lib/librte_vhost/rte_vhost_async.h | 1 + lib/librte_vhost/vhost.c | 27 +- lib/librte_vhost/vhost.h | 7 +- lib/librte_vhost/virtio_net.c | 603 ++++++++++++++++++++++--- 5 files changed, 560 insertions(+), 82 deletions(-)
--
2.29.2
PATCH v4 1/4 vhost: abstract and reorganize async split ring code
In order to improve code efficiency and readability when async packed ring support is enabled. This patch abstract some functions like shadow_ring_store and write_back_completed_descs_split. And improve the efficiency of some pointer offset calculation.
--- lib/librte_vhost/virtio_net.c | 146 +++++++++++++++++++--------------- 1 file changed, 84 insertions(+), 62 deletions(-)
lib/librte_vhost/virtio_net.c +84 -62
@@ -1458,6 +1458,29 @@ virtio_dev_rx_async_get_info_idx(uint16_t pkts_idx, (vq_size - n_inflight + pkts_idx) & (vq_size -1 ); } +static __rte_always_inline void +shadow_ring_store (struct vhost_virtqueue *vq,void *shadow_ring,void *d_ring, +uint16_t s_idx,uint16_t d_idx, +uint16_t count,uint16_t elem_size) +{ +if (s_idx + count <= vq->size) { +rte_memcpy ((void *)((uintptr_t )d_ring + d_idx * elem_size), + (void *)((uintptr_t )shadow_ring + s_idx * elem_size), + count * elem_size); + }else { +uint16_t size = vq->size - d_idx; + +rte_memcpy ((void *)((uintptr_t )d_ring + d_idx * elem_size), + (void *)((uintptr_t )shadow_ring + s_idx * elem_size), + size * elem_size); + +rte_memcpy ((void *)((uintptr_t )d_ring), + (void *)((uintptr_t )shadow_ring + + (s_idx + size) * elem_size), + (count - size) * elem_size); + } +} + static __rte_noinline uint32_t virtio_dev_rx_async_submit_split(struct virtio_net *dev, struct vhost_virtqueue *vq, uint16_t queue_id,
@@ -1478,6 +1501,7 @@ virtio_dev_rx_async_submit_split(struct virtio_net *dev,struct rte_vhost_iov_iter *dst_it = it_pool +1 ;uint16_t slot_idx =0 ;uint16_t segs_await =0 ; +uint16_t iovec_idx =0 , it_idx =0 ;struct async_inflight_info *pkts_info = vq->async_pkts_info;uint32_t n_pkts =0 , pkt_err =0 ;uint32_t num_async_pkts =0 , num_done_pkts =0 ;
@@ -1513,27 +1537,32 @@ virtio_dev_rx_async_submit_split(struct virtio_net *dev,if (async_mbuf_to_desc (dev, vq, pkts[pkt_idx], buf_vec, nr_vec, num_buffers, - src_iovec, dst_iovec, src_it, dst_it) <0 ) { + &src_iovec[iovec_idx], + &dst_iovec[iovec_idx], + &src_it[it_idx], + &dst_it[it_idx]) <0 ) { vq->shadow_used_idx -= num_buffers;break ; } slot_idx = (vq->async_pkts_idx + num_async_pkts) & (vq->size -1 ); -if (src_it->count) { +if (src_it[it_idx].count) {uint16_t from, to; -async_fill_desc (&tdes[pkt_burst_idx++], src_it, dst_it); +async_fill_desc (&tdes[pkt_burst_idx++], + &src_it[it_idx], + &dst_it[it_idx]); pkts_info[slot_idx].descs = num_buffers; pkts_info[slot_idx].mbuf = pkts[pkt_idx]; async_pkts_log[num_async_pkts].pkt_idx = pkt_idx; async_pkts_log[num_async_pkts++].last_avail_idx = vq->last_avail_idx; - src_iovec += src_it->nr_segs; - dst_iovec += dst_it->nr_segs; - src_it +=2 ; - dst_it +=2 ; - segs_await += src_it->nr_segs; + + iovec_idx += src_it[it_idx].nr_segs; + it_idx +=2 ; + + segs_await += src_it[it_idx].nr_segs;/** * recover shadow used ring and keep DMA-occupied
@@ -1541,23 +1570,12 @@ virtio_dev_rx_async_submit_split(struct virtio_net *dev,*/ from = vq->shadow_used_idx - num_buffers; to = vq->async_desc_idx & (vq->size -1 ); -if (num_buffers + to <= vq->size) { -rte_memcpy (&vq->async_descs_split[to], - &vq->shadow_used_split[from], - num_buffers * -sizeof (struct vring_used_elem )); - }else { -int size = vq->size - to; - -rte_memcpy (&vq->async_descs_split[to], - &vq->shadow_used_split[from], - size * -sizeof (struct vring_used_elem )); -rte_memcpy (vq->async_descs_split, - &vq->shadow_used_split[from + - size], (num_buffers - size) * -sizeof (struct vring_used_elem )); - } + +shadow_ring_store (vq, vq->shadow_used_split, + vq->async_descs_split, + from, to, num_buffers, +sizeof (struct vring_used_elem )); + vq->async_desc_idx += num_buffers; vq->shadow_used_idx -= num_buffers; }else
@@ -1575,10 +1593,9 @@ virtio_dev_rx_async_submit_split(struct virtio_net *dev, BUF_VECTOR_MAX))) { n_pkts = vq->async_ops.transfer_data (dev->vid, queue_id, tdes,0 , pkt_burst_idx); - src_iovec = vec_pool; - dst_iovec = vec_pool + (VHOST_MAX_ASYNC_VEC >>1 ); - src_it = it_pool; - dst_it = it_pool +1 ; + iovec_idx =0 ; + it_idx =0 ; + segs_await =0 ; vq->async_pkts_inflight_n += n_pkts;
@@ -1639,6 +1656,43 @@ virtio_dev_rx_async_submit_split(struct virtio_net *dev,return pkt_idx; } +static __rte_always_inline void +write_back_completed_descs_split (struct vhost_virtqueue *vq,uint16_t n_descs) +{ +uint16_t nr_left = n_descs; +uint16_t nr_copy; +uint16_t to, from; + +do { + from = vq->last_async_desc_idx & (vq->size -1 ); + nr_copy = nr_left + from <= vq->size ? nr_left : + vq->size - from; + to = vq->last_used_idx & (vq->size -1 ); + +if (to + nr_copy <= vq->size) { +rte_memcpy (&vq->used->ring[to], + &vq->async_descs_split[from], + nr_copy * +sizeof (struct vring_used_elem )); + }else { +uint16_t size = vq->size - to; + +rte_memcpy (&vq->used->ring[to], + &vq->async_descs_split[from], + size * +sizeof (struct vring_used_elem )); +rte_memcpy (vq->used->ring, + &vq->async_descs_split[from + + size], (nr_copy - size) * +sizeof (struct vring_used_elem )); + } + + vq->last_async_desc_idx += nr_copy; + vq->last_used_idx += nr_copy; + nr_left -= nr_copy; + }while (nr_left >0 ); +} +uint16_t rte_vhost_poll_enqueue_completed (int vid,uint16_t queue_id,struct rte_mbuf **pkts,uint16_t count) {
@@ -1695,39 +1749,7 @@ uint16_t rte_vhost_poll_enqueue_completed(int vid, uint16_t queue_id, vq->async_pkts_inflight_n -= n_pkts_put;if (likely (vq->enabled && vq->access_ok)) { -uint16_t nr_left = n_descs; -uint16_t nr_copy; -uint16_t to; - -/* write back completed descriptors to used ring */ -do { - from = vq->last_async_desc_idx & (vq->size -1 ); - nr_copy = nr_left + from <= vq->size ? nr_left : - vq->size - from; - to = vq->last_used_idx & (vq->size -1 ); - -if (to + nr_copy <= vq->size) { -rte_memcpy (&vq->used->ring[to], - &vq->async_descs_split[from], - nr_copy * -sizeof (struct vring_used_elem )); - }else { -uint16_t size = vq->size - to; - -rte_memcpy (&vq->used->ring[to], - &vq->async_descs_split[from], - size * -sizeof (struct vring_used_elem )); -rte_memcpy (vq->used->ring, - &vq->async_descs_split[from + - size], (nr_copy - size) * -sizeof (struct vring_used_elem )); - } - - vq->last_async_desc_idx += nr_copy; - vq->last_used_idx += nr_copy; - nr_left -= nr_copy; - }while (nr_left >0 ); +write_back_completed_descs_split (vq, n_descs);__atomic_add_fetch (&vq->used->idx, n_descs, __ATOMIC_RELEASE);vhost_vring_call_split (dev, vq);
Signature · 1 line
2.29.2
PATCH v4 1/4 vhost: abstract and reorganize async split ring code
In reply to Cheng JiangIn order to improve code efficiency and readability when async packed ring support is enabled. This patch abstract some functions like shadow_ring_store and write_back_completed_descs_split. And improve the efficiency of some pointer offset calculation.
--- lib/librte_vhost/virtio_net.c | 146 +++++++++++++++++++--------------- 1 file changed, 84 insertions(+), 62 deletions(-)
lib/librte_vhost/virtio_net.c +84 -62
@@ -1458,6 +1458,29 @@ virtio_dev_rx_async_get_info_idx(uint16_t pkts_idx, (vq_size - n_inflight + pkts_idx) & (vq_size -1 ); } +static __rte_always_inline void +shadow_ring_store (struct vhost_virtqueue *vq,void *shadow_ring,void *d_ring, +uint16_t s_idx,uint16_t d_idx, +uint16_t count,uint16_t elem_size) +{ +if (s_idx + count <= vq->size) { +rte_memcpy ((void *)((uintptr_t )d_ring + d_idx * elem_size), + (void *)((uintptr_t )shadow_ring + s_idx * elem_size), + count * elem_size); + }else { +uint16_t size = vq->size - d_idx; + +rte_memcpy ((void *)((uintptr_t )d_ring + d_idx * elem_size), + (void *)((uintptr_t )shadow_ring + s_idx * elem_size), + size * elem_size); + +rte_memcpy ((void *)((uintptr_t )d_ring), + (void *)((uintptr_t )shadow_ring + + (s_idx + size) * elem_size), + (count - size) * elem_size); + } +} + static __rte_noinline uint32_t virtio_dev_rx_async_submit_split(struct virtio_net *dev, struct vhost_virtqueue *vq, uint16_t queue_id,
@@ -1478,6 +1501,7 @@ virtio_dev_rx_async_submit_split(struct virtio_net *dev,struct rte_vhost_iov_iter *dst_it = it_pool +1 ;uint16_t slot_idx =0 ;uint16_t segs_await =0 ; +uint16_t iovec_idx =0 , it_idx =0 ;struct async_inflight_info *pkts_info = vq->async_pkts_info;uint32_t n_pkts =0 , pkt_err =0 ;uint32_t num_async_pkts =0 , num_done_pkts =0 ;
@@ -1513,27 +1537,32 @@ virtio_dev_rx_async_submit_split(struct virtio_net *dev,if (async_mbuf_to_desc (dev, vq, pkts[pkt_idx], buf_vec, nr_vec, num_buffers, - src_iovec, dst_iovec, src_it, dst_it) <0 ) { + &src_iovec[iovec_idx], + &dst_iovec[iovec_idx], + &src_it[it_idx], + &dst_it[it_idx]) <0 ) { vq->shadow_used_idx -= num_buffers;break ; } slot_idx = (vq->async_pkts_idx + num_async_pkts) & (vq->size -1 ); -if (src_it->count) { +if (src_it[it_idx].count) {uint16_t from, to; -async_fill_desc (&tdes[pkt_burst_idx++], src_it, dst_it); +async_fill_desc (&tdes[pkt_burst_idx++], + &src_it[it_idx], + &dst_it[it_idx]); pkts_info[slot_idx].descs = num_buffers; pkts_info[slot_idx].mbuf = pkts[pkt_idx]; async_pkts_log[num_async_pkts].pkt_idx = pkt_idx; async_pkts_log[num_async_pkts++].last_avail_idx = vq->last_avail_idx; - src_iovec += src_it->nr_segs; - dst_iovec += dst_it->nr_segs; - src_it +=2 ; - dst_it +=2 ; - segs_await += src_it->nr_segs; + + iovec_idx += src_it[it_idx].nr_segs; + it_idx +=2 ; + + segs_await += src_it[it_idx].nr_segs;/** * recover shadow used ring and keep DMA-occupied
@@ -1541,23 +1570,12 @@ virtio_dev_rx_async_submit_split(struct virtio_net *dev,*/ from = vq->shadow_used_idx - num_buffers; to = vq->async_desc_idx & (vq->size -1 ); -if (num_buffers + to <= vq->size) { -rte_memcpy (&vq->async_descs_split[to], - &vq->shadow_used_split[from], - num_buffers * -sizeof (struct vring_used_elem )); - }else { -int size = vq->size - to; - -rte_memcpy (&vq->async_descs_split[to], - &vq->shadow_used_split[from], - size * -sizeof (struct vring_used_elem )); -rte_memcpy (vq->async_descs_split, - &vq->shadow_used_split[from + - size], (num_buffers - size) * -sizeof (struct vring_used_elem )); - } + +shadow_ring_store (vq, vq->shadow_used_split, + vq->async_descs_split, + from, to, num_buffers, +sizeof (struct vring_used_elem )); + vq->async_desc_idx += num_buffers; vq->shadow_used_idx -= num_buffers; }else
@@ -1575,10 +1593,9 @@ virtio_dev_rx_async_submit_split(struct virtio_net *dev, BUF_VECTOR_MAX))) { n_pkts = vq->async_ops.transfer_data (dev->vid, queue_id, tdes,0 , pkt_burst_idx); - src_iovec = vec_pool; - dst_iovec = vec_pool + (VHOST_MAX_ASYNC_VEC >>1 ); - src_it = it_pool; - dst_it = it_pool +1 ; + iovec_idx =0 ; + it_idx =0 ; + segs_await =0 ; vq->async_pkts_inflight_n += n_pkts;
@@ -1639,6 +1656,43 @@ virtio_dev_rx_async_submit_split(struct virtio_net *dev,return pkt_idx; } +static __rte_always_inline void +write_back_completed_descs_split (struct vhost_virtqueue *vq,uint16_t n_descs) +{ +uint16_t nr_left = n_descs; +uint16_t nr_copy; +uint16_t to, from; + +do { + from = vq->last_async_desc_idx & (vq->size -1 ); + nr_copy = nr_left + from <= vq->size ? nr_left : + vq->size - from; + to = vq->last_used_idx & (vq->size -1 ); + +if (to + nr_copy <= vq->size) { +rte_memcpy (&vq->used->ring[to], + &vq->async_descs_split[from], + nr_copy * +sizeof (struct vring_used_elem )); + }else { +uint16_t size = vq->size - to; + +rte_memcpy (&vq->used->ring[to], + &vq->async_descs_split[from], + size * +sizeof (struct vring_used_elem )); +rte_memcpy (vq->used->ring, + &vq->async_descs_split[from + + size], (nr_copy - size) * +sizeof (struct vring_used_elem )); + } + + vq->last_async_desc_idx += nr_copy; + vq->last_used_idx += nr_copy; + nr_left -= nr_copy; + }while (nr_left >0 ); +} +uint16_t rte_vhost_poll_enqueue_completed (int vid,uint16_t queue_id,struct rte_mbuf **pkts,uint16_t count) {
@@ -1695,39 +1749,7 @@ uint16_t rte_vhost_poll_enqueue_completed(int vid, uint16_t queue_id, vq->async_pkts_inflight_n -= n_pkts_put;if (likely (vq->enabled && vq->access_ok)) { -uint16_t nr_left = n_descs; -uint16_t nr_copy; -uint16_t to; - -/* write back completed descriptors to used ring */ -do { - from = vq->last_async_desc_idx & (vq->size -1 ); - nr_copy = nr_left + from <= vq->size ? nr_left : - vq->size - from; - to = vq->last_used_idx & (vq->size -1 ); - -if (to + nr_copy <= vq->size) { -rte_memcpy (&vq->used->ring[to], - &vq->async_descs_split[from], - nr_copy * -sizeof (struct vring_used_elem )); - }else { -uint16_t size = vq->size - to; - -rte_memcpy (&vq->used->ring[to], - &vq->async_descs_split[from], - size * -sizeof (struct vring_used_elem )); -rte_memcpy (vq->used->ring, - &vq->async_descs_split[from + - size], (nr_copy - size) * -sizeof (struct vring_used_elem )); - } - - vq->last_async_desc_idx += nr_copy; - vq->last_used_idx += nr_copy; - nr_left -= nr_copy; - }while (nr_left >0 ); +write_back_completed_descs_split (vq, n_descs);__atomic_add_fetch (&vq->used->idx, n_descs, __ATOMIC_RELEASE);vhost_vring_call_split (dev, vq);
Signature · 1 line
2.29.2
PATCH v4 2/4 vhost: add support for packed ring in async vhost
In reply to Cheng JiangFor now async vhost data path only supports split ring structure. In order to make async vhost compatible with virtio 1.1 spec this patch enables packed ring in async vhost data path.
--- lib/librte_vhost/rte_vhost_async.h | 1 + lib/librte_vhost/vhost.c | 27 +- lib/librte_vhost/vhost.h | 7 +- lib/librte_vhost/virtio_net.c | 428 ++++++++++++++++++++++++++++- 4 files changed, 441 insertions(+), 22 deletions(-)
lib/librte_vhost/rte_vhost_async.h +1 -0
@@ -89,6 +89,7 @@ struct rte_vhost_async_channel_ops {struct async_inflight_info {struct rte_mbuf *mbuf;uint16_t descs;/* num of descs inflight */ +uint16_t nr_buffers;/* num of buffers inflight for packed ring */ };/**
lib/librte_vhost/vhost.c +20 -7
@@ -342,15 +342,21 @@ vhost_free_async_mem(struct vhost_virtqueue *vq) {if (vq->async_pkts_info)rte_free (vq->async_pkts_info); -if (vq->async_descs_split) +if (vq->async_buffers_packed) { +rte_free (vq->async_buffers_packed); + vq->async_buffers_packed =NULL ; + } +if (vq->async_descs_split) {rte_free (vq->async_descs_split); + vq->async_descs_split =NULL ; + } +if (vq->it_pool)rte_free (vq->it_pool);if (vq->vec_pool)rte_free (vq->vec_pool); vq->async_pkts_info =NULL ; - vq->async_descs_split =NULL ; vq->it_pool =NULL ; vq->vec_pool =NULL ; }
@@ -1627,9 +1633,9 @@ int rte_vhost_async_channel_register(int vid, uint16_t queue_id,return -1 ;/* packed queue is not supported */ -if (unlikely (vq_is_packed (dev) || !f.async_inorder)) { +if (unlikely (!f.async_inorder)) {VHOST_LOG_CONFIG (ERR , -"async copy is not supported on packed queue or non-inorder mode " +"async copy is not supported on non-inorder mode " "(vid %d, qid: %d)\n" , vid, queue_id);return -1 ; }
@@ -1667,11 +1673,18 @@ int rte_vhost_async_channel_register(int vid, uint16_t queue_id, vq->vec_pool =rte_malloc_socket (NULL ,VHOST_MAX_ASYNC_VEC *sizeof (struct iovec ),RTE_CACHE_LINE_SIZE , node); - vq->async_descs_split =rte_malloc_socket (NULL , +if (vq_is_packed (dev)) { + vq->async_buffers_packed =rte_malloc_socket (NULL , + vq->size *sizeof (struct vring_used_elem_packed ), +RTE_CACHE_LINE_SIZE , node); + }else { + vq->async_descs_split =rte_malloc_socket (NULL , vq->size *sizeof (struct vring_used_elem ),RTE_CACHE_LINE_SIZE , node); -if (!vq->async_descs_split || !vq->async_pkts_info || - !vq->it_pool || !vq->vec_pool) { + } + +if (!vq->async_buffers_packed || !vq->async_descs_split || + !vq->async_pkts_info || !vq->it_pool || !vq->vec_pool) {vhost_free_async_mem (vq);VHOST_LOG_CONFIG (ERR , "async register failed: cannot allocate memory for vq data "
lib/librte_vhost/vhost.h +6 -1
@@ -201,9 +201,14 @@ struct vhost_virtqueue {uint16_t async_pkts_idx;uint16_t async_pkts_inflight_n;uint16_t async_last_pkts_n; -struct vring_used_elem *async_descs_split; +union { +struct vring_used_elem *async_descs_split; +struct vring_used_elem_packed *async_buffers_packed; + };uint16_t async_desc_idx; +uint16_t async_packed_buffer_idx;uint16_t last_async_desc_idx; +uint16_t last_async_buffer_idx;/* vq async features */ bool async_inorder;
lib/librte_vhost/virtio_net.c +414 -14
482 lines not on this page · raw message
Signature · 1 line
2.29.2
PATCH v4 3/4 vhost: add batch datapath for async vhost packed ring
In reply to Cheng JiangAdd batch datapath for async vhost packed ring to improve the performance of small packet.
--- lib/librte_vhost/virtio_net.c | 43 +++++++++++++++++++++++++++++++---- 1 file changed, 38 insertions(+), 5 deletions(-)
lib/librte_vhost/virtio_net.c +38 -5
@@ -1721,6 +1721,29 @@ virtio_dev_rx_async_submit_split(struct virtio_net *dev,return pkt_idx; } +static __rte_always_inline int +virtio_dev_rx_async_batch_packed (struct virtio_net *dev, +struct vhost_virtqueue *vq, +struct rte_mbuf **pkts, +struct rte_mbuf **comp_pkts,uint32_t *pkt_done) +{ +uint16_t i; +uint32_t cpy_threshold = vq->async_threshold; + +vhost_for_each_try_unroll (i,0 ,PACKED_BATCH_SIZE ) { +if (unlikely (pkts[i]->pkt_len >= cpy_threshold)) +return -1 ; + } +if (!virtio_dev_rx_batch_packed (dev, vq, pkts)) { +vhost_for_each_try_unroll (i,0 ,PACKED_BATCH_SIZE ) + comp_pkts[(*pkt_done)++] = pkts[i]; + +return 0 ; + } + +return -1 ; +} + static __rte_always_inline int vhost_enqueue_async_single_packed(struct virtio_net *dev, struct vhost_virtqueue *vq,
@@ -1844,6 +1867,7 @@ virtio_dev_rx_async_submit_packed(struct virtio_net *dev, struct rte_mbuf **comp_pkts, uint32_t *comp_count) { uint32_t pkt_idx = 0, pkt_burst_idx = 0; +uint32_t remained = count;uint16_t async_descs_idx =0 ;uint16_t num_buffers;uint16_t num_desc;
@@ -1863,9 +1887,17 @@ virtio_dev_rx_async_submit_packed(struct virtio_net *dev,uint32_t num_async_pkts =0 , num_done_pkts =0 ;struct vring_packed_desc async_descs[vq->size]; -rte_prefetch0 (&vq->desc_packed[vq->last_avail_idx & (vq->size -1 )]); - -for (pkt_idx =0 ; pkt_idx < count; pkt_idx++) { + do { + rte_prefetch0(&vq->desc_packed[vq->last_avail_idx & + (vq->size - 1)]); + if (remained >= PACKED_BATCH_SIZE) { + if (!virtio_dev_rx_async_batch_packed(dev, vq, + &pkts[pkt_idx], comp_pkts, &num_done_pkts)) { + pkt_idx += PACKED_BATCH_SIZE; + remained -= PACKED_BATCH_SIZE; + continue; + } + } if (unlikely(virtio_dev_rx_async_single_packed(dev, vq, pkts[pkt_idx], &num_desc, &num_buffers,
@@ -1912,6 +1944,8 @@ virtio_dev_rx_async_submit_packed(struct virtio_net *dev, }else comp_pkts[num_done_pkts++] = pkts[pkt_idx]; + pkt_idx++; + remained--;vq_inc_last_avail_packed (vq, num_desc);/*
@@ -1937,13 +1971,12 @@ virtio_dev_rx_async_submit_packed(struct virtio_net *dev,*/ pkt_err = pkt_burst_idx - n_pkts; pkt_burst_idx =0 ; - pkt_idx++;break ; } pkt_burst_idx =0 ; } - } + }while (pkt_idx < count);if (pkt_burst_idx) { n_pkts = vq->async_ops.transfer_data(dev->vid,
Signature · 1 line
2.29.2
PATCH v4 4/4 doc: add release note for vhost async packed ring
In reply to Cheng JiangAdd release note for the support of vhost async packed ring.
--- doc/guides/rel_notes/release_21_05.rst | 4 ++++ 1 file changed, 4 insertions(+)
doc/guides/rel_notes/release_21_05.rst +4 -0
@@ -131,6 +131,10 @@ New Features * Added command to display Rx queue used descriptor count. ``show port (port_id) rxq (queue_id) desc used count`` +* **Added support for vhost async packed ring data path.** + + Added packed ring support for async vhost. + Removed Items -------------
Signature · 1 line
2.29.2
v5 cover add support for packed ring in async vhost
In reply to Cheng JiangFor now async vhost data path only supports split ring structure. In order to make async vhost compatible with virtio 1.1 spec this patch set cleans async split ring codes and enables packed ring in async vhost data path. Batch datapath is also enabled in async vhost packed ring.
v5:
* clean some codes for packed ring datapath
* fix an index error in shadow_ring_store()
v4:
* change the patch structure
* clean code for async split ring
* reuse some code from split ring
* change the error handler for DMA-copy packet
* add check for malloc
* remove useless code
* add doc update
v3:
* fix error handler for DMA-copy packet
v2:
* fix wrong buffer index in rte_vhost_poll_enqueue_completed()
* add async_buffers_packed memory free in vhost_free_async_mem()
Cheng Jiang (4):
vhost: abstract and reorganize async split ring code
vhost: add support for packed ring in async vhost
vhost: add batch datapath for async vhost packed ring
doc: add release note for vhost async packed ring
doc/guides/rel_notes/release_21_05.rst | 4 + lib/librte_vhost/rte_vhost_async.h | 1 + lib/librte_vhost/vhost.c | 27 +- lib/librte_vhost/vhost.h | 7 +- lib/librte_vhost/virtio_net.c | 613 +++++++++++++++++++++---- 5 files changed, 567 insertions(+), 85 deletions(-)
--
2.29.2
PATCH v5 1/4 vhost: abstract and reorganize async split ring code
In order to improve code efficiency and readability when async packed ring support is enabled. This patch abstract some functions like shadow_ring_store and write_back_completed_descs_split. And improve the efficiency of some pointer offset calculation.
--- lib/librte_vhost/virtio_net.c | 146 +++++++++++++++++++--------------- 1 file changed, 84 insertions(+), 62 deletions(-)
lib/librte_vhost/virtio_net.c +84 -62
@@ -1458,6 +1458,29 @@ virtio_dev_rx_async_get_info_idx(uint16_t pkts_idx, (vq_size - n_inflight + pkts_idx) & (vq_size -1 ); } +static __rte_always_inline void +shadow_ring_store (struct vhost_virtqueue *vq,void *shadow_ring,void *d_ring, +uint16_t s_idx,uint16_t d_idx, +uint16_t count,uint16_t elem_size) +{ +if (d_idx + count <= vq->size) { +rte_memcpy ((void *)((uintptr_t )d_ring + d_idx * elem_size), + (void *)((uintptr_t )shadow_ring + s_idx * elem_size), + count * elem_size); + }else { +uint16_t size = vq->size - d_idx; + +rte_memcpy ((void *)((uintptr_t )d_ring + d_idx * elem_size), + (void *)((uintptr_t )shadow_ring + s_idx * elem_size), + size * elem_size); + +rte_memcpy ((void *)((uintptr_t )d_ring), + (void *)((uintptr_t )shadow_ring + + (s_idx + size) * elem_size), + (count - size) * elem_size); + } +} + static __rte_noinline uint32_t virtio_dev_rx_async_submit_split(struct virtio_net *dev, struct vhost_virtqueue *vq, uint16_t queue_id,
@@ -1478,6 +1501,7 @@ virtio_dev_rx_async_submit_split(struct virtio_net *dev,struct rte_vhost_iov_iter *dst_it = it_pool +1 ;uint16_t slot_idx =0 ;uint16_t segs_await =0 ; +uint16_t iovec_idx =0 , it_idx =0 ;struct async_inflight_info *pkts_info = vq->async_pkts_info;uint32_t n_pkts =0 , pkt_err =0 ;uint32_t num_async_pkts =0 , num_done_pkts =0 ;
@@ -1513,27 +1537,32 @@ virtio_dev_rx_async_submit_split(struct virtio_net *dev,if (async_mbuf_to_desc (dev, vq, pkts[pkt_idx], buf_vec, nr_vec, num_buffers, - src_iovec, dst_iovec, src_it, dst_it) <0 ) { + &src_iovec[iovec_idx], + &dst_iovec[iovec_idx], + &src_it[it_idx], + &dst_it[it_idx]) <0 ) { vq->shadow_used_idx -= num_buffers;break ; } slot_idx = (vq->async_pkts_idx + num_async_pkts) & (vq->size -1 ); -if (src_it->count) { +if (src_it[it_idx].count) {uint16_t from, to; -async_fill_desc (&tdes[pkt_burst_idx++], src_it, dst_it); +async_fill_desc (&tdes[pkt_burst_idx++], + &src_it[it_idx], + &dst_it[it_idx]); pkts_info[slot_idx].descs = num_buffers; pkts_info[slot_idx].mbuf = pkts[pkt_idx]; async_pkts_log[num_async_pkts].pkt_idx = pkt_idx; async_pkts_log[num_async_pkts++].last_avail_idx = vq->last_avail_idx; - src_iovec += src_it->nr_segs; - dst_iovec += dst_it->nr_segs; - src_it +=2 ; - dst_it +=2 ; - segs_await += src_it->nr_segs; + + iovec_idx += src_it[it_idx].nr_segs; + it_idx +=2 ; + + segs_await += src_it[it_idx].nr_segs;/** * recover shadow used ring and keep DMA-occupied
@@ -1541,23 +1570,12 @@ virtio_dev_rx_async_submit_split(struct virtio_net *dev,*/ from = vq->shadow_used_idx - num_buffers; to = vq->async_desc_idx & (vq->size -1 ); -if (num_buffers + to <= vq->size) { -rte_memcpy (&vq->async_descs_split[to], - &vq->shadow_used_split[from], - num_buffers * -sizeof (struct vring_used_elem )); - }else { -int size = vq->size - to; - -rte_memcpy (&vq->async_descs_split[to], - &vq->shadow_used_split[from], - size * -sizeof (struct vring_used_elem )); -rte_memcpy (vq->async_descs_split, - &vq->shadow_used_split[from + - size], (num_buffers - size) * -sizeof (struct vring_used_elem )); - } + +shadow_ring_store (vq, vq->shadow_used_split, + vq->async_descs_split, + from, to, num_buffers, +sizeof (struct vring_used_elem )); + vq->async_desc_idx += num_buffers; vq->shadow_used_idx -= num_buffers; }else
@@ -1575,10 +1593,9 @@ virtio_dev_rx_async_submit_split(struct virtio_net *dev, BUF_VECTOR_MAX))) { n_pkts = vq->async_ops.transfer_data (dev->vid, queue_id, tdes,0 , pkt_burst_idx); - src_iovec = vec_pool; - dst_iovec = vec_pool + (VHOST_MAX_ASYNC_VEC >>1 ); - src_it = it_pool; - dst_it = it_pool +1 ; + iovec_idx =0 ; + it_idx =0 ; + segs_await =0 ; vq->async_pkts_inflight_n += n_pkts;
@@ -1639,6 +1656,43 @@ virtio_dev_rx_async_submit_split(struct virtio_net *dev,return pkt_idx; } +static __rte_always_inline void +write_back_completed_descs_split (struct vhost_virtqueue *vq,uint16_t n_descs) +{ +uint16_t nr_left = n_descs; +uint16_t nr_copy; +uint16_t to, from; + +do { + from = vq->last_async_desc_idx & (vq->size -1 ); + nr_copy = nr_left + from <= vq->size ? nr_left : + vq->size - from; + to = vq->last_used_idx & (vq->size -1 ); + +if (to + nr_copy <= vq->size) { +rte_memcpy (&vq->used->ring[to], + &vq->async_descs_split[from], + nr_copy * +sizeof (struct vring_used_elem )); + }else { +uint16_t size = vq->size - to; + +rte_memcpy (&vq->used->ring[to], + &vq->async_descs_split[from], + size * +sizeof (struct vring_used_elem )); +rte_memcpy (vq->used->ring, + &vq->async_descs_split[from + + size], (nr_copy - size) * +sizeof (struct vring_used_elem )); + } + + vq->last_async_desc_idx += nr_copy; + vq->last_used_idx += nr_copy; + nr_left -= nr_copy; + }while (nr_left >0 ); +} +uint16_t rte_vhost_poll_enqueue_completed (int vid,uint16_t queue_id,struct rte_mbuf **pkts,uint16_t count) {
@@ -1695,39 +1749,7 @@ uint16_t rte_vhost_poll_enqueue_completed(int vid, uint16_t queue_id, vq->async_pkts_inflight_n -= n_pkts_put;if (likely (vq->enabled && vq->access_ok)) { -uint16_t nr_left = n_descs; -uint16_t nr_copy; -uint16_t to; - -/* write back completed descriptors to used ring */ -do { - from = vq->last_async_desc_idx & (vq->size -1 ); - nr_copy = nr_left + from <= vq->size ? nr_left : - vq->size - from; - to = vq->last_used_idx & (vq->size -1 ); - -if (to + nr_copy <= vq->size) { -rte_memcpy (&vq->used->ring[to], - &vq->async_descs_split[from], - nr_copy * -sizeof (struct vring_used_elem )); - }else { -uint16_t size = vq->size - to; - -rte_memcpy (&vq->used->ring[to], - &vq->async_descs_split[from], - size * -sizeof (struct vring_used_elem )); -rte_memcpy (vq->used->ring, - &vq->async_descs_split[from + - size], (nr_copy - size) * -sizeof (struct vring_used_elem )); - } - - vq->last_async_desc_idx += nr_copy; - vq->last_used_idx += nr_copy; - nr_left -= nr_copy; - }while (nr_left >0 ); +write_back_completed_descs_split (vq, n_descs);__atomic_add_fetch (&vq->used->idx, n_descs, __ATOMIC_RELEASE);vhost_vring_call_split (dev, vq);
Signature · 1 line
2.29.2
Re: [dpdk-dev] [PATCH v5 1/4] vhost: abstract and reorganize async split ring code
Hi Cheng,
Some comments inline.
Quoted 9 lines
-----Original Message-----
From: Jiang, Cheng1 <[email protected]>
Sent: Monday, April 12, 2021 7:34 PM
To: [email protected]; Xia, Chenbo <[email protected]>
Cc: [email protected]; Hu, Jiayu <[email protected]>; Yang, YvonneX <[email protected]>; Wang, Yinan <[email protected]>; Liu, Yong <[email protected]>; Jiang, Cheng1 <[email protected]>
Subject: [PATCH v5 1/4] vhost: abstract and reorganize async split ring code
Quoted 4 lines
In order to improve code efficiency and readability when async packed ring support is enabled. This patch abstract some functions like
shadow_ring_storeandwrite_back_completed_descs_split. And improve the efficiency of some pointer offset calculation.
Need to improve grammar for commit log, as there is typo and incomplete sentence.
Quoted 52 lines
Signed-off-by Cheng Jiang <[email protected]>--- lib/librte_vhost/virtio_net.c | 146 +++++++++++++++++++--------------- 1 file changed, 84 insertions(+), 62 deletions(-)lib/librte_vhost/virtio_net.c +23
-0@@ -1458,6 +1458,29 @@ virtio_dev_rx_async_get_info_idx(uint16_t pkts_idx, (vq_size - n_inflight + pkts_idx) & (vq_size -1 ); } +static __rte_always_inline void +shadow_ring_store (struct vhost_virtqueue *vq,void *shadow_ring,void *d_ring, +uint16_t s_idx,uint16_t d_idx, +uint16_t count,uint16_t elem_size) +{ +if (d_idx + count <= vq->size) { +rte_memcpy ((void *)((uintptr_t )d_ring + d_idx * elem_size), + (void *)((uintptr_t )shadow_ring + s_idx * elem_size), + count * elem_size); + }else { +uint16_t size = vq->size - d_idx; + +rte_memcpy ((void *)((uintptr_t )d_ring + d_idx * elem_size), + (void *)((uintptr_t )shadow_ring + s_idx * elem_size), + size * elem_size); + +rte_memcpy ((void *)((uintptr_t )d_ring), + (void *)((uintptr_t )shadow_ring + + (s_idx + size) * elem_size), + (count - size) * elem_size); + } +} +static __rte_noinline uint32_tvirtio_dev_rx_async_submit_split(struct
virtio_net*dev,lib/librte_vhost/virtio_net.c +1
-0struct vhost_virtqueue *vq, uint16_t queue_id,@@ -1478,6 +1501,7 @@ virtio_dev_rx_async_submit_split(struct virtio_net *dev, struct rte_vhost_iov_iter *dst_it = it_pool + 1;uint16_t slot_idx =0 ;uint16_t segs_await =0 ; +uint16_t iovec_idx =0 , it_idx =0 ;struct async_inflight_info *pkts_info = vq->async_pkts_info;uint32_t n_pkts =0 , pkt_err =0 ;lib/librte_vhost/virtio_net.c +0
-0uint32_t num_async_pkts =0 , num_done_pkts =0 ;
lib/librte_vhost/virtio_net.c virtio_dev_rx_async_submit_split(struct · line 1544
Quoted 9 lines
lib/librte_vhost/virtio_net.c +4
-1@@ -1513,27 +1537,32 @@ virtio_dev_rx_async_submit_split(struct virtio_net *dev, if (async_mbuf_to_desc(dev, vq, pkts[pkt_idx], buf_vec, nr_vec, num_buffers, - src_iovec, dst_iovec, src_it, dst_it) < 0) { + &src_iovec[iovec_idx], + &dst_iovec[iovec_idx], + &src_it[it_idx], + &dst_it[it_idx]) < 0) {
When use index, it's strange to get src and dst iov_iter from dst_it and src_it respectively, as they are not start addresses of two separated iov_iter arrays but have overlapped elements. IMO, there is no need to use src/dst_it, as they can be simply indexed by it_pool[it_idx] and it_pool[it_idx+1].
Quoted 56 lines
lib/librte_vhost/virtio_net.c +9
-7vq->shadow_used_idx -= num_buffers;break ; } slot_idx = (vq->async_pkts_idx + num_async_pkts) & (vq->size -1 ); -if (src_it->count) { +if (src_it[it_idx].count) {uint16_t from, to; -async_fill_desc (&tdes[pkt_burst_idx++], src_it, dst_it); +async_fill_desc (&tdes[pkt_burst_idx++], + &src_it[it_idx], + &dst_it[it_idx]); pkts_info[slot_idx].descs = num_buffers; pkts_info[slot_idx].mbuf = pkts[pkt_idx]; async_pkts_log[num_async_pkts].pkt_idx = pkt_idx; async_pkts_log[num_async_pkts++].last_avail_idx = vq->last_avail_idx; - src_iovec += src_it->nr_segs; - dst_iovec += dst_it->nr_segs; - src_it +=2 ; - dst_it +=2 ; - segs_await += src_it->nr_segs; + + iovec_idx += src_it[it_idx].nr_segs; + it_idx +=2 ; + + segs_await += src_it[it_idx].nr_segs;/** lib/librte_vhost/virtio_net.c +0
-14* recover shadow used ring and keep DMA-occupied @@ -1541,23 +1570,12 @@ virtio_dev_rx_async_submit_split(structvirtio_net *dev, */ from = vq->shadow_used_idx - num_buffers; to = vq->async_desc_idx & (vq->size -1 ); -if (num_buffers + to <= vq->size) { -rte_memcpy (&vq->async_descs_split[to], - &vq- >shadow_used_split[from], - num_buffers * -sizeof (struct vring_used_elem)); - }else { -int size = vq->size - to; - -rte_memcpy (&vq->async_descs_split[to], - &vq- >shadow_used_split[from], - size * -sizeof (struct vring_used_elem)); - rte_memcpy(vq->async_descs_split, - &vq-Quoted 1 line
shadow_used_split[from +
lib/librte_vhost/virtio_net.c virtio_dev_rx_async_submit_split(struct virtio_net *dev, · line 1577
Quoted 8 lines
lib/librte_vhost/virtio_net.c +5
-3- size], (num_buffers - size) * - sizeof(struct vring_used_elem)); - } + +shadow_ring_store (vq, vq->shadow_used_split, + vq->async_descs_split, + from, to, num_buffers, +sizeof (struct vring_used_elem ));
This function is to store DMA-occupied desc, but " shadow_ring_store" is not a good name for it. In addition, I think there is no need to pass vq as a parameter. What you need is the size of shadow ring and async desc ring.
Thanks,
Jiayu
Quoted 117 lines
lib/librte_vhost/virtio_net.c +4
-4+ vq->async_desc_idx += num_buffers; vq->shadow_used_idx -= num_buffers; }else @@ -1575,10 +1593,9 @@ virtio_dev_rx_async_submit_split(structvirtio_net *dev, BUF_VECTOR_MAX))) { n_pkts = vq->async_ops.transfer_data (dev->vid, queue_id, tdes,0 , pkt_burst_idx); - src_iovec = vec_pool; - dst_iovec = vec_pool + (VHOST_MAX_ASYNC_VEC >> 1); - src_it = it_pool; - dst_it = it_pool +1 ; + iovec_idx =0 ; + it_idx =0 ; + segs_await =0 ;lib/librte_vhost/virtio_net.c +37
-0vq->async_pkts_inflight_n += n_pkts;@@ -1639,6 +1656,43 @@ virtio_dev_rx_async_submit_split(structvirtio_net *dev, return pkt_idx; } +static __rte_always_inline void +write_back_completed_descs_split (struct vhost_virtqueue *vq,uint16_t n_descs) +{ +uint16_t nr_left = n_descs; +uint16_t nr_copy; +uint16_t to, from; + +do { + from = vq->last_async_desc_idx & (vq->size -1 ); + nr_copy = nr_left + from <= vq->size ? nr_left : + vq->size - from; + to = vq->last_used_idx & (vq->size -1 ); + +if (to + nr_copy <= vq->size) { +rte_memcpy (&vq->used->ring[to], + &vq->async_descs_split[from], + nr_copy * +sizeof (struct vring_used_elem )); + }else { +uint16_t size = vq->size - to; + +rte_memcpy (&vq->used->ring[to], + &vq->async_descs_split[from], + size * +sizeof (struct vring_used_elem )); +rte_memcpy (vq->used->ring, + &vq->async_descs_split[from + + size], (nr_copy - size) * +sizeof (struct vring_used_elem )); + } + + vq->last_async_desc_idx += nr_copy; + vq->last_used_idx += nr_copy; + nr_left -= nr_copy; + }while (nr_left >0 ); +} + uint16_t rte_vhost_poll_enqueue_completed(int vid, uint16_t queue_id,lib/librte_vhost/virtio_net.c +0
-23struct rte_mbuf **pkts, uint16_t count) {@@ -1695,39 +1749,7 @@ uint16_t rte_vhost_poll_enqueue_completed(int vid, uint16_t queue_id, vq->async_pkts_inflight_n -= n_pkts_put;if (likely (vq->enabled && vq->access_ok)) { - uint16_t nr_left = n_descs; - uint16_t nr_copy; - uint16_t to; - - /* write back completed descriptors to used ring */ - do { - from = vq->last_async_desc_idx & (vq->size - 1); - nr_copy = nr_left + from <= vq->size ? nr_left : - vq->size - from; - to = vq->last_used_idx & (vq->size - 1); - - if (to + nr_copy <= vq->size) { - rte_memcpy(&vq->used->ring[to], - &vq- >async_descs_split[from], - nr_copy * - sizeof(struct vring_used_elem)); - } else { - uint16_t size = vq->size - to; - - rte_memcpy(&vq->used->ring[to], - &vq- >async_descs_split[from], - size * - sizeof(struct
vring_used_elem));lib/librte_vhost/virtio_net.c +1
-4- rte_memcpy(vq->used->ring, - &vq->async_descs_split[from + - size], (nr_copy - size) * - sizeof(struct
vring_used_elem));lib/librte_vhost/virtio_net.c +1
-6- } - - vq->last_async_desc_idx += nr_copy; - vq->last_used_idx += nr_copy; - nr_left -= nr_copy; - }while (nr_left >0 ); +write_back_completed_descs_split (vq, n_descs); __atomic_add_fetch(&vq->used->idx, n_descs,
__ATOMIC_RELEASE);
vhost_vring_call_split(dev, vq);
--
2.29.2
Re: [dpdk-dev] [PATCH v5 1/4] vhost: abstract and reorganize async split ring code
Hi Jiayu,
Quoted 24 lines
-----Original Message-----
From: Hu, Jiayu <[email protected]>
Sent: Tuesday, April 13, 2021 10:44 AM
To: Jiang, Cheng1 <[email protected]>; [email protected]; Xia, Chenbo <[email protected]>
Cc: [email protected]; Yang, YvonneX <[email protected]>; Wang, Yinan <[email protected]>; Liu, Yong <[email protected]>
Subject: RE: [PATCH v5 1/4] vhost: abstract and reorganize async split ring codeHi Cheng,
Some comments inline.
Quoted 10 lines
-----Original Message-----
From: Jiang, Cheng1 <[email protected]>
Sent: Monday, April 12, 2021 7:34 PM
To: [email protected]; Xia, Chenbo <[email protected]>
Cc: [email protected]; Hu, Jiayu <[email protected]>; Yang, YvonneX <[email protected]>; Wang, Yinan <[email protected]>; Liu, Yong <[email protected]>; Jiang, Cheng1 <[email protected]>
Subject: [PATCH v5 1/4] vhost: abstract and reorganize async split ring code
Quoted 8 lines
Quoted 4 lines
In order to improve code efficiency and readability when async packed ring support is enabled. This patch abstract some functions like
shadow_ring_storeandwrite_back_completed_descs_split. And improve the efficiency of some pointer offset calculation.Need to improve grammar for commit log, as there is typo and incomplete sentence.
Sure, I'll fix it in the next version.
Quoted 47 lines
Quoted 47 lines
Signed-off-by Cheng Jiang <[email protected]>--- lib/librte_vhost/virtio_net.c | 146 +++++++++++++++++++--------------- 1 file changed, 84 insertions(+), 62 deletions(-)(quoted diff) +0
-0
b/lib/librte_vhost/virtio_net.cindexff3987860..c43ab0093100644lib/librte_vhost/virtio_net.c +18
-0@@ -1458,6 +1458,29 @@ virtio_dev_rx_async_get_info_idx(uint16_t pkts_idx, (vq_size - n_inflight + pkts_idx) & (vq_size -1 ); } +static __rte_always_inline void +shadow_ring_store (struct vhost_virtqueue *vq,void *shadow_ring, +void *d_ring, +uint16_t s_idx,uint16_t d_idx, +uint16_t count,uint16_t elem_size) +{ +if (d_idx + count <= vq->size) { +rte_memcpy ((void *)((uintptr_t )d_ring + d_idx * elem_size), (void +*)((uintptr_t )shadow_ring + s_idx * elem_size), count * elem_size); } +else {uint16_t size = vq->size - d_idx; + +rte_memcpy ((void *)((uintptr_t )d_ring + d_idx * elem_size), (void +*)((uintptr_t )shadow_ring + s_idx * elem_size), size * elem_size); + +rte_memcpy ((void *)((uintptr_t )d_ring), (void +*)((uintptr_t )shadow_ring + (s_idx + size) * elem_size), (count - +size) * elem_size); } } + static __rte_noinline uint32_t virtio_dev_rx_async_submit_split(struct virtio_net *dev, struct
vhost_virtqueue*vq,uint16_tqueue_id, @@ -1478,6 +1501,7 @@ virtio_dev_rx_async_submit_split(structvirtio_net*dev, structrte_vhost_iov_iter*dst_it=it_pool+ 1;uint16_tslot_idx= 0;uint16_tsegs_await= 0;
+uint16_tiovec_idx= 0,it_idx= 0;
structasync_inflight_info*pkts_info=vq->async_pkts_info;uint32_tn_pkts= 0,pkt_err= 0;uint32_tnum_async_pkts= 0,num_done_pkts= 0; @@ -1513,27 +1537,32 @@ virtio_dev_rx_async_submit_split(structvirtio_net*dev,
Quoted 11 lines
Quoted 6 lines
if (async_mbuf_to_desc(dev, vq, pkts[pkt_idx],
buf_vec,nr_vec,num_buffers, -src_iovec,dst_iovec,src_it,dst_it) < 0) { +&src_iovec[iovec_idx],
+&dst_iovec[iovec_idx],
+&src_it[it_idx],
+&dst_it[it_idx]) < 0) {When use index, it's strange to get src and dst
iov_iterfromdst_itandsrc_itrespectively, as they are not start addresses of two separatediov_iterarrays but have overlapped elements. IMO, there is no need to use src/dst_it, as they can be simply indexed by it_pool[it_idx] and it_pool[it_idx+1].
Yes, I think it make sense, I'll fix it in the next version.
Quoted 50 lines
Quoted 50 lines
vq->shadow_used_idx-=num_buffers;
break;
}
slot_idx= (vq->async_pkts_idx+num_async_pkts) & (vq->size- 1);lib/librte_vhost/virtio_net.c +4
-2-if (src_it->count) { +if (src_it[it_idx].count) {uint16_t from, to; -async_fill_desc (&tdes[pkt_burst_idx++], src_it, dst_it); +async_fill_desc (&tdes[pkt_burst_idx++], +&src_it[it_idx], +&dst_it[it_idx]); pkts_info[slot_idx].descs = num_buffers; pkts_info[slot_idx].mbuf =pkts[pkt_idx]; async_pkts_log[num_async_pkts].pkt_idx =
pkt_idx; async_pkts_log[num_async_pkts++].last_avail_idx =vq->last_avail_idx;lib/librte_vhost/virtio_net.c +7
-1-src_iovec += src_it->nr_segs; -dst_iovec += dst_it->nr_segs; -src_it += 2; -dst_it += 2; -segs_await += src_it->nr_segs; + +iovec_idx += src_it[it_idx].nr_segs; +it_idx +=2 ; + +segs_await += src_it[it_idx].nr_segs;/** * recover shadow used ring and keep DMA-occupied @@ -1541,23 +1570,12 @@ virtio_dev_rx_async_submit_split(struct
virtio_net*dev,
*/
from =vq->shadow_used_idx-num_buffers; to =vq->async_desc_idx&
(vq->size- 1); -if (num_buffers+ to <=vq->size) { -rte_memcpy(&vq->async_descs_split[to],
-&vq-Quoted 1 line
shadow_used_split[from],
lib/librte_vhost/virtio_net.c +0
-2-num_buffers * -sizeof(struct
vring_used_elem));lib/librte_vhost/virtio_net.c +0
-5-}else { -int size = vq->size - to; - -rte_memcpy(&vq->async_descs_split[to], -&vq-Quoted 1 line
shadow_used_split[from],
lib/librte_vhost/virtio_net.c +0
-2-size * -sizeof(struct
vring_used_elem));
-rte_memcpy(vq->async_descs_split,
-&vq-Quoted 1 line
shadow_used_split[from +
Quoted 12 lines
lib/librte_vhost/virtio_net.c virtio_dev_rx_async_submit_split(struct virtio_net *dev, · line 1577
Quoted 8 lines
lib/librte_vhost/virtio_net.c +5
-3-size], (num_buffers - size) * - sizeof(struct vring_used_elem)); -} + +shadow_ring_store (vq, vq->shadow_used_split, +vq->async_descs_split, +from, to, num_buffers, +sizeof (struct vring_used_elem ));This function is to store DMA-occupied desc, but "
shadow_ring_store" is not a good name for it. In addition, I think there is no need to pass vq as a parameter. What you need is the size of shadow ring and async desc ring.
Ok, I think we can use the name " store_dma_desc_info()".
Thanks a lot.
Cheng
Quoted 114 lines
Thanks,
JiayuQuoted 110 lines
lib/librte_vhost/virtio_net.c +41
-3+ vq->async_desc_idx += num_buffers; vq->shadow_used_idx -= num_buffers; }else @@ -1575,10 +1593,9 @@ virtio_dev_rx_async_submit_split(structvirtio_net *dev, BUF_VECTOR_MAX))) { n_pkts = vq->async_ops.transfer_data (dev->vid, queue_id, tdes,0 , pkt_burst_idx); -src_iovec = vec_pool; -dst_iovec = vec_pool + (VHOST_MAX_ASYNC_VEC >>1 ); -src_it = it_pool; -dst_it = it_pool +1 ; +iovec_idx =0 ; +it_idx =0 ; + segs_await =0 ; vq->async_pkts_inflight_n += n_pkts;@@ -1639,6 +1656,43 @@ virtio_dev_rx_async_submit_split(structvirtio_net *dev, return pkt_idx; } +static __rte_always_inline void +write_back_completed_descs_split (struct vhost_virtqueue *vq,uint16_t n_descs) +{ +uint16_t nr_left = n_descs; +uint16_t nr_copy; +uint16_t to, from; + +do { +from = vq->last_async_desc_idx & (vq->size -1 ); nr_copy = nr_left + +from <= vq->size ? nr_left : +vq->size - from; +to = vq->last_used_idx & (vq->size -1 ); + +if (to + nr_copy <= vq->size) { +rte_memcpy (&vq->used->ring[to], +&vq->async_descs_split[from], +nr_copy * +sizeof (struct vring_used_elem )); +}else { +uint16_t size = vq->size - to; + +rte_memcpy (&vq->used->ring[to], +&vq->async_descs_split[from], +size * +sizeof (struct vring_used_elem )); +rte_memcpy (vq->used->ring, +&vq->async_descs_split[from + +size], (nr_copy - size) * +sizeof (struct vring_used_elem )); +} + +vq->last_async_desc_idx += nr_copy; +vq->last_used_idx += nr_copy; +nr_left -= nr_copy; +}while (nr_left >0 ); +} + uint16_t rte_vhost_poll_enqueue_completed(int vid, uint16_t queue_id,struct
rte_mbuf**pkts,uint16_tcount) { @@ -1695,39 +1749,7 @@uint16_trte_vhost_poll_enqueue_completed(int
vid,uint16_tqueue_id,
vq->async_pkts_inflight_n-=n_pkts_put;if (
likely(vq->enabled && vq->access_ok)) { -uint16_tnr_left=n_descs; -uint16_tnr_copy; -uint16_t to;lib/librte_vhost/virtio_net.c +0
-2- -/* write back completed descriptors to used ring */ -do { -from =
vq->last_async_desc_idx& (vq->size- 1); -nr_copy =nr_left+ from <=vq->size?nr_left:lib/librte_vhost/virtio_net.c +0
-6-vq->size - from; -to = vq->last_used_idx & (vq->size -1 ); - -if (to + nr_copy <= vq->size) { -rte_memcpy(&vq->used->ring[to], -&vq-Quoted 1 line
async_descs_split[from],
lib/librte_vhost/virtio_net.c +0
-2-nr_copy * -sizeof(struct
vring_used_elem));lib/librte_vhost/virtio_net.c +0
-5-}else { -uint16_t size = vq->size - to; - -rte_memcpy(&vq->used->ring[to], -&vq-Quoted 1 line
async_descs_split[from],
lib/librte_vhost/virtio_net.c +0
-2-size * -sizeof(struct
vring_used_elem));lib/librte_vhost/virtio_net.c +1
-4-rte_memcpy(vq->used->ring, -&vq->async_descs_split[from + -size], (nr_copy - size) * -sizeof(struct
vring_used_elem));lib/librte_vhost/virtio_net.c +1
-6-} - -vq->last_async_desc_idx += nr_copy; -vq->last_used_idx += nr_copy; -nr_left -= nr_copy; -}while (nr_left >0 ); +write_back_completed_descs_split (vq, n_descs);__atomic_add_fetch (&vq->used->idx, n_descs, __ATOMIC_RELEASE);
vhost_vring_call_split(dev, vq);
--
2.29.2
Re: [dpdk-dev] [PATCH v5 1/4] vhost: abstract and reorganize async split ring code
In reply to Cheng JiangHi Cheng,
Quoted 110 lines · Cheng Jiang
In order to improve code efficiency and readability when async packed ring support is enabled. This patch abstract some functions like
shadow_ring_storeandwrite_back_completed_descs_split. And improve the efficiency of some pointer offset calculation.Signed-off-by Cheng Jiang <[email protected]>--- lib/librte_vhost/virtio_net.c | 146 +++++++++++++++++++--------------- 1 file changed, 84 insertions(+), 62 deletions(-)lib/librte_vhost/virtio_net.c +37
-21@@ -1458,6 +1458,29 @@ virtio_dev_rx_async_get_info_idx(uint16_t pkts_idx, (vq_size - n_inflight + pkts_idx) & (vq_size -1 ); } +static __rte_always_inline void +shadow_ring_store (struct vhost_virtqueue *vq,void *shadow_ring,void *d_ring, +uint16_t s_idx,uint16_t d_idx, +uint16_t count,uint16_t elem_size) +{ +if (d_idx + count <= vq->size) { +rte_memcpy ((void *)((uintptr_t )d_ring + d_idx * elem_size), + (void *)((uintptr_t )shadow_ring + s_idx * elem_size), + count * elem_size); + }else { +uint16_t size = vq->size - d_idx; + +rte_memcpy ((void *)((uintptr_t )d_ring + d_idx * elem_size), + (void *)((uintptr_t )shadow_ring + s_idx * elem_size), + size * elem_size); + +rte_memcpy ((void *)((uintptr_t )d_ring), + (void *)((uintptr_t )shadow_ring + + (s_idx + size) * elem_size), + (count - size) * elem_size); + } +} + static __rte_noinline uint32_t virtio_dev_rx_async_submit_split(struct virtio_net *dev, struct vhost_virtqueue *vq, uint16_t queue_id,@@ -1478,6 +1501,7 @@ virtio_dev_rx_async_submit_split(struct virtio_net *dev,struct rte_vhost_iov_iter *dst_it = it_pool +1 ;uint16_t slot_idx =0 ;uint16_t segs_await =0 ; +uint16_t iovec_idx =0 , it_idx =0 ;struct async_inflight_info *pkts_info = vq->async_pkts_info;uint32_t n_pkts =0 , pkt_err =0 ;uint32_t num_async_pkts =0 , num_done_pkts =0 ;@@ -1513,27 +1537,32 @@ virtio_dev_rx_async_submit_split(struct virtio_net *dev,if (async_mbuf_to_desc (dev, vq, pkts[pkt_idx], buf_vec, nr_vec, num_buffers, - src_iovec, dst_iovec, src_it, dst_it) <0 ) { + &src_iovec[iovec_idx], + &dst_iovec[iovec_idx], + &src_it[it_idx], + &dst_it[it_idx]) <0 ) { vq->shadow_used_idx -= num_buffers;break ; } slot_idx = (vq->async_pkts_idx + num_async_pkts) & (vq->size -1 ); -if (src_it->count) { +if (src_it[it_idx].count) {uint16_t from, to; -async_fill_desc (&tdes[pkt_burst_idx++], src_it, dst_it); +async_fill_desc (&tdes[pkt_burst_idx++], + &src_it[it_idx], + &dst_it[it_idx]); pkts_info[slot_idx].descs = num_buffers; pkts_info[slot_idx].mbuf = pkts[pkt_idx]; async_pkts_log[num_async_pkts].pkt_idx = pkt_idx; async_pkts_log[num_async_pkts++].last_avail_idx = vq->last_avail_idx; - src_iovec += src_it->nr_segs; - dst_iovec += dst_it->nr_segs; - src_it +=2 ; - dst_it +=2 ; - segs_await += src_it->nr_segs; + + iovec_idx += src_it[it_idx].nr_segs; + it_idx +=2 ; + + segs_await += src_it[it_idx].nr_segs;/** * recover shadow used ring and keep DMA-occupied @@ -1541,23 +1570,12 @@ virtio_dev_rx_async_submit_split(struct virtio_net *dev,*/ from = vq->shadow_used_idx - num_buffers; to = vq->async_desc_idx & (vq->size -1 ); -if (num_buffers + to <= vq->size) { -rte_memcpy (&vq->async_descs_split[to], - &vq->shadow_used_split[from], - num_buffers * -sizeof (struct vring_used_elem )); - }else { -int size = vq->size - to; - -rte_memcpy (&vq->async_descs_split[to], - &vq->shadow_used_split[from], - size * -sizeof (struct vring_used_elem )); - rte_memcpy(vq->async_descs_split,
lib/librte_vhost/virtio_net.c virtio_dev_rx_async_submit_split(struct virtio_net *dev, · line 1578
Quoted 10 lines
lib/librte_vhost/virtio_net.c +6
-4- &vq->shadow_used_split[from + - size], (num_buffers - size) * - sizeof(struct vring_used_elem)); - } + +shadow_ring_store (vq, vq->shadow_used_split, + vq->async_descs_split, + from, to, num_buffers, +sizeof (struct vring_used_elem )); +
I'm not convinced with this rework.
I think it is good to create a dedicated function for this to simplify this huge virtio_dev_rx_async_submit_split() function. But we should have a dedicated version for split ring. Having a single function for both split and packed ring does not improve readability, and unlikely improve performance.
Quoted 37 lines
lib/librte_vhost/virtio_net.c +19
-4vq->async_desc_idx += num_buffers; vq->shadow_used_idx -= num_buffers; }else @@ -1575,10 +1593,9 @@ virtio_dev_rx_async_submit_split(struct virtio_net *dev, BUF_VECTOR_MAX))) { n_pkts = vq->async_ops.transfer_data (dev->vid, queue_id, tdes,0 , pkt_burst_idx); - src_iovec = vec_pool; - dst_iovec = vec_pool + (VHOST_MAX_ASYNC_VEC >>1 ); - src_it = it_pool; - dst_it = it_pool +1 ; + iovec_idx =0 ; + it_idx =0 ; + segs_await =0 ; vq->async_pkts_inflight_n += n_pkts;@@ -1639,6 +1656,43 @@ virtio_dev_rx_async_submit_split(struct virtio_net *dev,return pkt_idx; } +static __rte_always_inline void +write_back_completed_descs_split(struct vhost_virtqueue *vq, uint16_t n_descs) +{ + uint16_t nr_left = n_descs; + uint16_t nr_copy; + uint16_t to, from; + + do { + from = vq->last_async_desc_idx & (vq->size - 1); + nr_copy = nr_left + from <= vq->size ? nr_left : + vq->size - from; + to = vq->last_used_idx & (vq->size - 1); + + if (to + nr_copy <= vq->size) { + rte_memcpy(&vq->used->ring[to], + &vq->async_descs_split[from],
lib/librte_vhost/virtio_net.c virtio_dev_rx_async_submit_split(struct virtio_net *dev, · line 1684
Quoted 10 lines
lib/librte_vhost/virtio_net.c +10
-0+nr_copy * + sizeof(struct vring_used_elem)); + }else { +uint16_t size = vq->size - to; + +rte_memcpy (&vq->used->ring[to], + &vq->async_descs_split[from], + size * +sizeof (struct vring_used_elem )); + rte_memcpy(vq->used->ring,
&vq->used->ring[0] for consistency
lib/librte_vhost/virtio_net.c virtio_dev_rx_async_submit_split(struct virtio_net *dev, · line 1687
Quoted 3 lines
lib/librte_vhost/virtio_net.c +3
-0+ &vq->async_descs_split[from + + size], (nr_copy - size) * + sizeof(struct vring_used_elem));
Lines can now be up to 100 chars.
Please take the opportunity to indent properly not to have parts of each args being put on the same line. It will help readability.
Quoted 53 lines
lib/librte_vhost/virtio_net.c +9
-33+ } + + vq->last_async_desc_idx += nr_copy; + vq->last_used_idx += nr_copy; + nr_left -= nr_copy; + }while (nr_left >0 ); +} +uint16_t rte_vhost_poll_enqueue_completed (int vid,uint16_t queue_id,struct rte_mbuf **pkts,uint16_t count) {@@ -1695,39 +1749,7 @@ uint16_t rte_vhost_poll_enqueue_completed(int vid, uint16_t queue_id, vq->async_pkts_inflight_n -= n_pkts_put;if (likely (vq->enabled && vq->access_ok)) { -uint16_t nr_left = n_descs; -uint16_t nr_copy; -uint16_t to; - -/* write back completed descriptors to used ring */ -do { - from = vq->last_async_desc_idx & (vq->size -1 ); - nr_copy = nr_left + from <= vq->size ? nr_left : - vq->size - from; - to = vq->last_used_idx & (vq->size -1 ); - -if (to + nr_copy <= vq->size) { -rte_memcpy (&vq->used->ring[to], - &vq->async_descs_split[from], - nr_copy * -sizeof (struct vring_used_elem )); - }else { -uint16_t size = vq->size - to; - -rte_memcpy (&vq->used->ring[to], - &vq->async_descs_split[from], - size * -sizeof (struct vring_used_elem )); -rte_memcpy (vq->used->ring, - &vq->async_descs_split[from + - size], (nr_copy - size) * -sizeof (struct vring_used_elem )); - } - - vq->last_async_desc_idx += nr_copy; - vq->last_used_idx += nr_copy; - nr_left -= nr_copy; - }while (nr_left >0 ); +write_back_completed_descs_split (vq, n_descs);__atomic_add_fetch (&vq->used->idx, n_descs, __ATOMIC_RELEASE);vhost_vring_call_split (dev, vq);
Re: [dpdk-dev] [PATCH v5 1/4] vhost: abstract and reorganize async split ring code
Hi Maxime,
Quoted 147 lines
-----Original Message-----
From: Maxime Coquelin <[email protected]>
Sent: Tuesday, April 13, 2021 3:12 PM
To: Jiang, Cheng1 <[email protected]>; Xia, Chenbo <[email protected]>
Cc: [email protected]; Hu, Jiayu <[email protected]>; Yang, YvonneX <[email protected]>; Wang, Yinan <[email protected]>; Liu, Yong <[email protected]>
Subject: Re: [PATCH v5 1/4] vhost: abstract and reorganize async split ring codeHi Cheng,
lib/librte_vhost/virtio_net.c virtio_dev_rx_async_get_info_idx(uint16_t
Quoted 16 lines · Cheng Jiang
In order to improve code efficiency and readability when async packed ring support is enabled. This patch abstract some functions like
shadow_ring_storeandwrite_back_completed_descs_split. And improve the efficiency of some pointer offset calculation.Signed-off-by Cheng Jiang <[email protected]>--- lib/librte_vhost/virtio_net.c | 146 +++++++++++++++++++--------------- 1 file changed, 84 insertions(+), 62 deletions(-)(quoted diff) +0
-0
b/lib/librte_vhost/virtio_net.cindexff3987860..c43ab0093100644lib/librte_vhost/virtio_net.c +0
-0@@ -1458,6 +1458,29 @@ virtio_dev_rx_async_get_info_idx(uint16_t
pkts_idx,lib/librte_vhost/virtio_net.c virtio_dev_rx_async_get_info_idx(uint16_t pkts_idx,
Quoted 4 lines
lib/librte_vhost/virtio_net.c +2
-0(vq_size - n_inflight + pkts_idx) & (vq_size -1 ); } +static __rte_always_inline void +shadow_ring_store(struct vhost_virtqueue *vq, void *shadow_ring, void
*d_ring,Quoted 13 lines
lib/librte_vhost/virtio_net.c +13
-0+ uint16_t s_idx, uint16_t d_idx, + uint16_t count, uint16_t elem_size) { + if (d_idx + count <= vq->size) { + rte_memcpy((void *)((uintptr_t)d_ring + d_idx * elem_size), + (void *)((uintptr_t)shadow_ring + s_idx * elem_size), +count * elem_size); + } else { +uint16_t size = vq->size - d_idx; + +rte_memcpy ((void *)((uintptr_t )d_ring + d_idx * elem_size), + (void *)((uintptr_t )shadow_ring + s_idx * elem_size), + size * elem_size); +lib/librte_vhost/virtio_net.c virtio_dev_rx_async_get_info_idx(uint16_t pkts_idx,
Quoted 10 lines
lib/librte_vhost/virtio_net.c +7
-0+rte_memcpy ((void *)((uintptr_t )d_ring), + (void *)((uintptr_t )shadow_ring + + (s_idx + size) * elem_size), + (count - size) * elem_size); + } +} + static __rte_noinline uint32_t virtio_dev_rx_async_submit_split(struct virtio_net *dev, struct vhost_virtqueue *vq, uint16_t queue_id, @@ -1478,6 +1501,7@@
lib/librte_vhost/virtio_net.c virtio_dev_rx_async_submit_split(struct virtio_net *dev,
Quoted 8 lines
lib/librte_vhost/virtio_net.c +1
-0virtio_dev_rx_async_submit_split(struct virtio_net *dev, struct rte_vhost_iov_iter *dst_it = it_pool + 1;uint16_t slot_idx =0 ;uint16_t segs_await =0 ; +uint16_t iovec_idx =0 , it_idx =0 ;struct async_inflight_info *pkts_info = vq->async_pkts_info;uint32_t n_pkts =0 , pkt_err =0 ; uint32_t num_async_pkts = 0, num_done_pkts = 0; @@ -1513,27+1537,32
Quoted 10 lines
@@ virtio_dev_rx_async_submit_split(struct
virtio_net*dev,lib/librte_vhost/virtio_net.c +4
-1if (async_mbuf_to_desc (dev, vq, pkts[pkt_idx], buf_vec, nr_vec, num_buffers, - src_iovec, dst_iovec, src_it, dst_it) <0 ) { + &src_iovec[iovec_idx], + &dst_iovec[iovec_idx], + &src_it[it_idx], + &dst_it[it_idx]) <0 ) { vq->shadow_used_idx -= num_buffers;lib/librte_vhost/virtio_net.c virtio_dev_rx_async_submit_split(struct virtio_net *dev,
Quoted 10 lines
lib/librte_vhost/virtio_net.c +1
-2break ; } slot_idx = (vq->async_pkts_idx + num_async_pkts) & (vq->size -1 ); -if (src_it->count) { +if (src_it[it_idx].count) {uint16_t from, to; - async_fill_desc(&tdes[pkt_burst_idx++], src_it,
dst_it);Quoted 11 lines
lib/librte_vhost/virtio_net.c +3
-3+async_fill_desc (&tdes[pkt_burst_idx++], + &src_it[it_idx], + &dst_it[it_idx]); pkts_info[slot_idx].descs = num_buffers; pkts_info[slot_idx].mbuf = pkts[pkt_idx]; async_pkts_log[num_async_pkts].pkt_idx = pkt_idx; async_pkts_log[num_async_pkts++].last_avail_idx = vq->last_avail_idx; - src_iovec += src_it->nr_segs; - dst_iovec += dst_it->nr_segs; - src_it +=2 ;lib/librte_vhost/virtio_net.c virtio_dev_rx_async_submit_split(struct virtio_net *dev, · line 1568
Quoted 10 lines
lib/librte_vhost/virtio_net.c +5
-2- dst_it +=2 ; - segs_await += src_it->nr_segs; + + iovec_idx += src_it[it_idx].nr_segs; + it_idx +=2 ; + + segs_await += src_it[it_idx].nr_segs;/** * recover shadow used ring and keep DMA-occupied @@ -1541,23
lib/librte_vhost/virtio_net.c
Quoted 10 lines
+1570,12 @@ virtio_dev_rx_async_submit_split(struct
virtio_net*dev,lib/librte_vhost/virtio_net.c +0
-3*/ from = vq->shadow_used_idx - num_buffers; to = vq->async_desc_idx & (vq->size -1 ); -if (num_buffers + to <= vq->size) { - rte_memcpy(&vq->async_descs_split[to], - &vq-shadow_used_split[from],
lib/librte_vhost/virtio_net.c +0
-2-num_buffers * - sizeof(struct
vring_used_elem));lib/librte_vhost/virtio_net.c
Quoted 8 lines
lib/librte_vhost/virtio_net.c +0
-5- }else { -int size = vq->size - to; - - rte_memcpy(&vq->async_descs_split[to], - &vq-shadow_used_split[from],
lib/librte_vhost/virtio_net.c +0
-2-size * - sizeof(struct
vring_used_elem));lib/librte_vhost/virtio_net.c virtio_dev_rx_async_submit_split(struct virtio_net *dev, · line 1578
Quoted 12 lines
lib/librte_vhost/virtio_net.c +0
-2- rte_memcpy(vq->async_descs_split, - &vq-shadow_used_split[from +
lib/librte_vhost/virtio_net.c +6
-3- size], (num_buffers - size) * - sizeof(struct vring_used_elem)); - } + +shadow_ring_store (vq, vq->shadow_used_split, + vq->async_descs_split, + from, to, num_buffers, +sizeof (struct vring_used_elem )); +I'm not convinced with this rework.
Quoted 4 lines
I think it is good to create a dedicated function for this to simplify this huge
virtio_dev_rx_async_submit_split()function. But we should have a dedicated version for split ring. Having a single function for both split and packed ring does not improve readability, and unlikely improve performance.
Sure, I'm agree with you. I will use two functions for split and packed separately in the next version.
Quoted 44 lines
lib/librte_vhost/virtio_net.c virtio_dev_rx_async_submit_split(struct
Quoted 5 lines
lib/librte_vhost/virtio_net.c +0
-0vq->async_desc_idx += num_buffers; vq->shadow_used_idx -= num_buffers; }else @@ -1575,10 +1593,9 @@ virtio_dev_rx_async_submit_split(struct
virtio_net*dev,lib/librte_vhost/virtio_net.c virtio_dev_rx_async_submit_split(struct virtio_net *dev,
Quoted 5 lines
lib/librte_vhost/virtio_net.c +0
-2BUF_VECTOR_MAX))) { n_pkts = vq->async_ops.transfer_data (dev->vid, queue_id, tdes,0 , pkt_burst_idx); - src_iovec = vec_pool; - dst_iovec = vec_pool + (VHOST_MAX_ASYNC_VEC >>1);
lib/librte_vhost/virtio_net.c virtio_dev_rx_async_submit_split(struct
Quoted 9 lines
lib/librte_vhost/virtio_net.c +3
-2- src_it = it_pool; - dst_it = it_pool +1 ; + iovec_idx =0 ; + it_idx =0 ; + segs_await =0 ; vq->async_pkts_inflight_n += n_pkts;@@ -1639,6 +1656,43 @@ virtio_dev_rx_async_submit_split(struct
virtio_net*dev,Quoted 22 lines
lib/librte_vhost/virtio_net.c +19
-0return pkt_idx; } +static __rte_always_inline void +write_back_completed_descs_split (struct vhost_virtqueue *vq,uint16_t +n_descs) { +uint16_t nr_left = n_descs; +uint16_t nr_copy; +uint16_t to, from; + + do { + from = vq->last_async_desc_idx & (vq->size - 1); + nr_copy = nr_left + from <= vq->size ? nr_left : + vq->size - from; + to = vq->last_used_idx & (vq->size - 1); + + if (to + nr_copy <= vq->size) { + rte_memcpy(&vq->used->ring[to], + &vq->async_descs_split[from], + nr_copy * + sizeof(struct vring_used_elem)); + } else {
Quoted 8 lines
lib/librte_vhost/virtio_net.c virtio_dev_rx_async_submit_split(struct virtio_net *dev, · line 1684
Quoted 7 lines
lib/librte_vhost/virtio_net.c +7
-0+uint16_t size = vq->size - to; + +rte_memcpy (&vq->used->ring[to], + &vq->async_descs_split[from], + size * +sizeof (struct vring_used_elem )); + rte_memcpy(vq->used->ring,&vq->used->ring[0] for consistency
It will be fixed in the next version.
Quoted 7 lines
lib/librte_vhost/virtio_net.c virtio_dev_rx_async_submit_split(struct virtio_net *dev, · line 1687
Quoted 3 lines
lib/librte_vhost/virtio_net.c +3
-0+ &vq->async_descs_split[from + + size], (nr_copy - size) * + sizeof(struct vring_used_elem));Lines can now be up to 100 chars.
Please take the opportunity to indent properly not to have parts of each args being put on the same line. It will help readability.
Ok, glad to know. I will fix them in the next version.
Thanks a lot.
Cheng
Quoted 61 lines
lib/librte_vhost/virtio_net.c virtio_dev_rx_async_submit_split(struct virtio_net *dev,
Quoted 11 lines
lib/librte_vhost/virtio_net.c +8
-0+ } + + vq->last_async_desc_idx += nr_copy; + vq->last_used_idx += nr_copy; + nr_left -= nr_copy; + }while (nr_left >0 ); +} +uint16_t rte_vhost_poll_enqueue_completed (int vid,uint16_t queue_id, struct rte_mbuf **pkts, uint16_t count) { @@ -1695,39+1749,7 @@
Quoted 19 lines
lib/librte_vhost/virtio_net.c +0
-0uint16_t rte_vhost_poll_enqueue_completed(int vid, uint16_t queue_id,lib/librte_vhost/virtio_net.c +0
-14vq->async_pkts_inflight_n -= n_pkts_put;if (likely (vq->enabled && vq->access_ok)) { - uint16_t nr_left = n_descs; - uint16_t nr_copy; - uint16_t to; - - /* write back completed descriptors to used ring */ - do { - from = vq->last_async_desc_idx & (vq->size - 1); - nr_copy = nr_left + from <= vq->size ? nr_left : - vq->size - from; - to = vq->last_used_idx & (vq->size - 1); - - if (to + nr_copy <= vq->size) { - rte_memcpy(&vq->used->ring[to], - &vq-async_descs_split[from],
lib/librte_vhost/virtio_net.c
Quoted 2 lines
lib/librte_vhost/virtio_net.c +0
-2-nr_copy * - sizeof(struct
vring_used_elem));lib/librte_vhost/virtio_net.c
Quoted 8 lines
lib/librte_vhost/virtio_net.c +0
-5- }else { -uint16_t size = vq->size - to; - - rte_memcpy(&vq->used->ring[to], - &vq-async_descs_split[from],
lib/librte_vhost/virtio_net.c +0
-2-size * - sizeof(struct
vring_used_elem));lib/librte_vhost/virtio_net.c
Quoted 2 lines
lib/librte_vhost/virtio_net.c +0
-2-rte_memcpy (vq->used->ring, - &vq->async_descs_split[from+
lib/librte_vhost/virtio_net.c
Quoted 2 lines
lib/librte_vhost/virtio_net.c +0
-2- size], (nr_copy - size) * - sizeof(struct
vring_used_elem));lib/librte_vhost/virtio_net.c uint16_t rte_vhost_poll_enqueue_completed(int vid, uint16_t queue_id,
Quoted 9 lines
lib/librte_vhost/virtio_net.c +1
-6- } - - vq->last_async_desc_idx += nr_copy; - vq->last_used_idx += nr_copy; - nr_left -= nr_copy; - }while (nr_left >0 ); +write_back_completed_descs_split (vq, n_descs); __atomic_add_fetch(&vq->used->idx, n_descs,
__ATOMIC_RELEASE);Quoted 2 lines
vhost_vring_call_split(dev, vq);
PATCH v5 2/4 vhost: add support for packed ring in async vhost
In reply to Cheng JiangFor now async vhost data path only supports split ring structure. In order to make async vhost compatible with virtio 1.1 spec this patch enables packed ring in async vhost data path.
--- lib/librte_vhost/rte_vhost_async.h | 1 + lib/librte_vhost/vhost.c | 27 +- lib/librte_vhost/vhost.h | 7 +- lib/librte_vhost/virtio_net.c | 438 +++++++++++++++++++++++++++-- 4 files changed, 448 insertions(+), 25 deletions(-)
lib/librte_vhost/rte_vhost_async.h +1 -0
@@ -89,6 +89,7 @@ struct rte_vhost_async_channel_ops {struct async_inflight_info {struct rte_mbuf *mbuf;uint16_t descs;/* num of descs inflight */ +uint16_t nr_buffers;/* num of buffers inflight for packed ring */ };/**
lib/librte_vhost/vhost.c +20 -7
@@ -342,15 +342,21 @@ vhost_free_async_mem(struct vhost_virtqueue *vq) {if (vq->async_pkts_info)rte_free (vq->async_pkts_info); -if (vq->async_descs_split) +if (vq->async_buffers_packed) { +rte_free (vq->async_buffers_packed); + vq->async_buffers_packed =NULL ; + } +if (vq->async_descs_split) {rte_free (vq->async_descs_split); + vq->async_descs_split =NULL ; + } +if (vq->it_pool)rte_free (vq->it_pool);if (vq->vec_pool)rte_free (vq->vec_pool); vq->async_pkts_info =NULL ; - vq->async_descs_split =NULL ; vq->it_pool =NULL ; vq->vec_pool =NULL ; }
@@ -1627,9 +1633,9 @@ int rte_vhost_async_channel_register(int vid, uint16_t queue_id,return -1 ;/* packed queue is not supported */ -if (unlikely (vq_is_packed (dev) || !f.async_inorder)) { +if (unlikely (!f.async_inorder)) {VHOST_LOG_CONFIG (ERR , -"async copy is not supported on packed queue or non-inorder mode " +"async copy is not supported on non-inorder mode " "(vid %d, qid: %d)\n" , vid, queue_id);return -1 ; }
@@ -1667,11 +1673,18 @@ int rte_vhost_async_channel_register(int vid, uint16_t queue_id, vq->vec_pool =rte_malloc_socket (NULL ,VHOST_MAX_ASYNC_VEC *sizeof (struct iovec ),RTE_CACHE_LINE_SIZE , node); - vq->async_descs_split =rte_malloc_socket (NULL , +if (vq_is_packed (dev)) { + vq->async_buffers_packed =rte_malloc_socket (NULL , + vq->size *sizeof (struct vring_used_elem_packed ), +RTE_CACHE_LINE_SIZE , node); + }else { + vq->async_descs_split =rte_malloc_socket (NULL , vq->size *sizeof (struct vring_used_elem ),RTE_CACHE_LINE_SIZE , node); -if (!vq->async_descs_split || !vq->async_pkts_info || - !vq->it_pool || !vq->vec_pool) { + } + +if (!vq->async_buffers_packed || !vq->async_descs_split || + !vq->async_pkts_info || !vq->it_pool || !vq->vec_pool) {vhost_free_async_mem (vq);VHOST_LOG_CONFIG (ERR , "async register failed: cannot allocate memory for vq data "
lib/librte_vhost/vhost.h +6 -1
@@ -201,9 +201,14 @@ struct vhost_virtqueue {uint16_t async_pkts_idx;uint16_t async_pkts_inflight_n;uint16_t async_last_pkts_n; -struct vring_used_elem *async_descs_split; +union { +struct vring_used_elem *async_descs_split; +struct vring_used_elem_packed *async_buffers_packed; + };uint16_t async_desc_idx; +uint16_t async_packed_buffer_idx;uint16_t last_async_desc_idx; +uint16_t last_async_buffer_idx;/* vq async features */ bool async_inorder;
lib/librte_vhost/virtio_net.c +421 -17
495 lines not on this page · raw message
Signature · 1 line
2.29.2
Quoted 29 lines · Cheng Jiang
For now async vhost data path only supports split ring structure. In order to make async vhost compatible with virtio 1.1 spec this patch enables packed ring in async vhost data path.
Signed-off-by Cheng Jiang <[email protected]>--- lib/librte_vhost/rte_vhost_async.h | 1 + lib/librte_vhost/vhost.c | 27 +- lib/librte_vhost/vhost.h | 7 +- lib/librte_vhost/virtio_net.c | 438 +++++++++++++++++++++++++++-- 4 files changed, 448 insertions(+), 25 deletions(-)lib/librte_vhost/rte_vhost_async.h +1
-0@@ -89,6 +89,7 @@ struct rte_vhost_async_channel_ops {struct async_inflight_info {struct rte_mbuf *mbuf;uint16_t descs;/* num of descs inflight */ +uint16_t nr_buffers;/* num of buffers inflight for packed ring */ };/** lib/librte_vhost/vhost.c +0
-0
lib/librte_vhost/vhost.c vhost_free_async_mem(struct vhost_virtqueue *vq) · line 349
Quoted 9 lines
lib/librte_vhost/vhost.c +5
-1@@ -342,15 +342,21 @@ vhost_free_async_mem(struct vhost_virtqueue *vq) {if (vq->async_pkts_info)rte_free (vq->async_pkts_info); -if (vq->async_descs_split) +if (vq->async_buffers_packed) { +rte_free (vq->async_buffers_packed); + vq->async_buffers_packed =NULL ; + } +if (vq->async_descs_split) {
You can remove the check, rte_free is safe with NULL pointers. You can do the same for the other ones in this function.
Quoted 53 lines
lib/librte_vhost/vhost.c +15
-6rte_free (vq->async_descs_split); + vq->async_descs_split =NULL ; + } +if (vq->it_pool)rte_free (vq->it_pool);if (vq->vec_pool)rte_free (vq->vec_pool); vq->async_pkts_info =NULL ; - vq->async_descs_split =NULL ; vq->it_pool =NULL ; vq->vec_pool =NULL ; }@@ -1627,9 +1633,9 @@ int rte_vhost_async_channel_register(int vid, uint16_t queue_id,return -1 ;/* packed queue is not supported */ -if (unlikely (vq_is_packed (dev) || !f.async_inorder)) { +if (unlikely (!f.async_inorder)) {VHOST_LOG_CONFIG (ERR , -"async copy is not supported on packed queue or non-inorder mode " +"async copy is not supported on non-inorder mode " "(vid %d, qid: %d)\n" , vid, queue_id);return -1 ; }@@ -1667,11 +1673,18 @@ int rte_vhost_async_channel_register(int vid, uint16_t queue_id, vq->vec_pool =rte_malloc_socket (NULL ,VHOST_MAX_ASYNC_VEC *sizeof (struct iovec ),RTE_CACHE_LINE_SIZE , node); - vq->async_descs_split =rte_malloc_socket (NULL , +if (vq_is_packed (dev)) { + vq->async_buffers_packed =rte_malloc_socket (NULL , + vq->size *sizeof (struct vring_used_elem_packed ), +RTE_CACHE_LINE_SIZE , node); + }else { + vq->async_descs_split =rte_malloc_socket (NULL , vq->size *sizeof (struct vring_used_elem ),RTE_CACHE_LINE_SIZE , node); -if (!vq->async_descs_split || !vq->async_pkts_info || - !vq->it_pool || !vq->vec_pool) { + } + +if (!vq->async_buffers_packed || !vq->async_descs_split || + !vq->async_pkts_info || !vq->it_pool || !vq->vec_pool) {vhost_free_async_mem (vq);VHOST_LOG_CONFIG (ERR , "async register failed: cannot allocate memory for vq data "lib/librte_vhost/vhost.h +0
-0
lib/librte_vhost/vhost.h struct vhost_virtqueue { · line 209
Quoted 10 lines
lib/librte_vhost/vhost.h +5
-1@@ -201,9 +201,14 @@ struct vhost_virtqueue {uint16_t async_pkts_idx;uint16_t async_pkts_inflight_n;uint16_t async_last_pkts_n; -struct vring_used_elem *async_descs_split; +union { +struct vring_used_elem *async_descs_split; +struct vring_used_elem_packed *async_buffers_packed; + };uint16_t async_desc_idx; +uint16_t async_packed_buffer_idx;
Don't dupplicate variable names, async_desc_idx can be reused for packed ring. Also, they are representing the same thing, why use desc in one case and buffer in the other?
lib/librte_vhost/vhost.h struct vhost_virtqueue { · line 211
Quoted 2 lines
lib/librte_vhost/vhost.h +1
-0uint16_t last_async_desc_idx; +uint16_t last_async_buffer_idx;
Same remark here.
Quoted 45 lines
lib/librte_vhost/vhost.h +0
-0/* vq async features */ bool async_inorder;lib/librte_vhost/virtio_net.c +16
-5@@ -363,14 +363,14 @@ vhost_shadow_dequeue_single_packed_inorder(struct vhost_virtqueue *vq, } static __rte_always_inline void -vhost_shadow_enqueue_single_packed (struct virtio_net *dev, -struct vhost_virtqueue *vq, -uint32_t len[], -uint16_t id[], -uint16_t count[], +vhost_shadow_enqueue_packed (struct vhost_virtqueue *vq, +uint32_t *len, +uint16_t *id, +uint16_t *count,uint16_t num_buffers) {uint16_t i; +for (i =0 ; i < num_buffers; i++) {/* enqueue shadow flush action aligned with batch num */ if (!vq->shadow_used_idx)@@ -382,6 +382,17 @@ vhost_shadow_enqueue_single_packed(struct virtio_net *dev, vq->shadow_aligned_idx += count[i]; vq->shadow_used_idx++; } +} + +static __rte_always_inline void +vhost_shadow_enqueue_single_packed (struct virtio_net *dev, +struct vhost_virtqueue *vq, +uint32_t *len, +uint16_t *id, +uint16_t *count, +uint16_t num_buffers) +{ +vhost_shadow_enqueue_packed (vq, len, id, count, num_buffers);if (vq->shadow_aligned_idx >=PACKED_BATCH_SIZE ) {do_data_copy_enqueue (dev, vq);
lib/librte_vhost/virtio_net.c shadow_ring_store(struct vhost_virtqueue *vq, void *shadow_ring, void *d_ring, · line 1501
Quoted 10 lines
lib/librte_vhost/virtio_net.c +7
-0@@ -1481,6 +1492,62 @@ shadow_ring_store(struct vhost_virtqueue *vq, void *shadow_ring, void *d_ring, } } +static __rte_always_inline void +vhost_update_used_packed (struct vhost_virtqueue *vq, +struct vring_used_elem_packed *shadow_ring, +uint16_t count) +{ +if (count ==0 ) +return ;
Move this after the variables declaration.
Quoted 113 lines
lib/librte_vhost/virtio_net.c +106
-0+ +int i; +uint16_t used_idx = vq->last_used_idx; +uint16_t head_idx = vq->last_used_idx; +uint16_t head_flags =0 ; + +/* Split loop in two to save memory barriers */ +for (i =0 ; i < count; i++) { + vq->desc_packed[used_idx].id = shadow_ring[i].id; + vq->desc_packed[used_idx].len = shadow_ring[i].len; + + used_idx += shadow_ring[i].count; +if (used_idx >= vq->size) + used_idx -= vq->size; + } + +/* The ordering for storing desc flags needs to be enforced. */ +rte_atomic_thread_fence (__ATOMIC_RELEASE); + +for (i =0 ; i < count; i++) { +uint16_t flags; + +if (vq->shadow_used_packed[i].len) + flags =VRING_DESC_F_WRITE ; +else + flags =0 ; + +if (vq->used_wrap_counter) { + flags |=VRING_DESC_F_USED ; + flags |=VRING_DESC_F_AVAIL ; + }else { + flags &= ~VRING_DESC_F_USED ; + flags &= ~VRING_DESC_F_AVAIL ; + } + +if (i >0 ) { + vq->desc_packed[vq->last_used_idx].flags = flags; + + }else { + head_idx = vq->last_used_idx; + head_flags = flags; + } + +vq_inc_last_used_packed (vq, shadow_ring[i].count); + } + + vq->desc_packed[head_idx].flags = head_flags; +} + static __rte_noinline uint32_t virtio_dev_rx_async_submit_split(struct virtio_net *dev, struct vhost_virtqueue *vq, uint16_t queue_id,@@ -1656,6 +1723,294 @@ virtio_dev_rx_async_submit_split(struct virtio_net *dev,return pkt_idx; } +static __rte_always_inline int +vhost_enqueue_async_single_packed (struct virtio_net *dev, +struct vhost_virtqueue *vq, +struct rte_mbuf *pkt, +struct buf_vector *buf_vec, +uint16_t *nr_descs, +uint16_t *nr_buffers, +struct vring_packed_desc *async_descs, +struct iovec *src_iovec,struct iovec *dst_iovec, +struct rte_vhost_iov_iter *src_it, +struct rte_vhost_iov_iter *dst_it) +{ +uint16_t nr_vec =0 ; +uint16_t avail_idx = vq->last_avail_idx; +uint16_t max_tries, tries =0 ; +uint16_t buf_id =0 ; +uint32_t len =0 ; +uint16_t desc_count =0 ; +uint32_t size = pkt->pkt_len +sizeof (struct virtio_net_hdr_mrg_rxbuf ); +uint32_t buffer_len[vq->size]; +uint16_t buffer_buf_id[vq->size]; +uint16_t buffer_desc_count[vq->size]; + *nr_buffers =0 ; + +if (rxvq_is_mergeable (dev)) + max_tries = vq->size -1 ; +else + max_tries =1 ; + +while (size >0 ) { +/* +* if we tried all available ring items, and still +* can't get enough buf, it means something abnormal +* happened. +*/ +if (unlikely (++tries > max_tries)) +return -1 ; + +if (unlikely (fill_vec_buf_packed (dev, vq, + avail_idx, &desc_count, + buf_vec, &nr_vec, + &buf_id, &len, +VHOST_ACCESS_RW ) <0 )) +return -1 ; + + len =RTE_MIN (len, size); + size -= len; + + buffer_len[*nr_buffers] = len; + buffer_buf_id[*nr_buffers] = buf_id; + buffer_desc_count[*nr_buffers] = desc_count; + *nr_buffers +=1 ; + + *nr_descs += desc_count; + avail_idx += desc_count; +if (avail_idx >= vq->size) + avail_idx -= vq->size;
lib/librte_vhost/virtio_net.c virtio_dev_rx_async_submit_split(struct virtio_net *dev, · line 1792
Quoted 10 lines
lib/librte_vhost/virtio_net.c +10
-0+ } + +if (async_mbuf_to_desc (dev, vq, pkt, buf_vec, nr_vec, *nr_buffers, + src_iovec, dst_iovec, src_it, dst_it) <0 ) +return -1 ; +/* store descriptors for DMA */ +if (avail_idx >= *nr_descs) +rte_memcpy (async_descs, + &vq->desc_packed[vq->last_avail_idx], + *nr_descs *sizeof (struct vring_packed_desc ));
Please add brackets for the 'if' since there are for the 'else'.
Quoted 66 lines
lib/librte_vhost/virtio_net.c +66
-0+else { +uint16_t nr_copy = vq->size - vq->last_avail_idx; +rte_memcpy (async_descs, + &vq->desc_packed[vq->last_avail_idx], + nr_copy *sizeof (struct vring_packed_desc )); +rte_memcpy (async_descs + nr_copy, + vq->desc_packed, (*nr_descs - nr_copy) * +sizeof (struct vring_packed_desc )); + } + +vhost_shadow_enqueue_packed (vq, buffer_len, buffer_buf_id, + buffer_desc_count, *nr_buffers); + +return 0 ; +} + +static __rte_always_inline int16_t +virtio_dev_rx_async_single_packed (struct virtio_net *dev, +struct vhost_virtqueue *vq, +struct rte_mbuf *pkt, +uint16_t *nr_descs,uint16_t *nr_buffers, +struct vring_packed_desc *async_descs, +struct iovec *src_iovec,struct iovec *dst_iovec, +struct rte_vhost_iov_iter *src_it, +struct rte_vhost_iov_iter *dst_it) +{ +struct buf_vector buf_vec[BUF_VECTOR_MAX ]; + *nr_descs =0 ; + *nr_buffers =0 ; + +if (unlikely (vhost_enqueue_async_single_packed (dev, vq, pkt, buf_vec, + nr_descs, + nr_buffers, + async_descs, + src_iovec, dst_iovec, + src_it, dst_it) <0 )) { +VHOST_LOG_DATA (DEBUG , +"(%d) failed to get enough desc from vring\n" , + dev->vid); +return -1 ; + } + +VHOST_LOG_DATA (DEBUG ,"(%d) current index %d | end index %d\n" , + dev->vid, vq->last_avail_idx, + vq->last_avail_idx + *nr_descs); + +return 0 ; +} + +static __rte_noinline uint32_t +virtio_dev_rx_async_submit_packed (struct virtio_net *dev, +struct vhost_virtqueue *vq,uint16_t queue_id, +struct rte_mbuf **pkts,uint32_t count, +struct rte_mbuf **comp_pkts,uint32_t *comp_count) +{ +uint32_t pkt_idx =0 , pkt_burst_idx =0 ; +uint16_t async_descs_idx =0 ; +uint16_t num_buffers; +uint16_t num_desc; + +struct rte_vhost_iov_iter *it_pool = vq->it_pool; +struct iovec *vec_pool = vq->vec_pool; +struct rte_vhost_async_desc tdes[MAX_PKT_BURST ]; +struct iovec *src_iovec = vec_pool; +struct iovec *dst_iovec = vec_pool + (VHOST_MAX_ASYNC_VEC >>1 ); +struct rte_vhost_iov_iter *src_it = it_pool;
lib/librte_vhost/virtio_net.c virtio_dev_rx_async_submit_split(struct virtio_net *dev, · line 1868
Quoted 10 lines
lib/librte_vhost/virtio_net.c +10
-0+struct rte_vhost_iov_iter *dst_it = it_pool +1 ; +uint16_t slot_idx =0 ; +uint16_t segs_await =0 ; +uint16_t iovec_idx =0 , it_idx =0 ; +struct async_inflight_info *pkts_info = vq->async_pkts_info; +uint32_t n_pkts =0 , pkt_err =0 ; +uint32_t num_async_pkts =0 , num_done_pkts =0 ; +struct vring_packed_desc async_descs[vq->size]; + +rte_prefetch0 (&vq->desc_packed[vq->last_avail_idx & (vq->size -1 )]);
The size of the ring is not necessarily a power of two with packed ring.
Quoted 8 lines
lib/librte_vhost/virtio_net.c +8
-0+ +for (pkt_idx =0 ; pkt_idx < count; pkt_idx++) { + if (unlikely(virtio_dev_rx_async_single_packed(dev, vq, + pkts[pkt_idx], + &num_desc, &num_buffers, + &async_descs[async_descs_idx], + &src_iovec[iovec_idx], + &dst_iovec[iovec_idx],
lib/librte_vhost/virtio_net.c virtio_dev_rx_async_submit_split(struct virtio_net *dev, · line 1886
Quoted 10 lines
lib/librte_vhost/virtio_net.c +10
-0+ &src_it[it_idx], + &dst_it[it_idx]) < 0)) + break; + +VHOST_LOG_DATA (DEBUG ,"(%d) current index %d | end index %d\n" , + dev->vid, vq->last_avail_idx, + vq->last_avail_idx + num_desc); + + slot_idx = (vq->async_pkts_idx + num_async_pkts) & + (vq->size -1 );
Same here.
Quoted 19 lines
lib/librte_vhost/virtio_net.c +19
-0+if (src_it[it_idx].count) { +uint16_t from, to; + + async_descs_idx += num_desc; +async_fill_desc (&tdes[pkt_burst_idx++], &src_it[it_idx], + &dst_it[it_idx]); + pkts_info[slot_idx].descs = num_desc; + pkts_info[slot_idx].nr_buffers = num_buffers; + pkts_info[slot_idx].mbuf = pkts[pkt_idx]; + num_async_pkts++; + iovec_idx += src_it[it_idx].nr_segs; + it_idx +=2 ; + + segs_await += src_it[it_idx].nr_segs; + +/** +* recover shadow used ring and keep DMA-occupied +* descriptors. +*/
lib/librte_vhost/virtio_net.c virtio_dev_rx_async_submit_split(struct virtio_net *dev, · line 1915
Quoted 10 lines
lib/librte_vhost/virtio_net.c +10
-0+ from = vq->shadow_used_idx - num_buffers; + to = vq->async_packed_buffer_idx & (vq->size -1 ); +shadow_ring_store (vq, vq->shadow_used_packed, + vq->async_buffers_packed, + from, to, num_buffers, +sizeof (struct vring_used_elem_packed )); + + vq->async_packed_buffer_idx += num_buffers; + vq->shadow_used_idx -= num_buffers; + }else
Brackets needed.
Quoted 46 lines
lib/librte_vhost/virtio_net.c +46
-0+ comp_pkts[num_done_pkts++] = pkts[pkt_idx]; + +vq_inc_last_avail_packed (vq, num_desc); + +/* +* conditions to trigger async device transfer: +* - buffered packet number reaches transfer threshold +* - unused async iov number is less than max vhost vector +*/ +if (unlikely (pkt_burst_idx >=VHOST_ASYNC_BATCH_THRESHOLD || + ((VHOST_MAX_ASYNC_VEC >>1 ) - segs_await < +BUF_VECTOR_MAX ))) { + n_pkts = vq->async_ops.transfer_data (dev->vid, + queue_id, tdes,0 , pkt_burst_idx); + iovec_idx =0 ; + it_idx =0 ; + segs_await =0 ; + vq->async_pkts_inflight_n += n_pkts; + +if (unlikely (n_pkts < pkt_burst_idx)) { +/* +* log error packets number here and do actual +* error processing when applications poll +* completion +*/ + pkt_err = pkt_burst_idx - n_pkts; + pkt_burst_idx =0 ; + pkt_idx++; +break ; + } + + pkt_burst_idx =0 ; + } + } + +if (pkt_burst_idx) { + n_pkts = vq->async_ops.transfer_data (dev->vid, + queue_id, tdes,0 , pkt_burst_idx); + vq->async_pkts_inflight_n += n_pkts; + +if (unlikely (n_pkts < pkt_burst_idx)) + pkt_err = pkt_burst_idx - n_pkts; + } + +do_data_copy_enqueue (dev, vq); +
lib/librte_vhost/virtio_net.c virtio_dev_rx_async_submit_split(struct virtio_net *dev, · line 1971
Quoted 10 lines
lib/librte_vhost/virtio_net.c +10
-0+if (unlikely (pkt_err)) { +uint16_t descs_err =0 ; +uint16_t buffers_err =0 ; + + num_async_pkts -= pkt_err; + pkt_idx -= pkt_err; +/* calculate the sum of buffers and descs of DMA-error packets. */ +while (pkt_err-- >0 ) { + descs_err += + pkts_info[slot_idx & (vq->size -1 )].descs;
The size of the ring is not necessarily a power of two with packed ring.
lib/librte_vhost/virtio_net.c virtio_dev_rx_async_submit_split(struct virtio_net *dev, · line 1973
Quoted 2 lines
lib/librte_vhost/virtio_net.c +2
-0+ buffers_err += + pkts_info[slot_idx & (vq->size -1 )].nr_buffers;
Ditto.
Quoted 19 lines
lib/librte_vhost/virtio_net.c +19
-0+ slot_idx--; + } + + vq->async_packed_buffer_idx -= buffers_err; + +if (vq->last_avail_idx >= descs_err) { + vq->last_avail_idx -= descs_err; + +rte_memcpy (&vq->desc_packed[vq->last_avail_idx], + &async_descs[async_descs_idx - descs_err], + descs_err *sizeof (struct vring_packed_desc )); + }else { +uint16_t nr_copy; + + vq->last_avail_idx = vq->last_avail_idx + vq->size + - descs_err; + nr_copy = vq->size - vq->last_avail_idx; + rte_memcpy(&vq->desc_packed[vq->last_avail_idx], + &async_descs[async_descs_idx - descs_err],
lib/librte_vhost/virtio_net.c virtio_dev_rx_async_submit_split(struct virtio_net *dev, · line 2002
Quoted 10 lines
lib/librte_vhost/virtio_net.c +10
-0+ nr_copy * sizeof(struct vring_packed_desc)); + descs_err -= nr_copy; +rte_memcpy (vq->desc_packed, + &async_descs[async_descs_idx - descs_err], + descs_err *sizeof (struct vring_packed_desc )); + vq->avail_wrap_counter ^=1 ; + } + + num_done_pkts = pkt_idx - num_async_pkts; + }
This error handling could be moved in a dedicated function.
lib/librte_vhost/virtio_net.c virtio_dev_rx_async_submit_split(struct virtio_net *dev, · line 2012
Quoted 10 lines
lib/librte_vhost/virtio_net.c +10
-0+ vq->async_pkts_idx += num_async_pkts; + *comp_count = num_done_pkts; + +if (likely (vq->shadow_used_idx)) { +vhost_flush_enqueue_shadow_packed (dev, vq); +vhost_vring_call_packed (dev, vq); + } + +return pkt_idx; +}
Above function is very big and complex, it should be possible to split it in several ones to make it maintainable.
Quoted 9 lines
lib/librte_vhost/virtio_net.c +2
-0+ static __rte_always_inline voidwrite_back_completed_descs_split (struct vhost_virtqueue *vq,uint16_t n_descs) {@@ -1693,12 +2048,40 @@ write_back_completed_descs_split(struct vhost_virtqueue *vq, uint16_t n_descs) }while (nr_left >0 ); } +static __rte_always_inline void
lib/librte_vhost/virtio_net.c write_back_completed_descs_split(struct vhost_virtqueue *vq, uint16_t n_descs) · line 2061
Quoted 10 lines
lib/librte_vhost/virtio_net.c +10
-0+write_back_completed_descs_packed(struct vhost_virtqueue *vq, + uint16_t n_buffers) +{ + uint16_t nr_left = n_buffers; +uint16_t from, to; + + do { + from = vq->last_async_buffer_idx & + (vq->size - 1); + to = (from + nr_left) & (vq->size - 1);
The size of the ring is not necessarily a power of two with packed ring.
Quoted 28 lines
lib/librte_vhost/virtio_net.c +18
-1+if (to > from) { +vhost_update_used_packed (vq, + vq->async_buffers_packed + from, + to - from); + vq->last_async_buffer_idx += nr_left; + nr_left =0 ; + }else { +vhost_update_used_packed (vq, + vq->async_buffers_packed + from, + vq->size - from); + vq->last_async_buffer_idx += + vq->size - from; + nr_left -= vq->size - from; + } + }while (nr_left >0 ); +} +uint16_t rte_vhost_poll_enqueue_completed (int vid,uint16_t queue_id,struct rte_mbuf **pkts,uint16_t count) {struct virtio_net *dev =get_device (vid);struct vhost_virtqueue *vq; -uint16_t n_pkts_cpl =0 , n_pkts_put =0 , n_descs =0 ; +uint16_t n_pkts_cpl =0 , n_pkts_put =0 , n_descs =0 , n_buffers =0 ;uint16_t start_idx, pkts_idx, vq_size;struct async_inflight_info *pkts_info;uint16_t from, i;
lib/librte_vhost/virtio_net.c uint16_t rte_vhost_poll_enqueue_completed(int vid, uint16_t queue_id, · line 2128
Quoted 10 lines
lib/librte_vhost/virtio_net.c +3
-4@@ -1740,21 +2123,41 @@ uint16_t rte_vhost_poll_enqueue_completed(int vid, uint16_t queue_id, goto done; } -for (i =0 ; i < n_pkts_put; i++) { - from = (start_idx + i) & (vq_size -1 ); - n_descs += pkts_info[from].descs; - pkts[i] = pkts_info[from].mbuf; +if (vq_is_packed (dev)) { +for (i =0 ; i < n_pkts_put; i++) { + from = (start_idx + i) & (vq_size -1 );
Unlike split ring, packed ring size is not necessarily a power of 2.
Quoted 54 lines
lib/librte_vhost/virtio_net.c +29
-7+ n_buffers += pkts_info[from].nr_buffers; + pkts[i] = pkts_info[from].mbuf; + } + }else { +for (i =0 ; i < n_pkts_put; i++) { + from = (start_idx + i) & (vq_size -1 ); + n_descs += pkts_info[from].descs; + pkts[i] = pkts_info[from].mbuf; + } } + vq->async_last_pkts_n = n_pkts_cpl - n_pkts_put; vq->async_pkts_inflight_n -= n_pkts_put;if (likely (vq->enabled && vq->access_ok)) { -write_back_completed_descs_split (vq, n_descs); +if (vq_is_packed (dev)) { +write_back_completed_descs_packed (vq, n_buffers); -__atomic_add_fetch (&vq->used->idx, n_descs, __ATOMIC_RELEASE); -vhost_vring_call_split (dev, vq); - }else - vq->last_async_desc_idx += n_descs; +vhost_vring_call_packed (dev, vq); + }else { +write_back_completed_descs_split (vq, n_descs); + +__atomic_add_fetch (&vq->used->idx, n_descs, + __ATOMIC_RELEASE); +vhost_vring_call_split (dev, vq); + } + }else { +if (vq_is_packed (dev)) + vq->last_async_buffer_idx += n_buffers; +else + vq->last_async_desc_idx += n_descs; + } done:rte_spinlock_unlock (&vq->access_lock);@@ -1795,9 +2198,10 @@ virtio_dev_rx_async_submit(struct virtio_net *dev, uint16_t queue_id,if (count ==0 ) goto out; -/* TODO: packed queue not implemented */ if (vq_is_packed (dev)) - nb_tx =0 ; + nb_tx =virtio_dev_rx_async_submit_packed (dev, + vq, queue_id, pkts, count, comp_pkts, + comp_count);else nb_tx = virtio_dev_rx_async_submit_split(dev, vq, queue_id, pkts, count, comp_pkts,
Hi Maxime,
Quoted 44 lines
-----Original Message-----
From: Maxime Coquelin <[email protected]>
Sent: Tuesday, April 13, 2021 4:37 PM
To: Jiang, Cheng1 <[email protected]>; Xia, Chenbo <[email protected]>
Cc: [email protected]; Hu, Jiayu <[email protected]>; Yang, YvonneX <[email protected]>; Wang, Yinan <[email protected]>; Liu, Yong <[email protected]>
Subject: Re: [PATCH v5 2/4] vhost: add support for packed ring in async vhostlib/librte_vhost/vhost.c vhost_free_async_mem(struct vhost_virtqueue
Quoted 30 lines · Cheng Jiang
For now async vhost data path only supports split ring structure. In order to make async vhost compatible with virtio 1.1 spec this patch enables packed ring in async vhost data path.
Signed-off-by Cheng Jiang <[email protected]>--- lib/librte_vhost/rte_vhost_async.h | 1 + lib/librte_vhost/vhost.c | 27 +- lib/librte_vhost/vhost.h | 7 +- lib/librte_vhost/virtio_net.c | 438 +++++++++++++++++++++++++++-- 4 files changed, 448 insertions(+), 25 deletions(-)lib/librte_vhost/rte_vhost_async.h +1
-0@@ -89,6 +89,7 @@ struct rte_vhost_async_channel_ops { struct async_inflight_info {struct rte_mbuf *mbuf;uint16_t descs;/* num of descs inflight */ +uint16_t nr_buffers;/* num of buffers inflight for packed ring */ };/** lib/librte_vhost/vhost.c index renamed from lib/librte_vhost/vhost.c +0
-0
a70fe01d8..8c9935c0f100644lib/librte_vhost/vhost.c +0
-0@@ -342,15 +342,21 @@ vhost_free_async_mem(struct vhost_virtqueue*vq)
Quoted 12 lines
lib/librte_vhost/vhost.c vhost_free_async_mem(struct vhost_virtqueue *vq) · line 349
Quoted 9 lines
lib/librte_vhost/vhost.c +5
-1{if (vq->async_pkts_info)rte_free (vq->async_pkts_info); -if (vq->async_descs_split) +if (vq->async_buffers_packed) { +rte_free (vq->async_buffers_packed); + vq->async_buffers_packed =NULL ; + } +if (vq->async_descs_split) {You can remove the check,
rte_freeis safe with NULL pointers. You can do the same for the other ones in this function.
OK, it will be fixed.
Quoted 64 lines
lib/librte_vhost/vhost.c int rte_vhost_async_channel_register(int vid,
Quoted 16 lines
lib/librte_vhost/vhost.c +3
-1rte_free (vq->async_descs_split); + vq->async_descs_split =NULL ; + } +if (vq->it_pool)rte_free (vq->it_pool);if (vq->vec_pool)rte_free (vq->vec_pool); vq->async_pkts_info =NULL ; - vq->async_descs_split =NULL ; vq->it_pool =NULL ; vq->vec_pool =NULL ; }@@ -1627,9 +1633,9 @@ int rte_vhost_async_channel_register(int vid,
uint16_tqueue_id,lib/librte_vhost/vhost.c int rte_vhost_async_channel_register(int vid, uint16_t queue_id,
Quoted 7 lines
lib/librte_vhost/vhost.c +1
-2return -1 ;/* packed queue is not supported */ -if (unlikely (vq_is_packed (dev) || !f.async_inorder)) { +if (unlikely (!f.async_inorder)) { VHOST_LOG_CONFIG(ERR, - "async copy is not supported on packed queue ornon-inorder mode "
lib/librte_vhost/vhost.c int rte_vhost_async_channel_register(int vid,
Quoted 5 lines
lib/librte_vhost/vhost.c +1
-0+"async copy is not supported on non-inorder mode " "(vid %d, qid: %d)\n", vid, queue_id);return -1 ; }@@ -1667,11 +1673,18 @@ int rte_vhost_async_channel_register(int vid,
uint16_tqueue_id,Quoted 11 lines
lib/librte_vhost/vhost.c +6
-1vq->vec_pool =rte_malloc_socket (NULL ,VHOST_MAX_ASYNC_VEC *sizeof (struct iovec ),RTE_CACHE_LINE_SIZE , node); - vq->async_descs_split = rte_malloc_socket(NULL, +if (vq_is_packed (dev)) { + vq->async_buffers_packed =rte_malloc_socket (NULL , + vq->size *sizeof (struct vring_used_elem_packed ), +RTE_CACHE_LINE_SIZE , node); + }else { + vq->async_descs_split = rte_malloc_socket(NULL, vq->size * sizeof(struct vring_used_elem),lib/librte_vhost/vhost.c int rte_vhost_async_channel_register(int vid, uint16_t queue_id,
Quoted 10 lines
lib/librte_vhost/vhost.c +4
-2RTE_CACHE_LINE_SIZE, node); -if (!vq->async_descs_split || !vq->async_pkts_info || - !vq->it_pool || !vq->vec_pool) { + } + +if (!vq->async_buffers_packed || !vq->async_descs_split || + !vq->async_pkts_info || !vq->it_pool || !vq->vec_pool) {vhost_free_async_mem (vq); VHOST_LOG_CONFIG(ERR, "async register failed: cannot allocatememory for vq data "
Quoted 11 lines
lib/librte_vhost/vhost.h index renamed from lib/librte_vhost/vhost.h +0
-0
f628714c2..fe131ae8f100644lib/librte_vhost/vhost.h +2
-1@@ -201,9 +201,14 @@ struct vhost_virtqueue {uint16_t async_pkts_idx;uint16_t async_pkts_inflight_n;uint16_t async_last_pkts_n; -struct vring_used_elem *async_descs_split; +union { +struct vring_used_elem *async_descs_split;
Quoted 8 lines
lib/librte_vhost/vhost.h struct vhost_virtqueue { · line 209
Quoted 4 lines
lib/librte_vhost/vhost.h +3
-0+struct vring_used_elem_packed *async_buffers_packed; + };uint16_t async_desc_idx; +uint16_t async_packed_buffer_idx;Don't dupplicate variable names,
async_desc_idxcan be reused for packed ring. Also, they are representing the same thing, why use desc in one case and buffer in the other?
The main reason is that the unit of the packed used ring is buffer, which can contain many desc.
I think using desc_idx will cause ambiguity, but if you think that I should reuse the desc_idx, I have no problem with that.
Quoted 58 lines
lib/librte_vhost/vhost.h struct vhost_virtqueue { · line 211
Quoted 3 lines
lib/librte_vhost/vhost.h +1
-0uint16_t last_async_desc_idx; +uint16_t last_async_buffer_idx;Same remark here.
Quoted 8 lines
lib/librte_vhost/vhost.h +0
-0/* vq async features */ bool async_inorder;(quoted diff) +0
-0
b/lib/librte_vhost/virtio_net.cindexc43ab0093..410be9678100644lib/librte_vhost/virtio_net.c +0
-0@@ -363,14 +363,14 @@vhost_shadow_dequeue_single_packed_inorder(struct
vhost_virtqueue*vq,
lib/librte_vhost/virtio_net.c vhost_shadow_enqueue_single_packed(struct
Quoted 20 lines
}
static
__rte_always_inlinevoidlib/librte_vhost/virtio_net.c +5
-5-vhost_shadow_enqueue_single_packed(struct virtio_net *dev, - struct vhost_virtqueue *vq, - uint32_t len[], - uint16_t id[], - uint16_t count[], +vhost_shadow_enqueue_packed(struct vhost_virtqueue *vq, + uint32_t *len, + uint16_t *id, + uint16_t *count, uint16_t num_buffers) { uint16_t i; +for (i =0 ; i < num_buffers; i++) {/* enqueue shadow flush action aligned with batch num */ if (!vq->shadow_used_idx)@@ -382,6 +382,17 @@ vhost_shadow_enqueue_single_packed(struct
virtio_net*dev,lib/librte_vhost/virtio_net.c shadow_ring_store(struct vhost_virtqueue *vq,
Quoted 18 lines
lib/librte_vhost/virtio_net.c +11
-0vq->shadow_aligned_idx += count[i]; vq->shadow_used_idx++; } +} + +static __rte_always_inline void +vhost_shadow_enqueue_single_packed (struct virtio_net *dev, +struct vhost_virtqueue *vq, +uint32_t *len, +uint16_t *id, +uint16_t *count, +uint16_t num_buffers) +{ +vhost_shadow_enqueue_packed (vq, len, id, count, num_buffers);if (vq->shadow_aligned_idx >=PACKED_BATCH_SIZE ) {do_data_copy_enqueue (dev, vq);@@ -1481,6 +1492,62 @@ shadow_ring_store(struct vhost_virtqueue *vq,void
*shadow_ring, void*d_ring,Quoted 3 lines
lib/librte_vhost/virtio_net.c +0
-0} }
Quoted 9 lines
lib/librte_vhost/virtio_net.c shadow_ring_store(struct vhost_virtqueue *vq, void *shadow_ring, void *d_ring, · line 1501
Quoted 7 lines
lib/librte_vhost/virtio_net.c +7
-0+static __rte_always_inline void +vhost_update_used_packed (struct vhost_virtqueue *vq, +struct vring_used_elem_packed *shadow_ring, +uint16_t count) +{ +if (count ==0 ) +return ;Move this after the variables declaration.
Sure.
Quoted 118 lines
Quoted 42 lines
lib/librte_vhost/virtio_net.c +41
-0+ +int i; +uint16_t used_idx = vq->last_used_idx; +uint16_t head_idx = vq->last_used_idx; +uint16_t head_flags =0 ; + +/* Split loop in two to save memory barriers */ +for (i =0 ; i < count; i++) { + vq->desc_packed[used_idx].id = shadow_ring[i].id; + vq->desc_packed[used_idx].len = shadow_ring[i].len; + + used_idx += shadow_ring[i].count; +if (used_idx >= vq->size) + used_idx -= vq->size; + } + +/* The ordering for storing desc flags needs to be enforced. */ +rte_atomic_thread_fence (__ATOMIC_RELEASE); + +for (i =0 ; i < count; i++) { +uint16_t flags; + +if (vq->shadow_used_packed[i].len) + flags =VRING_DESC_F_WRITE ; +else + flags =0 ; + +if (vq->used_wrap_counter) { + flags |=VRING_DESC_F_USED ; + flags |=VRING_DESC_F_AVAIL ; + }else { + flags &= ~VRING_DESC_F_USED ; + flags &= ~VRING_DESC_F_AVAIL ; + } + +if (i >0 ) { + vq->desc_packed[vq->last_used_idx].flags = flags; + + }else { + head_idx = vq->last_used_idx; + head_flags = flags;lib/librte_vhost/virtio_net.c shadow_ring_store(struct vhost_virtqueue *vq, void *shadow_ring, void *d_ring,
Quoted 10 lines
lib/librte_vhost/virtio_net.c +7
-0+ } + +vq_inc_last_used_packed (vq, shadow_ring[i].count); + } + + vq->desc_packed[head_idx].flags = head_flags; } + static __rte_noinline uint32_t virtio_dev_rx_async_submit_split(struct virtio_net *dev, struct vhost_virtqueue *vq, uint16_t queue_id, @@ -1656,6+1723,294
Quoted 12 lines
@@ virtio_dev_rx_async_submit_split(struct
virtio_net*dev,lib/librte_vhost/virtio_net.c +8
-0return pkt_idx; } +static __rte_always_inline int +vhost_enqueue_async_single_packed(struct virtio_net *dev, + struct vhost_virtqueue *vq, + struct rte_mbuf *pkt, + struct buf_vector *buf_vec, + uint16_t *nr_descs, + uint16_t *nr_buffers, + struct vring_packed_desc *async_descs,lib/librte_vhost/virtio_net.c virtio_dev_rx_async_submit_split(struct virtio_net *dev,
Quoted 10 lines
lib/librte_vhost/virtio_net.c +10
-0+ struct iovec *src_iovec, struct iovec *dst_iovec, + struct rte_vhost_iov_iter *src_it, + struct rte_vhost_iov_iter *dst_it) { + uint16_t nr_vec = 0; +uint16_t avail_idx = vq->last_avail_idx; +uint16_t max_tries, tries =0 ; +uint16_t buf_id =0 ; +uint32_t len =0 ; +uint16_t desc_count =0 ; + uint32_t size = pkt->pkt_len + sizeof(struct
virtio_net_hdr_mrg_rxbuf);Quoted 42 lines
lib/librte_vhost/virtio_net.c +42
-0+uint32_t buffer_len[vq->size]; +uint16_t buffer_buf_id[vq->size]; +uint16_t buffer_desc_count[vq->size]; + *nr_buffers =0 ; + +if (rxvq_is_mergeable (dev)) + max_tries = vq->size -1 ; +else + max_tries =1 ; + +while (size >0 ) { +/* +* if we tried all available ring items, and still +* can't get enough buf, it means something abnormal +* happened. +*/ +if (unlikely (++tries > max_tries)) +return -1 ; + +if (unlikely (fill_vec_buf_packed (dev, vq, + avail_idx, &desc_count, + buf_vec, &nr_vec, + &buf_id, &len, +VHOST_ACCESS_RW ) <0 )) +return -1 ; + + len =RTE_MIN (len, size); + size -= len; + + buffer_len[*nr_buffers] = len; + buffer_buf_id[*nr_buffers] = buf_id; + buffer_desc_count[*nr_buffers] = desc_count; + *nr_buffers +=1 ; + + *nr_descs += desc_count; + avail_idx += desc_count; +if (avail_idx >= vq->size) + avail_idx -= vq->size; + } + +if (async_mbuf_to_desc (dev, vq, pkt, buf_vec, nr_vec, *nr_buffers, + src_iovec, dst_iovec, src_it, dst_it) <0 )
Quoted 8 lines
lib/librte_vhost/virtio_net.c virtio_dev_rx_async_submit_split(struct virtio_net *dev, · line 1792
Quoted 6 lines
lib/librte_vhost/virtio_net.c +6
-0+return -1 ; +/* store descriptors for DMA */ +if (avail_idx >= *nr_descs) +rte_memcpy (async_descs, + &vq->desc_packed[vq->last_avail_idx], + *nr_descs *sizeof (struct vring_packed_desc ));Please add brackets for the 'if' since there are for the 'else'.
Sure, sorry for that.
Quoted 67 lines
Quoted 21 lines
lib/librte_vhost/virtio_net.c +20
-0+else { +uint16_t nr_copy = vq->size - vq->last_avail_idx; +rte_memcpy (async_descs, + &vq->desc_packed[vq->last_avail_idx], + nr_copy *sizeof (struct vring_packed_desc )); +rte_memcpy (async_descs + nr_copy, + vq->desc_packed, (*nr_descs - nr_copy) * +sizeof (struct vring_packed_desc )); + } + +vhost_shadow_enqueue_packed (vq, buffer_len, buffer_buf_id, + buffer_desc_count, *nr_buffers); + +return 0 ; +} + +static __rte_always_inline int16_t +virtio_dev_rx_async_single_packed(struct virtio_net *dev, + struct vhost_virtqueue *vq, + struct rte_mbuf *pkt,lib/librte_vhost/virtio_net.c virtio_dev_rx_async_submit_split(struct virtio_net *dev,
Quoted 10 lines
lib/librte_vhost/virtio_net.c +10
-0+ uint16_t *nr_descs, uint16_t *nr_buffers, + struct vring_packed_desc *async_descs, + struct iovec *src_iovec, struct iovec *dst_iovec, + struct rte_vhost_iov_iter *src_it, + struct rte_vhost_iov_iter *dst_it) { + struct buf_vector buf_vec[BUF_VECTOR_MAX]; + *nr_descs =0 ; + *nr_buffers =0 ; + + if (unlikely(vhost_enqueue_async_single_packed(dev, vq, pkt,
buf_vec,lib/librte_vhost/virtio_net.c virtio_dev_rx_async_submit_split(struct virtio_net *dev,
Quoted 12 lines
lib/librte_vhost/virtio_net.c +12
-0+ nr_descs, + nr_buffers, + async_descs, + src_iovec, dst_iovec, + src_it, dst_it) < 0)) { +VHOST_LOG_DATA (DEBUG , +"(%d) failed to get enough desc from vring\n" , + dev->vid); +return -1 ; + } + + VHOST_LOG_DATA(DEBUG, "(%d) current index %d | endindex %d\n",
Quoted 11 lines
lib/librte_vhost/virtio_net.c +11
-0+ dev->vid, vq->last_avail_idx, + vq->last_avail_idx + *nr_descs); + +return 0 ; +} + +static __rte_noinline uint32_t +virtio_dev_rx_async_submit_packed (struct virtio_net *dev, +struct vhost_virtqueue *vq,uint16_t queue_id, +struct rte_mbuf **pkts,uint32_t count, +struct rte_mbuf **comp_pkts,uint32_t *comp_count) {lib/librte_vhost/virtio_net.c virtio_dev_rx_async_submit_split(struct virtio_net *dev,
Quoted 10 lines
lib/librte_vhost/virtio_net.c +10
-0+uint32_t pkt_idx =0 , pkt_burst_idx =0 ; +uint16_t async_descs_idx =0 ; +uint16_t num_buffers; +uint16_t num_desc; + +struct rte_vhost_iov_iter *it_pool = vq->it_pool; +struct iovec *vec_pool = vq->vec_pool; +struct rte_vhost_async_desc tdes[MAX_PKT_BURST ]; +struct iovec *src_iovec = vec_pool; + struct iovec *dst_iovec = vec_pool + (VHOST_MAX_ASYNC_VEC >>1);
Quoted 14 lines
lib/librte_vhost/virtio_net.c virtio_dev_rx_async_submit_split(struct virtio_net *dev,
Quoted 12 lines
lib/librte_vhost/virtio_net.c +12
-0+struct rte_vhost_iov_iter *src_it = it_pool; +struct rte_vhost_iov_iter *dst_it = it_pool +1 ; +uint16_t slot_idx =0 ; +uint16_t segs_await =0 ; +uint16_t iovec_idx =0 , it_idx =0 ; +struct async_inflight_info *pkts_info = vq->async_pkts_info; +uint32_t n_pkts =0 , pkt_err =0 ; +uint32_t num_async_pkts =0 , num_done_pkts =0 ; +struct vring_packed_desc async_descs[vq->size]; + +rte_prefetch0 (&vq->desc_packed[vq->last_avail_idx & (vq->size - +1 )]);The size of the ring is not necessarily a power of two with packed ring.
For the size of the ring is not necessarily a power of two, so maybe I can use codes like
Indx % vq->size ?
I'm not sure if it's a good way to do that.
Quoted 16 lines
lib/librte_vhost/virtio_net.c virtio_dev_rx_async_submit_split(struct virtio_net *dev, · line 1880
Quoted 7 lines
lib/librte_vhost/virtio_net.c +6
-0+ +for (pkt_idx =0 ; pkt_idx < count; pkt_idx++) { + if (unlikely(virtio_dev_rx_async_single_packed(dev, vq, + pkts[pkt_idx], + &num_desc, &num_buffers, +&async_descs[async_descs_idx],
lib/librte_vhost/virtio_net.c virtio_dev_rx_async_submit_split(struct virtio_net *dev,
Quoted 7 lines
lib/librte_vhost/virtio_net.c +7
-0+ &src_iovec[iovec_idx], + &dst_iovec[iovec_idx], + &src_it[it_idx], + &dst_it[it_idx]) < 0)) + break; + + VHOST_LOG_DATA(DEBUG, "(%d) current index %d | endindex %d\n",
Quoted 7 lines
lib/librte_vhost/virtio_net.c virtio_dev_rx_async_submit_split(struct virtio_net *dev, · line 1886
Quoted 5 lines
lib/librte_vhost/virtio_net.c +5
-0+ dev->vid, vq->last_avail_idx, + vq->last_avail_idx + num_desc); + + slot_idx = (vq->async_pkts_idx + num_async_pkts) & + (vq->size -1 );Same here.
Sure.
Quoted 28 lines
lib/librte_vhost/virtio_net.c virtio_dev_rx_async_submit_split(struct virtio_net *dev,
Quoted 6 lines
lib/librte_vhost/virtio_net.c +5
-0+if (src_it[it_idx].count) { +uint16_t from, to; + + async_descs_idx += num_desc; + async_fill_desc(&tdes[pkt_burst_idx++],&src_it[it_idx],
Quoted 10 lines
lib/librte_vhost/virtio_net.c +10
-0+ &dst_it[it_idx]); + pkts_info[slot_idx].descs = num_desc; + pkts_info[slot_idx].nr_buffers = num_buffers; + pkts_info[slot_idx].mbuf = pkts[pkt_idx]; + num_async_pkts++; + iovec_idx += src_it[it_idx].nr_segs; + it_idx +=2 ; + + segs_await += src_it[it_idx].nr_segs; +lib/librte_vhost/virtio_net.c virtio_dev_rx_async_submit_split(struct virtio_net *dev,
Quoted 10 lines
lib/librte_vhost/virtio_net.c +10
-0+/** +* recover shadow used ring and keep DMA-occupied +* descriptors. +*/ + from = vq->shadow_used_idx - num_buffers; + to = vq->async_packed_buffer_idx & (vq->size -1 ); + shadow_ring_store(vq, vq->shadow_used_packed, + vq->async_buffers_packed, + from, to, num_buffers, + sizeof(struct
vring_used_elem_packed));
Quoted 6 lines
lib/librte_vhost/virtio_net.c virtio_dev_rx_async_submit_split(struct virtio_net *dev, · line 1915
Quoted 4 lines
lib/librte_vhost/virtio_net.c +4
-0+ + vq->async_packed_buffer_idx += num_buffers; + vq->shadow_used_idx -= num_buffers; + }else Brackets needed.
Sure.
Quoted 53 lines
lib/librte_vhost/virtio_net.c virtio_dev_rx_async_submit_split(struct virtio_net *dev,
Quoted 11 lines
lib/librte_vhost/virtio_net.c +10
-0+ comp_pkts[num_done_pkts++] = pkts[pkt_idx]; + +vq_inc_last_avail_packed (vq, num_desc); + +/* +* conditions to trigger async device transfer: +* - buffered packet number reaches transfer threshold +* - unused async iov number is less than max vhost vector +*/ + if (unlikely(pkt_burst_idx >=
VHOST_ASYNC_BATCH_THRESHOLD||lib/librte_vhost/virtio_net.c virtio_dev_rx_async_submit_split(struct virtio_net *dev,
Quoted 12 lines
lib/librte_vhost/virtio_net.c +12
-0+ ((VHOST_MAX_ASYNC_VEC >> 1) - segs_await < + BUF_VECTOR_MAX))) { + n_pkts = vq->async_ops.transfer_data (dev->vid, + queue_id, tdes,0 , pkt_burst_idx); + iovec_idx =0 ; + it_idx =0 ; + segs_await =0 ; + vq->async_pkts_inflight_n += n_pkts; + +if (unlikely (n_pkts < pkt_burst_idx)) { +/* +* log error packets number here and do actual
Quoted 28 lines
lib/librte_vhost/virtio_net.c +28
-0+* error processing when applications poll +* completion +*/ + pkt_err = pkt_burst_idx - n_pkts; + pkt_burst_idx =0 ; + pkt_idx++; +break ; + } + + pkt_burst_idx =0 ; + } + } + +if (pkt_burst_idx) { + n_pkts = vq->async_ops.transfer_data (dev->vid, + queue_id, tdes,0 , pkt_burst_idx); + vq->async_pkts_inflight_n += n_pkts; + +if (unlikely (n_pkts < pkt_burst_idx)) + pkt_err = pkt_burst_idx - n_pkts; + } + +do_data_copy_enqueue (dev, vq); + +if (unlikely (pkt_err)) { +uint16_t descs_err =0 ; +uint16_t buffers_err =0 ; +
Quoted 8 lines
lib/librte_vhost/virtio_net.c virtio_dev_rx_async_submit_split(struct virtio_net *dev, · line 1971
Quoted 6 lines
lib/librte_vhost/virtio_net.c +6
-0+ num_async_pkts -= pkt_err; + pkt_idx -= pkt_err; +/* calculate the sum of buffers and descs of DMA-error packets. */ +while (pkt_err-- >0 ) { + descs_err += + pkts_info[slot_idx & (vq->size -1 )].descs;The size of the ring is not necessarily a power of two with packed ring.
Will be fixed.
Quoted 6 lines
lib/librte_vhost/virtio_net.c
Quoted 3 lines
lib/librte_vhost/virtio_net.c +2
-0+ buffers_err += + pkts_info[slot_idx & (vq->size -1)].nr_buffers;
Ditto.
Will be fixed.
Quoted 27 lines
lib/librte_vhost/virtio_net.c virtio_dev_rx_async_submit_split(struct virtio_net *dev,
Quoted 12 lines
lib/librte_vhost/virtio_net.c +11
-0+ slot_idx--; + } + + vq->async_packed_buffer_idx -= buffers_err; + +if (vq->last_avail_idx >= descs_err) { + vq->last_avail_idx -= descs_err; + + rte_memcpy(&vq->desc_packed[vq->last_avail_idx], + &async_descs[async_descs_idx - descs_err], + descs_err * sizeof(struct
vring_packed_desc));lib/librte_vhost/virtio_net.c virtio_dev_rx_async_submit_split(struct virtio_net *dev,
Quoted 13 lines
lib/librte_vhost/virtio_net.c +13
-0+ }else { +uint16_t nr_copy; + + vq->last_avail_idx = vq->last_avail_idx + vq->size + - descs_err; + nr_copy = vq->size - vq->last_avail_idx; +rte_memcpy (&vq->desc_packed[vq->last_avail_idx], + &async_descs[async_descs_idx - descs_err], + nr_copy *sizeof (struct vring_packed_desc )); + descs_err -= nr_copy; + rte_memcpy(vq->desc_packed, + &async_descs[async_descs_idx - descs_err], + descs_err * sizeof(struct
vring_packed_desc));
Quoted 7 lines
lib/librte_vhost/virtio_net.c virtio_dev_rx_async_submit_split(struct virtio_net *dev, · line 2002
Quoted 5 lines
lib/librte_vhost/virtio_net.c +5
-0+ vq->avail_wrap_counter ^=1 ; + } + + num_done_pkts = pkt_idx - num_async_pkts; + }This error handling could be moved in a dedicated function.
Sure, will fix it in the next version.
Quoted 14 lines
lib/librte_vhost/virtio_net.c virtio_dev_rx_async_submit_split(struct virtio_net *dev, · line 2012
Quoted 11 lines
lib/librte_vhost/virtio_net.c +10
-0+ vq->async_pkts_idx += num_async_pkts; + *comp_count = num_done_pkts; + +if (likely (vq->shadow_used_idx)) { +vhost_flush_enqueue_shadow_packed (dev, vq); +vhost_vring_call_packed (dev, vq); + } + +return pkt_idx; +}Above function is very big and complex, it should be possible to split it in several ones to make it maintainable.
I think move the error handling code will make it smaller.
Thanks.
Cheng
Quoted 10 lines
Quoted 6 lines
+
static__rte_always_inlinevoid write_back_completed_descs_split(structvhost_virtqueue*vq,uint16_tn_descs) { @@ -1693,12 +2048,40 @@ write_back_completed_descs_split(structvhost_virtqueue*vq,uint16_t
n_descs)Quoted 3 lines
} while (
nr_left> 0);
}
Quoted 13 lines
lib/librte_vhost/virtio_net.c write_back_completed_descs_split(struct vhost_virtqueue *vq, uint16_t n_descs) · line 2061
Quoted 11 lines
lib/librte_vhost/virtio_net.c +11
-0+static __rte_always_inline void +write_back_completed_descs_packed (struct vhost_virtqueue *vq, +uint16_t n_buffers) +{ +uint16_t nr_left = n_buffers; +uint16_t from, to; + + do { + from = vq->last_async_buffer_idx & + (vq->size - 1); + to = (from + nr_left) & (vq->size - 1);The size of the ring is not necessarily a power of two with packed ring.
Sure.
Quoted 32 lines
lib/librte_vhost/virtio_net.c uint16_t
Quoted 28 lines
lib/librte_vhost/virtio_net.c +18
-1+if (to > from) { +vhost_update_used_packed (vq, + vq->async_buffers_packed + from, + to - from); + vq->last_async_buffer_idx += nr_left; + nr_left =0 ; + }else { +vhost_update_used_packed (vq, + vq->async_buffers_packed + from, + vq->size - from); + vq->last_async_buffer_idx += + vq->size - from; + nr_left -= vq->size - from; + } + }while (nr_left >0 ); +} +uint16_t rte_vhost_poll_enqueue_completed (int vid,uint16_t queue_id,struct rte_mbuf **pkts,uint16_t count) {struct virtio_net *dev =get_device (vid);struct vhost_virtqueue *vq; -uint16_t n_pkts_cpl =0 , n_pkts_put =0 , n_descs =0 ; +uint16_t n_pkts_cpl =0 , n_pkts_put =0 , n_descs =0 , n_buffers =0 ;uint16_t start_idx, pkts_idx, vq_size;struct async_inflight_info *pkts_info;uint16_t from, i;@@ -1740,21 +2123,41 @@ uint16_trte_vhost_poll_enqueue_completed(int vid,
uint16_tqueue_id,Quoted 3 lines
lib/librte_vhost/virtio_net.c +0
-0goto done; }
Quoted 9 lines
lib/librte_vhost/virtio_net.c uint16_t rte_vhost_poll_enqueue_completed(int vid, uint16_t queue_id, · line 2128
Quoted 7 lines
lib/librte_vhost/virtio_net.c +3
-4-for (i =0 ; i < n_pkts_put; i++) { - from = (start_idx + i) & (vq_size -1 ); - n_descs += pkts_info[from].descs; - pkts[i] = pkts_info[from].mbuf; +if (vq_is_packed (dev)) { +for (i =0 ; i < n_pkts_put; i++) { + from = (start_idx + i) & (vq_size -1 );Unlike split ring, packed ring size is not necessarily a power of 2.
Sure.
Thanks.
Quoted 58 lines
Quoted 9 lines
lib/librte_vhost/virtio_net.c +8
-0+ n_buffers += pkts_info[from].nr_buffers; + pkts[i] = pkts_info[from].mbuf; + } + }else { +for (i =0 ; i < n_pkts_put; i++) { + from = (start_idx + i) & (vq_size -1 ); + n_descs += pkts_info[from].descs; + pkts[i] = pkts_info[from].mbuf;lib/librte_vhost/virtio_net.c uint16_t rte_vhost_poll_enqueue_completed(int vid, uint16_t queue_id,
Quoted 10 lines
lib/librte_vhost/virtio_net.c +4
-1+ } } + vq->async_last_pkts_n = n_pkts_cpl - n_pkts_put; vq->async_pkts_inflight_n -= n_pkts_put;if (likely (vq->enabled && vq->access_ok)) { -write_back_completed_descs_split (vq, n_descs); +if (vq_is_packed (dev)) { + write_back_completed_descs_packed(vq,
n_buffers);lib/librte_vhost/virtio_net.c uint16_t · line 1753
Quoted 2 lines
lib/librte_vhost/virtio_net.c +0
-1- __atomic_add_fetch(&vq->used->idx, n_descs,
__ATOMIC_RELEASE);lib/librte_vhost/virtio_net.c virtio_dev_rx_async_submit(struct virtio_net
Quoted 21 lines
lib/librte_vhost/virtio_net.c +14
-3-vhost_vring_call_split (dev, vq); - }else - vq->last_async_desc_idx += n_descs; +vhost_vring_call_packed (dev, vq); + }else { +write_back_completed_descs_split (vq, n_descs); + +__atomic_add_fetch (&vq->used->idx, n_descs, + __ATOMIC_RELEASE); +vhost_vring_call_split (dev, vq); + } + }else { +if (vq_is_packed (dev)) + vq->last_async_buffer_idx += n_buffers; +else + vq->last_async_desc_idx += n_descs; + } done:rte_spinlock_unlock (&vq->access_lock);@@ -1795,9 +2198,10 @@ virtio_dev_rx_async_submit(struct virtio_net*dev,
uint16_tqueue_id,Quoted 13 lines
lib/librte_vhost/virtio_net.c +3
-2if (count ==0 ) goto out; -/* TODO: packed queue not implemented */ if (vq_is_packed (dev)) - nb_tx =0 ; + nb_tx =virtio_dev_rx_async_submit_packed (dev, + vq, queue_id, pkts, count, comp_pkts, + comp_count);else nb_tx = virtio_dev_rx_async_submit_split(dev, vq, queue_id, pkts, count, comp_pkts,
Quoted 134 lines · On 4/13/21 1:48 PM, Jiang, Cheng1 wrote:
Hi Maxime,
Quoted 44 lines
-----Original Message-----
From: Maxime Coquelin <[email protected]>
Sent: Tuesday, April 13, 2021 4:37 PM
To: Jiang, Cheng1 <[email protected]>; Xia, Chenbo <[email protected]>
Cc: [email protected]; Hu, Jiayu <[email protected]>; Yang, YvonneX <[email protected]>; Wang, Yinan <[email protected]>; Liu, Yong <[email protected]>
Subject: Re: [PATCH v5 2/4] vhost: add support for packed ring in async vhostlib/librte_vhost/vhost.c vhost_free_async_mem(struct vhost_virtqueue
Quoted 30 lines · Cheng Jiang
For now async vhost data path only supports split ring structure. In order to make async vhost compatible with virtio 1.1 spec this patch enables packed ring in async vhost data path.
Signed-off-by Cheng Jiang <[email protected]>--- lib/librte_vhost/rte_vhost_async.h | 1 + lib/librte_vhost/vhost.c | 27 +- lib/librte_vhost/vhost.h | 7 +- lib/librte_vhost/virtio_net.c | 438 +++++++++++++++++++++++++++-- 4 files changed, 448 insertions(+), 25 deletions(-)lib/librte_vhost/rte_vhost_async.h +1
-0@@ -89,6 +89,7 @@ struct rte_vhost_async_channel_ops { struct async_inflight_info {struct rte_mbuf *mbuf;uint16_t descs;/* num of descs inflight */ +uint16_t nr_buffers;/* num of buffers inflight for packed ring */ };/** lib/librte_vhost/vhost.c index renamed from lib/librte_vhost/vhost.c +0
-0
a70fe01d8..8c9935c0f100644lib/librte_vhost/vhost.c +0
-0@@ -342,15 +342,21 @@ vhost_free_async_mem(struct vhost_virtqueue*vq)
Quoted 12 lines
lib/librte_vhost/vhost.c vhost_free_async_mem(struct vhost_virtqueue *vq) · line 349
Quoted 9 lines
lib/librte_vhost/vhost.c +5
-1{if (vq->async_pkts_info)rte_free (vq->async_pkts_info); -if (vq->async_descs_split) +if (vq->async_buffers_packed) { +rte_free (vq->async_buffers_packed); + vq->async_buffers_packed =NULL ; + } +if (vq->async_descs_split) {You can remove the check,
rte_freeis safe with NULL pointers. You can do the same for the other ones in this function.OK, it will be fixed.
Quoted 64 lines
lib/librte_vhost/vhost.c int rte_vhost_async_channel_register(int vid,
Quoted 16 lines
lib/librte_vhost/vhost.c +3
-1rte_free (vq->async_descs_split); + vq->async_descs_split =NULL ; + } +if (vq->it_pool)rte_free (vq->it_pool);if (vq->vec_pool)rte_free (vq->vec_pool); vq->async_pkts_info =NULL ; - vq->async_descs_split =NULL ; vq->it_pool =NULL ; vq->vec_pool =NULL ; }@@ -1627,9 +1633,9 @@ int rte_vhost_async_channel_register(int vid,
uint16_tqueue_id,lib/librte_vhost/vhost.c int rte_vhost_async_channel_register(int vid, uint16_t queue_id,
Quoted 7 lines
lib/librte_vhost/vhost.c +1
-2return -1 ;/* packed queue is not supported */ -if (unlikely (vq_is_packed (dev) || !f.async_inorder)) { +if (unlikely (!f.async_inorder)) { VHOST_LOG_CONFIG(ERR, - "async copy is not supported on packed queue ornon-inorder mode "
lib/librte_vhost/vhost.c int rte_vhost_async_channel_register(int vid,
Quoted 5 lines
lib/librte_vhost/vhost.c +1
-0+"async copy is not supported on non-inorder mode " "(vid %d, qid: %d)\n", vid, queue_id);return -1 ; }@@ -1667,11 +1673,18 @@ int rte_vhost_async_channel_register(int vid,
uint16_tqueue_id,Quoted 11 lines
lib/librte_vhost/vhost.c +6
-1vq->vec_pool =rte_malloc_socket (NULL ,VHOST_MAX_ASYNC_VEC *sizeof (struct iovec ),RTE_CACHE_LINE_SIZE , node); - vq->async_descs_split = rte_malloc_socket(NULL, +if (vq_is_packed (dev)) { + vq->async_buffers_packed =rte_malloc_socket (NULL , + vq->size *sizeof (struct vring_used_elem_packed ), +RTE_CACHE_LINE_SIZE , node); + }else { + vq->async_descs_split = rte_malloc_socket(NULL, vq->size * sizeof(struct vring_used_elem),lib/librte_vhost/vhost.c int rte_vhost_async_channel_register(int vid, uint16_t queue_id,
Quoted 10 lines
lib/librte_vhost/vhost.c +4
-2RTE_CACHE_LINE_SIZE, node); -if (!vq->async_descs_split || !vq->async_pkts_info || - !vq->it_pool || !vq->vec_pool) { + } + +if (!vq->async_buffers_packed || !vq->async_descs_split || + !vq->async_pkts_info || !vq->it_pool || !vq->vec_pool) {vhost_free_async_mem (vq); VHOST_LOG_CONFIG(ERR, "async register failed: cannot allocatememory for vq data "
Quoted 11 lines
lib/librte_vhost/vhost.h index renamed from lib/librte_vhost/vhost.h +0
-0
f628714c2..fe131ae8f100644lib/librte_vhost/vhost.h +2
-1@@ -201,9 +201,14 @@ struct vhost_virtqueue {uint16_t async_pkts_idx;uint16_t async_pkts_inflight_n;uint16_t async_last_pkts_n; -struct vring_used_elem *async_descs_split; +union { +struct vring_used_elem *async_descs_split;Quoted 8 lines
lib/librte_vhost/vhost.h struct vhost_virtqueue { · line 209
Quoted 4 lines
lib/librte_vhost/vhost.h +3
-0+struct vring_used_elem_packed *async_buffers_packed; + };uint16_t async_desc_idx; +uint16_t async_packed_buffer_idx;Don't dupplicate variable names,
async_desc_idxcan be reused for packed ring. Also, they are representing the same thing, why use desc in one case and buffer in the other?
Quoted 2 lines
The main reason is that the unit of the packed used ring is buffer, which can contain many desc.
I think usingdesc_idxwill cause ambiguity, but if you think that I should reuse thedesc_idx, I have no problem with that.
OK, in this case please use a union not to waste memory.
Quoted 281 lines
Quoted 58 lines
lib/librte_vhost/vhost.h struct vhost_virtqueue { · line 211
Quoted 3 lines
lib/librte_vhost/vhost.h +1
-0uint16_t last_async_desc_idx; +uint16_t last_async_buffer_idx;Same remark here.
Quoted 8 lines
lib/librte_vhost/vhost.h +0
-0/* vq async features */ bool async_inorder;(quoted diff) +0
-0
b/lib/librte_vhost/virtio_net.cindexc43ab0093..410be9678100644lib/librte_vhost/virtio_net.c +0
-0@@ -363,14 +363,14 @@vhost_shadow_dequeue_single_packed_inorder(struct
vhost_virtqueue*vq,
lib/librte_vhost/virtio_net.c vhost_shadow_enqueue_single_packed(struct
Quoted 20 lines
}
static
__rte_always_inlinevoidlib/librte_vhost/virtio_net.c +5
-5-vhost_shadow_enqueue_single_packed(struct virtio_net *dev, - struct vhost_virtqueue *vq, - uint32_t len[], - uint16_t id[], - uint16_t count[], +vhost_shadow_enqueue_packed(struct vhost_virtqueue *vq, + uint32_t *len, + uint16_t *id, + uint16_t *count, uint16_t num_buffers) { uint16_t i; +for (i =0 ; i < num_buffers; i++) {/* enqueue shadow flush action aligned with batch num */ if (!vq->shadow_used_idx)@@ -382,6 +382,17 @@ vhost_shadow_enqueue_single_packed(struct
virtio_net*dev,lib/librte_vhost/virtio_net.c shadow_ring_store(struct vhost_virtqueue *vq,
Quoted 18 lines
lib/librte_vhost/virtio_net.c +11
-0vq->shadow_aligned_idx += count[i]; vq->shadow_used_idx++; } +} + +static __rte_always_inline void +vhost_shadow_enqueue_single_packed (struct virtio_net *dev, +struct vhost_virtqueue *vq, +uint32_t *len, +uint16_t *id, +uint16_t *count, +uint16_t num_buffers) +{ +vhost_shadow_enqueue_packed (vq, len, id, count, num_buffers);if (vq->shadow_aligned_idx >=PACKED_BATCH_SIZE ) {do_data_copy_enqueue (dev, vq);@@ -1481,6 +1492,62 @@ shadow_ring_store(struct vhost_virtqueue *vq,void
*shadow_ring, void*d_ring,Quoted 3 lines
lib/librte_vhost/virtio_net.c +0
-0} }Quoted 9 lines
lib/librte_vhost/virtio_net.c shadow_ring_store(struct vhost_virtqueue *vq, void *shadow_ring, void *d_ring, · line 1501
Quoted 7 lines
lib/librte_vhost/virtio_net.c +7
-0+static __rte_always_inline void +vhost_update_used_packed (struct vhost_virtqueue *vq, +struct vring_used_elem_packed *shadow_ring, +uint16_t count) +{ +if (count ==0 ) +return ;Move this after the variables declaration.
Sure.
Quoted 118 lines
Quoted 42 lines
lib/librte_vhost/virtio_net.c +41
-0+ +int i; +uint16_t used_idx = vq->last_used_idx; +uint16_t head_idx = vq->last_used_idx; +uint16_t head_flags =0 ; + +/* Split loop in two to save memory barriers */ +for (i =0 ; i < count; i++) { + vq->desc_packed[used_idx].id = shadow_ring[i].id; + vq->desc_packed[used_idx].len = shadow_ring[i].len; + + used_idx += shadow_ring[i].count; +if (used_idx >= vq->size) + used_idx -= vq->size; + } + +/* The ordering for storing desc flags needs to be enforced. */ +rte_atomic_thread_fence (__ATOMIC_RELEASE); + +for (i =0 ; i < count; i++) { +uint16_t flags; + +if (vq->shadow_used_packed[i].len) + flags =VRING_DESC_F_WRITE ; +else + flags =0 ; + +if (vq->used_wrap_counter) { + flags |=VRING_DESC_F_USED ; + flags |=VRING_DESC_F_AVAIL ; + }else { + flags &= ~VRING_DESC_F_USED ; + flags &= ~VRING_DESC_F_AVAIL ; + } + +if (i >0 ) { + vq->desc_packed[vq->last_used_idx].flags = flags; + + }else { + head_idx = vq->last_used_idx; + head_flags = flags;lib/librte_vhost/virtio_net.c shadow_ring_store(struct vhost_virtqueue *vq, void *shadow_ring, void *d_ring,
Quoted 10 lines
lib/librte_vhost/virtio_net.c +7
-0+ } + +vq_inc_last_used_packed (vq, shadow_ring[i].count); + } + + vq->desc_packed[head_idx].flags = head_flags; } + static __rte_noinline uint32_t virtio_dev_rx_async_submit_split(struct virtio_net *dev, struct vhost_virtqueue *vq, uint16_t queue_id, @@ -1656,6+1723,294
Quoted 12 lines
@@ virtio_dev_rx_async_submit_split(struct
virtio_net*dev,lib/librte_vhost/virtio_net.c +8
-0return pkt_idx; } +static __rte_always_inline int +vhost_enqueue_async_single_packed(struct virtio_net *dev, + struct vhost_virtqueue *vq, + struct rte_mbuf *pkt, + struct buf_vector *buf_vec, + uint16_t *nr_descs, + uint16_t *nr_buffers, + struct vring_packed_desc *async_descs,lib/librte_vhost/virtio_net.c virtio_dev_rx_async_submit_split(struct virtio_net *dev,
Quoted 10 lines
lib/librte_vhost/virtio_net.c +10
-0+ struct iovec *src_iovec, struct iovec *dst_iovec, + struct rte_vhost_iov_iter *src_it, + struct rte_vhost_iov_iter *dst_it) { + uint16_t nr_vec = 0; +uint16_t avail_idx = vq->last_avail_idx; +uint16_t max_tries, tries =0 ; +uint16_t buf_id =0 ; +uint32_t len =0 ; +uint16_t desc_count =0 ; + uint32_t size = pkt->pkt_len + sizeof(struct
virtio_net_hdr_mrg_rxbuf);Quoted 42 lines
lib/librte_vhost/virtio_net.c +42
-0+uint32_t buffer_len[vq->size]; +uint16_t buffer_buf_id[vq->size]; +uint16_t buffer_desc_count[vq->size]; + *nr_buffers =0 ; + +if (rxvq_is_mergeable (dev)) + max_tries = vq->size -1 ; +else + max_tries =1 ; + +while (size >0 ) { +/* +* if we tried all available ring items, and still +* can't get enough buf, it means something abnormal +* happened. +*/ +if (unlikely (++tries > max_tries)) +return -1 ; + +if (unlikely (fill_vec_buf_packed (dev, vq, + avail_idx, &desc_count, + buf_vec, &nr_vec, + &buf_id, &len, +VHOST_ACCESS_RW ) <0 )) +return -1 ; + + len =RTE_MIN (len, size); + size -= len; + + buffer_len[*nr_buffers] = len; + buffer_buf_id[*nr_buffers] = buf_id; + buffer_desc_count[*nr_buffers] = desc_count; + *nr_buffers +=1 ; + + *nr_descs += desc_count; + avail_idx += desc_count; +if (avail_idx >= vq->size) + avail_idx -= vq->size; + } + +if (async_mbuf_to_desc (dev, vq, pkt, buf_vec, nr_vec, *nr_buffers, + src_iovec, dst_iovec, src_it, dst_it) <0 )Quoted 8 lines
lib/librte_vhost/virtio_net.c virtio_dev_rx_async_submit_split(struct virtio_net *dev, · line 1792
Quoted 6 lines
lib/librte_vhost/virtio_net.c +6
-0+return -1 ; +/* store descriptors for DMA */ +if (avail_idx >= *nr_descs) +rte_memcpy (async_descs, + &vq->desc_packed[vq->last_avail_idx], + *nr_descs *sizeof (struct vring_packed_desc ));Please add brackets for the 'if' since there are for the 'else'.
Sure, sorry for that.
Quoted 67 lines
Quoted 21 lines
lib/librte_vhost/virtio_net.c +20
-0+else { +uint16_t nr_copy = vq->size - vq->last_avail_idx; +rte_memcpy (async_descs, + &vq->desc_packed[vq->last_avail_idx], + nr_copy *sizeof (struct vring_packed_desc )); +rte_memcpy (async_descs + nr_copy, + vq->desc_packed, (*nr_descs - nr_copy) * +sizeof (struct vring_packed_desc )); + } + +vhost_shadow_enqueue_packed (vq, buffer_len, buffer_buf_id, + buffer_desc_count, *nr_buffers); + +return 0 ; +} + +static __rte_always_inline int16_t +virtio_dev_rx_async_single_packed(struct virtio_net *dev, + struct vhost_virtqueue *vq, + struct rte_mbuf *pkt,lib/librte_vhost/virtio_net.c virtio_dev_rx_async_submit_split(struct virtio_net *dev,
Quoted 10 lines
lib/librte_vhost/virtio_net.c +10
-0+ uint16_t *nr_descs, uint16_t *nr_buffers, + struct vring_packed_desc *async_descs, + struct iovec *src_iovec, struct iovec *dst_iovec, + struct rte_vhost_iov_iter *src_it, + struct rte_vhost_iov_iter *dst_it) { + struct buf_vector buf_vec[BUF_VECTOR_MAX]; + *nr_descs =0 ; + *nr_buffers =0 ; + + if (unlikely(vhost_enqueue_async_single_packed(dev, vq, pkt,
buf_vec,lib/librte_vhost/virtio_net.c virtio_dev_rx_async_submit_split(struct virtio_net *dev,
Quoted 12 lines
lib/librte_vhost/virtio_net.c +12
-0+ nr_descs, + nr_buffers, + async_descs, + src_iovec, dst_iovec, + src_it, dst_it) < 0)) { +VHOST_LOG_DATA (DEBUG , +"(%d) failed to get enough desc from vring\n" , + dev->vid); +return -1 ; + } + + VHOST_LOG_DATA(DEBUG, "(%d) current index %d | endindex %d\n",
Quoted 11 lines
lib/librte_vhost/virtio_net.c +11
-0+ dev->vid, vq->last_avail_idx, + vq->last_avail_idx + *nr_descs); + +return 0 ; +} + +static __rte_noinline uint32_t +virtio_dev_rx_async_submit_packed (struct virtio_net *dev, +struct vhost_virtqueue *vq,uint16_t queue_id, +struct rte_mbuf **pkts,uint32_t count, +struct rte_mbuf **comp_pkts,uint32_t *comp_count) {lib/librte_vhost/virtio_net.c virtio_dev_rx_async_submit_split(struct virtio_net *dev,
Quoted 10 lines
lib/librte_vhost/virtio_net.c +10
-0+uint32_t pkt_idx =0 , pkt_burst_idx =0 ; +uint16_t async_descs_idx =0 ; +uint16_t num_buffers; +uint16_t num_desc; + +struct rte_vhost_iov_iter *it_pool = vq->it_pool; +struct iovec *vec_pool = vq->vec_pool; +struct rte_vhost_async_desc tdes[MAX_PKT_BURST ]; +struct iovec *src_iovec = vec_pool; + struct iovec *dst_iovec = vec_pool + (VHOST_MAX_ASYNC_VEC >>1);
Quoted 14 lines
lib/librte_vhost/virtio_net.c virtio_dev_rx_async_submit_split(struct virtio_net *dev,
Quoted 12 lines
lib/librte_vhost/virtio_net.c +12
-0+struct rte_vhost_iov_iter *src_it = it_pool; +struct rte_vhost_iov_iter *dst_it = it_pool +1 ; +uint16_t slot_idx =0 ; +uint16_t segs_await =0 ; +uint16_t iovec_idx =0 , it_idx =0 ; +struct async_inflight_info *pkts_info = vq->async_pkts_info; +uint32_t n_pkts =0 , pkt_err =0 ; +uint32_t num_async_pkts =0 , num_done_pkts =0 ; +struct vring_packed_desc async_descs[vq->size]; + +rte_prefetch0 (&vq->desc_packed[vq->last_avail_idx & (vq->size - +1 )]);The size of the ring is not necessarily a power of two with packed ring.
Quoted 4 lines
For the size of the ring is not necessarily a power of two, so maybe I can use codes like
Indx %vq->size?
I'm not sure if it's a good way to do that.
In this case it is OK.
Quoted 323 lines
Quoted 16 lines
lib/librte_vhost/virtio_net.c virtio_dev_rx_async_submit_split(struct virtio_net *dev, · line 1880
Quoted 7 lines
lib/librte_vhost/virtio_net.c +6
-0+ +for (pkt_idx =0 ; pkt_idx < count; pkt_idx++) { + if (unlikely(virtio_dev_rx_async_single_packed(dev, vq, + pkts[pkt_idx], + &num_desc, &num_buffers, +&async_descs[async_descs_idx],
lib/librte_vhost/virtio_net.c virtio_dev_rx_async_submit_split(struct virtio_net *dev,
Quoted 7 lines
lib/librte_vhost/virtio_net.c +7
-0+ &src_iovec[iovec_idx], + &dst_iovec[iovec_idx], + &src_it[it_idx], + &dst_it[it_idx]) < 0)) + break; + + VHOST_LOG_DATA(DEBUG, "(%d) current index %d | endindex %d\n",
Quoted 7 lines
lib/librte_vhost/virtio_net.c virtio_dev_rx_async_submit_split(struct virtio_net *dev, · line 1886
Quoted 5 lines
lib/librte_vhost/virtio_net.c +5
-0+ dev->vid, vq->last_avail_idx, + vq->last_avail_idx + num_desc); + + slot_idx = (vq->async_pkts_idx + num_async_pkts) & + (vq->size -1 );Same here.
Sure.
Quoted 28 lines
lib/librte_vhost/virtio_net.c virtio_dev_rx_async_submit_split(struct virtio_net *dev,
Quoted 6 lines
lib/librte_vhost/virtio_net.c +5
-0+if (src_it[it_idx].count) { +uint16_t from, to; + + async_descs_idx += num_desc; + async_fill_desc(&tdes[pkt_burst_idx++],&src_it[it_idx],
Quoted 10 lines
lib/librte_vhost/virtio_net.c +10
-0+ &dst_it[it_idx]); + pkts_info[slot_idx].descs = num_desc; + pkts_info[slot_idx].nr_buffers = num_buffers; + pkts_info[slot_idx].mbuf = pkts[pkt_idx]; + num_async_pkts++; + iovec_idx += src_it[it_idx].nr_segs; + it_idx +=2 ; + + segs_await += src_it[it_idx].nr_segs; +lib/librte_vhost/virtio_net.c virtio_dev_rx_async_submit_split(struct virtio_net *dev,
Quoted 10 lines
lib/librte_vhost/virtio_net.c +10
-0+/** +* recover shadow used ring and keep DMA-occupied +* descriptors. +*/ + from = vq->shadow_used_idx - num_buffers; + to = vq->async_packed_buffer_idx & (vq->size -1 ); + shadow_ring_store(vq, vq->shadow_used_packed, + vq->async_buffers_packed, + from, to, num_buffers, + sizeof(struct
vring_used_elem_packed));Quoted 6 lines
lib/librte_vhost/virtio_net.c virtio_dev_rx_async_submit_split(struct virtio_net *dev, · line 1915
Quoted 4 lines
lib/librte_vhost/virtio_net.c +4
-0+ + vq->async_packed_buffer_idx += num_buffers; + vq->shadow_used_idx -= num_buffers; + }else Brackets needed.
Sure.
Quoted 53 lines
lib/librte_vhost/virtio_net.c virtio_dev_rx_async_submit_split(struct virtio_net *dev,
Quoted 11 lines
lib/librte_vhost/virtio_net.c +10
-0+ comp_pkts[num_done_pkts++] = pkts[pkt_idx]; + +vq_inc_last_avail_packed (vq, num_desc); + +/* +* conditions to trigger async device transfer: +* - buffered packet number reaches transfer threshold +* - unused async iov number is less than max vhost vector +*/ + if (unlikely(pkt_burst_idx >=
VHOST_ASYNC_BATCH_THRESHOLD||lib/librte_vhost/virtio_net.c virtio_dev_rx_async_submit_split(struct virtio_net *dev,
Quoted 12 lines
lib/librte_vhost/virtio_net.c +12
-0+ ((VHOST_MAX_ASYNC_VEC >> 1) - segs_await < + BUF_VECTOR_MAX))) { + n_pkts = vq->async_ops.transfer_data (dev->vid, + queue_id, tdes,0 , pkt_burst_idx); + iovec_idx =0 ; + it_idx =0 ; + segs_await =0 ; + vq->async_pkts_inflight_n += n_pkts; + +if (unlikely (n_pkts < pkt_burst_idx)) { +/* +* log error packets number here and do actual
Quoted 28 lines
lib/librte_vhost/virtio_net.c +28
-0+* error processing when applications poll +* completion +*/ + pkt_err = pkt_burst_idx - n_pkts; + pkt_burst_idx =0 ; + pkt_idx++; +break ; + } + + pkt_burst_idx =0 ; + } + } + +if (pkt_burst_idx) { + n_pkts = vq->async_ops.transfer_data (dev->vid, + queue_id, tdes,0 , pkt_burst_idx); + vq->async_pkts_inflight_n += n_pkts; + +if (unlikely (n_pkts < pkt_burst_idx)) + pkt_err = pkt_burst_idx - n_pkts; + } + +do_data_copy_enqueue (dev, vq); + +if (unlikely (pkt_err)) { +uint16_t descs_err =0 ; +uint16_t buffers_err =0 ; +Quoted 8 lines
lib/librte_vhost/virtio_net.c virtio_dev_rx_async_submit_split(struct virtio_net *dev, · line 1971
Quoted 6 lines
lib/librte_vhost/virtio_net.c +6
-0+ num_async_pkts -= pkt_err; + pkt_idx -= pkt_err; +/* calculate the sum of buffers and descs of DMA-error packets. */ +while (pkt_err-- >0 ) { + descs_err += + pkts_info[slot_idx & (vq->size -1 )].descs;The size of the ring is not necessarily a power of two with packed ring.
Will be fixed.
Quoted 6 lines
lib/librte_vhost/virtio_net.c
Quoted 3 lines
lib/librte_vhost/virtio_net.c +2
-0+ buffers_err += + pkts_info[slot_idx & (vq->size -1)].nr_buffers;
Ditto.
Will be fixed.
Quoted 27 lines
lib/librte_vhost/virtio_net.c virtio_dev_rx_async_submit_split(struct virtio_net *dev,
Quoted 12 lines
lib/librte_vhost/virtio_net.c +11
-0+ slot_idx--; + } + + vq->async_packed_buffer_idx -= buffers_err; + +if (vq->last_avail_idx >= descs_err) { + vq->last_avail_idx -= descs_err; + + rte_memcpy(&vq->desc_packed[vq->last_avail_idx], + &async_descs[async_descs_idx - descs_err], + descs_err * sizeof(struct
vring_packed_desc));lib/librte_vhost/virtio_net.c virtio_dev_rx_async_submit_split(struct virtio_net *dev,
Quoted 13 lines
lib/librte_vhost/virtio_net.c +13
-0+ }else { +uint16_t nr_copy; + + vq->last_avail_idx = vq->last_avail_idx + vq->size + - descs_err; + nr_copy = vq->size - vq->last_avail_idx; +rte_memcpy (&vq->desc_packed[vq->last_avail_idx], + &async_descs[async_descs_idx - descs_err], + nr_copy *sizeof (struct vring_packed_desc )); + descs_err -= nr_copy; + rte_memcpy(vq->desc_packed, + &async_descs[async_descs_idx - descs_err], + descs_err * sizeof(struct
vring_packed_desc));Quoted 7 lines
lib/librte_vhost/virtio_net.c virtio_dev_rx_async_submit_split(struct virtio_net *dev, · line 2002
Quoted 5 lines
lib/librte_vhost/virtio_net.c +5
-0+ vq->avail_wrap_counter ^=1 ; + } + + num_done_pkts = pkt_idx - num_async_pkts; + }This error handling could be moved in a dedicated function.
Sure, will fix it in the next version.
Quoted 14 lines
lib/librte_vhost/virtio_net.c virtio_dev_rx_async_submit_split(struct virtio_net *dev, · line 2012
Quoted 11 lines
lib/librte_vhost/virtio_net.c +10
-0+ vq->async_pkts_idx += num_async_pkts; + *comp_count = num_done_pkts; + +if (likely (vq->shadow_used_idx)) { +vhost_flush_enqueue_shadow_packed (dev, vq); +vhost_vring_call_packed (dev, vq); + } + +return pkt_idx; +}Above function is very big and complex, it should be possible to split it in several ones to make it maintainable.
I think move the error handling code will make it smaller.
Thanks.
ChengQuoted 10 lines
Quoted 6 lines
+
static__rte_always_inlinevoid write_back_completed_descs_split(structvhost_virtqueue*vq,uint16_tn_descs) { @@ -1693,12 +2048,40 @@ write_back_completed_descs_split(structvhost_virtqueue*vq,uint16_t
n_descs)Quoted 3 lines
} while (
nr_left> 0);
}Quoted 13 lines
lib/librte_vhost/virtio_net.c write_back_completed_descs_split(struct vhost_virtqueue *vq, uint16_t n_descs) · line 2061
Quoted 11 lines
lib/librte_vhost/virtio_net.c +11
-0+static __rte_always_inline void +write_back_completed_descs_packed (struct vhost_virtqueue *vq, +uint16_t n_buffers) +{ +uint16_t nr_left = n_buffers; +uint16_t from, to; + + do { + from = vq->last_async_buffer_idx & + (vq->size - 1); + to = (from + nr_left) & (vq->size - 1);The size of the ring is not necessarily a power of two with packed ring.
Sure.
Quoted 32 lines
lib/librte_vhost/virtio_net.c uint16_t
Quoted 28 lines
lib/librte_vhost/virtio_net.c +18
-1+if (to > from) { +vhost_update_used_packed (vq, + vq->async_buffers_packed + from, + to - from); + vq->last_async_buffer_idx += nr_left; + nr_left =0 ; + }else { +vhost_update_used_packed (vq, + vq->async_buffers_packed + from, + vq->size - from); + vq->last_async_buffer_idx += + vq->size - from; + nr_left -= vq->size - from; + } + }while (nr_left >0 ); +} +uint16_t rte_vhost_poll_enqueue_completed (int vid,uint16_t queue_id,struct rte_mbuf **pkts,uint16_t count) {struct virtio_net *dev =get_device (vid);struct vhost_virtqueue *vq; -uint16_t n_pkts_cpl =0 , n_pkts_put =0 , n_descs =0 ; +uint16_t n_pkts_cpl =0 , n_pkts_put =0 , n_descs =0 , n_buffers =0 ;uint16_t start_idx, pkts_idx, vq_size;struct async_inflight_info *pkts_info;uint16_t from, i;@@ -1740,21 +2123,41 @@ uint16_trte_vhost_poll_enqueue_completed(int vid,
uint16_tqueue_id,Quoted 3 lines
lib/librte_vhost/virtio_net.c +0
-0goto done; }Quoted 9 lines
lib/librte_vhost/virtio_net.c uint16_t rte_vhost_poll_enqueue_completed(int vid, uint16_t queue_id, · line 2128
Quoted 7 lines
lib/librte_vhost/virtio_net.c +3
-4-for (i =0 ; i < n_pkts_put; i++) { - from = (start_idx + i) & (vq_size -1 ); - n_descs += pkts_info[from].descs; - pkts[i] = pkts_info[from].mbuf; +if (vq_is_packed (dev)) { +for (i =0 ; i < n_pkts_put; i++) { + from = (start_idx + i) & (vq_size -1 );Unlike split ring, packed ring size is not necessarily a power of 2.
Sure.
Thanks.Quoted 58 lines
Quoted 9 lines
lib/librte_vhost/virtio_net.c +8
-0+ n_buffers += pkts_info[from].nr_buffers; + pkts[i] = pkts_info[from].mbuf; + } + }else { +for (i =0 ; i < n_pkts_put; i++) { + from = (start_idx + i) & (vq_size -1 ); + n_descs += pkts_info[from].descs; + pkts[i] = pkts_info[from].mbuf;lib/librte_vhost/virtio_net.c uint16_t rte_vhost_poll_enqueue_completed(int vid, uint16_t queue_id,
Quoted 10 lines
lib/librte_vhost/virtio_net.c +4
-1+ } } + vq->async_last_pkts_n = n_pkts_cpl - n_pkts_put; vq->async_pkts_inflight_n -= n_pkts_put;if (likely (vq->enabled && vq->access_ok)) { -write_back_completed_descs_split (vq, n_descs); +if (vq_is_packed (dev)) { + write_back_completed_descs_packed(vq,
n_buffers);lib/librte_vhost/virtio_net.c uint16_t · line 1753
Quoted 2 lines
lib/librte_vhost/virtio_net.c +0
-1- __atomic_add_fetch(&vq->used->idx, n_descs,
__ATOMIC_RELEASE);lib/librte_vhost/virtio_net.c virtio_dev_rx_async_submit(struct virtio_net
Quoted 21 lines
lib/librte_vhost/virtio_net.c +14
-3-vhost_vring_call_split (dev, vq); - }else - vq->last_async_desc_idx += n_descs; +vhost_vring_call_packed (dev, vq); + }else { +write_back_completed_descs_split (vq, n_descs); + +__atomic_add_fetch (&vq->used->idx, n_descs, + __ATOMIC_RELEASE); +vhost_vring_call_split (dev, vq); + } + }else { +if (vq_is_packed (dev)) + vq->last_async_buffer_idx += n_buffers; +else + vq->last_async_desc_idx += n_descs; + } done:rte_spinlock_unlock (&vq->access_lock);@@ -1795,9 +2198,10 @@ virtio_dev_rx_async_submit(struct virtio_net*dev,
uint16_tqueue_id,Quoted 13 lines
lib/librte_vhost/virtio_net.c +3
-2if (count ==0 ) goto out; -/* TODO: packed queue not implemented */ if (vq_is_packed (dev)) - nb_tx =0 ; + nb_tx =virtio_dev_rx_async_submit_packed (dev, + vq, queue_id, pkts, count, comp_pkts, + comp_count);else nb_tx = virtio_dev_rx_async_submit_split(dev, vq, queue_id, pkts, count, comp_pkts,
Quoted 153 lines
-----Original Message-----
From: Maxime Coquelin <[email protected]>
Sent: Tuesday, April 13, 2021 9:08 PM
To: Jiang, Cheng1 <[email protected]>; Xia, Chenbo <[email protected]>
Cc: [email protected]; Hu, Jiayu <[email protected]>; Yang, YvonneX <[email protected]>; Wang, Yinan <[email protected]>; Liu, Yong <[email protected]>
Subject: Re: [PATCH v5 2/4] vhost: add support for packed ring in async vhostQuoted 26 lines · On 4/13/21 1:48 PM, Jiang, Cheng1 wrote:
Hi Maxime,
Quoted 24 lines
-----Original Message-----
From: Maxime Coquelin <[email protected]>
Sent: Tuesday, April 13, 2021 4:37 PM
To: Jiang, Cheng1 <[email protected]>; Xia, Chenbo <[email protected]>
Cc: [email protected]; Hu, Jiayu <[email protected]>; Yang, YvonneX <[email protected]>; Wang, Yinan <[email protected]>; Liu, Yong <[email protected]>
Subject: Re: [PATCH v5 2/4] vhost: add support for packed ring in async vhostQuoted 10 lines · Cheng Jiang
For now async vhost data path only supports split ring structure. In order to make async vhost compatible with virtio 1.1 spec this patch enables packed ring in async vhost data path.
Signed-off-by Cheng Jiang <[email protected]>--- lib/librte_vhost/rte_vhost_async.h | 1 + lib/librte_vhost/vhost.c | 27 +- lib/librte_vhost/vhost.h | 7 +- lib/librte_vhost/virtio_net.c | 438+++++++++++++++++++++++++++--
Quoted 14 lines
Quoted 14 lines
Quoted 14 lines
4 files changed, 448 insertions(+), 25 deletions(-)lib/librte_vhost/rte_vhost_async.h +1
-0@@ -89,6 +89,7 @@ struct rte_vhost_async_channel_ops { struct async_inflight_info {struct rte_mbuf *mbuf;uint16_t descs;/* num of descs inflight */ +uint16_t nr_buffers;/* num of buffers inflight for packed ring */ };Quoted 6 lines
Quoted 6 lines
lib/librte_vhost/vhost.c vhost_free_async_mem(struct
Quoted 6 lines
lib/librte_vhost/rte_vhost_async.h +0
-0/** lib/librte_vhost/vhost.c +0
-0@@ -342,15 +342,21 @@ vhost_free_async_mem(struct
vhost_virtqueueQuoted 90 lines
Quoted 13 lines
*vq)
lib/librte_vhost/vhost.c vhost_free_async_mem(struct vhost_virtqueue *vq) · line 349
Quoted 9 lines
lib/librte_vhost/vhost.c +5
-1{if (vq->async_pkts_info)rte_free (vq->async_pkts_info); -if (vq->async_descs_split) +if (vq->async_buffers_packed) { +rte_free (vq->async_buffers_packed); + vq->async_buffers_packed =NULL ; + } +if (vq->async_descs_split) {You can remove the check,
rte_freeis safe with NULL pointers. You can do the same for the other ones in this function.OK, it will be fixed.
Quoted 73 lines
lib/librte_vhost/vhost.c int rte_vhost_async_channel_register(int vid,
Quoted 16 lines
lib/librte_vhost/vhost.c +3
-1rte_free (vq->async_descs_split); + vq->async_descs_split =NULL ; + } +if (vq->it_pool)rte_free (vq->it_pool);if (vq->vec_pool)rte_free (vq->vec_pool); vq->async_pkts_info =NULL ; - vq->async_descs_split =NULL ; vq->it_pool =NULL ; vq->vec_pool =NULL ; }@@ -1627,9 +1633,9 @@ int rte_vhost_async_channel_register(int vid,
uint16_tqueue_id,lib/librte_vhost/vhost.c int rte_vhost_async_channel_register(int vid, uint16_t queue_id,
Quoted 7 lines
lib/librte_vhost/vhost.c +1
-2return -1 ;/* packed queue is not supported */ -if (unlikely (vq_is_packed (dev) || !f.async_inorder)) { +if (unlikely (!f.async_inorder)) { VHOST_LOG_CONFIG(ERR, - "async copy is not supported on packed queue ornon-inorder mode "
lib/librte_vhost/vhost.c int rte_vhost_async_channel_register(int · line 1673
Quoted 6 lines
lib/librte_vhost/vhost.c +1
-0+"async copy is not supported on non-inorder mode " "(vid %d, qid: %d)\n", vid, queue_id);return -1 ; }@@ -1667,11 +1673,18 @@ int rte_vhost_async_channel_register(int vid,
uint16_tqueue_id,Quoted 20 lines
lib/librte_vhost/vhost.c +10
-3vq->vec_pool =rte_malloc_socket (NULL ,VHOST_MAX_ASYNC_VEC *sizeof (struct iovec ),RTE_CACHE_LINE_SIZE , node); - vq->async_descs_split =rte_malloc_socket (NULL , +if (vq_is_packed (dev)) { + vq->async_buffers_packed =rte_malloc_socket (NULL , + vq->size *sizeof (struct vring_used_elem_packed ), +RTE_CACHE_LINE_SIZE , node); + }else { + vq->async_descs_split =rte_malloc_socket (NULL , vq->size *sizeof (struct vring_used_elem ),RTE_CACHE_LINE_SIZE , node); -if (!vq->async_descs_split || !vq->async_pkts_info || - !vq->it_pool || !vq->vec_pool) { + } + +if (!vq->async_buffers_packed || !vq->async_descs_split || + !vq->async_pkts_info || !vq->it_pool || !vq->vec_pool) {vhost_free_async_mem (vq); VHOST_LOG_CONFIG(ERR,Quoted 1 line
"async register failed: cannot allocate
memory for vq data "
Quoted 5 lines
lib/librte_vhost/vhost.h +0
-0lib/librte_vhost/vhost.h struct vhost_virtqueue { · line 209
Quoted 10 lines
lib/librte_vhost/vhost.h +5
-1@@ -201,9 +201,14 @@ struct vhost_virtqueue {uint16_t async_pkts_idx;uint16_t async_pkts_inflight_n;uint16_t async_last_pkts_n; -struct vring_used_elem *async_descs_split; +union { +struct vring_used_elem *async_descs_split; +struct vring_used_elem_packed *async_buffers_packed; + };uint16_t async_desc_idx; +uint16_t async_packed_buffer_idx;Don't dupplicate variable names,
async_desc_idxcan be reused for packed ring. Also, they are representing the same thing, why use desc in one case and buffer in the other?
Quoted 6 lines
Quoted 1 line
The main reason is that the unit of the packed used ring is buffer, which can
contain many desc.
Quoted 1 line
I think using
desc_idxwill cause ambiguity, but if you think that I shouldreuse the
desc_idx, I have no problem with that.OK, in this case please use a union not to waste memory.
Sure, I'll fix it.
Quoted 284 lines
Quoted 7 lines
Quoted 7 lines
lib/librte_vhost/vhost.h struct vhost_virtqueue { · line 211
Quoted 4 lines
lib/librte_vhost/vhost.h +1
-0uint16_t last_async_desc_idx; +uint16_t last_async_buffer_idx;Same remark here.
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
lib/librte_vhost/vhost.h +0
-0/* vq async features */ bool async_inorder;(quoted diff) +0
-0
b/lib/librte_vhost/virtio_net.cindexc43ab0093..410be9678100644lib/librte_vhost/virtio_net.c +0
-0@@ -363,14 +363,14 @@vhost_shadow_dequeue_single_packed_inorder(struct
vhost_virtqueueQuoted 37 lines
Quoted 37 lines
*vq,
lib/librte_vhost/virtio_net.c vhost_shadow_enqueue_single_packed(struct
Quoted 20 lines
}
static
__rte_always_inlinevoidlib/librte_vhost/virtio_net.c +5
-5-vhost_shadow_enqueue_single_packed(struct virtio_net *dev, - struct vhost_virtqueue *vq, - uint32_t len[], - uint16_t id[], - uint16_t count[], +vhost_shadow_enqueue_packed(struct vhost_virtqueue *vq, + uint32_t *len, + uint16_t *id, + uint16_t *count, uint16_t num_buffers) { uint16_t i; +for (i =0 ; i < num_buffers; i++) {/* enqueue shadow flush action aligned with batch num */ if (!vq->shadow_used_idx)@@ -382,6 +382,17 @@ vhost_shadow_enqueue_single_packed(struct
virtio_net*dev,Quoted 15 lines
lib/librte_vhost/virtio_net.c +11
-0vq->shadow_aligned_idx += count[i]; vq->shadow_used_idx++; } +} + +static __rte_always_inline void +vhost_shadow_enqueue_single_packed (struct virtio_net *dev, +struct vhost_virtqueue *vq, +uint32_t *len, +uint16_t *id, +uint16_t *count, +uint16_t num_buffers) +{ +vhost_shadow_enqueue_packed (vq, len, id, count, num_buffers);Quoted 3 lines
Quoted 3 lines
lib/librte_vhost/virtio_net.c shadow_ring_store(struct vhost_virtqueue
Quoted 3 lines
lib/librte_vhost/virtio_net.c +0
-0if (vq->shadow_aligned_idx >=PACKED_BATCH_SIZE ) {do_data_copy_enqueue (dev, vq);@@ -1481,6 +1492,62 @@ shadow_ring_store(struct vhost_virtqueue*vq,
Quoted 227 lines
Quoted 4 lines
void
*shadow_ring, void*d_ring,Quoted 3 lines
lib/librte_vhost/virtio_net.c +0
-0} }Quoted 9 lines
lib/librte_vhost/virtio_net.c shadow_ring_store(struct vhost_virtqueue *vq, void *shadow_ring, void *d_ring, · line 1501
Quoted 7 lines
lib/librte_vhost/virtio_net.c +7
-0+static __rte_always_inline void +vhost_update_used_packed (struct vhost_virtqueue *vq, +struct vring_used_elem_packed *shadow_ring, +uint16_t count) +{ +if (count ==0 ) +return ;Move this after the variables declaration.
Sure.
Quoted 118 lines
Quoted 42 lines
lib/librte_vhost/virtio_net.c +41
-0+ +int i; +uint16_t used_idx = vq->last_used_idx; +uint16_t head_idx = vq->last_used_idx; +uint16_t head_flags =0 ; + +/* Split loop in two to save memory barriers */ +for (i =0 ; i < count; i++) { + vq->desc_packed[used_idx].id = shadow_ring[i].id; + vq->desc_packed[used_idx].len = shadow_ring[i].len; + + used_idx += shadow_ring[i].count; +if (used_idx >= vq->size) + used_idx -= vq->size; + } + +/* The ordering for storing desc flags needs to be enforced. */ +rte_atomic_thread_fence (__ATOMIC_RELEASE); + +for (i =0 ; i < count; i++) { +uint16_t flags; + +if (vq->shadow_used_packed[i].len) + flags =VRING_DESC_F_WRITE ; +else + flags =0 ; + +if (vq->used_wrap_counter) { + flags |=VRING_DESC_F_USED ; + flags |=VRING_DESC_F_AVAIL ; + }else { + flags &= ~VRING_DESC_F_USED ; + flags &= ~VRING_DESC_F_AVAIL ; + } + +if (i >0 ) { + vq->desc_packed[vq->last_used_idx].flags = flags; + + }else { + head_idx = vq->last_used_idx; + head_flags = flags;lib/librte_vhost/virtio_net.c shadow_ring_store(struct vhost_virtqueue *vq, void *shadow_ring, void *d_ring,
Quoted 10 lines
lib/librte_vhost/virtio_net.c +7
-0+ } + +vq_inc_last_used_packed (vq, shadow_ring[i].count); + } + + vq->desc_packed[head_idx].flags = head_flags; } + static __rte_noinline uint32_t virtio_dev_rx_async_submit_split(struct virtio_net *dev, struct vhost_virtqueue *vq, uint16_t queue_id, @@ -1656,6+1723,294
Quoted 12 lines
@@ virtio_dev_rx_async_submit_split(struct
virtio_net*dev,lib/librte_vhost/virtio_net.c +8
-0return pkt_idx; } +static __rte_always_inline int +vhost_enqueue_async_single_packed(struct virtio_net *dev, + struct vhost_virtqueue *vq, + struct rte_mbuf *pkt, + struct buf_vector *buf_vec, + uint16_t *nr_descs, + uint16_t *nr_buffers, + struct vring_packed_desc *async_descs,lib/librte_vhost/virtio_net.c virtio_dev_rx_async_submit_split(struct virtio_net *dev,
Quoted 10 lines
lib/librte_vhost/virtio_net.c +10
-0+ struct iovec *src_iovec, struct iovec *dst_iovec, + struct rte_vhost_iov_iter *src_it, + struct rte_vhost_iov_iter *dst_it) { + uint16_t nr_vec = 0; +uint16_t avail_idx = vq->last_avail_idx; +uint16_t max_tries, tries =0 ; +uint16_t buf_id =0 ; +uint32_t len =0 ; +uint16_t desc_count =0 ; + uint32_t size = pkt->pkt_len + sizeof(struct
virtio_net_hdr_mrg_rxbuf);Quoted 42 lines
lib/librte_vhost/virtio_net.c +42
-0+uint32_t buffer_len[vq->size]; +uint16_t buffer_buf_id[vq->size]; +uint16_t buffer_desc_count[vq->size]; + *nr_buffers =0 ; + +if (rxvq_is_mergeable (dev)) + max_tries = vq->size -1 ; +else + max_tries =1 ; + +while (size >0 ) { +/* +* if we tried all available ring items, and still +* can't get enough buf, it means something abnormal +* happened. +*/ +if (unlikely (++tries > max_tries)) +return -1 ; + +if (unlikely (fill_vec_buf_packed (dev, vq, + avail_idx, &desc_count, + buf_vec, &nr_vec, + &buf_id, &len, +VHOST_ACCESS_RW ) <0 )) +return -1 ; + + len =RTE_MIN (len, size); + size -= len; + + buffer_len[*nr_buffers] = len; + buffer_buf_id[*nr_buffers] = buf_id; + buffer_desc_count[*nr_buffers] = desc_count; + *nr_buffers +=1 ; + + *nr_descs += desc_count; + avail_idx += desc_count; +if (avail_idx >= vq->size) + avail_idx -= vq->size; + } + +if (async_mbuf_to_desc (dev, vq, pkt, buf_vec, nr_vec, *nr_buffers, + src_iovec, dst_iovec, src_it, dst_it) <0 )Quoted 8 lines
lib/librte_vhost/virtio_net.c virtio_dev_rx_async_submit_split(struct virtio_net *dev, · line 1792
Quoted 6 lines
lib/librte_vhost/virtio_net.c +6
-0+return -1 ; +/* store descriptors for DMA */ +if (avail_idx >= *nr_descs) +rte_memcpy (async_descs, + &vq->desc_packed[vq->last_avail_idx], + *nr_descs *sizeof (struct vring_packed_desc ));Please add brackets for the 'if' since there are for the 'else'.
Sure, sorry for that.
Quoted 81 lines
Quoted 21 lines
lib/librte_vhost/virtio_net.c +20
-0+else { +uint16_t nr_copy = vq->size - vq->last_avail_idx; +rte_memcpy (async_descs, + &vq->desc_packed[vq->last_avail_idx], + nr_copy *sizeof (struct vring_packed_desc )); +rte_memcpy (async_descs + nr_copy, + vq->desc_packed, (*nr_descs - nr_copy) * +sizeof (struct vring_packed_desc )); + } + +vhost_shadow_enqueue_packed (vq, buffer_len, buffer_buf_id, + buffer_desc_count, *nr_buffers); + +return 0 ; +} + +static __rte_always_inline int16_t +virtio_dev_rx_async_single_packed(struct virtio_net *dev, + struct vhost_virtqueue *vq, + struct rte_mbuf *pkt,lib/librte_vhost/virtio_net.c virtio_dev_rx_async_submit_split(struct virtio_net *dev,
Quoted 10 lines
lib/librte_vhost/virtio_net.c +10
-0+ uint16_t *nr_descs, uint16_t *nr_buffers, + struct vring_packed_desc *async_descs, + struct iovec *src_iovec, struct iovec *dst_iovec, + struct rte_vhost_iov_iter *src_it, + struct rte_vhost_iov_iter *dst_it) { + struct buf_vector buf_vec[BUF_VECTOR_MAX]; + *nr_descs =0 ; + *nr_buffers =0 ; + + if (unlikely(vhost_enqueue_async_single_packed(dev, vq, pkt,
buf_vec,lib/librte_vhost/virtio_net.c virtio_dev_rx_async_submit_split(struct virtio_net *dev,
Quoted 12 lines
lib/librte_vhost/virtio_net.c +12
-0+ nr_descs, + nr_buffers, + async_descs, + src_iovec, dst_iovec, + src_it, dst_it) < 0)) { +VHOST_LOG_DATA (DEBUG , +"(%d) failed to get enough desc from vring\n" , + dev->vid); +return -1 ; + } + + VHOST_LOG_DATA(DEBUG, "(%d) current index %d | endindex %d\n",
Quoted 11 lines
lib/librte_vhost/virtio_net.c +11
-0+ dev->vid, vq->last_avail_idx, + vq->last_avail_idx + *nr_descs); + +return 0 ; +} + +static __rte_noinline uint32_t +virtio_dev_rx_async_submit_packed (struct virtio_net *dev, +struct vhost_virtqueue *vq,uint16_t queue_id, +struct rte_mbuf **pkts,uint32_t count, +struct rte_mbuf **comp_pkts,uint32_t *comp_count) {lib/librte_vhost/virtio_net.c virtio_dev_rx_async_submit_split(struct virtio_net *dev,
Quoted 10 lines
lib/librte_vhost/virtio_net.c +10
-0+uint32_t pkt_idx =0 , pkt_burst_idx =0 ; +uint16_t async_descs_idx =0 ; +uint16_t num_buffers; +uint16_t num_desc; + +struct rte_vhost_iov_iter *it_pool = vq->it_pool; +struct iovec *vec_pool = vq->vec_pool; +struct rte_vhost_async_desc tdes[MAX_PKT_BURST ]; +struct iovec *src_iovec = vec_pool; + struct iovec *dst_iovec = vec_pool + (VHOST_MAX_ASYNC_VEC >>1);
lib/librte_vhost/virtio_net.c virtio_dev_rx_async_submit_split(struct virtio_net *dev,
Quoted 12 lines
lib/librte_vhost/virtio_net.c +12
-0+struct rte_vhost_iov_iter *src_it = it_pool; +struct rte_vhost_iov_iter *dst_it = it_pool +1 ; +uint16_t slot_idx =0 ; +uint16_t segs_await =0 ; +uint16_t iovec_idx =0 , it_idx =0 ; +struct async_inflight_info *pkts_info = vq->async_pkts_info; +uint32_t n_pkts =0 , pkt_err =0 ; +uint32_t num_async_pkts =0 , num_done_pkts =0 ; +struct vring_packed_desc async_descs[vq->size]; + +rte_prefetch0 (&vq->desc_packed[vq->last_avail_idx & (vq->size - +1 )]);The size of the ring is not necessarily a power of two with packed ring.
Quoted 5 lines
Quoted 3 lines
For the size of the ring is not necessarily a power of two, so maybe I can use codes like Indx %
vq->size?
I'm not sure if it's a good way to do that.In this case it is OK.
OK. I'll fix them in the next version.
Thanks a lot.
Cheng
Quoted 328 lines
Quoted 233 lines
Quoted 17 lines
lib/librte_vhost/virtio_net.c virtio_dev_rx_async_submit_split(struct virtio_net *dev, · line 1880
Quoted 8 lines
lib/librte_vhost/virtio_net.c +6
-0+ +for (pkt_idx =0 ; pkt_idx < count; pkt_idx++) { + if (unlikely(virtio_dev_rx_async_single_packed(dev, vq, + pkts[pkt_idx], + &num_desc, &num_buffers, +&async_descs[async_descs_idx],
lib/librte_vhost/virtio_net.c virtio_dev_rx_async_submit_split(struct virtio_net *dev,
Quoted 7 lines
lib/librte_vhost/virtio_net.c +7
-0+ &src_iovec[iovec_idx], + &dst_iovec[iovec_idx], + &src_it[it_idx], + &dst_it[it_idx]) < 0)) + break; + + VHOST_LOG_DATA(DEBUG, "(%d) current index %d | endindex %d\n",
Quoted 7 lines
lib/librte_vhost/virtio_net.c virtio_dev_rx_async_submit_split(struct virtio_net *dev, · line 1886
Quoted 5 lines
lib/librte_vhost/virtio_net.c +5
-0+ dev->vid, vq->last_avail_idx, + vq->last_avail_idx + num_desc); + + slot_idx = (vq->async_pkts_idx + num_async_pkts) & + (vq->size -1 );Same here.
Sure.
Quoted 28 lines
lib/librte_vhost/virtio_net.c virtio_dev_rx_async_submit_split(struct virtio_net *dev,
Quoted 6 lines
lib/librte_vhost/virtio_net.c +5
-0+if (src_it[it_idx].count) { +uint16_t from, to; + + async_descs_idx += num_desc; + async_fill_desc(&tdes[pkt_burst_idx++],&src_it[it_idx],
Quoted 10 lines
lib/librte_vhost/virtio_net.c +10
-0+ &dst_it[it_idx]); + pkts_info[slot_idx].descs = num_desc; + pkts_info[slot_idx].nr_buffers = num_buffers; + pkts_info[slot_idx].mbuf = pkts[pkt_idx]; + num_async_pkts++; + iovec_idx += src_it[it_idx].nr_segs; + it_idx +=2 ; + + segs_await += src_it[it_idx].nr_segs; +lib/librte_vhost/virtio_net.c virtio_dev_rx_async_submit_split(struct virtio_net *dev,
Quoted 10 lines
lib/librte_vhost/virtio_net.c +10
-0+/** +* recover shadow used ring and keep DMA-occupied +* descriptors. +*/ + from = vq->shadow_used_idx - num_buffers; + to = vq->async_packed_buffer_idx & (vq->size -1 ); + shadow_ring_store(vq, vq->shadow_used_packed, + vq->async_buffers_packed, + from, to, num_buffers, + sizeof(struct
vring_used_elem_packed));Quoted 6 lines
lib/librte_vhost/virtio_net.c virtio_dev_rx_async_submit_split(struct virtio_net *dev, · line 1915
Quoted 4 lines
lib/librte_vhost/virtio_net.c +4
-0+ + vq->async_packed_buffer_idx += num_buffers; + vq->shadow_used_idx -= num_buffers; + }else Brackets needed.
Sure.
Quoted 53 lines
lib/librte_vhost/virtio_net.c virtio_dev_rx_async_submit_split(struct virtio_net *dev,
Quoted 11 lines
lib/librte_vhost/virtio_net.c +10
-0+ comp_pkts[num_done_pkts++] = pkts[pkt_idx]; + +vq_inc_last_avail_packed (vq, num_desc); + +/* +* conditions to trigger async device transfer: +* - buffered packet number reaches transfer threshold +* - unused async iov number is less than max vhost vector +*/ + if (unlikely(pkt_burst_idx >=
VHOST_ASYNC_BATCH_THRESHOLD||lib/librte_vhost/virtio_net.c virtio_dev_rx_async_submit_split(struct virtio_net *dev,
Quoted 12 lines
lib/librte_vhost/virtio_net.c +12
-0+ ((VHOST_MAX_ASYNC_VEC >> 1) - segs_await < + BUF_VECTOR_MAX))) { + n_pkts = vq->async_ops.transfer_data (dev->vid, + queue_id, tdes,0 , pkt_burst_idx); + iovec_idx =0 ; + it_idx =0 ; + segs_await =0 ; + vq->async_pkts_inflight_n += n_pkts; + +if (unlikely (n_pkts < pkt_burst_idx)) { +/* +* log error packets number here and do actual
Quoted 28 lines
lib/librte_vhost/virtio_net.c +28
-0+* error processing when applications poll +* completion +*/ + pkt_err = pkt_burst_idx - n_pkts; + pkt_burst_idx =0 ; + pkt_idx++; +break ; + } + + pkt_burst_idx =0 ; + } + } + +if (pkt_burst_idx) { + n_pkts = vq->async_ops.transfer_data (dev->vid, + queue_id, tdes,0 , pkt_burst_idx); + vq->async_pkts_inflight_n += n_pkts; + +if (unlikely (n_pkts < pkt_burst_idx)) + pkt_err = pkt_burst_idx - n_pkts; + } + +do_data_copy_enqueue (dev, vq); + +if (unlikely (pkt_err)) { +uint16_t descs_err =0 ; +uint16_t buffers_err =0 ; +Quoted 8 lines
lib/librte_vhost/virtio_net.c virtio_dev_rx_async_submit_split(struct virtio_net *dev, · line 1971
Quoted 6 lines
lib/librte_vhost/virtio_net.c +6
-0+ num_async_pkts -= pkt_err; + pkt_idx -= pkt_err; +/* calculate the sum of buffers and descs of DMA-error packets. */ +while (pkt_err-- >0 ) { + descs_err += + pkts_info[slot_idx & (vq->size -1 )].descs;The size of the ring is not necessarily a power of two with packed ring.
Will be fixed.
Quoted 6 lines
lib/librte_vhost/virtio_net.c
Quoted 3 lines
lib/librte_vhost/virtio_net.c +2
-0+ buffers_err += + pkts_info[slot_idx & (vq->size -1)].nr_buffers;
Ditto.
Will be fixed.
Quoted 27 lines
lib/librte_vhost/virtio_net.c virtio_dev_rx_async_submit_split(struct virtio_net *dev,
Quoted 12 lines
lib/librte_vhost/virtio_net.c +11
-0+ slot_idx--; + } + + vq->async_packed_buffer_idx -= buffers_err; + +if (vq->last_avail_idx >= descs_err) { + vq->last_avail_idx -= descs_err; + + rte_memcpy(&vq->desc_packed[vq->last_avail_idx], + &async_descs[async_descs_idx - descs_err], + descs_err * sizeof(struct
vring_packed_desc));lib/librte_vhost/virtio_net.c virtio_dev_rx_async_submit_split(struct virtio_net *dev,
Quoted 13 lines
lib/librte_vhost/virtio_net.c +13
-0+ }else { +uint16_t nr_copy; + + vq->last_avail_idx = vq->last_avail_idx + vq->size + - descs_err; + nr_copy = vq->size - vq->last_avail_idx; +rte_memcpy (&vq->desc_packed[vq->last_avail_idx], + &async_descs[async_descs_idx - descs_err], + nr_copy *sizeof (struct vring_packed_desc )); + descs_err -= nr_copy; + rte_memcpy(vq->desc_packed, + &async_descs[async_descs_idx - descs_err], + descs_err * sizeof(struct
vring_packed_desc));Quoted 7 lines
lib/librte_vhost/virtio_net.c virtio_dev_rx_async_submit_split(struct virtio_net *dev, · line 2002
Quoted 5 lines
lib/librte_vhost/virtio_net.c +5
-0+ vq->avail_wrap_counter ^=1 ; + } + + num_done_pkts = pkt_idx - num_async_pkts; + }This error handling could be moved in a dedicated function.
Sure, will fix it in the next version.
Quoted 14 lines
lib/librte_vhost/virtio_net.c virtio_dev_rx_async_submit_split(struct virtio_net *dev, · line 2012
Quoted 11 lines
lib/librte_vhost/virtio_net.c +10
-0+ vq->async_pkts_idx += num_async_pkts; + *comp_count = num_done_pkts; + +if (likely (vq->shadow_used_idx)) { +vhost_flush_enqueue_shadow_packed (dev, vq); +vhost_vring_call_packed (dev, vq); + } + +return pkt_idx; +}Above function is very big and complex, it should be possible to split it in several ones to make it maintainable.
I think move the error handling code will make it smaller.
Thanks.
ChengQuoted 12 lines
Quoted 8 lines
+
static__rte_always_inlinevoid write_back_completed_descs_split(structvhost_virtqueue*vq,uint16_tn_descs) { @@ -1693,12 +2048,40 @@ write_back_completed_descs_split(structvhost_virtqueue*vq,uint16_t
n_descs)Quoted 3 lines
} while (
nr_left> 0);
}Quoted 13 lines
lib/librte_vhost/virtio_net.c write_back_completed_descs_split(struct vhost_virtqueue *vq, uint16_t n_descs) · line 2061
Quoted 11 lines
lib/librte_vhost/virtio_net.c +11
-0+static __rte_always_inline void +write_back_completed_descs_packed (struct vhost_virtqueue *vq, +uint16_t n_buffers) +{ +uint16_t nr_left = n_buffers; +uint16_t from, to; + + do { + from = vq->last_async_buffer_idx & + (vq->size - 1); + to = (from + nr_left) & (vq->size - 1);The size of the ring is not necessarily a power of two with packed ring.
Sure.
Quoted 11 lines
Quoted 11 lines
lib/librte_vhost/virtio_net.c +10
-0+if (to > from) { +vhost_update_used_packed (vq, + vq->async_buffers_packed + from, + to - from); + vq->last_async_buffer_idx += nr_left; + nr_left =0 ; + }else { +vhost_update_used_packed (vq, + vq->async_buffers_packed + from, + vq->size - from);Quoted 8 lines
Quoted 8 lines
lib/librte_vhost/virtio_net.c write_back_completed_descs_split(struct vhost_virtqueue *vq, uint16_t n_descs)
Quoted 8 lines
lib/librte_vhost/virtio_net.c +7
-0+ vq->last_async_buffer_idx += + vq->size - from; + nr_left -= vq->size - from; + } + }while (nr_left >0 ); +} + uint16_t rte_vhost_poll_enqueue_completed(int vid, uint16_t
queue_id,Quoted 86 lines
Quoted 14 lines
lib/librte_vhost/virtio_net.c uint16_t
Quoted 10 lines
lib/librte_vhost/virtio_net.c +2
-1struct rte_mbuf **pkts, uint16_t count) {struct virtio_net *dev =get_device (vid);struct vhost_virtqueue *vq; -uint16_t n_pkts_cpl =0 , n_pkts_put =0 , n_descs =0 ; +uint16_t n_pkts_cpl =0 , n_pkts_put =0 , n_descs =0 , n_buffers = +0 ;uint16_t start_idx, pkts_idx, vq_size;struct async_inflight_info *pkts_info;uint16_t from, i;@@ -1740,21 +2123,41 @@ uint16_trte_vhost_poll_enqueue_completed(int vid,
uint16_tqueue_id,Quoted 3 lines
lib/librte_vhost/virtio_net.c +0
-0goto done; }Quoted 9 lines
lib/librte_vhost/virtio_net.c uint16_t rte_vhost_poll_enqueue_completed(int vid, uint16_t queue_id, · line 2128
Quoted 7 lines
lib/librte_vhost/virtio_net.c +3
-4-for (i =0 ; i < n_pkts_put; i++) { - from = (start_idx + i) & (vq_size -1 ); - n_descs += pkts_info[from].descs; - pkts[i] = pkts_info[from].mbuf; +if (vq_is_packed (dev)) { +for (i =0 ; i < n_pkts_put; i++) { + from = (start_idx + i) & (vq_size -1 );Unlike split ring, packed ring size is not necessarily a power of 2.
Sure.
Thanks.Quoted 58 lines
Quoted 9 lines
lib/librte_vhost/virtio_net.c +8
-0+ n_buffers += pkts_info[from].nr_buffers; + pkts[i] = pkts_info[from].mbuf; + } + }else { +for (i =0 ; i < n_pkts_put; i++) { + from = (start_idx + i) & (vq_size -1 ); + n_descs += pkts_info[from].descs; + pkts[i] = pkts_info[from].mbuf;lib/librte_vhost/virtio_net.c uint16_t rte_vhost_poll_enqueue_completed(int vid, uint16_t queue_id,
Quoted 10 lines
lib/librte_vhost/virtio_net.c +4
-1+ } } + vq->async_last_pkts_n = n_pkts_cpl - n_pkts_put; vq->async_pkts_inflight_n -= n_pkts_put;if (likely (vq->enabled && vq->access_ok)) { -write_back_completed_descs_split (vq, n_descs); +if (vq_is_packed (dev)) { + write_back_completed_descs_packed(vq,
n_buffers);lib/librte_vhost/virtio_net.c uint16_t · line 1753
Quoted 2 lines
lib/librte_vhost/virtio_net.c +0
-1- __atomic_add_fetch(&vq->used->idx, n_descs,
__ATOMIC_RELEASE);lib/librte_vhost/virtio_net.c virtio_dev_rx_async_submit(struct virtio_net
Quoted 21 lines
lib/librte_vhost/virtio_net.c +14
-3-vhost_vring_call_split (dev, vq); - }else - vq->last_async_desc_idx += n_descs; +vhost_vring_call_packed (dev, vq); + }else { +write_back_completed_descs_split (vq, n_descs); + +__atomic_add_fetch (&vq->used->idx, n_descs, + __ATOMIC_RELEASE); +vhost_vring_call_split (dev, vq); + } + }else { +if (vq_is_packed (dev)) + vq->last_async_buffer_idx += n_buffers; +else + vq->last_async_desc_idx += n_descs; + } done:rte_spinlock_unlock (&vq->access_lock);@@ -1795,9 +2198,10 @@ virtio_dev_rx_async_submit(struct virtio_net*dev,
uint16_tqueue_id,Quoted 13 lines
lib/librte_vhost/virtio_net.c +3
-2if (count ==0 ) goto out; -/* TODO: packed queue not implemented */ if (vq_is_packed (dev)) - nb_tx =0 ; + nb_tx =virtio_dev_rx_async_submit_packed (dev, + vq, queue_id, pkts, count, comp_pkts, + comp_count);else nb_tx = virtio_dev_rx_async_submit_split(dev, vq, queue_id, pkts, count, comp_pkts,
PATCH v5 3/4 vhost: add batch datapath for async vhost packed ring
In reply to Cheng JiangAdd batch datapath for async vhost packed ring to improve the performance of small packet.
--- lib/librte_vhost/virtio_net.c | 43 +++++++++++++++++++++++++++++++---- 1 file changed, 38 insertions(+), 5 deletions(-)
lib/librte_vhost/virtio_net.c +38 -5
@@ -1723,6 +1723,29 @@ virtio_dev_rx_async_submit_split(struct virtio_net *dev,return pkt_idx; } +static __rte_always_inline int +virtio_dev_rx_async_batch_packed (struct virtio_net *dev, +struct vhost_virtqueue *vq, +struct rte_mbuf **pkts, +struct rte_mbuf **comp_pkts,uint32_t *pkt_done) +{ +uint16_t i; +uint32_t cpy_threshold = vq->async_threshold; + +vhost_for_each_try_unroll (i,0 ,PACKED_BATCH_SIZE ) { +if (unlikely (pkts[i]->pkt_len >= cpy_threshold)) +return -1 ; + } +if (!virtio_dev_rx_batch_packed (dev, vq, pkts)) { +vhost_for_each_try_unroll (i,0 ,PACKED_BATCH_SIZE ) + comp_pkts[(*pkt_done)++] = pkts[i]; + +return 0 ; + } + +return -1 ; +} + static __rte_always_inline int vhost_enqueue_async_single_packed(struct virtio_net *dev, struct vhost_virtqueue *vq,
@@ -1846,6 +1869,7 @@ virtio_dev_rx_async_submit_packed(struct virtio_net *dev, struct rte_mbuf **comp_pkts, uint32_t *comp_count) { uint32_t pkt_idx = 0, pkt_burst_idx = 0; +uint32_t remained = count;uint16_t async_descs_idx =0 ;uint16_t num_buffers;uint16_t num_desc;
@@ -1865,9 +1889,17 @@ virtio_dev_rx_async_submit_packed(struct virtio_net *dev,uint32_t num_async_pkts =0 , num_done_pkts =0 ;struct vring_packed_desc async_descs[vq->size]; -rte_prefetch0 (&vq->desc_packed[vq->last_avail_idx & (vq->size -1 )]); - -for (pkt_idx =0 ; pkt_idx < count; pkt_idx++) { + do { + rte_prefetch0(&vq->desc_packed[vq->last_avail_idx & + (vq->size - 1)]); + if (remained >= PACKED_BATCH_SIZE) { + if (!virtio_dev_rx_async_batch_packed(dev, vq, + &pkts[pkt_idx], comp_pkts, &num_done_pkts)) { + pkt_idx += PACKED_BATCH_SIZE; + remained -= PACKED_BATCH_SIZE; + continue; + } + } if (unlikely(virtio_dev_rx_async_single_packed(dev, vq, pkts[pkt_idx], &num_desc, &num_buffers,
@@ -1915,6 +1947,8 @@ virtio_dev_rx_async_submit_packed(struct virtio_net *dev, }else comp_pkts[num_done_pkts++] = pkts[pkt_idx]; + pkt_idx++; + remained--;vq_inc_last_avail_packed (vq, num_desc);/*
@@ -1940,13 +1974,12 @@ virtio_dev_rx_async_submit_packed(struct virtio_net *dev,*/ pkt_err = pkt_burst_idx - n_pkts; pkt_burst_idx =0 ; - pkt_idx++;break ; } pkt_burst_idx =0 ; } - } + }while (pkt_idx < count);if (pkt_burst_idx) { n_pkts = vq->async_ops.transfer_data(dev->vid,
Signature · 1 line
2.29.2
PATCH v5 4/4 doc: add release note for vhost async packed ring
In reply to Cheng JiangAdd release note for the support of vhost async packed ring.
--- doc/guides/rel_notes/release_21_05.rst | 4 ++++ 1 file changed, 4 insertions(+)
doc/guides/rel_notes/release_21_05.rst +4 -0
@@ -131,6 +131,10 @@ New Features * Added command to display Rx queue used descriptor count. ``show port (port_id) rxq (queue_id) desc used count`` +* **Added support for vhost async packed ring data path.** + + Added packed ring support for async vhost. + Removed Items -------------
Signature · 1 line
2.29.2
v6 cover add support for packed ring in async vhost
In reply to Cheng JiangFor now async vhost data path only supports split ring structure. In order to make async vhost compatible with virtio 1.1 spec this patch set cleans async split ring codes and enables packed ring in async vhost data path. Batch datapath is also enabled in async vhost packed ring.
v6:
* fix some typos in commit log
* improve index usage
* remove shadow_ring_store()
* add store_dma_desc_info_split() store_dma_desc_info_packed()
* remove some checks in vhost_free_async_mem()
* change index calculation since the size isn't necessarily a power of 2
* move error handling in a dedicated function
* clean codes
v5:
* clean some codes for packed ring datapath
* fix an index error in shadow_ring_store()
v4:
* change the patch structure
* clean code for async split ring
* reuse some code from split ring
* change the error handler for DMA-copy packet
* add check for malloc
* remove useless code
* add doc update
v3:
* fix error handler for DMA-copy packet
v2:
* fix wrong buffer index in rte_vhost_poll_enqueue_completed()
* add async_buffers_packed memory free in vhost_free_async_mem()
Cheng Jiang (4):
vhost: abstract and reorganize async split ring code
vhost: add support for packed ring in async vhost
vhost: add batch datapath for async vhost packed ring
doc: add release note for vhost async packed ring
doc/guides/rel_notes/release_21_05.rst | 4 + lib/librte_vhost/rte_vhost_async.h | 1 + lib/librte_vhost/vhost.c | 37 +- lib/librte_vhost/vhost.h | 15 +- lib/librte_vhost/virtio_net.c | 593 +++++++++++++++++++++---- 5 files changed, 550 insertions(+), 100 deletions(-)
--
2.29.2
PATCH v6 1/4 vhost: abstract and reorganize async split ring code
This patch puts some codes of async vhost split ring into inline functions to improve the readability of the code. And, it changes the pointer index style of iterator to make the code more concise.
--- lib/librte_vhost/virtio_net.c | 132 +++++++++++++++++----------------- 1 file changed, 66 insertions(+), 66 deletions(-)
lib/librte_vhost/virtio_net.c +66 -66
@@ -1458,6 +1458,22 @@ virtio_dev_rx_async_get_info_idx(uint16_t pkts_idx, (vq_size - n_inflight + pkts_idx) & (vq_size -1 ); } +static __rte_always_inline void +store_dma_desc_info_split (struct vring_used_elem *s_ring,struct vring_used_elem *d_ring, +uint16_t ring_size,uint16_t s_idx,uint16_t d_idx,uint16_t count) +{ +uint16_t elem_size =sizeof (struct vring_used_elem ); + +if (d_idx + count <= ring_size) { +rte_memcpy (d_ring + d_idx, s_ring + s_idx, count * elem_size); + }else { +uint16_t size = ring_size - d_idx; + +rte_memcpy (d_ring + d_idx, s_ring + s_idx, size * elem_size); +rte_memcpy (d_ring, s_ring + s_idx + size, (count - size) * elem_size); + } +} + static __rte_noinline uint32_t virtio_dev_rx_async_submit_split(struct virtio_net *dev, struct vhost_virtqueue *vq, uint16_t queue_id,
@@ -1474,10 +1490,9 @@ virtio_dev_rx_async_submit_split(struct virtio_net *dev,struct rte_vhost_async_desc tdes[MAX_PKT_BURST ];struct iovec *src_iovec = vec_pool;struct iovec *dst_iovec = vec_pool + (VHOST_MAX_ASYNC_VEC >>1 ); -struct rte_vhost_iov_iter *src_it = it_pool; -struct rte_vhost_iov_iter *dst_it = it_pool +1 ;uint16_t slot_idx =0 ;uint16_t segs_await =0 ; +uint16_t iovec_idx =0 , it_idx =0 ;struct async_inflight_info *pkts_info = vq->async_pkts_info;uint32_t n_pkts =0 , pkt_err =0 ;uint32_t num_async_pkts =0 , num_done_pkts =0 ;
@@ -1511,29 +1526,30 @@ virtio_dev_rx_async_submit_split(struct virtio_net *dev, dev->vid, vq->last_avail_idx, vq->last_avail_idx + num_buffers); -if (async_mbuf_to_desc (dev, vq, pkts[pkt_idx], - buf_vec, nr_vec, num_buffers, - src_iovec, dst_iovec, src_it, dst_it) <0 ) { +if (async_mbuf_to_desc (dev, vq, pkts[pkt_idx], buf_vec, nr_vec, num_buffers, + &src_iovec[iovec_idx], &dst_iovec[iovec_idx], + &it_pool[it_idx], &it_pool[it_idx +1 ]) <0 ) { vq->shadow_used_idx -= num_buffers;break ; } slot_idx = (vq->async_pkts_idx + num_async_pkts) & (vq->size -1 ); -if (src_it->count) { +if (it_pool[it_idx].count) {uint16_t from, to; -async_fill_desc (&tdes[pkt_burst_idx++], src_it, dst_it); +async_fill_desc (&tdes[pkt_burst_idx++], + &it_pool[it_idx], &it_pool[it_idx +1 ]); pkts_info[slot_idx].descs = num_buffers; pkts_info[slot_idx].mbuf = pkts[pkt_idx]; async_pkts_log[num_async_pkts].pkt_idx = pkt_idx; async_pkts_log[num_async_pkts++].last_avail_idx = vq->last_avail_idx; - src_iovec += src_it->nr_segs; - dst_iovec += dst_it->nr_segs; - src_it +=2 ; - dst_it +=2 ; - segs_await += src_it->nr_segs; + + iovec_idx += it_pool[it_idx].nr_segs; + it_idx +=2 ; + + segs_await += it_pool[it_idx].nr_segs;/** * recover shadow used ring and keep DMA-occupied
@@ -1541,23 +1557,10 @@ virtio_dev_rx_async_submit_split(struct virtio_net *dev,*/ from = vq->shadow_used_idx - num_buffers; to = vq->async_desc_idx & (vq->size -1 ); -if (num_buffers + to <= vq->size) { -rte_memcpy (&vq->async_descs_split[to], - &vq->shadow_used_split[from], - num_buffers * -sizeof (struct vring_used_elem )); - }else { -int size = vq->size - to; - -rte_memcpy (&vq->async_descs_split[to], - &vq->shadow_used_split[from], - size * -sizeof (struct vring_used_elem )); -rte_memcpy (vq->async_descs_split, - &vq->shadow_used_split[from + - size], (num_buffers - size) * -sizeof (struct vring_used_elem )); - } + +store_dma_desc_info_split (vq->shadow_used_split, + vq->async_descs_split, vq->size, from, to, num_buffers); + vq->async_desc_idx += num_buffers; vq->shadow_used_idx -= num_buffers; }else
@@ -1575,10 +1578,9 @@ virtio_dev_rx_async_submit_split(struct virtio_net *dev, BUF_VECTOR_MAX))) { n_pkts = vq->async_ops.transfer_data (dev->vid, queue_id, tdes,0 , pkt_burst_idx); - src_iovec = vec_pool; - dst_iovec = vec_pool + (VHOST_MAX_ASYNC_VEC >>1 ); - src_it = it_pool; - dst_it = it_pool +1 ; + iovec_idx =0 ; + it_idx =0 ; + segs_await =0 ; vq->async_pkts_inflight_n += n_pkts;
@@ -1639,6 +1641,36 @@ virtio_dev_rx_async_submit_split(struct virtio_net *dev,return pkt_idx; } +static __rte_always_inline void +write_back_completed_descs_split (struct vhost_virtqueue *vq,uint16_t n_descs) +{ +uint16_t nr_left = n_descs; +uint16_t nr_copy; +uint16_t to, from; + +do { + from = vq->last_async_desc_idx & (vq->size -1 ); + nr_copy = nr_left + from <= vq->size ? nr_left : vq->size - from; + to = vq->last_used_idx & (vq->size -1 ); + +if (to + nr_copy <= vq->size) { +rte_memcpy (&vq->used->ring[to], &vq->async_descs_split[from], + nr_copy *sizeof (struct vring_used_elem )); + }else { +uint16_t size = vq->size - to; + +rte_memcpy (&vq->used->ring[to], &vq->async_descs_split[from], + size *sizeof (struct vring_used_elem )); +rte_memcpy (&vq->used->ring[0 ], &vq->async_descs_split[from + size], + (nr_copy - size) *sizeof (struct vring_used_elem )); + } + + vq->last_async_desc_idx += nr_copy; + vq->last_used_idx += nr_copy; + nr_left -= nr_copy; + }while (nr_left >0 ); +} +uint16_t rte_vhost_poll_enqueue_completed (int vid,uint16_t queue_id,struct rte_mbuf **pkts,uint16_t count) {
@@ -1695,39 +1727,7 @@ uint16_t rte_vhost_poll_enqueue_completed(int vid, uint16_t queue_id, vq->async_pkts_inflight_n -= n_pkts_put;if (likely (vq->enabled && vq->access_ok)) { -uint16_t nr_left = n_descs; -uint16_t nr_copy; -uint16_t to; - -/* write back completed descriptors to used ring */ -do { - from = vq->last_async_desc_idx & (vq->size -1 ); - nr_copy = nr_left + from <= vq->size ? nr_left : - vq->size - from; - to = vq->last_used_idx & (vq->size -1 ); - -if (to + nr_copy <= vq->size) { -rte_memcpy (&vq->used->ring[to], - &vq->async_descs_split[from], - nr_copy * -sizeof (struct vring_used_elem )); - }else { -uint16_t size = vq->size - to; - -rte_memcpy (&vq->used->ring[to], - &vq->async_descs_split[from], - size * -sizeof (struct vring_used_elem )); -rte_memcpy (vq->used->ring, - &vq->async_descs_split[from + - size], (nr_copy - size) * -sizeof (struct vring_used_elem )); - } - - vq->last_async_desc_idx += nr_copy; - vq->last_used_idx += nr_copy; - nr_left -= nr_copy; - }while (nr_left >0 ); +write_back_completed_descs_split (vq, n_descs);__atomic_add_fetch (&vq->used->idx, n_descs, __ATOMIC_RELEASE);vhost_vring_call_split (dev, vq);
Signature · 1 line
2.29.2
PATCH v6 2/4 vhost: add support for packed ring in async vhost
In reply to Cheng JiangFor now async vhost data path only supports split ring. This patch enables packed ring in async vhost data path to make async vhost compatible with virtio 1.1 spec.
--- lib/librte_vhost/rte_vhost_async.h | 1 + lib/librte_vhost/vhost.c | 37 ++- lib/librte_vhost/vhost.h | 15 +- lib/librte_vhost/virtio_net.c | 432 +++++++++++++++++++++++++++-- 4 files changed, 449 insertions(+), 36 deletions(-)
lib/librte_vhost/rte_vhost_async.h +1 -0
@@ -89,6 +89,7 @@ struct rte_vhost_async_channel_ops {struct async_inflight_info {struct rte_mbuf *mbuf;uint16_t descs;/* num of descs inflight */ +uint16_t nr_buffers;/* num of buffers inflight for packed ring */ };/**
lib/librte_vhost/vhost.c +22 -15
@@ -340,17 +340,18 @@ cleanup_device(struct virtio_net *dev, int destroy)static void vhost_free_async_mem (struct vhost_virtqueue *vq) { -if (vq->async_pkts_info) -rte_free (vq->async_pkts_info); -if (vq->async_descs_split) -rte_free (vq->async_descs_split); -if (vq->it_pool) -rte_free (vq->it_pool); -if (vq->vec_pool) -rte_free (vq->vec_pool); +rte_free (vq->async_pkts_info); - vq->async_pkts_info =NULL ; +rte_free (vq->async_buffers_packed); +rte_free (vq->async_descs_split); + +rte_free (vq->it_pool); +rte_free (vq->vec_pool); + + vq->async_buffers_packed =NULL ; vq->async_descs_split =NULL ; + + vq->async_pkts_info =NULL ; vq->it_pool =NULL ; vq->vec_pool =NULL ; }
@@ -1626,10 +1627,9 @@ int rte_vhost_async_channel_register(int vid, uint16_t queue_id,if (unlikely (vq ==NULL || !dev->async_copy))return -1 ; -/* packed queue is not supported */ -if (unlikely (vq_is_packed (dev) || !f.async_inorder)) { +if (unlikely (!f.async_inorder)) {VHOST_LOG_CONFIG (ERR , -"async copy is not supported on packed queue or non-inorder mode " +"async copy is not supported on non-inorder mode " "(vid %d, qid: %d)\n" , vid, queue_id);return -1 ; }
@@ -1667,11 +1667,18 @@ int rte_vhost_async_channel_register(int vid, uint16_t queue_id, vq->vec_pool =rte_malloc_socket (NULL ,VHOST_MAX_ASYNC_VEC *sizeof (struct iovec ),RTE_CACHE_LINE_SIZE , node); - vq->async_descs_split =rte_malloc_socket (NULL , +if (vq_is_packed (dev)) { + vq->async_buffers_packed =rte_malloc_socket (NULL , + vq->size *sizeof (struct vring_used_elem_packed ), +RTE_CACHE_LINE_SIZE , node); + }else { + vq->async_descs_split =rte_malloc_socket (NULL , vq->size *sizeof (struct vring_used_elem ),RTE_CACHE_LINE_SIZE , node); -if (!vq->async_descs_split || !vq->async_pkts_info || - !vq->it_pool || !vq->vec_pool) { + } + +if (!vq->async_buffers_packed || !vq->async_descs_split || + !vq->async_pkts_info || !vq->it_pool || !vq->vec_pool) {vhost_free_async_mem (vq);VHOST_LOG_CONFIG (ERR , "async register failed: cannot allocate memory for vq data "
lib/librte_vhost/vhost.h +12 -3
@@ -201,9 +201,18 @@ struct vhost_virtqueue {uint16_t async_pkts_idx;uint16_t async_pkts_inflight_n;uint16_t async_last_pkts_n; -struct vring_used_elem *async_descs_split; -uint16_t async_desc_idx; -uint16_t last_async_desc_idx; +union { +struct vring_used_elem *async_descs_split; +struct vring_used_elem_packed *async_buffers_packed; + }; +union { +uint16_t async_desc_idx; +uint16_t async_packed_buffer_idx; + }; +union { +uint16_t last_async_desc_idx; +uint16_t last_async_buffer_idx; + };/* vq async features */ bool async_inorder;
lib/librte_vhost/virtio_net.c +414 -18
495 lines not on this page · raw message
Signature · 1 line
2.29.2
PATCH v6 3/4 vhost: add batch datapath for async vhost packed ring
In reply to Cheng JiangAdd batch datapath for async vhost packed ring to improve the performance of small packet processing.
--- lib/librte_vhost/virtio_net.c | 41 +++++++++++++++++++++++++++++++---- 1 file changed, 37 insertions(+), 4 deletions(-)
lib/librte_vhost/virtio_net.c +37 -4
@@ -1725,6 +1725,29 @@ vhost_update_used_packed(struct vhost_virtqueue *vq, vq->desc_packed[head_idx].flags = head_flags; } +static __rte_always_inline int +virtio_dev_rx_async_batch_packed (struct virtio_net *dev, +struct vhost_virtqueue *vq, +struct rte_mbuf **pkts, +struct rte_mbuf **comp_pkts,uint32_t *pkt_done) +{ +uint16_t i; +uint32_t cpy_threshold = vq->async_threshold; + +vhost_for_each_try_unroll (i,0 ,PACKED_BATCH_SIZE ) { +if (unlikely (pkts[i]->pkt_len >= cpy_threshold)) +return -1 ; + } +if (!virtio_dev_rx_batch_packed (dev, vq, pkts)) { +vhost_for_each_try_unroll (i,0 ,PACKED_BATCH_SIZE ) + comp_pkts[(*pkt_done)++] = pkts[i]; + +return 0 ; + } + +return -1 ; +} + static __rte_always_inline int vhost_enqueue_async_single_packed(struct virtio_net *dev, struct vhost_virtqueue *vq,
@@ -1875,6 +1898,7 @@ virtio_dev_rx_async_submit_packed(struct virtio_net *dev, struct rte_mbuf **comp_pkts, uint32_t *comp_count) { uint32_t pkt_idx = 0, pkt_burst_idx = 0; +uint32_t remained = count;uint16_t async_descs_idx =0 ;uint16_t num_buffers;uint16_t num_desc;
@@ -1892,9 +1916,17 @@ virtio_dev_rx_async_submit_packed(struct virtio_net *dev,uint32_t num_async_pkts =0 , num_done_pkts =0 ;struct vring_packed_desc async_descs[vq->size]; -rte_prefetch0 (&vq->desc_packed[vq->last_avail_idx]); + do { + rte_prefetch0(&vq->desc_packed[vq->last_avail_idx]); + if (remained >= PACKED_BATCH_SIZE) { + if (!virtio_dev_rx_async_batch_packed(dev, vq, + &pkts[pkt_idx], comp_pkts, &num_done_pkts)) { + pkt_idx += PACKED_BATCH_SIZE; + remained -= PACKED_BATCH_SIZE; + continue; + } + } -for (pkt_idx =0 ; pkt_idx < count; pkt_idx++) { if (unlikely(virtio_dev_rx_async_single_packed(dev, vq, pkts[pkt_idx], &num_desc, &num_buffers, &async_descs[async_descs_idx],
@@ -1937,6 +1969,8 @@ virtio_dev_rx_async_submit_packed(struct virtio_net *dev, comp_pkts[num_done_pkts++] = pkts[pkt_idx]; } + pkt_idx++; + remained--;vq_inc_last_avail_packed (vq, num_desc);/*
@@ -1961,13 +1995,12 @@ virtio_dev_rx_async_submit_packed(struct virtio_net *dev,*/ pkt_err = pkt_burst_idx - n_pkts; pkt_burst_idx =0 ; - pkt_idx++;break ; } pkt_burst_idx =0 ; } - } + }while (pkt_idx < count);if (pkt_burst_idx) { n_pkts = vq->async_ops.transfer_data (dev->vid, queue_id, tdes,0 , pkt_burst_idx);
Signature · 1 line
2.29.2
PATCH v6 4/4 doc: add release note for vhost async packed ring
In reply to Cheng JiangAdd release note for the support of vhost async packed ring.
--- doc/guides/rel_notes/release_21_05.rst | 4 ++++ 1 file changed, 4 insertions(+)
doc/guides/rel_notes/release_21_05.rst +4 -0
@@ -131,6 +131,10 @@ New Features * Added command to display Rx queue used descriptor count. ``show port (port_id) rxq (queue_id) desc used count`` +* **Added support for vhost async packed ring data path.** + + Added packed ring support for async vhost. + Removed Items -------------
Signature · 1 line
2.29.2
v7 cover add support for packed ring in async vhost
In reply to Cheng JiangFor now async vhost data path only supports split ring structure. In order to make async vhost compatible with virtio 1.1 spec this patch set cleans async split ring codes and enables packed ring in async vhost data path. Batch datapath is also enabled in async vhost packed ring.
v7:
* fix compile issues
* add argument *dev in vhost_free_async_mem() for ring type decision
v6:
* fix some typos in commit log
* improve index usage
* remove shadow_ring_store()
* add store_dma_desc_info_split() store_dma_desc_info_packed()
* remove some checks in vhost_free_async_mem()
* change index calculation since the size isn't necessarily a power of 2
* move error handling in a dedicated function
* clean codes
v5:
* clean some codes for packed ring datapath
* fix an index error in shadow_ring_store()
v4:
* change the patch structure
* clean code for async split ring
* reuse some code from split ring
* change the error handler for DMA-copy packet
* add check for malloc
* remove useless code
* add doc update
v3:
* fix error handler for DMA-copy packet
v2:
* fix wrong buffer index in rte_vhost_poll_enqueue_completed()
* add async_buffers_packed memory free in vhost_free_async_mem()
Cheng Jiang (4):
vhost: abstract and reorganize async split ring code
vhost: add support for packed ring in async vhost
vhost: add batch datapath for async vhost packed ring
doc: add release note for vhost async packed ring
doc/guides/rel_notes/release_21_05.rst | 4 + lib/librte_vhost/rte_vhost_async.h | 1 + lib/librte_vhost/vhost.c | 49 +- lib/librte_vhost/vhost.h | 15 +- lib/librte_vhost/virtio_net.c | 593 +++++++++++++++++++++---- 5 files changed, 557 insertions(+), 105 deletions(-)
--
2.29.2
PATCH v7 1/4 vhost: abstract and reorganize async split ring code
This patch puts some codes of async vhost split ring into inline functions to improve the readability of the code. And, it changes the pointer index style of iterator to make the code more concise.
--- lib/librte_vhost/virtio_net.c | 132 +++++++++++++++++----------------- 1 file changed, 66 insertions(+), 66 deletions(-)
lib/librte_vhost/virtio_net.c +66 -66
@@ -1458,6 +1458,22 @@ virtio_dev_rx_async_get_info_idx(uint16_t pkts_idx, (vq_size - n_inflight + pkts_idx) & (vq_size -1 ); } +static __rte_always_inline void +store_dma_desc_info_split (struct vring_used_elem *s_ring,struct vring_used_elem *d_ring, +uint16_t ring_size,uint16_t s_idx,uint16_t d_idx,uint16_t count) +{ +uint16_t elem_size =sizeof (struct vring_used_elem ); + +if (d_idx + count <= ring_size) { +rte_memcpy (d_ring + d_idx, s_ring + s_idx, count * elem_size); + }else { +uint16_t size = ring_size - d_idx; + +rte_memcpy (d_ring + d_idx, s_ring + s_idx, size * elem_size); +rte_memcpy (d_ring, s_ring + s_idx + size, (count - size) * elem_size); + } +} + static __rte_noinline uint32_t virtio_dev_rx_async_submit_split(struct virtio_net *dev, struct vhost_virtqueue *vq, uint16_t queue_id,
@@ -1474,10 +1490,9 @@ virtio_dev_rx_async_submit_split(struct virtio_net *dev,struct rte_vhost_async_desc tdes[MAX_PKT_BURST ];struct iovec *src_iovec = vec_pool;struct iovec *dst_iovec = vec_pool + (VHOST_MAX_ASYNC_VEC >>1 ); -struct rte_vhost_iov_iter *src_it = it_pool; -struct rte_vhost_iov_iter *dst_it = it_pool +1 ;uint16_t slot_idx =0 ;uint16_t segs_await =0 ; +uint16_t iovec_idx =0 , it_idx =0 ;struct async_inflight_info *pkts_info = vq->async_pkts_info;uint32_t n_pkts =0 , pkt_err =0 ;uint32_t num_async_pkts =0 , num_done_pkts =0 ;
@@ -1511,29 +1526,30 @@ virtio_dev_rx_async_submit_split(struct virtio_net *dev, dev->vid, vq->last_avail_idx, vq->last_avail_idx + num_buffers); -if (async_mbuf_to_desc (dev, vq, pkts[pkt_idx], - buf_vec, nr_vec, num_buffers, - src_iovec, dst_iovec, src_it, dst_it) <0 ) { +if (async_mbuf_to_desc (dev, vq, pkts[pkt_idx], buf_vec, nr_vec, num_buffers, + &src_iovec[iovec_idx], &dst_iovec[iovec_idx], + &it_pool[it_idx], &it_pool[it_idx +1 ]) <0 ) { vq->shadow_used_idx -= num_buffers;break ; } slot_idx = (vq->async_pkts_idx + num_async_pkts) & (vq->size -1 ); -if (src_it->count) { +if (it_pool[it_idx].count) {uint16_t from, to; -async_fill_desc (&tdes[pkt_burst_idx++], src_it, dst_it); +async_fill_desc (&tdes[pkt_burst_idx++], + &it_pool[it_idx], &it_pool[it_idx +1 ]); pkts_info[slot_idx].descs = num_buffers; pkts_info[slot_idx].mbuf = pkts[pkt_idx]; async_pkts_log[num_async_pkts].pkt_idx = pkt_idx; async_pkts_log[num_async_pkts++].last_avail_idx = vq->last_avail_idx; - src_iovec += src_it->nr_segs; - dst_iovec += dst_it->nr_segs; - src_it +=2 ; - dst_it +=2 ; - segs_await += src_it->nr_segs; + + iovec_idx += it_pool[it_idx].nr_segs; + it_idx +=2 ; + + segs_await += it_pool[it_idx].nr_segs;/** * recover shadow used ring and keep DMA-occupied
@@ -1541,23 +1557,10 @@ virtio_dev_rx_async_submit_split(struct virtio_net *dev,*/ from = vq->shadow_used_idx - num_buffers; to = vq->async_desc_idx & (vq->size -1 ); -if (num_buffers + to <= vq->size) { -rte_memcpy (&vq->async_descs_split[to], - &vq->shadow_used_split[from], - num_buffers * -sizeof (struct vring_used_elem )); - }else { -int size = vq->size - to; - -rte_memcpy (&vq->async_descs_split[to], - &vq->shadow_used_split[from], - size * -sizeof (struct vring_used_elem )); -rte_memcpy (vq->async_descs_split, - &vq->shadow_used_split[from + - size], (num_buffers - size) * -sizeof (struct vring_used_elem )); - } + +store_dma_desc_info_split (vq->shadow_used_split, + vq->async_descs_split, vq->size, from, to, num_buffers); + vq->async_desc_idx += num_buffers; vq->shadow_used_idx -= num_buffers; }else
@@ -1575,10 +1578,9 @@ virtio_dev_rx_async_submit_split(struct virtio_net *dev, BUF_VECTOR_MAX))) { n_pkts = vq->async_ops.transfer_data (dev->vid, queue_id, tdes,0 , pkt_burst_idx); - src_iovec = vec_pool; - dst_iovec = vec_pool + (VHOST_MAX_ASYNC_VEC >>1 ); - src_it = it_pool; - dst_it = it_pool +1 ; + iovec_idx =0 ; + it_idx =0 ; + segs_await =0 ; vq->async_pkts_inflight_n += n_pkts;
@@ -1639,6 +1641,36 @@ virtio_dev_rx_async_submit_split(struct virtio_net *dev,return pkt_idx; } +static __rte_always_inline void +write_back_completed_descs_split (struct vhost_virtqueue *vq,uint16_t n_descs) +{ +uint16_t nr_left = n_descs; +uint16_t nr_copy; +uint16_t to, from; + +do { + from = vq->last_async_desc_idx & (vq->size -1 ); + nr_copy = nr_left + from <= vq->size ? nr_left : vq->size - from; + to = vq->last_used_idx & (vq->size -1 ); + +if (to + nr_copy <= vq->size) { +rte_memcpy (&vq->used->ring[to], &vq->async_descs_split[from], + nr_copy *sizeof (struct vring_used_elem )); + }else { +uint16_t size = vq->size - to; + +rte_memcpy (&vq->used->ring[to], &vq->async_descs_split[from], + size *sizeof (struct vring_used_elem )); +rte_memcpy (&vq->used->ring[0 ], &vq->async_descs_split[from + size], + (nr_copy - size) *sizeof (struct vring_used_elem )); + } + + vq->last_async_desc_idx += nr_copy; + vq->last_used_idx += nr_copy; + nr_left -= nr_copy; + }while (nr_left >0 ); +} +uint16_t rte_vhost_poll_enqueue_completed (int vid,uint16_t queue_id,struct rte_mbuf **pkts,uint16_t count) {
@@ -1695,39 +1727,7 @@ uint16_t rte_vhost_poll_enqueue_completed(int vid, uint16_t queue_id, vq->async_pkts_inflight_n -= n_pkts_put;if (likely (vq->enabled && vq->access_ok)) { -uint16_t nr_left = n_descs; -uint16_t nr_copy; -uint16_t to; - -/* write back completed descriptors to used ring */ -do { - from = vq->last_async_desc_idx & (vq->size -1 ); - nr_copy = nr_left + from <= vq->size ? nr_left : - vq->size - from; - to = vq->last_used_idx & (vq->size -1 ); - -if (to + nr_copy <= vq->size) { -rte_memcpy (&vq->used->ring[to], - &vq->async_descs_split[from], - nr_copy * -sizeof (struct vring_used_elem )); - }else { -uint16_t size = vq->size - to; - -rte_memcpy (&vq->used->ring[to], - &vq->async_descs_split[from], - size * -sizeof (struct vring_used_elem )); -rte_memcpy (vq->used->ring, - &vq->async_descs_split[from + - size], (nr_copy - size) * -sizeof (struct vring_used_elem )); - } - - vq->last_async_desc_idx += nr_copy; - vq->last_used_idx += nr_copy; - nr_left -= nr_copy; - }while (nr_left >0 ); +write_back_completed_descs_split (vq, n_descs);__atomic_add_fetch (&vq->used->idx, n_descs, __ATOMIC_RELEASE);vhost_vring_call_split (dev, vq);
Signature · 1 line
2.29.2
Re: [dpdk-dev] [PATCH v7 1/4] vhost: abstract and reorganize async split ring code
Quoted 9 lines · Cheng Jiang
This patch puts some codes of async vhost split ring into inline functions to improve the readability of the code. And, it changes the pointer index style of iterator to make the code more concise.
Signed-off-by Cheng Jiang <[email protected]>--- lib/librte_vhost/virtio_net.c | 132 +++++++++++++++++----------------- 1 file changed, 66 insertions(+), 66 deletions(-)
Thanks,
Maxime
PATCH v7 2/4 vhost: add support for packed ring in async vhost
In reply to Cheng JiangFor now async vhost data path only supports split ring. This patch enables packed ring in async vhost data path to make async vhost compatible with virtio 1.1 spec.
--- lib/librte_vhost/rte_vhost_async.h | 1 + lib/librte_vhost/vhost.c | 49 ++-- lib/librte_vhost/vhost.h | 15 +- lib/librte_vhost/virtio_net.c | 432 +++++++++++++++++++++++++++-- 4 files changed, 456 insertions(+), 41 deletions(-)
lib/librte_vhost/rte_vhost_async.h +1 -0
@@ -89,6 +89,7 @@ struct rte_vhost_async_channel_ops {struct async_inflight_info {struct rte_mbuf *mbuf;uint16_t descs;/* num of descs inflight */ +uint16_t nr_buffers;/* num of buffers inflight for packed ring */ };/**
lib/librte_vhost/vhost.c +29 -20
87 lines not on this page · raw message
lib/librte_vhost/vhost.h +12 -3
@@ -201,9 +201,18 @@ struct vhost_virtqueue {uint16_t async_pkts_idx;uint16_t async_pkts_inflight_n;uint16_t async_last_pkts_n; -struct vring_used_elem *async_descs_split; -uint16_t async_desc_idx; -uint16_t last_async_desc_idx; +union { +struct vring_used_elem *async_descs_split; +struct vring_used_elem_packed *async_buffers_packed; + }; +union { +uint16_t async_desc_idx; +uint16_t async_packed_buffer_idx; + }; +union { +uint16_t last_async_desc_idx; +uint16_t last_async_buffer_idx; + };/* vq async features */ bool async_inorder;
lib/librte_vhost/virtio_net.c +414 -18
495 lines not on this page · raw message
Signature · 1 line
2.29.2
Quoted 34 lines · Cheng Jiang
For now async vhost data path only supports split ring. This patch enables packed ring in async vhost data path to make async vhost compatible with virtio 1.1 spec.
Signed-off-by Cheng Jiang <[email protected]>--- lib/librte_vhost/rte_vhost_async.h | 1 + lib/librte_vhost/vhost.c | 49 ++-- lib/librte_vhost/vhost.h | 15 +- lib/librte_vhost/virtio_net.c | 432 +++++++++++++++++++++++++++-- 4 files changed, 456 insertions(+), 41 deletions(-)lib/librte_vhost/rte_vhost_async.h +1
-0@@ -89,6 +89,7 @@ struct rte_vhost_async_channel_ops {struct async_inflight_info {struct rte_mbuf *mbuf;uint16_t descs;/* num of descs inflight */ +uint16_t nr_buffers;/* num of buffers inflight for packed ring */ };/** lib/librte_vhost/vhost.c +1
-1@@ -338,19 +338,22 @@ cleanup_device(struct virtio_net *dev, int destroy) }static void -vhost_free_async_mem (struct vhost_virtqueue *vq) +vhost_free_async_mem (struct virtio_net *dev,struct vhost_virtqueue *vq)
lib/librte_vhost/vhost.c cleanup_device(struct virtio_net *dev, int destroy) · line 348
Quoted 10 lines
lib/librte_vhost/vhost.c +6
-3{ -if (vq->async_pkts_info) -rte_free (vq->async_pkts_info); -if (vq->async_descs_split) +rte_free (vq->async_pkts_info); + +if (vq_is_packed (dev)) { +rte_free (vq->async_buffers_packed); + vq->async_buffers_packed =NULL ; + }else {
Doing this is not necessary:
rte_free(vq->async_buffers_packed); vq->async_buffers_packed = NULL; rte_free(vq->async_descs_split); vq->async_descs_split = NULL;
Above will just work and will avoid adding dev parameter.
Quoted 53 lines
lib/librte_vhost/vhost.c +15
-12rte_free (vq->async_descs_split); -if (vq->it_pool) -rte_free (vq->it_pool); -if (vq->vec_pool) -rte_free (vq->vec_pool); + vq->async_descs_split =NULL ; + } + +rte_free (vq->it_pool); +rte_free (vq->vec_pool); vq->async_pkts_info =NULL ; - vq->async_descs_split =NULL ; vq->it_pool =NULL ; vq->vec_pool =NULL ; }@@ -360,10 +363,10 @@ free_vq(struct virtio_net *dev, struct vhost_virtqueue *vq) {if (vq_is_packed (dev))rte_free (vq->shadow_used_packed); -else { +else rte_free (vq->shadow_used_split); -vhost_free_async_mem (vq); - } + +vhost_free_async_mem (dev, vq);rte_free (vq->batch_copy_elems);if (vq->iotlb_pool)rte_mempool_free (vq->iotlb_pool);@@ -1626,10 +1629,9 @@ int rte_vhost_async_channel_register(int vid, uint16_t queue_id,if (unlikely (vq ==NULL || !dev->async_copy))return -1 ; -/* packed queue is not supported */ -if (unlikely (vq_is_packed (dev) || !f.async_inorder)) { +if (unlikely (!f.async_inorder)) {VHOST_LOG_CONFIG (ERR , -"async copy is not supported on packed queue or non-inorder mode " +"async copy is not supported on non-inorder mode " "(vid %d, qid: %d)\n" , vid, queue_id);return -1 ; }@@ -1667,12 +1669,19 @@ int rte_vhost_async_channel_register(int vid, uint16_t queue_id, vq->vec_pool =rte_malloc_socket (NULL ,VHOST_MAX_ASYNC_VEC *sizeof (struct iovec ),RTE_CACHE_LINE_SIZE , node); - vq->async_descs_split = rte_malloc_socket(NULL, +if (vq_is_packed (dev)) { + vq->async_buffers_packed =rte_malloc_socket (NULL , + vq->size *sizeof (struct vring_used_elem_packed ), +RTE_CACHE_LINE_SIZE , node); + }else {
lib/librte_vhost/vhost.c int rte_vhost_async_channel_register(int vid, uint16_t queue_id, · line 1683
Quoted 10 lines
lib/librte_vhost/vhost.c +5
-3+ vq->async_descs_split =rte_malloc_socket (NULL , vq->size *sizeof (struct vring_used_elem ),RTE_CACHE_LINE_SIZE , node); -if (!vq->async_descs_split || !vq->async_pkts_info || - !vq->it_pool || !vq->vec_pool) { -vhost_free_async_mem (vq); + } + +if (!vq->async_buffers_packed || !vq->async_descs_split || + !vq->async_pkts_info || !vq->it_pool || !vq->vec_pool) {
Not really than of this error handling. Checking after every malloc if it suceed would be cleaner.
Quoted 26 lines
lib/librte_vhost/vhost.c +2
-1+vhost_free_async_mem (dev, vq);VHOST_LOG_CONFIG (ERR ,"async register failed: cannot allocate memory for vq data " "(vid %d, qid: %d)\n" , vid, queue_id);@@ -1728,7 +1737,7 @@ int rte_vhost_async_channel_unregister(int vid, uint16_t queue_id) goto out; } -vhost_free_async_mem (vq); +vhost_free_async_mem (dev, vq); vq->async_ops.transfer_data =NULL ; vq->async_ops.check_completed_copies =NULL ;lib/librte_vhost/vhost.h +2
-3@@ -201,9 +201,18 @@ struct vhost_virtqueue {uint16_t async_pkts_idx;uint16_t async_pkts_inflight_n;uint16_t async_last_pkts_n; -struct vring_used_elem *async_descs_split; -uint16_t async_desc_idx; -uint16_t last_async_desc_idx; +union { +struct vring_used_elem *async_descs_split;
lib/librte_vhost/vhost.h struct vhost_virtqueue { · line 215
Quoted 10 lines
lib/librte_vhost/vhost.h +10
-0+struct vring_used_elem_packed *async_buffers_packed; + }; +union { +uint16_t async_desc_idx; +uint16_t async_packed_buffer_idx; + }; +union { +uint16_t last_async_desc_idx; +uint16_t last_async_buffer_idx; + };
Looks almost good to me now, thanks for doing the change. Only minor issue is the naming which is not consistent in the different fields. Sometimes it contains split or packed, sometimes not.
Maxime
Hi Maxime,
Quoted 62 lines
-----Original Message-----
From: Maxime Coquelin <[email protected]>
Sent: Wednesday, April 14, 2021 9:41 PM
To: Jiang, Cheng1 <[email protected]>; Xia, Chenbo <[email protected]>
Cc: [email protected]; Hu, Jiayu <[email protected]>; Yang, YvonneX <[email protected]>; Wang, Yinan <[email protected]>; Liu, Yong <[email protected]>
Subject: Re: [PATCH v7 2/4] vhost: add support for packed ring in async vhostQuoted 36 lines · Cheng Jiang
For now async vhost data path only supports split ring. This patch enables packed ring in async vhost data path to make async vhost compatible with virtio 1.1 spec.
Signed-off-by Cheng Jiang <[email protected]>--- lib/librte_vhost/rte_vhost_async.h | 1 + lib/librte_vhost/vhost.c | 49 ++-- lib/librte_vhost/vhost.h | 15 +- lib/librte_vhost/virtio_net.c | 432 +++++++++++++++++++++++++++-- 4 files changed, 456 insertions(+), 41 deletions(-)lib/librte_vhost/rte_vhost_async.h +1
-0@@ -89,6 +89,7 @@ struct rte_vhost_async_channel_ops { struct async_inflight_info {struct rte_mbuf *mbuf;uint16_t descs;/* num of descs inflight */ +uint16_t nr_buffers;/* num of buffers inflight for packed ring */ };/** lib/librte_vhost/vhost.c index renamed from lib/librte_vhost/vhost.c +0
-0
a70fe01d8..f509186c6100644lib/librte_vhost/vhost.c +2
-1@@ -338,19 +338,22 @@ cleanup_device(struct virtio_net *dev, int destroy) }static void -vhost_free_async_mem (struct vhost_virtqueue *vq) +vhost_free_async_mem (struct virtio_net *dev,struct vhost_virtqueue +*vq)lib/librte_vhost/vhost.c cleanup_device(struct virtio_net *dev, int · line 349
Quoted 10 lines
lib/librte_vhost/vhost.c +6
-3{ -if (vq->async_pkts_info) -rte_free (vq->async_pkts_info); -if (vq->async_descs_split) +rte_free (vq->async_pkts_info); + +if (vq_is_packed (dev)) { +rte_free (vq->async_buffers_packed); + vq->async_buffers_packed =NULL ; + }else {Doing this is not necessary:
Quoted 6 lines
rte_free(vq->async_buffers_packed); vq->async_buffers_packed = NULL; rte_free(vq->async_descs_split); vq->async_descs_split = NULL;Above will just work and will avoid adding dev parameter.
async_buffers_packed and async_descs_split are two members of a union.
If I rte_free(vq->async_buffers_packed), then there is no need to rte_free(vq->async_descs_split).
So I use dev to determine which one I need to free.
Sure, I can free then both with no condition(I can also only free any one of them), but I think it's a little strange, Right?
Quoted 63 lines
lib/librte_vhost/vhost.c int rte_vhost_async_channel_register(int vid,
Quoted 33 lines
lib/librte_vhost/vhost.c +8
-8rte_free (vq->async_descs_split); -if (vq->it_pool) -rte_free (vq->it_pool); -if (vq->vec_pool) -rte_free (vq->vec_pool); + vq->async_descs_split =NULL ; + } + +rte_free (vq->it_pool); +rte_free (vq->vec_pool); vq->async_pkts_info =NULL ; - vq->async_descs_split =NULL ; vq->it_pool =NULL ; vq->vec_pool =NULL ; }@@ -360,10 +363,10 @@ free_vq(struct virtio_net *dev, struct vhost_virtqueue *vq) {if (vq_is_packed (dev))rte_free (vq->shadow_used_packed); -else { +else rte_free (vq->shadow_used_split); -vhost_free_async_mem (vq); - } + +vhost_free_async_mem (dev, vq);rte_free (vq->batch_copy_elems);if (vq->iotlb_pool)rte_mempool_free (vq->iotlb_pool);@@ -1626,10 +1629,9 @@ int rte_vhost_async_channel_register(int vid,
uint16_tqueue_id,lib/librte_vhost/vhost.c int rte_vhost_async_channel_register(int vid, uint16_t queue_id,
Quoted 8 lines
lib/librte_vhost/vhost.c +1
-3if (unlikely (vq ==NULL || !dev->async_copy))return -1 ; -/* packed queue is not supported */ -if (unlikely (vq_is_packed (dev) || !f.async_inorder)) { +if (unlikely (!f.async_inorder)) { VHOST_LOG_CONFIG(ERR, - "async copy is not supported on packed queue ornon-inorder mode "
lib/librte_vhost/vhost.c int rte_vhost_async_channel_register(int vid,
Quoted 5 lines
lib/librte_vhost/vhost.c +1
-0+"async copy is not supported on non-inorder mode " "(vid %d, qid: %d)\n", vid, queue_id);return -1 ; }@@ -1667,12 +1669,19 @@ int rte_vhost_async_channel_register(int vid,
uint16_tqueue_id,Quoted 14 lines
lib/librte_vhost/vhost.c +6
-3vq->vec_pool =rte_malloc_socket (NULL ,VHOST_MAX_ASYNC_VEC *sizeof (struct iovec ),RTE_CACHE_LINE_SIZE , node); - vq->async_descs_split =rte_malloc_socket (NULL , +if (vq_is_packed (dev)) { + vq->async_buffers_packed =rte_malloc_socket (NULL , + vq->size *sizeof (struct vring_used_elem_packed ), +RTE_CACHE_LINE_SIZE , node); + }else { + vq->async_descs_split =rte_malloc_socket (NULL , vq->size *sizeof (struct vring_used_elem ),RTE_CACHE_LINE_SIZE , node); -if (!vq->async_descs_split || !vq->async_pkts_info || - !vq->it_pool || !vq->vec_pool) {
Quoted 8 lines
lib/librte_vhost/vhost.c int rte_vhost_async_channel_register(int vid, uint16_t queue_id, · line 1683
Quoted 5 lines
lib/librte_vhost/vhost.c +4
-1-vhost_free_async_mem (vq); + } + +if (!vq->async_buffers_packed || !vq->async_descs_split || + !vq->async_pkts_info || !vq->it_pool || !vq->vec_pool) {Not really than of this error handling. Checking after every malloc if it suceed would be cleaner.
OK, make sense to me. But that means I need to add log(which can be more specific) after every check, do you thinks it's ok? If you thinks it's ok, then I'll fix it in the next version.
Quoted 35 lines
lib/librte_vhost/vhost.c int rte_vhost_async_channel_register(int vid, uint16_t queue_id,
Quoted 4 lines
lib/librte_vhost/vhost.c +1
-0+vhost_free_async_mem (dev, vq); VHOST_LOG_CONFIG(ERR, "async register failed: cannot allocatememory for vq data "
lib/librte_vhost/vhost.c int rte_vhost_async_channel_register(int vid, · line 1687
Quoted 1 line
lib/librte_vhost/vhost.c +0
-0"(vid %d, qid: %d)\n", vid, queue_id); @@ -1728,7 +1737,7 @@ int
Quoted 28 lines
rte_vhost_async_channel_unregister(int vid, uint16_t queue_id)lib/librte_vhost/vhost.c +1
-1goto out; } -vhost_free_async_mem (vq); +vhost_free_async_mem (dev, vq); vq->async_ops.transfer_data =NULL ; vq->async_ops.check_completed_copies = NULL; diff --git
a/lib/librte_vhost/vhost.hb/lib/librte_vhost/vhost.hindex f628714c2..673335217 100644lib/librte_vhost/vhost.h +8
-3@@ -201,9 +201,18 @@ struct vhost_virtqueue {uint16_t async_pkts_idx;uint16_t async_pkts_inflight_n;uint16_t async_last_pkts_n; -struct vring_used_elem *async_descs_split; -uint16_t async_desc_idx; -uint16_t last_async_desc_idx; +union { +struct vring_used_elem *async_descs_split; +struct vring_used_elem_packed *async_buffers_packed; + }; +union { +uint16_t async_desc_idx; +uint16_t async_packed_buffer_idx; + };
Quoted 8 lines
lib/librte_vhost/vhost.h struct vhost_virtqueue { · line 215
Quoted 4 lines
lib/librte_vhost/vhost.h +4
-0+union { +uint16_t last_async_desc_idx; +uint16_t last_async_buffer_idx; + };Looks almost good to me now, thanks for doing the change.
Only minor issue is the naming which is not consistent in the different fields. Sometimes it contains split or packed, sometimes not.
OK, I'll check these names, and fix them.
Thanks a lot.
Cheng
Quoted 2 lines
Maxime
Hi Cheng,
Quoted 110 lines
-----Original Message-----
From: Jiang, Cheng1 <[email protected]>
Sent: Wednesday, April 14, 2021 2:14 PM
To: [email protected]; Xia, Chenbo <[email protected]>
Cc: [email protected]; Hu, Jiayu <[email protected]>; Yang, YvonneX <[email protected]>; Wang, Yinan <[email protected]>; Liu, Yong <[email protected]>; Jiang, Cheng1 <[email protected]>
Subject: [PATCH v7 2/4] vhost: add support for packed ring in async vhostFor now async vhost data path only supports split ring. This patch enables packed ring in async vhost data path to make async vhost compatible with virtio 1.1 spec.
Signed-off-by Cheng Jiang <[email protected]>--- lib/librte_vhost/rte_vhost_async.h | 1 + lib/librte_vhost/vhost.c | 49 ++-- lib/librte_vhost/vhost.h | 15 +- lib/librte_vhost/virtio_net.c | 432 +++++++++++++++++++++++++++-- 4 files changed, 456 insertions(+), 41 deletions(-)lib/librte_vhost/rte_vhost_async.h +1
-0@@ -89,6 +89,7 @@ struct rte_vhost_async_channel_ops {struct async_inflight_info {struct rte_mbuf *mbuf;uint16_t descs;/* num of descs inflight */ +uint16_t nr_buffers;/* num of buffers inflight for packed ring */ };/** lib/librte_vhost/vhost.c +15
-12@@ -338,19 +338,22 @@ cleanup_device(struct virtio_net *dev, int destroy) }static void -vhost_free_async_mem (struct vhost_virtqueue *vq) +vhost_free_async_mem (struct virtio_net *dev,struct vhost_virtqueue *vq) { -if (vq->async_pkts_info) -rte_free (vq->async_pkts_info); -if (vq->async_descs_split) +rte_free (vq->async_pkts_info); + +if (vq_is_packed (dev)) { +rte_free (vq->async_buffers_packed); + vq->async_buffers_packed =NULL ; + }else {rte_free (vq->async_descs_split); -if (vq->it_pool) -rte_free (vq->it_pool); -if (vq->vec_pool) -rte_free (vq->vec_pool); + vq->async_descs_split =NULL ; + } + +rte_free (vq->it_pool); +rte_free (vq->vec_pool); vq->async_pkts_info =NULL ; - vq->async_descs_split =NULL ; vq->it_pool =NULL ; vq->vec_pool =NULL ; }@@ -360,10 +363,10 @@ free_vq(struct virtio_net *dev, struct vhost_virtqueue *vq) {if (vq_is_packed (dev))rte_free (vq->shadow_used_packed); -else { +else rte_free (vq->shadow_used_split); -vhost_free_async_mem (vq); - } + +vhost_free_async_mem (dev, vq);rte_free (vq->batch_copy_elems);if (vq->iotlb_pool)lib/librte_vhost/vhost.c +1
-3rte_mempool_free (vq->iotlb_pool);@@ -1626,10 +1629,9 @@ int rte_vhost_async_channel_register(int vid, uint16_t queue_id, if (unlikely(vq == NULL || !dev->async_copy)) return -1; -/* packed queue is not supported */ -if (unlikely (vq_is_packed (dev) || !f.async_inorder)) { +if (unlikely (!f.async_inorder)) { VHOST_LOG_CONFIG(ERR, - "async copy is not supported on packed queue ornon-inorder mode "
lib/librte_vhost/vhost.c +5
-1+"async copy is not supported on non-inorder mode " "(vid %d, qid: %d)\n", vid, queue_id);return -1 ; }@@ -1667,12 +1669,19 @@ int rte_vhost_async_channel_register(int vid,uint16_t queue_id, vq->vec_pool = rte_malloc_socket(NULL,VHOST_MAX_ASYNC_VEC *sizeof (struct iovec ),RTE_CACHE_LINE_SIZE , node); - vq->async_descs_split = rte_malloc_socket(NULL, +if (vq_is_packed (dev)) { + vq->async_buffers_packed =rte_malloc_socket (NULL , + vq->size *sizeof (struct vring_used_elem_packed ), +RTE_CACHE_LINE_SIZE , node);
lib/librte_vhost/vhost.c int rte_vhost_async_channel_register(int vid, · line 1683
Quoted 10 lines
lib/librte_vhost/vhost.c +5
-3+ }else { + vq->async_descs_split =rte_malloc_socket (NULL , vq->size *sizeof (struct vring_used_elem ),RTE_CACHE_LINE_SIZE , node); -if (!vq->async_descs_split || !vq->async_pkts_info || - !vq->it_pool || !vq->vec_pool) { -vhost_free_async_mem (vq); + } + + if (!vq->async_buffers_packed || !vq->async_descs_split ||
async_buffers_packed and async_descs_split are two members of a union. Like the way processed in vhost_free_async_mem(), do you think it's better to check if they are NULL in if-else respectively?
Quoted 154 lines
lib/librte_vhost/vhost.c +2
-0+ !vq->async_pkts_info || !vq->it_pool || !vq->vec_pool) { +vhost_free_async_mem (dev, vq); VHOST_LOG_CONFIG(ERR, "async register failed: cannot allocatememory for vq data "
lib/librte_vhost/vhost.c +1
-1"(vid %d, qid: %d)\n", vid, queue_id);@@ -1728,7 +1737,7 @@ int rte_vhost_async_channel_unregister(int vid, uint16_t queue_id) goto out; } -vhost_free_async_mem (vq); +vhost_free_async_mem (dev, vq); vq->async_ops.transfer_data =NULL ;lib/librte_vhost/vhost.c +0
-0vq->async_ops.check_completed_copies =NULL ;lib/librte_vhost/vhost.h +12
-3@@ -201,9 +201,18 @@ struct vhost_virtqueue {uint16_t async_pkts_idx;uint16_t async_pkts_inflight_n;uint16_t async_last_pkts_n; -struct vring_used_elem *async_descs_split; -uint16_t async_desc_idx; -uint16_t last_async_desc_idx; +union { +struct vring_used_elem *async_descs_split; +struct vring_used_elem_packed *async_buffers_packed; + }; +union { +uint16_t async_desc_idx; +uint16_t async_packed_buffer_idx; + }; +union { +uint16_t last_async_desc_idx; +uint16_t last_async_buffer_idx; + };/* vq async features */ bool async_inorder;lib/librte_vhost/virtio_net.c +5
-5@@ -363,14 +363,14 @@ vhost_shadow_dequeue_single_packed_inorder(struct vhost_virtqueue *vq, } static __rte_always_inline void -vhost_shadow_enqueue_single_packed (struct virtio_net *dev, -struct vhost_virtqueue *vq, -uint32_t len[], -uint16_t id[], -uint16_t count[], +vhost_shadow_enqueue_packed (struct vhost_virtqueue *vq, +uint32_t *len, +uint16_t *id, +uint16_t *count,uint16_t num_buffers) {uint16_t i; +for (i =0 ; i < num_buffers; i++) {/* enqueue shadow flush action aligned with batch num */ lib/librte_vhost/virtio_net.c +11
-0if (!vq->shadow_used_idx)@@ -382,6 +382,17 @@ vhost_shadow_enqueue_single_packed(struct virtio_net *dev, vq->shadow_aligned_idx += count[i]; vq->shadow_used_idx++; } +} + +static __rte_always_inline void +vhost_shadow_enqueue_single_packed (struct virtio_net *dev, +struct vhost_virtqueue *vq, +uint32_t *len, +uint16_t *id, +uint16_t *count, +uint16_t num_buffers) +{ +vhost_shadow_enqueue_packed (vq, len, id, count, num_buffers);if (vq->shadow_aligned_idx >=PACKED_BATCH_SIZE ) {lib/librte_vhost/virtio_net.c +0
-0do_data_copy_enqueue (dev, vq);@@ -1474,6 +1485,23 @@ store_dma_desc_info_split(struct
vring_used_elem*s_ring, structvring_used_elemlib/librte_vhost/virtio_net.c +4
-0} } +static __rte_always_inline void +store_dma_desc_info_packed (struct vring_used_elem_packed *s_ring, +struct vring_used_elem_packed *d_ring, + uint16_t ring_size, uint16_t s_idx, uint16_t d_idx, uint16_tcount)
lib/librte_vhost/virtio_net.c +5
-0+{ +uint16_t elem_size =sizeof (struct vring_used_elem_packed ); + +if (d_idx + count <= ring_size) { + rte_memcpy(d_ring + d_idx, s_ring + s_idx, count *
elem_size);lib/librte_vhost/virtio_net.c +5
-0+ }else { +uint16_t size = ring_size - d_idx; + +rte_memcpy (d_ring + d_idx, s_ring + s_idx, size * elem_size); + rte_memcpy(d_ring, s_ring + s_idx + size, (count - size) *
elem_size);lib/librte_vhost/virtio_net.c +38
-0+ } +} + static __rte_noinline uint32_t virtio_dev_rx_async_submit_split(struct virtio_net *dev, struct vhost_virtqueue *vq, uint16_t queue_id,@@ -1641,6 +1669,330 @@ virtio_dev_rx_async_submit_split(structvirtio_net *dev, return pkt_idx; } +static __rte_always_inline void +vhost_update_used_packed (struct vhost_virtqueue *vq, +struct vring_used_elem_packed *shadow_ring, +uint16_t count) +{ +int i; +uint16_t used_idx = vq->last_used_idx; +uint16_t head_idx = vq->last_used_idx; +uint16_t head_flags =0 ; + +if (count ==0 ) +return ; + +/* Split loop in two to save memory barriers */ +for (i =0 ; i < count; i++) { + vq->desc_packed[used_idx].id = shadow_ring[i].id; + vq->desc_packed[used_idx].len = shadow_ring[i].len; + + used_idx += shadow_ring[i].count; +if (used_idx >= vq->size) + used_idx -= vq->size; + } + +/* The ordering for storing desc flags needs to be enforced. */ +rte_atomic_thread_fence (__ATOMIC_RELEASE); + +for (i =0 ; i < count; i++) { +uint16_t flags; + +if (vq->shadow_used_packed[i].len) + flags =VRING_DESC_F_WRITE ; +else + flags =0 ; + +if (vq->used_wrap_counter) {
lib/librte_vhost/virtio_net.c virtio_dev_rx_async_submit_split(struct · line 1717
Quoted 10 lines
lib/librte_vhost/virtio_net.c +10
-0+ flags |=VRING_DESC_F_USED ; + flags |=VRING_DESC_F_AVAIL ; + }else { + flags &= ~VRING_DESC_F_USED ; + flags &= ~VRING_DESC_F_AVAIL ; + } + +if (i >0 ) { + vq->desc_packed[vq->last_used_idx].flags = flags; +
No need a blank line above.
Quoted 134 lines
lib/librte_vhost/virtio_net.c +51
-0+ }else { + head_idx = vq->last_used_idx; + head_flags = flags; + } + +vq_inc_last_used_packed (vq, shadow_ring[i].count); + } + + vq->desc_packed[head_idx].flags = head_flags; +} + +static __rte_always_inline int +vhost_enqueue_async_single_packed (struct virtio_net *dev, +struct vhost_virtqueue *vq, +struct rte_mbuf *pkt, +struct buf_vector *buf_vec, +uint16_t *nr_descs, +uint16_t *nr_buffers, +struct vring_packed_desc *async_descs, +struct iovec *src_iovec,struct iovec *dst_iovec, +struct rte_vhost_iov_iter *src_it, +struct rte_vhost_iov_iter *dst_it) +{ +uint16_t nr_vec =0 ; +uint16_t avail_idx = vq->last_avail_idx; +uint16_t max_tries, tries =0 ; +uint16_t buf_id =0 ; +uint32_t len =0 ; +uint16_t desc_count =0 ; +uint32_t size = pkt->pkt_len +sizeof (struct virtio_net_hdr_mrg_rxbuf ); +uint32_t buffer_len[vq->size]; +uint16_t buffer_buf_id[vq->size]; +uint16_t buffer_desc_count[vq->size]; + *nr_buffers =0 ; + +if (rxvq_is_mergeable (dev)) + max_tries = vq->size -1 ; +else + max_tries =1 ; + +while (size >0 ) { +/* +* if we tried all available ring items, and still +* can't get enough buf, it means something abnormal +* happened. +*/ +if (unlikely (++tries > max_tries)) +return -1 ; + + if (unlikely(fill_vec_buf_packed(dev, vq, avail_idx, &desc_count, buf_vec, &nr_vec, + &buf_id, &len,
VHOST_ACCESS_RW) < 0))lib/librte_vhost/virtio_net.c +17
-0+return -1 ; + + len =RTE_MIN (len, size); + size -= len; + + buffer_len[*nr_buffers] = len; + buffer_buf_id[*nr_buffers] = buf_id; + buffer_desc_count[*nr_buffers] = desc_count; + *nr_buffers +=1 ; + + *nr_descs += desc_count; + avail_idx += desc_count; +if (avail_idx >= vq->size) + avail_idx -= vq->size; + } + + if (async_mbuf_to_desc(dev, vq, pkt, buf_vec, nr_vec, *nr_buffers,
src_iovec,dst_iovec,lib/librte_vhost/virtio_net.c +5
-0+ src_it, dst_it) < 0) +return -1 ; +/* store descriptors for DMA */ + if (avail_idx >= *nr_descs) { + rte_memcpy(async_descs, &vq->desc_packed[vq-Quoted 1 line
last_avail_idx],lib/librte_vhost/virtio_net.c +4
-0+ *nr_descs * sizeof(struct vring_packed_desc)); + } else { + uint16_t nr_copy = vq->size - vq->last_avail_idx; + rte_memcpy(async_descs, &vq->desc_packed[vq-Quoted 1 line
last_avail_idx],lib/librte_vhost/virtio_net.c +3
-0+ nr_copy * sizeof(struct vring_packed_desc)); + rte_memcpy(async_descs + nr_copy, vq->desc_packed, + (*nr_descs - nr_copy) * sizeof(struct
vring_packed_desc));lib/librte_vhost/virtio_net.c +3
-0+ } + + vhost_shadow_enqueue_packed(vq, buffer_len, buffer_buf_id,
buffer_desc_count,*nr_buffers);lib/librte_vhost/virtio_net.c +6
-0+ +return 0 ; +} + +static __rte_always_inline int16_t +virtio_dev_rx_async_single_packed(struct virtio_net *dev, struct
vhost_virtqueue*vq,lib/librte_vhost/virtio_net.c +1
-0+ struct rte_mbuf *pkt, uint16_t *nr_descs, uint16_t
*nr_buffers,lib/librte_vhost/virtio_net.c +3
-0+struct vring_packed_desc *async_descs, + struct iovec *src_iovec, struct iovec *dst_iovec, + struct rte_vhost_iov_iter *src_it, struct
rte_vhost_iov_iter*dst_it)lib/librte_vhost/virtio_net.c +6
-0+{ +struct buf_vector buf_vec[BUF_VECTOR_MAX ]; + *nr_descs =0 ; + *nr_buffers =0 ; + + if (unlikely(vhost_enqueue_async_single_packed(dev, vq, pkt,
buf_vec,nr_descs,nr_buffers,lib/librte_vhost/virtio_net.c +1
-0+ async_descs, src_iovec,
dst_iovec,lib/librte_vhost/virtio_net.c +2
-0+ src_it, dst_it) < 0)) { + VHOST_LOG_DATA(DEBUG, "(%d) failed to get enough descfrom vring\n",
dev->vid);lib/librte_vhost/virtio_net.c +4
-0+return -1 ; + } + + VHOST_LOG_DATA(DEBUG, "(%d) current index %d | endindex %d\n",
lib/librte_vhost/virtio_net.c +1
-0+ dev->vid, vq->last_avail_idx, vq->last_avail_idx +
*nr_descs);lib/librte_vhost/virtio_net.c +6
-0+ +return 0 ; +} + +static __rte_always_inline void +dma_error_handler_packed(struct vhost_virtqueue *vq, struct
vring_packed_desc*async_descs,lib/librte_vhost/virtio_net.c +1
-0+ uint16_t async_descs_idx, uint16_t slot_idx, uint32_t
nr_err,lib/librte_vhost/virtio_net.c +1
-0+ uint32_t *pkt_idx, uint32_t *num_async_pkts,
uint32_t*num_done_pkts)
lib/librte_vhost/virtio_net.c virtio_dev_rx_async_submit_split(struct virtio_net *dev, · line 1841
Quoted 10 lines
lib/librte_vhost/virtio_net.c +10
-0+{ +uint16_t descs_err =0 ; +uint16_t buffers_err =0 ; +struct async_inflight_info *pkts_info = vq->async_pkts_info; + + *num_async_pkts -= nr_err; + *pkt_idx -= nr_err; +/* calculate the sum of buffers and descs of DMA-error packets. */ +while (nr_err-- >0 ) { + descs_err += pkts_info[slot_idx % vq->size].descs;
I notice there are several parts using "%" to wrap around index, but existed code uses "& (vq->size - 1)" instead. I think it's better to keep it consistent.
Thanks,
Jiayu
Hi Jiayu,
Quoted 117 lines
-----Original Message-----
From: Hu, Jiayu <[email protected]>
Sent: Thursday, April 15, 2021 10:03 AM
To: Jiang, Cheng1 <[email protected]>; [email protected]; Xia, Chenbo <[email protected]>
Cc: [email protected]; Yang, YvonneX <[email protected]>; Wang, Yinan <[email protected]>; Liu, Yong <[email protected]>
Subject: RE: [PATCH v7 2/4] vhost: add support for packed ring in async vhostHi Cheng,
Quoted 86 lines
-----Original Message-----
From: Jiang, Cheng1 <[email protected]>
Sent: Wednesday, April 14, 2021 2:14 PM
To: [email protected]; Xia, Chenbo <[email protected]>
Cc: [email protected]; Hu, Jiayu <[email protected]>; Yang, YvonneX <[email protected]>; Wang, Yinan <[email protected]>; Liu, Yong <[email protected]>; Jiang, Cheng1 <[email protected]>
Subject: [PATCH v7 2/4] vhost: add support for packed ring in async vhostFor now async vhost data path only supports split ring. This patch enables packed ring in async vhost data path to make async vhost compatible with virtio 1.1 spec.
Signed-off-by Cheng Jiang <[email protected]>--- lib/librte_vhost/rte_vhost_async.h | 1 + lib/librte_vhost/vhost.c | 49 ++-- lib/librte_vhost/vhost.h | 15 +- lib/librte_vhost/virtio_net.c | 432 +++++++++++++++++++++++++++-- 4 files changed, 456 insertions(+), 41 deletions(-)lib/librte_vhost/rte_vhost_async.h +0
-0@@ -89,6 +89,7 @@ struct rte_vhost_async_channel_ops { struct
async_inflight_info{ structrte_mbuf*mbuf;uint16_tdescs; /* num of descs inflight */lib/librte_vhost/rte_vhost_async.h +1
-0+uint16_t nr_buffers;/* num of buffers inflight for packed ring */ };/** lib/librte_vhost/vhost.c index renamed from lib/librte_vhost/vhost.c +0
-0
a70fe01d8..f509186c6100644lib/librte_vhost/vhost.c +16
-11@@ -338,19 +338,22 @@ cleanup_device(struct virtio_net *dev, int destroy) }static void -vhost_free_async_mem (struct vhost_virtqueue *vq) +vhost_free_async_mem (struct virtio_net *dev,struct vhost_virtqueue +*vq) { -if (vq->async_pkts_info) -rte_free (vq->async_pkts_info); -if (vq->async_descs_split) +rte_free (vq->async_pkts_info); + +if (vq_is_packed (dev)) { +rte_free (vq->async_buffers_packed); +vq->async_buffers_packed =NULL ; +}else {rte_free (vq->async_descs_split); -if (vq->it_pool) -rte_free (vq->it_pool); -if (vq->vec_pool) -rte_free (vq->vec_pool); +vq->async_descs_split =NULL ; +} + +rte_free (vq->it_pool); +rte_free (vq->vec_pool); vq->async_pkts_info =NULL ; -vq->async_descs_split =NULL ; vq->it_pool =NULL ; vq->vec_pool =NULL ; }@@ -360,10 +363,10 @@ free_vq(struct virtio_net *dev, struct vhost_virtqueue *vq) { if (vq_is_packed(dev)) rte_free(vq->shadow_used_packed); -else { +else rte_free(vq->shadow_used_split); -vhost_free_async_mem (vq); -} + +vhost_free_async_mem (dev, vq);rte_free (vq->batch_copy_elems);if (vq->iotlb_pool)rte_mempool_free (vq->iotlb_pool);@@ -1626,10 +1629,9 @@ int rte_vhost_async_channel_register(int vid, uint16_t queue_id, if (unlikely(vq == NULL || !dev->async_copy)) return -1;lib/librte_vhost/vhost.c int rte_vhost_async_channel_register(int vid, · line 1637
Quoted 10 lines
lib/librte_vhost/vhost.c +3
-3-/* packed queue is not supported */ -if (unlikely (vq_is_packed (dev) || !f.async_inorder)) { +if (unlikely (!f.async_inorder)) {VHOST_LOG_CONFIG (ERR , -"async copy is not supported on packed queue or non-inorder mode " +"async copy is not supported on non-inorder mode " "(vid %d, qid: %d)\n", vid, queue_id); return -1; } @@ -1667,12 +1669,19 @@ int rte_vhost_async_channel_register(int vid, uint16_t queue_id, vq->vec_pool = rte_malloc_socket(NULL,
VHOST_MAX_ASYNC_VECQuoted 9 lines
* sizeof(struct iovec),
RTE_CACHE_LINE_SIZE, node);lib/librte_vhost/vhost.c +6
-1-vq->async_descs_split = rte_malloc_socket(NULL, +if (vq_is_packed (dev)) { +vq->async_buffers_packed =rte_malloc_socket (NULL , size * +vq->sizeof(struct vring_used_elem_packed), +RTE_CACHE_LINE_SIZE , node); +}else { +vq->async_descs_split = rte_malloc_socket(NULL, vq->size * sizeof(struct vring_used_elem), RTE_CACHE_LINE_SIZE,
Quoted 8 lines
lib/librte_vhost/vhost.c int rte_vhost_async_channel_register(int vid, uint16_t queue_id, · line 1682
Quoted 5 lines
node); -if (!vq->async_descs_split || !vq->async_pkts_info || -!vq->it_pool || !vq->vec_pool) { -vhost_free_async_mem(vq);
lib/librte_vhost/vhost.c +3
-0+} + +if (!vq->async_buffers_packed || !vq->async_descs_split ||
async_buffers_packedandasync_descs_splitare two members of a union. Like the way processed invhost_free_async_mem(), do you think it's better to check if they are NULL in if-else respectively?
Sure, make sense to me. I'll fix them together with other async mem check.
Quoted 140 lines
Quoted 35 lines
+!vq->async_pkts_info || !vq->it_pool || !vq->vec_pool) { +vhost_free_async_mem(dev, vq);
VHOST_LOG_CONFIG(ERR,
"async register failed: cannot allocate memory for vq data " "(vid %d, qid: %d)\n", vid,queue_id); @@ -1728,7 +1737,7 @@ intrte_vhost_async_channel_unregister(int vid, uint16_t queue_id)goto out; }lib/librte_vhost/vhost.c +1
-1-vhost_free_async_mem (vq); +vhost_free_async_mem (dev, vq); vq->async_ops.transfer_data =NULL ; vq->async_ops.check_completed_copies = NULL; diff --git
a/lib/librte_vhost/vhost.hb/lib/librte_vhost/vhost.hindex f628714c2..673335217 100644lib/librte_vhost/vhost.h +0
-0@@ -201,9 +201,18 @@ struct vhost_virtqueue { uint16_tasync_pkts_idx;
uint16_tasync_pkts_inflight_n;uint16_tasync_last_pkts_n; -structvring_used_elem*async_descs_split; -uint16_tasync_desc_idx;lib/librte_vhost/vhost.h +5
-1-uint16_t last_async_desc_idx; +union { +struct vring_used_elem *async_descs_split;struct +vring_used_elem_packed *async_buffers_packed; };union {uint16_t +async_desc_idx;uint16_t async_packed_buffer_idx; };union {uint16_t +last_async_desc_idx;uint16_t last_async_buffer_idx; };/* vq async features */ boolasync_inorder;(quoted diff) +0
-0
b/lib/librte_vhost/virtio_net.cindex438bdafd1..54e11e3a5100644lib/librte_vhost/virtio_net.c +0
-0@@ -363,14 +363,14 @@Quoted 1 line
vhost_shadow_dequeue_single_packed_inorder(struct
vhost_virtqueue*vq,
Quoted 103 lines
}
static
__rte_always_inlinevoidlib/librte_vhost/virtio_net.c +5
-5-vhost_shadow_enqueue_single_packed(struct virtio_net *dev, - struct vhost_virtqueue *vq, - uint32_t len[], - uint16_t id[], - uint16_t count[], +vhost_shadow_enqueue_packed(struct vhost_virtqueue *vq, + uint32_t *len, + uint16_t *id, + uint16_t *count, uint16_t num_buffers) { uint16_t i; +for (i =0 ; i < num_buffers; i++) { /* enqueue shadow flush action aligned with batch num */ if(!vq->shadow_used_idx) @@ -382,6 +382,17 @@
vhost_shadow_enqueue_single_packed(structvirtio_net*dev,
vq->shadow_aligned_idx+= count[i];
vq->shadow_used_idx++;
}lib/librte_vhost/virtio_net.c +11
-0+} + +static __rte_always_inline void +vhost_shadow_enqueue_single_packed (struct virtio_net *dev, +struct vhost_virtqueue *vq, +uint32_t *len, +uint16_t *id, +uint16_t *count, +uint16_t num_buffers) +{ +vhost_shadow_enqueue_packed (vq, len, id, count, num_buffers);if (vq->shadow_aligned_idx >=PACKED_BATCH_SIZE ) {
do_data_copy_enqueue(dev, vq); @@ -1474,6 +1485,23 @@ store_dma_desc_info_split(structvring_used_elem*s_ring, structvring_used_elem} }lib/librte_vhost/virtio_net.c +4
-0+static __rte_always_inline void +store_dma_desc_info_packed (struct vring_used_elem_packed *s_ring, +struct vring_used_elem_packed *d_ring,uint16_t ring_size,uint16_t +s_idx, uint16_t d_idx, uint16_tcount)
lib/librte_vhost/virtio_net.c +5
-0+{ +uint16_t elem_size =sizeof (struct vring_used_elem_packed ); + +if (d_idx + count <= ring_size) { +rte_memcpy(d_ring + d_idx, s_ring + s_idx, count *
elem_size);lib/librte_vhost/virtio_net.c +5
-0+}else { +uint16_t size = ring_size - d_idx; + +rte_memcpy (d_ring + d_idx, s_ring + s_idx, size * elem_size); +rte_memcpy(d_ring, s_ring + s_idx + size, (count - size) *
elem_size);lib/librte_vhost/virtio_net.c +3
-0+} +} + static __rte_noinline uint32_t virtio_dev_rx_async_submit_split(struct virtio_net *dev, struct
vhost_virtqueue*vq,uint16_tqueue_id, @@ -1641,6 +1669,330 @@ virtio_dev_rx_async_submit_split(structvirtio_net*dev,
returnpkt_idx;
}lib/librte_vhost/virtio_net.c +34
-0+static __rte_always_inline void +vhost_update_used_packed (struct vhost_virtqueue *vq,struct +vring_used_elem_packed *shadow_ring,uint16_t count) {int i; +uint16_t used_idx = vq->last_used_idx;uint16_t head_idx = +vq->last_used_idx;uint16_t head_flags =0 ; + +if (count ==0 ) +return ; + +/* Split loop in two to save memory barriers */ for (i =0 ; i < +count; i++) { +vq->desc_packed[used_idx].id = shadow_ring[i].id; +vq->desc_packed[used_idx].len = shadow_ring[i].len; + +used_idx += shadow_ring[i].count; +if (used_idx >= vq->size) +used_idx -= vq->size; +} + +/* The ordering for storing desc flags needs to be enforced. */ +rte_atomic_thread_fence (__ATOMIC_RELEASE); + +for (i =0 ; i < count; i++) { +uint16_t flags; + +if (vq->shadow_used_packed[i].len) +flags =VRING_DESC_F_WRITE ; +else +flags =0 ; + +if (vq->used_wrap_counter) { +flags |=VRING_DESC_F_USED ; +flags |=VRING_DESC_F_AVAIL ; +}else {
Quoted 8 lines
lib/librte_vhost/virtio_net.c virtio_dev_rx_async_submit_split(struct virtio_net *dev, · line 1716
Quoted 7 lines
lib/librte_vhost/virtio_net.c +7
-0+flags &= ~VRING_DESC_F_USED ; +flags &= ~VRING_DESC_F_AVAIL ; +} + +if (i >0 ) { +vq->desc_packed[vq->last_used_idx].flags = flags; +No need a blank line above.
Sure, thanks.
Quoted 129 lines
Quoted 95 lines
lib/librte_vhost/virtio_net.c +24
-0+}else { +head_idx = vq->last_used_idx; +head_flags = flags; +} + +vq_inc_last_used_packed (vq, shadow_ring[i].count); } + +vq->desc_packed[head_idx].flags = head_flags; +} + +static __rte_always_inline int +vhost_enqueue_async_single_packed (struct virtio_net *dev, +struct vhost_virtqueue *vq, +struct rte_mbuf *pkt, +struct buf_vector *buf_vec, +uint16_t *nr_descs, +uint16_t *nr_buffers, +struct vring_packed_desc *async_descs, +struct iovec *src_iovec,struct iovec *dst_iovec, +struct rte_vhost_iov_iter *src_it, +struct rte_vhost_iov_iter *dst_it) {uint16_t nr_vec =0 ; +uint16_t avail_idx = vq->last_avail_idx;uint16_t max_tries, tries = +0 ;uint16_t buf_id =0 ;uint32_t len =0 ;uint16_t desc_count =0 ; +uint32_t size = pkt->pkt_len + sizeof(struct
virtio_net_hdr_mrg_rxbuf);lib/librte_vhost/virtio_net.c +19
-0+uint32_t buffer_len[vq->size]; +uint16_t buffer_buf_id[vq->size]; +uint16_t buffer_desc_count[vq->size]; *nr_buffers =0 ; + +if (rxvq_is_mergeable (dev)) +max_tries = vq->size -1 ; +else +max_tries =1 ; + +while (size >0 ) { +/* +* if we tried all available ring items, and still +* can't get enough buf, it means something abnormal +* happened. +*/ +if (unlikely (++tries > max_tries)) +return -1 ; + +if (unlikely(fill_vec_buf_packed(dev, vq, avail_idx,
&desc_count,buf_vec,&nr_vec,
+&buf_id, &len,VHOST_ACCESS_RW) < 0))lib/librte_vhost/virtio_net.c +16
-0+return -1 ; + +len =RTE_MIN (len, size); +size -= len; + +buffer_len[*nr_buffers] = len; +buffer_buf_id[*nr_buffers] = buf_id; +buffer_desc_count[*nr_buffers] = desc_count; *nr_buffers +=1 ; + +*nr_descs += desc_count; +avail_idx += desc_count; +if (avail_idx >= vq->size) +avail_idx -= vq->size; +} + +if (async_mbuf_to_desc(dev, vq, pkt, buf_vec, nr_vec, *nr_buffers,
src_iovec,dst_iovec,lib/librte_vhost/virtio_net.c +5
-0+src_it, dst_it) < 0) +return -1 ; +/* store descriptors for DMA */ +if (avail_idx >= *nr_descs) { +rte_memcpy(async_descs, &vq->desc_packed[vq-Quoted 1 line
last_avail_idx],lib/librte_vhost/virtio_net.c +3
-0+*nr_descs * sizeof(struct vring_packed_desc)); } else { uint16_t +nr_copy = vq->size - vq->last_avail_idx; rte_memcpy(async_descs, +&vq->desc_packed[vq-Quoted 1 line
last_avail_idx],lib/librte_vhost/virtio_net.c +2
-0+nr_copy * sizeof(struct vring_packed_desc)); rte_memcpy(async_descs + +nr_copy, vq->desc_packed, (*nr_descs - nr_copy) * sizeof(struct
vring_packed_desc));lib/librte_vhost/virtio_net.c +3
-0+} + +vhost_shadow_enqueue_packed(vq, buffer_len, buffer_buf_id,
buffer_desc_count,*nr_buffers);lib/librte_vhost/virtio_net.c +6
-0+ +return 0 ; +} + +static __rte_always_inline int16_t +virtio_dev_rx_async_single_packed(struct virtio_net *dev, struct
vhost_virtqueue*vq,
+ structrte_mbuf*pkt,uint16_t*nr_descs,uint16_t*nr_buffers,lib/librte_vhost/virtio_net.c +3
-0+struct vring_packed_desc *async_descs, + struct iovec *src_iovec, struct iovec *dst_iovec, + struct rte_vhost_iov_iter *src_it, struct
rte_vhost_iov_iter*dst_it)lib/librte_vhost/virtio_net.c
Quoted 2 lines
lib/librte_vhost/virtio_net.c +2
-0+{ +struct buf_vector buf_vec[BUF_VECTOR_MAX ]; *nr_descs =0 ;
*nr_buffersQuoted 31 lines
+= 0;
lib/librte_vhost/virtio_net.c +2
-0+ +if (unlikely(vhost_enqueue_async_single_packed(dev, vq, pkt,
buf_vec,nr_descs,nr_buffers,
+async_descs,src_iovec,dst_iovec,
+src_it,dst_it) < 0)) { +VHOST_LOG_DATA(DEBUG, "(%d) failed to get enough desc from vring\n",dev->vid);lib/librte_vhost/virtio_net.c +4
-0+return -1 ; +} + +VHOST_LOG_DATA(DEBUG, "(%d) current index %d | endindex %d\n",
+dev->vid,vq->last_avail_idx,vq->last_avail_idx+*nr_descs);lib/librte_vhost/virtio_net.c +6
-0+ +return 0 ; +} + +static __rte_always_inline void +dma_error_handler_packed(struct vhost_virtqueue *vq, struct
vring_packed_desc*async_descs,
+uint16_tasync_descs_idx,uint16_tslot_idx,uint32_tnr_err,
+uint32_t*pkt_idx,uint32_t*num_async_pkts,uint32_t*num_done_pkts)lib/librte_vhost/virtio_net.c +4
-0+{ +uint16_t descs_err =0 ; +uint16_t buffers_err =0 ; +struct async_inflight_info *pkts_info = vq->async_pkts_info;
Quoted 8 lines
lib/librte_vhost/virtio_net.c virtio_dev_rx_async_submit_split(struct virtio_net *dev,
Quoted 6 lines
lib/librte_vhost/virtio_net.c +6
-0+ +*num_async_pkts -= nr_err; +*pkt_idx -= nr_err; +/* calculate the sum of buffers and descs of DMA-error packets. */ +while (nr_err-- >0 ) { descs_err += pkts_info[slot_idx % +vq->size].descs;I notice there are several parts using "%" to wrap around index, but existed code uses "& (
vq->size- 1)" instead. I think it's better to keep it consistent.
Unlike split ring, packed ring size is not necessarily a power of 2. So I can't use "& (vq->size - 1) in packed ring.
Thanks,
Cheng
Quoted 3 lines
Thanks,
Jiayu
PATCH v7 3/4 vhost: add batch datapath for async vhost packed ring
In reply to Cheng JiangAdd batch datapath for async vhost packed ring to improve the performance of small packet processing.
--- lib/librte_vhost/virtio_net.c | 41 +++++++++++++++++++++++++++++++---- 1 file changed, 37 insertions(+), 4 deletions(-)
lib/librte_vhost/virtio_net.c +37 -4
@@ -1725,6 +1725,29 @@ vhost_update_used_packed(struct vhost_virtqueue *vq, vq->desc_packed[head_idx].flags = head_flags; } +static __rte_always_inline int +virtio_dev_rx_async_batch_packed (struct virtio_net *dev, +struct vhost_virtqueue *vq, +struct rte_mbuf **pkts, +struct rte_mbuf **comp_pkts,uint32_t *pkt_done) +{ +uint16_t i; +uint32_t cpy_threshold = vq->async_threshold; + +vhost_for_each_try_unroll (i,0 ,PACKED_BATCH_SIZE ) { +if (unlikely (pkts[i]->pkt_len >= cpy_threshold)) +return -1 ; + } +if (!virtio_dev_rx_batch_packed (dev, vq, pkts)) { +vhost_for_each_try_unroll (i,0 ,PACKED_BATCH_SIZE ) + comp_pkts[(*pkt_done)++] = pkts[i]; + +return 0 ; + } + +return -1 ; +} + static __rte_always_inline int vhost_enqueue_async_single_packed(struct virtio_net *dev, struct vhost_virtqueue *vq,
@@ -1875,6 +1898,7 @@ virtio_dev_rx_async_submit_packed(struct virtio_net *dev, struct rte_mbuf **comp_pkts, uint32_t *comp_count) { uint32_t pkt_idx = 0, pkt_burst_idx = 0; +uint32_t remained = count;uint16_t async_descs_idx =0 ;uint16_t num_buffers;uint16_t num_desc;
@@ -1892,9 +1916,17 @@ virtio_dev_rx_async_submit_packed(struct virtio_net *dev,uint32_t num_async_pkts =0 , num_done_pkts =0 ;struct vring_packed_desc async_descs[vq->size]; -rte_prefetch0 (&vq->desc_packed[vq->last_avail_idx]); + do { + rte_prefetch0(&vq->desc_packed[vq->last_avail_idx]); + if (remained >= PACKED_BATCH_SIZE) { + if (!virtio_dev_rx_async_batch_packed(dev, vq, + &pkts[pkt_idx], comp_pkts, &num_done_pkts)) { + pkt_idx += PACKED_BATCH_SIZE; + remained -= PACKED_BATCH_SIZE; + continue; + } + } -for (pkt_idx =0 ; pkt_idx < count; pkt_idx++) { if (unlikely(virtio_dev_rx_async_single_packed(dev, vq, pkts[pkt_idx], &num_desc, &num_buffers, &async_descs[async_descs_idx],
@@ -1937,6 +1969,8 @@ virtio_dev_rx_async_submit_packed(struct virtio_net *dev, comp_pkts[num_done_pkts++] = pkts[pkt_idx]; } + pkt_idx++; + remained--;vq_inc_last_avail_packed (vq, num_desc);/*
@@ -1961,13 +1995,12 @@ virtio_dev_rx_async_submit_packed(struct virtio_net *dev,*/ pkt_err = pkt_burst_idx - n_pkts; pkt_burst_idx =0 ; - pkt_idx++;break ; } pkt_burst_idx =0 ; } - } + }while (pkt_idx < count);if (pkt_burst_idx) { n_pkts = vq->async_ops.transfer_data (dev->vid, queue_id, tdes,0 , pkt_burst_idx);
Signature · 1 line
2.29.2
PATCH v7 4/4 doc: add release note for vhost async packed ring
In reply to Cheng JiangAdd release note for the support of vhost async packed ring.
--- doc/guides/rel_notes/release_21_05.rst | 4 ++++ 1 file changed, 4 insertions(+)
doc/guides/rel_notes/release_21_05.rst +4 -0
@@ -131,6 +131,10 @@ New Features * Added command to display Rx queue used descriptor count. ``show port (port_id) rxq (queue_id) desc used count`` +* **Added support for vhost async packed ring data path.** + + Added packed ring support for async vhost. + Removed Items -------------
Signature · 1 line
2.29.2
v8 cover add support for packed ring in async vhost
In reply to Cheng JiangFor now async vhost data path only supports split ring structure. In order to make async vhost compatible with virtio 1.1 spec this patch set cleans async split ring codes and enables packed ring in async vhost data path. Batch datapath is also enabled in async vhost packed ring.
v8:
* fix some variable names for consistency
* clean codes
v7:
* fix compile issues
* add argument *dev in vhost_free_async_mem() for ring type decision
v6:
* fix some typos in commit log
* improve index usage
* remove shadow_ring_store()
* add store_dma_desc_info_split() store_dma_desc_info_packed()
* remove some checks in vhost_free_async_mem()
* change index calculation since the size isn't necessarily a power of 2
* move error handling in a dedicated function
* clean codes
v5:
* clean some codes for packed ring datapath
* fix an index error in shadow_ring_store()
v4:
* change the patch structure
* clean code for async split ring
* reuse some code from split ring
* change the error handler for DMA-copy packet
* add check for malloc
* remove useless code
* add doc update
v3:
* fix error handler for DMA-copy packet
v2:
* fix wrong buffer index in rte_vhost_poll_enqueue_completed()
* add async_buffers_packed memory free in vhost_free_async_mem()
Cheng Jiang (4):
vhost: abstract and reorganize async split ring code
vhost: add support for packed ring in async vhost
vhost: add batch datapath for async vhost packed ring
doc: add release note for vhost async packed ring
doc/guides/rel_notes/release_21_05.rst | 4 + lib/librte_vhost/rte_vhost_async.h | 1 + lib/librte_vhost/vhost.c | 79 +++- lib/librte_vhost/vhost.h | 15 +- lib/librte_vhost/virtio_net.c | 598 +++++++++++++++++++++---- 5 files changed, 587 insertions(+), 110 deletions(-)
--
2.29.2
PATCH v8 1/4 vhost: abstract and reorganize async split ring code
This patch puts some codes of async vhost split ring into inline functions to improve the readability of the code. And, it changes the pointer index style of iterator to make the code more concise.
--- lib/librte_vhost/virtio_net.c | 132 +++++++++++++++++----------------- 1 file changed, 66 insertions(+), 66 deletions(-)
lib/librte_vhost/virtio_net.c +66 -66
@@ -1458,6 +1458,22 @@ virtio_dev_rx_async_get_info_idx(uint16_t pkts_idx, (vq_size - n_inflight + pkts_idx) & (vq_size -1 ); } +static __rte_always_inline void +store_dma_desc_info_split (struct vring_used_elem *s_ring,struct vring_used_elem *d_ring, +uint16_t ring_size,uint16_t s_idx,uint16_t d_idx,uint16_t count) +{ +uint16_t elem_size =sizeof (struct vring_used_elem ); + +if (d_idx + count <= ring_size) { +rte_memcpy (d_ring + d_idx, s_ring + s_idx, count * elem_size); + }else { +uint16_t size = ring_size - d_idx; + +rte_memcpy (d_ring + d_idx, s_ring + s_idx, size * elem_size); +rte_memcpy (d_ring, s_ring + s_idx + size, (count - size) * elem_size); + } +} + static __rte_noinline uint32_t virtio_dev_rx_async_submit_split(struct virtio_net *dev, struct vhost_virtqueue *vq, uint16_t queue_id,
@@ -1474,10 +1490,9 @@ virtio_dev_rx_async_submit_split(struct virtio_net *dev,struct rte_vhost_async_desc tdes[MAX_PKT_BURST ];struct iovec *src_iovec = vec_pool;struct iovec *dst_iovec = vec_pool + (VHOST_MAX_ASYNC_VEC >>1 ); -struct rte_vhost_iov_iter *src_it = it_pool; -struct rte_vhost_iov_iter *dst_it = it_pool +1 ;uint16_t slot_idx =0 ;uint16_t segs_await =0 ; +uint16_t iovec_idx =0 , it_idx =0 ;struct async_inflight_info *pkts_info = vq->async_pkts_info;uint32_t n_pkts =0 , pkt_err =0 ;uint32_t num_async_pkts =0 , num_done_pkts =0 ;
@@ -1511,29 +1526,30 @@ virtio_dev_rx_async_submit_split(struct virtio_net *dev, dev->vid, vq->last_avail_idx, vq->last_avail_idx + num_buffers); -if (async_mbuf_to_desc (dev, vq, pkts[pkt_idx], - buf_vec, nr_vec, num_buffers, - src_iovec, dst_iovec, src_it, dst_it) <0 ) { +if (async_mbuf_to_desc (dev, vq, pkts[pkt_idx], buf_vec, nr_vec, num_buffers, + &src_iovec[iovec_idx], &dst_iovec[iovec_idx], + &it_pool[it_idx], &it_pool[it_idx +1 ]) <0 ) { vq->shadow_used_idx -= num_buffers;break ; } slot_idx = (vq->async_pkts_idx + num_async_pkts) & (vq->size -1 ); -if (src_it->count) { +if (it_pool[it_idx].count) {uint16_t from, to; -async_fill_desc (&tdes[pkt_burst_idx++], src_it, dst_it); +async_fill_desc (&tdes[pkt_burst_idx++], + &it_pool[it_idx], &it_pool[it_idx +1 ]); pkts_info[slot_idx].descs = num_buffers; pkts_info[slot_idx].mbuf = pkts[pkt_idx]; async_pkts_log[num_async_pkts].pkt_idx = pkt_idx; async_pkts_log[num_async_pkts++].last_avail_idx = vq->last_avail_idx; - src_iovec += src_it->nr_segs; - dst_iovec += dst_it->nr_segs; - src_it +=2 ; - dst_it +=2 ; - segs_await += src_it->nr_segs; + + iovec_idx += it_pool[it_idx].nr_segs; + it_idx +=2 ; + + segs_await += it_pool[it_idx].nr_segs;/** * recover shadow used ring and keep DMA-occupied
@@ -1541,23 +1557,10 @@ virtio_dev_rx_async_submit_split(struct virtio_net *dev,*/ from = vq->shadow_used_idx - num_buffers; to = vq->async_desc_idx & (vq->size -1 ); -if (num_buffers + to <= vq->size) { -rte_memcpy (&vq->async_descs_split[to], - &vq->shadow_used_split[from], - num_buffers * -sizeof (struct vring_used_elem )); - }else { -int size = vq->size - to; - -rte_memcpy (&vq->async_descs_split[to], - &vq->shadow_used_split[from], - size * -sizeof (struct vring_used_elem )); -rte_memcpy (vq->async_descs_split, - &vq->shadow_used_split[from + - size], (num_buffers - size) * -sizeof (struct vring_used_elem )); - } + +store_dma_desc_info_split (vq->shadow_used_split, + vq->async_descs_split, vq->size, from, to, num_buffers); + vq->async_desc_idx += num_buffers; vq->shadow_used_idx -= num_buffers; }else
@@ -1575,10 +1578,9 @@ virtio_dev_rx_async_submit_split(struct virtio_net *dev, BUF_VECTOR_MAX))) { n_pkts = vq->async_ops.transfer_data (dev->vid, queue_id, tdes,0 , pkt_burst_idx); - src_iovec = vec_pool; - dst_iovec = vec_pool + (VHOST_MAX_ASYNC_VEC >>1 ); - src_it = it_pool; - dst_it = it_pool +1 ; + iovec_idx =0 ; + it_idx =0 ; + segs_await =0 ; vq->async_pkts_inflight_n += n_pkts;
@@ -1639,6 +1641,36 @@ virtio_dev_rx_async_submit_split(struct virtio_net *dev,return pkt_idx; } +static __rte_always_inline void +write_back_completed_descs_split (struct vhost_virtqueue *vq,uint16_t n_descs) +{ +uint16_t nr_left = n_descs; +uint16_t nr_copy; +uint16_t to, from; + +do { + from = vq->last_async_desc_idx & (vq->size -1 ); + nr_copy = nr_left + from <= vq->size ? nr_left : vq->size - from; + to = vq->last_used_idx & (vq->size -1 ); + +if (to + nr_copy <= vq->size) { +rte_memcpy (&vq->used->ring[to], &vq->async_descs_split[from], + nr_copy *sizeof (struct vring_used_elem )); + }else { +uint16_t size = vq->size - to; + +rte_memcpy (&vq->used->ring[to], &vq->async_descs_split[from], + size *sizeof (struct vring_used_elem )); +rte_memcpy (&vq->used->ring[0 ], &vq->async_descs_split[from + size], + (nr_copy - size) *sizeof (struct vring_used_elem )); + } + + vq->last_async_desc_idx += nr_copy; + vq->last_used_idx += nr_copy; + nr_left -= nr_copy; + }while (nr_left >0 ); +} +uint16_t rte_vhost_poll_enqueue_completed (int vid,uint16_t queue_id,struct rte_mbuf **pkts,uint16_t count) {
@@ -1695,39 +1727,7 @@ uint16_t rte_vhost_poll_enqueue_completed(int vid, uint16_t queue_id, vq->async_pkts_inflight_n -= n_pkts_put;if (likely (vq->enabled && vq->access_ok)) { -uint16_t nr_left = n_descs; -uint16_t nr_copy; -uint16_t to; - -/* write back completed descriptors to used ring */ -do { - from = vq->last_async_desc_idx & (vq->size -1 ); - nr_copy = nr_left + from <= vq->size ? nr_left : - vq->size - from; - to = vq->last_used_idx & (vq->size -1 ); - -if (to + nr_copy <= vq->size) { -rte_memcpy (&vq->used->ring[to], - &vq->async_descs_split[from], - nr_copy * -sizeof (struct vring_used_elem )); - }else { -uint16_t size = vq->size - to; - -rte_memcpy (&vq->used->ring[to], - &vq->async_descs_split[from], - size * -sizeof (struct vring_used_elem )); -rte_memcpy (vq->used->ring, - &vq->async_descs_split[from + - size], (nr_copy - size) * -sizeof (struct vring_used_elem )); - } - - vq->last_async_desc_idx += nr_copy; - vq->last_used_idx += nr_copy; - nr_left -= nr_copy; - }while (nr_left >0 ); +write_back_completed_descs_split (vq, n_descs);__atomic_add_fetch (&vq->used->idx, n_descs, __ATOMIC_RELEASE);vhost_vring_call_split (dev, vq);
--
2.29.2
Re: [dpdk-dev] [PATCH v8 1/4] vhost: abstract and reorganize async split ring code
Quoted 253 lines
-----Original Message-----
From: Jiang, Cheng1 <[email protected]>
Sent: Monday, April 19, 2021 4:51 PM
To: [email protected]; Xia, Chenbo <[email protected]>
Cc: [email protected]; Hu, Jiayu <[email protected]>; Yang, YvonneX <[email protected]>; Wang, Yinan <[email protected]>; Liu, Yong <[email protected]>; Jiang, Cheng1 <[email protected]>
Subject: [PATCH v8 1/4] vhost: abstract and reorganize async split ring codeThis patch puts some codes of async vhost split ring into inline functions to improve the readability of the code. And, it changes the pointer index style of iterator to make the code more concise.
Signed-off-by Cheng Jiang <[email protected]>Reviewed-by Maxime Coquelin <[email protected]>--- lib/librte_vhost/virtio_net.c | 132 +++++++++++++++++----------------- 1 file changed, 66 insertions(+), 66 deletions(-)lib/librte_vhost/virtio_net.c +8
-0@@ -1458,6 +1458,22 @@ virtio_dev_rx_async_get_info_idx(uint16_t pkts_idx, (vq_size - n_inflight + pkts_idx) & (vq_size -1 ); } +static __rte_always_inline void +store_dma_desc_info_split (struct vring_used_elem *s_ring,struct vring_used_elem *d_ring, +uint16_t ring_size,uint16_t s_idx,uint16_t d_idx,uint16_t count) +{ +uint16_t elem_size =sizeof (struct vring_used_elem ); + +if (d_idx + count <= ring_size) { + rte_memcpy(d_ring + d_idx, s_ring + s_idx, count *
elem_size);lib/librte_vhost/virtio_net.c +5
-0+ }else { +uint16_t size = ring_size - d_idx; + +rte_memcpy (d_ring + d_idx, s_ring + s_idx, size * elem_size); + rte_memcpy(d_ring, s_ring + s_idx + size, (count - size) *
elem_size);lib/librte_vhost/virtio_net.c +4
-2+ } +} + static __rte_noinline uint32_t virtio_dev_rx_async_submit_split(struct virtio_net *dev, struct vhost_virtqueue *vq, uint16_t queue_id,@@ -1474,10 +1490,9 @@ virtio_dev_rx_async_submit_split(structvirtio_net *dev, struct rte_vhost_async_desc tdes[MAX_PKT_BURST];struct iovec *src_iovec = vec_pool;struct iovec *dst_iovec = vec_pool + (VHOST_MAX_ASYNC_VEC >>1 ); -struct rte_vhost_iov_iter *src_it = it_pool; -struct rte_vhost_iov_iter *dst_it = it_pool +1 ;uint16_t slot_idx =0 ;uint16_t segs_await =0 ; +uint16_t iovec_idx =0 , it_idx =0 ;struct async_inflight_info *pkts_info = vq->async_pkts_info;uint32_t n_pkts =0 , pkt_err =0 ;lib/librte_vhost/virtio_net.c +11
-10uint32_t num_async_pkts =0 , num_done_pkts =0 ;@@ -1511,29 +1526,30 @@ virtio_dev_rx_async_submit_split(struct virtio_net *dev, dev->vid, vq->last_avail_idx, vq->last_avail_idx + num_buffers); -if (async_mbuf_to_desc (dev, vq, pkts[pkt_idx], - buf_vec, nr_vec, num_buffers, - src_iovec, dst_iovec, src_it, dst_it) <0 ) { +if (async_mbuf_to_desc (dev, vq, pkts[pkt_idx], buf_vec, nr_vec, num_buffers, + &src_iovec[iovec_idx], &dst_iovec[iovec_idx], + &it_pool[it_idx], &it_pool[it_idx +1 ]) <0 ) { vq->shadow_used_idx -= num_buffers;break ; } slot_idx = (vq->async_pkts_idx + num_async_pkts) & (vq->size -1 ); -if (src_it->count) { +if (it_pool[it_idx].count) {uint16_t from, to; -async_fill_desc (&tdes[pkt_burst_idx++], src_it, dst_it); +async_fill_desc (&tdes[pkt_burst_idx++], + &it_pool[it_idx], &it_pool[it_idx +1 ]); pkts_info[slot_idx].descs = num_buffers; pkts_info[slot_idx].mbuf = pkts[pkt_idx]; async_pkts_log[num_async_pkts].pkt_idx = pkt_idx; async_pkts_log[num_async_pkts++].last_avail_idx = vq->last_avail_idx; - src_iovec += src_it->nr_segs; - dst_iovec += dst_it->nr_segs; - src_it +=2 ; - dst_it +=2 ; - segs_await += src_it->nr_segs; + + iovec_idx += it_pool[it_idx].nr_segs; + it_idx +=2 ; + + segs_await += it_pool[it_idx].nr_segs;lib/librte_vhost/virtio_net.c +0
-14/** * recover shadow used ring and keep DMA-occupied @@ -1541,23 +1557,10 @@ virtio_dev_rx_async_submit_split(structvirtio_net *dev, */ from = vq->shadow_used_idx - num_buffers; to = vq->async_desc_idx & (vq->size -1 ); -if (num_buffers + to <= vq->size) { -rte_memcpy (&vq->async_descs_split[to], - &vq- >shadow_used_split[from], - num_buffers * -sizeof (struct vring_used_elem)); - }else { -int size = vq->size - to; - -rte_memcpy (&vq->async_descs_split[to], - &vq- >shadow_used_split[from], - size * -sizeof (struct vring_used_elem)); - rte_memcpy(vq->async_descs_split, - &vq-Quoted 1 line
shadow_used_split[from +
lib/librte_vhost/virtio_net.c +3
-3- size], (num_buffers - size) * - sizeof(struct vring_used_elem)); - } + + store_dma_desc_info_split(vq->shadow_used_split, + vq->async_descs_split, vq->size, from,to,
num_buffers);lib/librte_vhost/virtio_net.c +4
-4+ vq->async_desc_idx += num_buffers; vq->shadow_used_idx -= num_buffers; }else @@ -1575,10 +1578,9 @@ virtio_dev_rx_async_submit_split(structvirtio_net *dev, BUF_VECTOR_MAX))) { n_pkts = vq->async_ops.transfer_data (dev->vid, queue_id, tdes,0 , pkt_burst_idx); - src_iovec = vec_pool; - dst_iovec = vec_pool + (VHOST_MAX_ASYNC_VEC >> 1); - src_it = it_pool; - dst_it = it_pool +1 ; + iovec_idx =0 ; + it_idx =0 ; + segs_await =0 ;lib/librte_vhost/virtio_net.c +15
-0vq->async_pkts_inflight_n += n_pkts;@@ -1639,6 +1641,36 @@ virtio_dev_rx_async_submit_split(struct virtio_net *dev, return pkt_idx; } +static __rte_always_inline void +write_back_completed_descs_split(struct vhost_virtqueue *vq, uint16_t n_descs) +{ + uint16_t nr_left = n_descs; + uint16_t nr_copy; + uint16_t to, from; + + do { + from = vq->last_async_desc_idx & (vq->size - 1); + nr_copy = nr_left + from <= vq->size ? nr_left : vq->size - from; + to = vq->last_used_idx & (vq->size - 1); + + if (to + nr_copy <= vq->size) { + rte_memcpy(&vq->used->ring[to], &vq- >async_descs_split[from], + nr_copy * sizeof(struct
vring_used_elem));lib/librte_vhost/virtio_net.c +4
-0+ }else { +uint16_t size = vq->size - to; + + rte_memcpy(&vq->used->ring[to], &vq-Quoted 1 line
async_descs_split[from],
lib/librte_vhost/virtio_net.c +2
-0+ size * sizeof(struct vring_used_elem)); + rte_memcpy(&vq->used->ring[0], &vq-Quoted 1 line
async_descs_split[from + size],
lib/librte_vhost/virtio_net.c +1
-0+ (nr_copy - size) * sizeof(struct
vring_used_elem));lib/librte_vhost/virtio_net.c +8
-23+ } + + vq->last_async_desc_idx += nr_copy; + vq->last_used_idx += nr_copy; + nr_left -= nr_copy; + }while (nr_left >0 ); +} +uint16_t rte_vhost_poll_enqueue_completed (int vid,uint16_t queue_id,struct rte_mbuf **pkts,uint16_t count) {@@ -1695,39 +1727,7 @@ uint16_t rte_vhost_poll_enqueue_completed(int vid, uint16_t queue_id, vq->async_pkts_inflight_n -= n_pkts_put;if (likely (vq->enabled && vq->access_ok)) { - uint16_t nr_left = n_descs; - uint16_t nr_copy; - uint16_t to; - - /* write back completed descriptors to used ring */ - do { - from = vq->last_async_desc_idx & (vq->size - 1); - nr_copy = nr_left + from <= vq->size ? nr_left : - vq->size - from; - to = vq->last_used_idx & (vq->size - 1); - - if (to + nr_copy <= vq->size) { - rte_memcpy(&vq->used->ring[to], - &vq- >async_descs_split[from], - nr_copy * - sizeof(struct vring_used_elem)); - } else { - uint16_t size = vq->size - to; - - rte_memcpy(&vq->used->ring[to], - &vq- >async_descs_split[from], - size * - sizeof(struct
vring_used_elem));lib/librte_vhost/virtio_net.c +1
-4- rte_memcpy(vq->used->ring, - &vq->async_descs_split[from + - size], (nr_copy - size) * - sizeof(struct
vring_used_elem));lib/librte_vhost/virtio_net.c +1
-6- } - - vq->last_async_desc_idx += nr_copy; - vq->last_used_idx += nr_copy; - nr_left -= nr_copy; - }while (nr_left >0 ); +write_back_completed_descs_split (vq, n_descs); __atomic_add_fetch(&vq->used->idx, n_descs,
__ATOMIC_RELEASE);
vhost_vring_call_split(dev, vq);
--
2.29.2
PATCH v8 2/4 vhost: add support for packed ring in async vhost
In reply to Cheng JiangFor now async vhost data path only supports split ring. This patch enables packed ring in async vhost data path to make async vhost compatible with virtio 1.1 spec.
--- lib/librte_vhost/rte_vhost_async.h | 1 + lib/librte_vhost/vhost.c | 79 ++++-- lib/librte_vhost/vhost.h | 15 +- lib/librte_vhost/virtio_net.c | 441 +++++++++++++++++++++++++++-- 4 files changed, 488 insertions(+), 48 deletions(-)
lib/librte_vhost/rte_vhost_async.h +1 -0
@@ -89,6 +89,7 @@ struct rte_vhost_async_channel_ops {struct async_inflight_info {struct rte_mbuf *mbuf;uint16_t descs;/* num of descs inflight */ +uint16_t nr_buffers;/* num of buffers inflight for packed ring */ };/**
lib/librte_vhost/vhost.c +57 -22
118 lines not on this page · raw message
lib/librte_vhost/vhost.h +12 -3
@@ -201,9 +201,18 @@ struct vhost_virtqueue {uint16_t async_pkts_idx;uint16_t async_pkts_inflight_n;uint16_t async_last_pkts_n; -struct vring_used_elem *async_descs_split; -uint16_t async_desc_idx; -uint16_t last_async_desc_idx; +union { +struct vring_used_elem *async_descs_split; +struct vring_used_elem_packed *async_buffers_packed; + }; +union { +uint16_t async_desc_idx_split; +uint16_t async_buffer_idx_packed; + }; +union { +uint16_t last_async_desc_idx_split; +uint16_t last_async_buffer_idx_packed; + };/* vq async features */ bool async_inorder;
lib/librte_vhost/virtio_net.c +418 -23
531 lines not on this page · raw message
Signature · 1 line
2.29.2
Hi Cheng,
Some comments are inline.
Quoted 196 lines
-----Original Message-----
From: Jiang, Cheng1 <[email protected]>
Sent: Monday, April 19, 2021 4:51 PM
To: [email protected]; Xia, Chenbo <[email protected]>
Cc: [email protected]; Hu, Jiayu <[email protected]>; Yang, YvonneX <[email protected]>; Wang, Yinan <[email protected]>; Liu, Yong <[email protected]>; Jiang, Cheng1 <[email protected]>
Subject: [PATCH v8 2/4] vhost: add support for packed ring in async vhostFor now async vhost data path only supports split ring. This patch enables packed ring in async vhost data path to make async vhost compatible with virtio 1.1 spec.
Signed-off-by Cheng Jiang <[email protected]>--- lib/librte_vhost/rte_vhost_async.h | 1 + lib/librte_vhost/vhost.c | 79 ++++-- lib/librte_vhost/vhost.h | 15 +- lib/librte_vhost/virtio_net.c | 441 +++++++++++++++++++++++++++-- 4 files changed, 488 insertions(+), 48 deletions(-)lib/librte_vhost/virtio_net.c +5
-5@@ -363,14 +363,14 @@ vhost_shadow_dequeue_single_packed_inorder(struct vhost_virtqueue *vq, } static __rte_always_inline void -vhost_shadow_enqueue_single_packed (struct virtio_net *dev, -struct vhost_virtqueue *vq, -uint32_t len[], -uint16_t id[], -uint16_t count[], +vhost_shadow_enqueue_packed (struct vhost_virtqueue *vq, +uint32_t *len, +uint16_t *id, +uint16_t *count,uint16_t num_buffers) {uint16_t i; +for (i =0 ; i < num_buffers; i++) {/* enqueue shadow flush action aligned with batch num */ lib/librte_vhost/virtio_net.c +11
-0if (!vq->shadow_used_idx)@@ -382,6 +382,17 @@ vhost_shadow_enqueue_single_packed(struct virtio_net *dev, vq->shadow_aligned_idx += count[i]; vq->shadow_used_idx++; } +} + +static __rte_always_inline void +vhost_shadow_enqueue_single_packed (struct virtio_net *dev, +struct vhost_virtqueue *vq, +uint32_t *len, +uint16_t *id, +uint16_t *count, +uint16_t num_buffers) +{ +vhost_shadow_enqueue_packed (vq, len, id, count, num_buffers);if (vq->shadow_aligned_idx >=PACKED_BATCH_SIZE ) {lib/librte_vhost/virtio_net.c +0
-0do_data_copy_enqueue (dev, vq);@@ -1474,6 +1485,23 @@ store_dma_desc_info_split(struct
vring_used_elem*s_ring, structvring_used_elemlib/librte_vhost/virtio_net.c +4
-0} } +static __rte_always_inline void +store_dma_desc_info_packed (struct vring_used_elem_packed *s_ring, +struct vring_used_elem_packed *d_ring, + uint16_t ring_size, uint16_t s_idx, uint16_t d_idx, uint16_tcount)
lib/librte_vhost/virtio_net.c +5
-0+{ +uint16_t elem_size =sizeof (struct vring_used_elem_packed ); + +if (d_idx + count <= ring_size) { + rte_memcpy(d_ring + d_idx, s_ring + s_idx, count *
elem_size);lib/librte_vhost/virtio_net.c +5
-0+ }else { +uint16_t size = ring_size - d_idx; + +rte_memcpy (d_ring + d_idx, s_ring + s_idx, size * elem_size); + rte_memcpy(d_ring, s_ring + s_idx + size, (count - size) *
elem_size);lib/librte_vhost/virtio_net.c +5
-2+ } +} + static __rte_noinline uint32_t virtio_dev_rx_async_submit_split(struct virtio_net *dev, struct vhost_virtqueue *vq, uint16_t queue_id,@@ -1556,12 +1584,12 @@ virtio_dev_rx_async_submit_split(structvirtio_net *dev, * descriptors. */ from = vq->shadow_used_idx - num_buffers; - to = vq->async_desc_idx & (vq->size -1 ); + to = vq->async_desc_idx_split & (vq->size -1 );store_dma_desc_info_split (vq->shadow_used_split, vq->async_descs_split, vq->size, from, to, num_buffers); - vq->async_desc_idx += num_buffers; + vq->async_desc_idx_split += num_buffers; vq->shadow_used_idx -= num_buffers;lib/librte_vhost/virtio_net.c +1
-1}else comp_pkts[num_done_pkts++] = pkts[pkt_idx];@@ -1619,7 +1647,7 @@ virtio_dev_rx_async_submit_split(struct virtio_net *dev, num_descs += pkts_info[slot_idx & (vq->size -1 )].descs; slot_idx--; } - vq->async_desc_idx -= num_descs; + vq->async_desc_idx_split -= num_descs;/* recover shadow used ring and available ring */
vq->shadow_used_idx-= (vq->last_avail_idx-async_pkts_log[num_async_pkts].last_avail_idx -
lib/librte_vhost/virtio_net.c +69
-0@@ -1641,6 +1669,329 @@ virtio_dev_rx_async_submit_split(structvirtio_net *dev, return pkt_idx; } +static __rte_always_inline void +vhost_update_used_packed (struct vhost_virtqueue *vq, +struct vring_used_elem_packed *shadow_ring, +uint16_t count) +{ +int i; +uint16_t used_idx = vq->last_used_idx; +uint16_t head_idx = vq->last_used_idx; +uint16_t head_flags =0 ; + +if (count ==0 ) +return ; + +/* Split loop in two to save memory barriers */ +for (i =0 ; i < count; i++) { + vq->desc_packed[used_idx].id = shadow_ring[i].id; + vq->desc_packed[used_idx].len = shadow_ring[i].len; + + used_idx += shadow_ring[i].count; +if (used_idx >= vq->size) + used_idx -= vq->size; + } + +/* The ordering for storing desc flags needs to be enforced. */ +rte_atomic_thread_fence (__ATOMIC_RELEASE); + +for (i =0 ; i < count; i++) { +uint16_t flags; + +if (vq->shadow_used_packed[i].len) + flags =VRING_DESC_F_WRITE ; +else + flags =0 ; + +if (vq->used_wrap_counter) { + flags |=VRING_DESC_F_USED ; + flags |=VRING_DESC_F_AVAIL ; + }else { + flags &= ~VRING_DESC_F_USED ; + flags &= ~VRING_DESC_F_AVAIL ; + } + +if (i >0 ) { + vq->desc_packed[vq->last_used_idx].flags = flags; + }else { + head_idx = vq->last_used_idx; + head_flags = flags; + } + +vq_inc_last_used_packed (vq, shadow_ring[i].count); + } + + vq->desc_packed[head_idx].flags = head_flags; +} + +static __rte_always_inline int +vhost_enqueue_async_single_packed (struct virtio_net *dev, +struct vhost_virtqueue *vq, +struct rte_mbuf *pkt, +struct buf_vector *buf_vec, +uint16_t *nr_descs, +uint16_t *nr_buffers, +struct vring_packed_desc *async_descs, +struct iovec *src_iovec,struct iovec *dst_iovec, +struct rte_vhost_iov_iter *src_it, +struct rte_vhost_iov_iter *dst_it) +{ +uint16_t nr_vec =0 ; +uint16_t avail_idx = vq->last_avail_idx;
lib/librte_vhost/virtio_net.c virtio_dev_rx_async_submit_split(struct · line 1751
Quoted 10 lines
lib/librte_vhost/virtio_net.c +9
-0+uint16_t max_tries, tries =0 ; +uint16_t buf_id =0 ; +uint32_t len =0 ; +uint16_t desc_count =0 ; +uint32_t size = pkt->pkt_len +sizeof (struct virtio_net_hdr_mrg_rxbuf ); +uint32_t buffer_len[vq->size]; +uint16_t buffer_buf_id[vq->size]; +uint16_t buffer_desc_count[vq->size]; + *nr_buffers =0 ;
nr_buffers and nr_descs are pointers of num_buffers and num_desc in virtio_dev_rx_async_submit_packed(), and num_buffers and num_desc don't have init values. I think you need to init them before pass their pointers to another function, as it will read/update values pointed by the pointers.
In addition, *nr_buffers is set to 0, but *nr_descs is not, and both of them are set to 0 in virtio_dev_rx_async_single_packed(). It looks strange.
Quoted 43 lines
lib/librte_vhost/virtio_net.c +17
-0+ +if (rxvq_is_mergeable (dev)) + max_tries = vq->size -1 ; +else + max_tries =1 ; + +while (size >0 ) { +/* +* if we tried all available ring items, and still +* can't get enough buf, it means something abnormal +* happened. +*/ +if (unlikely (++tries > max_tries)) +return -1 ; + + if (unlikely(fill_vec_buf_packed(dev, vq, avail_idx, &desc_count, buf_vec, &nr_vec, + &buf_id, &len,
VHOST_ACCESS_RW) < 0))lib/librte_vhost/virtio_net.c +17
-0+return -1 ; + + len =RTE_MIN (len, size); + size -= len; + + buffer_len[*nr_buffers] = len; + buffer_buf_id[*nr_buffers] = buf_id; + buffer_desc_count[*nr_buffers] = desc_count; + *nr_buffers +=1 ; + + *nr_descs += desc_count; + avail_idx += desc_count; +if (avail_idx >= vq->size) + avail_idx -= vq->size; + } + + if (async_mbuf_to_desc(dev, vq, pkt, buf_vec, nr_vec, *nr_buffers,
src_iovec,dst_iovec,lib/librte_vhost/virtio_net.c +5
-0+ src_it, dst_it) < 0) +return -1 ; +/* store descriptors for DMA */ + if (avail_idx >= *nr_descs) { + rte_memcpy(async_descs, &vq->desc_packed[vq-Quoted 1 line
last_avail_idx],
lib/librte_vhost/virtio_net.c virtio_dev_rx_async_submit_split(struct virtio_net *dev, · line 1791
Quoted 3 lines
lib/librte_vhost/virtio_net.c +3
-0+ *nr_descs * sizeof(struct vring_packed_desc)); + }else { +uint16_t nr_copy = vq->size - vq->last_avail_idx;
It needs a blank line.
Quoted 93 lines
lib/librte_vhost/virtio_net.c +1
-0+ rte_memcpy(async_descs, &vq->desc_packed[vq-Quoted 1 line
last_avail_idx],lib/librte_vhost/virtio_net.c +3
-0+ nr_copy * sizeof(struct vring_packed_desc)); + rte_memcpy(async_descs + nr_copy, vq->desc_packed, + (*nr_descs - nr_copy) * sizeof(struct
vring_packed_desc));lib/librte_vhost/virtio_net.c +3
-0+ } + + vhost_shadow_enqueue_packed(vq, buffer_len, buffer_buf_id,
buffer_desc_count,*nr_buffers);lib/librte_vhost/virtio_net.c +6
-0+ +return 0 ; +} + +static __rte_always_inline int16_t +virtio_dev_rx_async_single_packed(struct virtio_net *dev, struct
vhost_virtqueue*vq,lib/librte_vhost/virtio_net.c +1
-0+ struct rte_mbuf *pkt, uint16_t *nr_descs, uint16_t
*nr_buffers,lib/librte_vhost/virtio_net.c +3
-0+struct vring_packed_desc *async_descs, + struct iovec *src_iovec, struct iovec *dst_iovec, + struct rte_vhost_iov_iter *src_it, struct
rte_vhost_iov_iter*dst_it)lib/librte_vhost/virtio_net.c +6
-0+{ +struct buf_vector buf_vec[BUF_VECTOR_MAX ]; + *nr_descs =0 ; + *nr_buffers =0 ; + + if (unlikely(vhost_enqueue_async_single_packed(dev, vq, pkt,
buf_vec,nr_descs,nr_buffers,lib/librte_vhost/virtio_net.c +1
-0+ async_descs, src_iovec,
dst_iovec,lib/librte_vhost/virtio_net.c +2
-0+ src_it, dst_it) < 0)) { + VHOST_LOG_DATA(DEBUG, "(%d) failed to get enough descfrom vring\n",
dev->vid);lib/librte_vhost/virtio_net.c +4
-0+return -1 ; + } + + VHOST_LOG_DATA(DEBUG, "(%d) current index %d | endindex %d\n",
lib/librte_vhost/virtio_net.c +1
-0+ dev->vid, vq->last_avail_idx, vq->last_avail_idx +
*nr_descs);lib/librte_vhost/virtio_net.c +6
-0+ +return 0 ; +} + +static __rte_always_inline void +dma_error_handler_packed(struct vhost_virtqueue *vq, struct
vring_packed_desc*async_descs,lib/librte_vhost/virtio_net.c +1
-0+ uint16_t async_descs_idx, uint16_t slot_idx, uint32_t
nr_err,lib/librte_vhost/virtio_net.c +1
-0+ uint32_t *pkt_idx, uint32_t *num_async_pkts,
uint32_t*num_done_pkts)lib/librte_vhost/virtio_net.c +32
-0+{ +uint16_t descs_err =0 ; +uint16_t buffers_err =0 ; +struct async_inflight_info *pkts_info = vq->async_pkts_info; + + *num_async_pkts -= nr_err; + *pkt_idx -= nr_err; +/* calculate the sum of buffers and descs of DMA-error packets. */ +while (nr_err-- >0 ) { + descs_err += pkts_info[slot_idx % vq->size].descs; + buffers_err += pkts_info[slot_idx % vq->size].nr_buffers; + slot_idx--; + } + + vq->async_buffer_idx_packed -= buffers_err; + +if (vq->last_avail_idx >= descs_err) { + vq->last_avail_idx -= descs_err; + +rte_memcpy (&vq->desc_packed[vq->last_avail_idx], + &async_descs[async_descs_idx - descs_err], + descs_err *sizeof (struct vring_packed_desc )); + }else { +uint16_t nr_copy; + + vq->last_avail_idx = vq->last_avail_idx + vq->size - descs_err; + nr_copy = vq->size - vq->last_avail_idx; +rte_memcpy (&vq->desc_packed[vq->last_avail_idx], + &async_descs[async_descs_idx - descs_err], + nr_copy *sizeof (struct vring_packed_desc )); + descs_err -= nr_copy; + rte_memcpy(&vq->desc_packed[0],&async_descs[async_descs_idx -
descs_err],lib/librte_vhost/virtio_net.c +7
-0+ descs_err * sizeof(struct vring_packed_desc)); + vq->avail_wrap_counter ^=1 ; + } + + *num_done_pkts = *pkt_idx - *num_async_pkts; +} +
lib/librte_vhost/virtio_net.c virtio_dev_rx_async_submit_split(struct virtio_net *dev, · line 1879
Quoted 10 lines
lib/librte_vhost/virtio_net.c +10
-0+static __rte_noinline uint32_t +virtio_dev_rx_async_submit_packed (struct virtio_net *dev, +struct vhost_virtqueue *vq,uint16_t queue_id, +struct rte_mbuf **pkts,uint32_t count, +struct rte_mbuf **comp_pkts,uint32_t *comp_count) +{ +uint32_t pkt_idx =0 , pkt_burst_idx =0 ; +uint16_t async_descs_idx =0 ; +uint16_t num_buffers; +uint16_t num_desc;
How about using "num_descs" to make naming consist with "num_buffers"?
Thanks,
Jiayu
Hi Jiayu,
Quoted 208 lines
-----Original Message-----
From: Hu, Jiayu <[email protected]>
Sent: Tuesday, April 27, 2021 1:16 PM
To: Jiang, Cheng1 <[email protected]>; [email protected]; Xia, Chenbo <[email protected]>
Cc: [email protected]; Yang, YvonneX <[email protected]>; Wang, Yinan <[email protected]>; Liu, Yong <[email protected]>
Subject: RE: [PATCH v8 2/4] vhost: add support for packed ring in async vhostHi Cheng,
Some comments are inline.
Quoted 27 lines
-----Original Message-----
From: Jiang, Cheng1 <[email protected]>
Sent: Monday, April 19, 2021 4:51 PM
To: [email protected]; Xia, Chenbo <[email protected]>
Cc: [email protected]; Hu, Jiayu <[email protected]>; Yang, YvonneX <[email protected]>; Wang, Yinan <[email protected]>; Liu, Yong <[email protected]>; Jiang, Cheng1 <[email protected]>
Subject: [PATCH v8 2/4] vhost: add support for packed ring in async vhostFor now async vhost data path only supports split ring. This patch enables packed ring in async vhost data path to make async vhost compatible with virtio 1.1 spec.
Signed-off-by Cheng Jiang <[email protected]>--- lib/librte_vhost/rte_vhost_async.h | 1 + lib/librte_vhost/vhost.c | 79 ++++-- lib/librte_vhost/vhost.h | 15 +- lib/librte_vhost/virtio_net.c | 441 +++++++++++++++++++++++++++-- 4 files changed, 488 insertions(+), 48 deletions(-)(quoted diff) +0
-0
b/lib/librte_vhost/virtio_net.cindex438bdafd1..ce88ad3c0100644lib/librte_vhost/virtio_net.c +0
-0@@ -363,14 +363,14 @@Quoted 1 line
vhost_shadow_dequeue_single_packed_inorder(struct
vhost_virtqueue*vq,
Quoted 158 lines
}
static
__rte_always_inlinevoidlib/librte_vhost/virtio_net.c +5
-5-vhost_shadow_enqueue_single_packed(struct virtio_net *dev, - struct vhost_virtqueue *vq, - uint32_t len[], - uint16_t id[], - uint16_t count[], +vhost_shadow_enqueue_packed(struct vhost_virtqueue *vq, + uint32_t *len, + uint16_t *id, + uint16_t *count, uint16_t num_buffers) { uint16_t i; +for (i =0 ; i < num_buffers; i++) { /* enqueue shadow flush action aligned with batch num */ if(!vq->shadow_used_idx) @@ -382,6 +382,17 @@
vhost_shadow_enqueue_single_packed(structvirtio_net*dev,
vq->shadow_aligned_idx+= count[i];
vq->shadow_used_idx++;
}lib/librte_vhost/virtio_net.c +11
-0+} + +static __rte_always_inline void +vhost_shadow_enqueue_single_packed (struct virtio_net *dev, +struct vhost_virtqueue *vq, +uint32_t *len, +uint16_t *id, +uint16_t *count, +uint16_t num_buffers) +{ +vhost_shadow_enqueue_packed (vq, len, id, count, num_buffers);if (vq->shadow_aligned_idx >=PACKED_BATCH_SIZE ) {
do_data_copy_enqueue(dev, vq); @@ -1474,6 +1485,23 @@ store_dma_desc_info_split(structvring_used_elem*s_ring, structvring_used_elem} }lib/librte_vhost/virtio_net.c +4
-0+static __rte_always_inline void +store_dma_desc_info_packed (struct vring_used_elem_packed *s_ring, +struct vring_used_elem_packed *d_ring,uint16_t ring_size,uint16_t +s_idx, uint16_t d_idx, uint16_tcount)
lib/librte_vhost/virtio_net.c +5
-0+{ +uint16_t elem_size =sizeof (struct vring_used_elem_packed ); + +if (d_idx + count <= ring_size) { +rte_memcpy(d_ring + d_idx, s_ring + s_idx, count *
elem_size);lib/librte_vhost/virtio_net.c +5
-0+}else { +uint16_t size = ring_size - d_idx; + +rte_memcpy (d_ring + d_idx, s_ring + s_idx, size * elem_size); +rte_memcpy(d_ring, s_ring + s_idx + size, (count - size) *
elem_size);lib/librte_vhost/virtio_net.c +3
-0+} +} + static __rte_noinline uint32_t virtio_dev_rx_async_submit_split(struct virtio_net *dev, struct
vhost_virtqueue*vq,uint16_tqueue_id, @@ -1556,12 +1584,12 @@ virtio_dev_rx_async_submit_split(structvirtio_net*dev,
* descriptors.
*/
from =vq->shadow_used_idx-num_buffers; -to =vq->async_desc_idx&
(vq->size- 1);lib/librte_vhost/virtio_net.c +2
-1+to = vq->async_desc_idx_split & (vq->size -1 );store_dma_desc_info_split (vq->shadow_used_split, vq->async_descs_split, vq->size, from, to, num_buffers); -vq->async_desc_idx += num_buffers; +vq->async_desc_idx_split += num_buffers; vq->shadow_used_idx -= num_buffers; }else comp_pkts[num_done_pkts++] = pkts[pkt_idx]; @@ -1619,7 +1647,7 @@virtio_dev_rx_async_submit_split(struct
virtio_net*dev,num_descs+= pkts_info[slot_idx & (vq->size- 1)].descs; slot_idx--; }lib/librte_vhost/virtio_net.c +1
-1-vq->async_desc_idx -= num_descs; +vq->async_desc_idx_split -= num_descs;/* recover shadow used ring and available ring */
vq->shadow_used_idx-= (vq->last_avail_idx-async_pkts_log[num_async_pkts].last_avail_idx - @@ -1641,6 +1669,329 @@ virtio_dev_rx_async_submit_split(struct
virtio_net*dev,
returnpkt_idx;
}lib/librte_vhost/virtio_net.c +64
-0+static __rte_always_inline void +vhost_update_used_packed (struct vhost_virtqueue *vq,struct +vring_used_elem_packed *shadow_ring,uint16_t count) {int i; +uint16_t used_idx = vq->last_used_idx;uint16_t head_idx = +vq->last_used_idx;uint16_t head_flags =0 ; + +if (count ==0 ) +return ; + +/* Split loop in two to save memory barriers */ for (i =0 ; i < +count; i++) { +vq->desc_packed[used_idx].id = shadow_ring[i].id; +vq->desc_packed[used_idx].len = shadow_ring[i].len; + +used_idx += shadow_ring[i].count; +if (used_idx >= vq->size) +used_idx -= vq->size; +} + +/* The ordering for storing desc flags needs to be enforced. */ +rte_atomic_thread_fence (__ATOMIC_RELEASE); + +for (i =0 ; i < count; i++) { +uint16_t flags; + +if (vq->shadow_used_packed[i].len) +flags =VRING_DESC_F_WRITE ; +else +flags =0 ; + +if (vq->used_wrap_counter) { +flags |=VRING_DESC_F_USED ; +flags |=VRING_DESC_F_AVAIL ; +}else { +flags &= ~VRING_DESC_F_USED ; +flags &= ~VRING_DESC_F_AVAIL ; +} + +if (i >0 ) { +vq->desc_packed[vq->last_used_idx].flags = flags; +}else { +head_idx = vq->last_used_idx; +head_flags = flags; +} + +vq_inc_last_used_packed (vq, shadow_ring[i].count); } + +vq->desc_packed[head_idx].flags = head_flags; +} + +static __rte_always_inline int +vhost_enqueue_async_single_packed (struct virtio_net *dev, +struct vhost_virtqueue *vq, +struct rte_mbuf *pkt, +struct buf_vector *buf_vec, +uint16_t *nr_descs, +uint16_t *nr_buffers, +struct vring_packed_desc *async_descs, +struct iovec *src_iovec,struct iovec *dst_iovec, +struct rte_vhost_iov_iter *src_it, +struct rte_vhost_iov_iter *dst_it) {uint16_t nr_vec =0 ; +uint16_t avail_idx = vq->last_avail_idx;uint16_t max_tries, tries = +0 ;uint16_t buf_id =0 ;uint32_t len =0 ;uint16_t desc_count =0 ; +uint32_t size = pkt->pkt_len + sizeof(struct
virtio_net_hdr_mrg_rxbuf);lib/librte_vhost/virtio_net.c virtio_dev_rx_async_submit_split(struct virtio_net *dev,
Quoted 3 lines
lib/librte_vhost/virtio_net.c +3
-0+uint32_t buffer_len[vq->size]; +uint16_t buffer_buf_id[vq->size]; +uint16_t buffer_desc_count[vq->size]; *nr_buffers =0 ;
nr_buffersandnr_descsare pointers ofnum_buffersandnum_descinvirtio_dev_rx_async_submit_packed(), andnum_buffersandnum_descdon't have init values. I think you need to init them before pass their pointers to another function, as it will read/update values pointed by the pointers.
Quoted 3 lines
In addition,
*nr_buffersis set to 0, but*nr_descsis not, and both of them are set to
0 invirtio_dev_rx_async_single_packed(). It looks strange.
Sure, I'll init them in virtio_dev_rx_async_submit_packed().
Quoted 42 lines
Quoted 42 lines
lib/librte_vhost/virtio_net.c +16
-0+ +if (rxvq_is_mergeable (dev)) +max_tries = vq->size -1 ; +else +max_tries =1 ; + +while (size >0 ) { +/* +* if we tried all available ring items, and still +* can't get enough buf, it means something abnormal +* happened. +*/ +if (unlikely (++tries > max_tries)) +return -1 ; + +if (unlikely(fill_vec_buf_packed(dev, vq, avail_idx,
&desc_count,buf_vec,&nr_vec,
+&buf_id, &len,VHOST_ACCESS_RW) < 0))lib/librte_vhost/virtio_net.c +16
-0+return -1 ; + +len =RTE_MIN (len, size); +size -= len; + +buffer_len[*nr_buffers] = len; +buffer_buf_id[*nr_buffers] = buf_id; +buffer_desc_count[*nr_buffers] = desc_count; *nr_buffers +=1 ; + +*nr_descs += desc_count; +avail_idx += desc_count; +if (avail_idx >= vq->size) +avail_idx -= vq->size; +} + +if (async_mbuf_to_desc(dev, vq, pkt, buf_vec, nr_vec, *nr_buffers,
src_iovec,dst_iovec,lib/librte_vhost/virtio_net.c +5
-0+src_it, dst_it) < 0) +return -1 ; +/* store descriptors for DMA */ +if (avail_idx >= *nr_descs) { +rte_memcpy(async_descs, &vq->desc_packed[vq-
Quoted 5 lines
lib/librte_vhost/virtio_net.c
Quoted 3 lines
Quoted 1 line
last_avail_idx],lib/librte_vhost/virtio_net.c +2
-0+*nr_descs * sizeof(struct vring_packed_desc)); } else { uint16_t +nr_copy = vq->size - vq->last_avail_idx;It needs a blank line.
OK.
Quoted 86 lines
Quoted 23 lines
+rte_memcpy(async_descs, &vq->desc_packed[vq-
Quoted 1 line
last_avail_idx],lib/librte_vhost/virtio_net.c +2
-0+nr_copy * sizeof(struct vring_packed_desc)); rte_memcpy(async_descs + +nr_copy, vq->desc_packed, (*nr_descs - nr_copy) * sizeof(struct
vring_packed_desc));lib/librte_vhost/virtio_net.c +3
-0+} + +vhost_shadow_enqueue_packed(vq, buffer_len, buffer_buf_id,
buffer_desc_count,*nr_buffers);lib/librte_vhost/virtio_net.c +6
-0+ +return 0 ; +} + +static __rte_always_inline int16_t +virtio_dev_rx_async_single_packed(struct virtio_net *dev, struct
vhost_virtqueue*vq,
+ structrte_mbuf*pkt,uint16_t*nr_descs,uint16_t*nr_buffers,lib/librte_vhost/virtio_net.c +3
-0+struct vring_packed_desc *async_descs, + struct iovec *src_iovec, struct iovec *dst_iovec, + struct rte_vhost_iov_iter *src_it, struct
rte_vhost_iov_iter*dst_it)lib/librte_vhost/virtio_net.c
Quoted 2 lines
lib/librte_vhost/virtio_net.c +2
-0+{ +struct buf_vector buf_vec[BUF_VECTOR_MAX ]; *nr_descs =0 ;
*nr_buffersQuoted 60 lines
+= 0;
lib/librte_vhost/virtio_net.c +2
-0+ +if (unlikely(vhost_enqueue_async_single_packed(dev, vq, pkt,
buf_vec,nr_descs,nr_buffers,
+async_descs,src_iovec,dst_iovec,
+src_it,dst_it) < 0)) { +VHOST_LOG_DATA(DEBUG, "(%d) failed to get enough desc from vring\n",dev->vid);lib/librte_vhost/virtio_net.c +4
-0+return -1 ; +} + +VHOST_LOG_DATA(DEBUG, "(%d) current index %d | endindex %d\n",
+dev->vid,vq->last_avail_idx,vq->last_avail_idx+*nr_descs);lib/librte_vhost/virtio_net.c +6
-0+ +return 0 ; +} + +static __rte_always_inline void +dma_error_handler_packed(struct vhost_virtqueue *vq, struct
vring_packed_desc*async_descs,
+uint16_tasync_descs_idx,uint16_tslot_idx,uint32_tnr_err,
+uint32_t*pkt_idx,uint32_t*num_async_pkts,uint32_t*num_done_pkts)lib/librte_vhost/virtio_net.c +27
-0+{ +uint16_t descs_err =0 ; +uint16_t buffers_err =0 ; +struct async_inflight_info *pkts_info = vq->async_pkts_info; + +*num_async_pkts -= nr_err; +*pkt_idx -= nr_err; +/* calculate the sum of buffers and descs of DMA-error packets. */ +while (nr_err-- >0 ) { descs_err += pkts_info[slot_idx % +vq->size].descs; buffers_err += pkts_info[slot_idx % +vq->size].nr_buffers; slot_idx--; } + +vq->async_buffer_idx_packed -= buffers_err; + +if (vq->last_avail_idx >= descs_err) { +vq->last_avail_idx -= descs_err; + +rte_memcpy (&vq->desc_packed[vq->last_avail_idx], +&async_descs[async_descs_idx - descs_err], descs_err *sizeof (struct +vring_packed_desc )); }else {uint16_t nr_copy; + +vq->last_avail_idx = vq->last_avail_idx + vq->size - descs_err; +nr_copy = vq->size - vq->last_avail_idx; +rte_memcpy (&vq->desc_packed[vq->last_avail_idx], +&async_descs[async_descs_idx - descs_err], nr_copy *sizeof (struct +vring_packed_desc )); descs_err -= nr_copy; +rte_memcpy(&vq->desc_packed[0],&async_descs[async_descs_idx -
descs_err],lib/librte_vhost/virtio_net.c +5
-0+descs_err * sizeof(struct vring_packed_desc)); +vq->avail_wrap_counter ^=1 ; +} + +*num_done_pkts = *pkt_idx - *num_async_pkts; }
Quoted 8 lines
lib/librte_vhost/virtio_net.c
Quoted 7 lines
lib/librte_vhost/virtio_net.c +7
-0+ +static __rte_noinline uint32_t +virtio_dev_rx_async_submit_packed (struct virtio_net *dev,struct +vhost_virtqueue *vq,uint16_t queue_id,struct rte_mbuf **pkts, +uint32_t count,struct rte_mbuf **comp_pkts,uint32_t *comp_count) { +uint32_t pkt_idx =0 , pkt_burst_idx =0 ;uint16_t async_descs_idx = +0 ;uint16_t num_buffers;uint16_t num_desc;How about using "
num_descs" to make naming consist with "num_buffers"?
Sure, that make sense, thanks a lot.
Cheng
Quoted 3 lines
Thanks,
Jiayu
PATCH v8 3/4 vhost: add batch datapath for async vhost packed ring
In reply to Cheng JiangAdd batch datapath for async vhost packed ring to improve the performance of small packet processing.
--- lib/librte_vhost/virtio_net.c | 41 +++++++++++++++++++++++++++++++---- 1 file changed, 37 insertions(+), 4 deletions(-)
lib/librte_vhost/virtio_net.c +37 -4
@@ -1724,6 +1724,29 @@ vhost_update_used_packed(struct vhost_virtqueue *vq, vq->desc_packed[head_idx].flags = head_flags; } +static __rte_always_inline int +virtio_dev_rx_async_batch_packed (struct virtio_net *dev, +struct vhost_virtqueue *vq, +struct rte_mbuf **pkts, +struct rte_mbuf **comp_pkts,uint32_t *pkt_done) +{ +uint16_t i; +uint32_t cpy_threshold = vq->async_threshold; + +vhost_for_each_try_unroll (i,0 ,PACKED_BATCH_SIZE ) { +if (unlikely (pkts[i]->pkt_len >= cpy_threshold)) +return -1 ; + } +if (!virtio_dev_rx_batch_packed (dev, vq, pkts)) { +vhost_for_each_try_unroll (i,0 ,PACKED_BATCH_SIZE ) + comp_pkts[(*pkt_done)++] = pkts[i]; + +return 0 ; + } + +return -1 ; +} + static __rte_always_inline int vhost_enqueue_async_single_packed(struct virtio_net *dev, struct vhost_virtqueue *vq,
@@ -1874,6 +1897,7 @@ virtio_dev_rx_async_submit_packed(struct virtio_net *dev, struct rte_mbuf **comp_pkts, uint32_t *comp_count) { uint32_t pkt_idx = 0, pkt_burst_idx = 0; +uint32_t remained = count;uint16_t async_descs_idx =0 ;uint16_t num_buffers;uint16_t num_desc;
@@ -1891,9 +1915,17 @@ virtio_dev_rx_async_submit_packed(struct virtio_net *dev,uint32_t num_async_pkts =0 , num_done_pkts =0 ;struct vring_packed_desc async_descs[vq->size]; -rte_prefetch0 (&vq->desc_packed[vq->last_avail_idx]); + do { + rte_prefetch0(&vq->desc_packed[vq->last_avail_idx]); + if (remained >= PACKED_BATCH_SIZE) { + if (!virtio_dev_rx_async_batch_packed(dev, vq, + &pkts[pkt_idx], comp_pkts, &num_done_pkts)) { + pkt_idx += PACKED_BATCH_SIZE; + remained -= PACKED_BATCH_SIZE; + continue; + } + } -for (pkt_idx =0 ; pkt_idx < count; pkt_idx++) { if (unlikely(virtio_dev_rx_async_single_packed(dev, vq, pkts[pkt_idx], &num_desc, &num_buffers, &async_descs[async_descs_idx],
@@ -1936,6 +1968,8 @@ virtio_dev_rx_async_submit_packed(struct virtio_net *dev, comp_pkts[num_done_pkts++] = pkts[pkt_idx]; } + pkt_idx++; + remained--;vq_inc_last_avail_packed (vq, num_desc);/*
@@ -1960,13 +1994,12 @@ virtio_dev_rx_async_submit_packed(struct virtio_net *dev,*/ pkt_err = pkt_burst_idx - n_pkts; pkt_burst_idx =0 ; - pkt_idx++;break ; } pkt_burst_idx =0 ; } - } + }while (pkt_idx < count);if (pkt_burst_idx) { n_pkts = vq->async_ops.transfer_data (dev->vid, queue_id, tdes,0 , pkt_burst_idx);
Signature · 1 line
2.29.2
PATCH v8 4/4 doc: add release note for vhost async packed ring
In reply to Cheng JiangAdd release note for the support of vhost async packed ring.
--- doc/guides/rel_notes/release_21_05.rst | 4 ++++ 1 file changed, 4 insertions(+)
doc/guides/rel_notes/release_21_05.rst +4 -0
@@ -131,6 +131,10 @@ New Features * Added command to display Rx queue used descriptor count. ``show port (port_id) rxq (queue_id) desc used count`` +* **Added support for vhost async packed ring data path.** + + Added packed ring support for async vhost. + Removed Items -------------
Signature · 1 line
2.29.2
v9 cover add support for packed ring in async vhost
In reply to Cheng JiangFor now async vhost data path only supports split ring structure. In order to make async vhost compatible with virtio 1.1 spec this patch set cleans async split ring codes and enables packed ring in async vhost data path. Batch datapath is also enabled in async vhost packed ring.
v9:
* improve some variable initiation
* fix some variable names for consistency
* rebase on the latest code
v8:
* fix some variable names for consistency
* clean codes
v7:
* fix compile issues
* add argument *dev in vhost_free_async_mem() for ring type decision
v6:
* fix some typos in commit log
* improve index usage
* remove shadow_ring_store()
* add store_dma_desc_info_split() store_dma_desc_info_packed()
* remove some checks in vhost_free_async_mem()
* change index calculation since the size isn't necessarily a power of 2
* move error handling in a dedicated function
* clean codes
v5:
* clean some codes for packed ring datapath
* fix an index error in shadow_ring_store()
v4:
* change the patch structure
* clean code for async split ring
* reuse some code from split ring
* change the error handler for DMA-copy packet
* add check for malloc
* remove useless code
* add doc update
v3:
* fix error handler for DMA-copy packet
v2:
* fix wrong buffer index in rte_vhost_poll_enqueue_completed()
* add async_buffers_packed memory free in vhost_free_async_mem()
Cheng Jiang (4):
vhost: abstract and reorganize async split ring code
vhost: add support for packed ring in async vhost
vhost: add batch datapath for async vhost packed ring
doc: add release note for vhost async packed ring
doc/guides/rel_notes/release_21_05.rst | 4 + lib/vhost/rte_vhost_async.h | 1 + lib/vhost/vhost.c | 79 +++- lib/vhost/vhost.h | 15 +- lib/vhost/virtio_net.c | 598 +++++++++++++++++++++---- 5 files changed, 587 insertions(+), 110 deletions(-)
--
2.29.2
PATCH v9 1/4 vhost: abstract and reorganize async split ring code
This patch puts some codes of async vhost split ring into inline functions to improve the readability of the code. And, it changes the pointer index style of iterator to make the code more concise.
--- lib/vhost/virtio_net.c | 132 ++++++++++++++++++++--------------------- 1 file changed, 66 insertions(+), 66 deletions(-)
lib/vhost/virtio_net.c +66 -66
@@ -1458,6 +1458,22 @@ virtio_dev_rx_async_get_info_idx(uint16_t pkts_idx, (vq_size - n_inflight + pkts_idx) & (vq_size -1 ); } +static __rte_always_inline void +store_dma_desc_info_split (struct vring_used_elem *s_ring,struct vring_used_elem *d_ring, +uint16_t ring_size,uint16_t s_idx,uint16_t d_idx,uint16_t count) +{ +uint16_t elem_size =sizeof (struct vring_used_elem ); + +if (d_idx + count <= ring_size) { +rte_memcpy (d_ring + d_idx, s_ring + s_idx, count * elem_size); + }else { +uint16_t size = ring_size - d_idx; + +rte_memcpy (d_ring + d_idx, s_ring + s_idx, size * elem_size); +rte_memcpy (d_ring, s_ring + s_idx + size, (count - size) * elem_size); + } +} + static __rte_noinline uint32_t virtio_dev_rx_async_submit_split(struct virtio_net *dev, struct vhost_virtqueue *vq, uint16_t queue_id,
@@ -1474,10 +1490,9 @@ virtio_dev_rx_async_submit_split(struct virtio_net *dev,struct rte_vhost_async_desc tdes[MAX_PKT_BURST ];struct iovec *src_iovec = vec_pool;struct iovec *dst_iovec = vec_pool + (VHOST_MAX_ASYNC_VEC >>1 ); -struct rte_vhost_iov_iter *src_it = it_pool; -struct rte_vhost_iov_iter *dst_it = it_pool +1 ;uint16_t slot_idx =0 ;uint16_t segs_await =0 ; +uint16_t iovec_idx =0 , it_idx =0 ;struct async_inflight_info *pkts_info = vq->async_pkts_info;uint32_t n_pkts =0 , pkt_err =0 ;uint32_t num_async_pkts =0 , num_done_pkts =0 ;
@@ -1511,29 +1526,30 @@ virtio_dev_rx_async_submit_split(struct virtio_net *dev, dev->vid, vq->last_avail_idx, vq->last_avail_idx + num_buffers); -if (async_mbuf_to_desc (dev, vq, pkts[pkt_idx], - buf_vec, nr_vec, num_buffers, - src_iovec, dst_iovec, src_it, dst_it) <0 ) { +if (async_mbuf_to_desc (dev, vq, pkts[pkt_idx], buf_vec, nr_vec, num_buffers, + &src_iovec[iovec_idx], &dst_iovec[iovec_idx], + &it_pool[it_idx], &it_pool[it_idx +1 ]) <0 ) { vq->shadow_used_idx -= num_buffers;break ; } slot_idx = (vq->async_pkts_idx + num_async_pkts) & (vq->size -1 ); -if (src_it->count) { +if (it_pool[it_idx].count) {uint16_t from, to; -async_fill_desc (&tdes[pkt_burst_idx++], src_it, dst_it); +async_fill_desc (&tdes[pkt_burst_idx++], + &it_pool[it_idx], &it_pool[it_idx +1 ]); pkts_info[slot_idx].descs = num_buffers; pkts_info[slot_idx].mbuf = pkts[pkt_idx]; async_pkts_log[num_async_pkts].pkt_idx = pkt_idx; async_pkts_log[num_async_pkts++].last_avail_idx = vq->last_avail_idx; - src_iovec += src_it->nr_segs; - dst_iovec += dst_it->nr_segs; - src_it +=2 ; - dst_it +=2 ; - segs_await += src_it->nr_segs; + + iovec_idx += it_pool[it_idx].nr_segs; + it_idx +=2 ; + + segs_await += it_pool[it_idx].nr_segs;/** * recover shadow used ring and keep DMA-occupied
@@ -1541,23 +1557,10 @@ virtio_dev_rx_async_submit_split(struct virtio_net *dev,*/ from = vq->shadow_used_idx - num_buffers; to = vq->async_desc_idx & (vq->size -1 ); -if (num_buffers + to <= vq->size) { -rte_memcpy (&vq->async_descs_split[to], - &vq->shadow_used_split[from], - num_buffers * -sizeof (struct vring_used_elem )); - }else { -int size = vq->size - to; - -rte_memcpy (&vq->async_descs_split[to], - &vq->shadow_used_split[from], - size * -sizeof (struct vring_used_elem )); -rte_memcpy (vq->async_descs_split, - &vq->shadow_used_split[from + - size], (num_buffers - size) * -sizeof (struct vring_used_elem )); - } + +store_dma_desc_info_split (vq->shadow_used_split, + vq->async_descs_split, vq->size, from, to, num_buffers); + vq->async_desc_idx += num_buffers; vq->shadow_used_idx -= num_buffers; }else
@@ -1575,10 +1578,9 @@ virtio_dev_rx_async_submit_split(struct virtio_net *dev, BUF_VECTOR_MAX))) { n_pkts = vq->async_ops.transfer_data (dev->vid, queue_id, tdes,0 , pkt_burst_idx); - src_iovec = vec_pool; - dst_iovec = vec_pool + (VHOST_MAX_ASYNC_VEC >>1 ); - src_it = it_pool; - dst_it = it_pool +1 ; + iovec_idx =0 ; + it_idx =0 ; + segs_await =0 ; vq->async_pkts_inflight_n += n_pkts;
@@ -1639,6 +1641,36 @@ virtio_dev_rx_async_submit_split(struct virtio_net *dev,return pkt_idx; } +static __rte_always_inline void +write_back_completed_descs_split (struct vhost_virtqueue *vq,uint16_t n_descs) +{ +uint16_t nr_left = n_descs; +uint16_t nr_copy; +uint16_t to, from; + +do { + from = vq->last_async_desc_idx & (vq->size -1 ); + nr_copy = nr_left + from <= vq->size ? nr_left : vq->size - from; + to = vq->last_used_idx & (vq->size -1 ); + +if (to + nr_copy <= vq->size) { +rte_memcpy (&vq->used->ring[to], &vq->async_descs_split[from], + nr_copy *sizeof (struct vring_used_elem )); + }else { +uint16_t size = vq->size - to; + +rte_memcpy (&vq->used->ring[to], &vq->async_descs_split[from], + size *sizeof (struct vring_used_elem )); +rte_memcpy (&vq->used->ring[0 ], &vq->async_descs_split[from + size], + (nr_copy - size) *sizeof (struct vring_used_elem )); + } + + vq->last_async_desc_idx += nr_copy; + vq->last_used_idx += nr_copy; + nr_left -= nr_copy; + }while (nr_left >0 ); +} +uint16_t rte_vhost_poll_enqueue_completed (int vid,uint16_t queue_id,struct rte_mbuf **pkts,uint16_t count) {
@@ -1695,39 +1727,7 @@ uint16_t rte_vhost_poll_enqueue_completed(int vid, uint16_t queue_id, vq->async_pkts_inflight_n -= n_pkts_put;if (likely (vq->enabled && vq->access_ok)) { -uint16_t nr_left = n_descs; -uint16_t nr_copy; -uint16_t to; - -/* write back completed descriptors to used ring */ -do { - from = vq->last_async_desc_idx & (vq->size -1 ); - nr_copy = nr_left + from <= vq->size ? nr_left : - vq->size - from; - to = vq->last_used_idx & (vq->size -1 ); - -if (to + nr_copy <= vq->size) { -rte_memcpy (&vq->used->ring[to], - &vq->async_descs_split[from], - nr_copy * -sizeof (struct vring_used_elem )); - }else { -uint16_t size = vq->size - to; - -rte_memcpy (&vq->used->ring[to], - &vq->async_descs_split[from], - size * -sizeof (struct vring_used_elem )); -rte_memcpy (vq->used->ring, - &vq->async_descs_split[from + - size], (nr_copy - size) * -sizeof (struct vring_used_elem )); - } - - vq->last_async_desc_idx += nr_copy; - vq->last_used_idx += nr_copy; - nr_left -= nr_copy; - }while (nr_left >0 ); +write_back_completed_descs_split (vq, n_descs);__atomic_add_fetch (&vq->used->idx, n_descs, __ATOMIC_RELEASE);vhost_vring_call_split (dev, vq);
Signature · 1 line
2.29.2
PATCH v9 2/4 vhost: add support for packed ring in async vhost
In reply to Cheng JiangFor now async vhost data path only supports split ring. This patch enables packed ring in async vhost data path to make async vhost compatible with virtio 1.1 spec.
--- lib/vhost/rte_vhost_async.h | 1 + lib/vhost/vhost.c | 79 +++++-- lib/vhost/vhost.h | 15 +- lib/vhost/virtio_net.c | 442 ++++++++++++++++++++++++++++++++++-- 4 files changed, 489 insertions(+), 48 deletions(-)
lib/vhost/rte_vhost_async.h +1 -0
@@ -89,6 +89,7 @@ struct rte_vhost_async_channel_ops {struct async_inflight_info {struct rte_mbuf *mbuf;uint16_t descs;/* num of descs inflight */ +uint16_t nr_buffers;/* num of buffers inflight for packed ring */ };/**
lib/vhost/vhost.c +57 -22
118 lines not on this page · raw message
lib/vhost/vhost.h +12 -3
@@ -201,9 +201,18 @@ struct vhost_virtqueue {uint16_t async_pkts_idx;uint16_t async_pkts_inflight_n;uint16_t async_last_pkts_n; -struct vring_used_elem *async_descs_split; -uint16_t async_desc_idx; -uint16_t last_async_desc_idx; +union { +struct vring_used_elem *async_descs_split; +struct vring_used_elem_packed *async_buffers_packed; + }; +union { +uint16_t async_desc_idx_split; +uint16_t async_buffer_idx_packed; + }; +union { +uint16_t last_async_desc_idx_split; +uint16_t last_async_buffer_idx_packed; + };/* vq async features */ bool async_inorder;
lib/vhost/virtio_net.c +419 -23
532 lines not on this page · raw message
Signature · 1 line
2.29.2
Quoted 21 lines
-----Original Message-----
From: Jiang, Cheng1 <[email protected]>
Sent: Tuesday, April 27, 2021 4:04 PM
To: [email protected]; Xia, Chenbo <[email protected]>
Cc: [email protected]; Hu, Jiayu <[email protected]>; Yang, YvonneX <[email protected]>; Wang, Yinan <[email protected]>; Liu, Yong <[email protected]>; Jiang, Cheng1 <[email protected]>
Subject: [PATCH v9 2/4] vhost: add support for packed ring in async vhostFor now async vhost data path only supports split ring. This patch enables packed ring in async vhost data path to make async vhost compatible with virtio 1.1 spec.
Signed-off-by Cheng Jiang <[email protected]>--- lib/vhost/rte_vhost_async.h | 1 + lib/vhost/vhost.c | 79 +++++-- lib/vhost/vhost.h | 15 +- lib/vhost/virtio_net.c | 442 ++++++++++++++++++++++++++++++++++-- 4 files changed, 489 insertions(+), 48 deletions(-)
Quoted 4 lines · Cheng Jiang
For now async vhost data path only supports split ring. This patch enables packed ring in async vhost data path to make async vhost compatible with virtio 1.1 spec.
Quoted 8 lines
Signed-off-by Cheng Jiang <[email protected]>--- lib/vhost/rte_vhost_async.h | 1 + lib/vhost/vhost.c | 79 +++++-- lib/vhost/vhost.h | 15 +- lib/vhost/virtio_net.c | 442 ++++++++++++++++++++++++++++++++++-- 4 files changed, 489 insertions(+), 48 deletions(-)
Thanks,
Maxime
PATCH v9 3/4 vhost: add batch datapath for async vhost packed ring
In reply to Cheng JiangAdd batch datapath for async vhost packed ring to improve the performance of small packet processing.
--- lib/vhost/virtio_net.c | 42 +++++++++++++++++++++++++++++++++++++----- 1 file changed, 37 insertions(+), 5 deletions(-)
lib/vhost/virtio_net.c +37 -5
@@ -1724,6 +1724,29 @@ vhost_update_used_packed(struct vhost_virtqueue *vq, vq->desc_packed[head_idx].flags = head_flags; } +static __rte_always_inline int +virtio_dev_rx_async_batch_packed (struct virtio_net *dev, +struct vhost_virtqueue *vq, +struct rte_mbuf **pkts, +struct rte_mbuf **comp_pkts,uint32_t *pkt_done) +{ +uint16_t i; +uint32_t cpy_threshold = vq->async_threshold; + +vhost_for_each_try_unroll (i,0 ,PACKED_BATCH_SIZE ) { +if (unlikely (pkts[i]->pkt_len >= cpy_threshold)) +return -1 ; + } +if (!virtio_dev_rx_batch_packed (dev, vq, pkts)) { +vhost_for_each_try_unroll (i,0 ,PACKED_BATCH_SIZE ) + comp_pkts[(*pkt_done)++] = pkts[i]; + +return 0 ; + } + +return -1 ; +} + static __rte_always_inline int vhost_enqueue_async_single_packed(struct virtio_net *dev, struct vhost_virtqueue *vq,
@@ -1872,6 +1895,7 @@ virtio_dev_rx_async_submit_packed(struct virtio_net *dev, struct rte_mbuf **comp_pkts, uint32_t *comp_count) { uint32_t pkt_idx = 0, pkt_burst_idx = 0; +uint32_t remained = count;uint16_t async_descs_idx =0 ;uint16_t num_buffers;uint16_t num_descs;
@@ -1889,12 +1913,19 @@ virtio_dev_rx_async_submit_packed(struct virtio_net *dev,uint32_t num_async_pkts =0 , num_done_pkts =0 ;struct vring_packed_desc async_descs[vq->size]; -rte_prefetch0 (&vq->desc_packed[vq->last_avail_idx]); + do { + rte_prefetch0(&vq->desc_packed[vq->last_avail_idx]); + if (remained >= PACKED_BATCH_SIZE) { + if (!virtio_dev_rx_async_batch_packed(dev, vq, + &pkts[pkt_idx], comp_pkts, &num_done_pkts)) { + pkt_idx += PACKED_BATCH_SIZE; + remained -= PACKED_BATCH_SIZE; + continue; + } + } -for (pkt_idx =0 ; pkt_idx < count; pkt_idx++) { num_buffers = 0; num_descs = 0; - if (unlikely(virtio_dev_rx_async_single_packed(dev, vq, pkts[pkt_idx], &num_descs, &num_buffers, &async_descs[async_descs_idx],
@@ -1937,6 +1968,8 @@ virtio_dev_rx_async_submit_packed(struct virtio_net *dev, comp_pkts[num_done_pkts++] = pkts[pkt_idx]; } + pkt_idx++; + remained--;vq_inc_last_avail_packed (vq, num_descs);/*
@@ -1961,13 +1994,12 @@ virtio_dev_rx_async_submit_packed(struct virtio_net *dev,*/ pkt_err = pkt_burst_idx - n_pkts; pkt_burst_idx =0 ; - pkt_idx++;break ; } pkt_burst_idx =0 ; } - } + }while (pkt_idx < count);if (pkt_burst_idx) { n_pkts = vq->async_ops.transfer_data (dev->vid, queue_id, tdes,0 , pkt_burst_idx);
Signature · 1 line
2.29.2
Re: [dpdk-dev] [PATCH v9 3/4] vhost: add batch datapath for async vhost packed ring
Quoted 8 lines · Cheng Jiang
Add batch datapath for async vhost packed ring to improve the performance of small packet processing.
Signed-off-by Cheng Jiang <[email protected]>--- lib/vhost/virtio_net.c | 42 +++++++++++++++++++++++++++++++++++++----- 1 file changed, 37 insertions(+), 5 deletions(-)
Thanks,
Maxime
PATCH v9 4/4 doc: add release note for vhost async packed ring
In reply to Cheng JiangAdd release note for the support of vhost async packed ring.
--- doc/guides/rel_notes/release_21_05.rst | 4 ++++ 1 file changed, 4 insertions(+)
doc/guides/rel_notes/release_21_05.rst +4 -0
@@ -271,6 +271,10 @@ New Features * Added support for crypto adapter forward mode in octeontx2 event and crypto device driver. +* **Added support for vhost async packed ring data path.** + + Added packed ring support for async vhost. + Removed Items -------------
Signature · 1 line
2.29.2
Re: [dpdk-dev] [PATCH v9 4/4] doc: add release note for vhost async packed ring
Quoted 13 lines · Cheng Jiang
Add release note for the support of vhost async packed ring.
Signed-off-by Cheng Jiang <[email protected]>--- doc/guides/rel_notes/release_21_05.rst | 4 ++++ 1 file changed, 4 insertions(+)doc/guides/rel_notes/release_21_05.rst +0
-0
doc/guides/rel_notes/release_21_05.rst New Features · line 280
Quoted 10 lines
doc/guides/rel_notes/release_21_05.rst +4
-0@@ -271,6 +271,10 @@ New Features * Added support for crypto adapter forward mode in octeontx2 event and crypto device driver. +* **Added support for vhost async packed ring data path.** + + Added packed ring support for async vhost. + Removed Items -------------
Thanks,
Maxime
Re: [dpdk-dev] [PATCH v9 4/4] doc: add release note for vhost async packed ring
In reply to Cheng JiangQuoted 3 lines · Cheng Jiang
Add release note for the support of vhost async packed ring.
Signed-off-by Cheng Jiang <[email protected]>
Squashed into relevant commit in next-net, thanks.
Maxime Coquelin
AppliedRe: [dpdk-dev] [PATCH v9 0/4] add support for packed ring in async vhost
In reply to Cheng JiangQuoted 55 lines · Cheng Jiang
For now async vhost data path only supports split ring structure. In order to make async vhost compatible with virtio 1.1 spec this patch set cleans async split ring codes and enables packed ring in async vhost data path. Batch datapath is also enabled in async vhost packed ring.
v9:
* improve some variable initiation
* fix some variable names for consistency
* rebase on the latest code
v8:
* fix some variable names for consistency
* clean codes
v7:
* fix compile issues
* add argument *dev invhost_free_async_mem()for ring type decision
v6:
* fix some typos in commit log
* improve index usage
* removeshadow_ring_store()
* addstore_dma_desc_info_split()store_dma_desc_info_packed()
* remove some checks invhost_free_async_mem()
* change index calculation since the size isn't necessarily a power of 2
* move error handling in a dedicated function
* clean codes
v5:
* clean some codes for packed ring datapath
* fix an index error inshadow_ring_store()
v4:
* change the patch structure
* clean code for async split ring
* reuse some code from split ring
* change the error handler for DMA-copy packet
* add check for malloc
* remove useless code
* add doc update
v3:
* fix error handler for DMA-copy packet
v2:
* fix wrong buffer index inrte_vhost_poll_enqueue_completed()
* addasync_buffers_packedmemory free invhost_free_async_mem()Cheng Jiang (4):
vhost: abstract and reorganize async split ring code
vhost: add support for packed ring in async vhost
vhost: add batch datapath for async vhost packed ring
doc: add release note for vhost async packed ringdoc/guides/rel_notes/release_21_05.rst | 4 + lib/vhost/rte_vhost_async.h | 1 + lib/vhost/vhost.c | 79 +++- lib/vhost/vhost.h | 15 +- lib/vhost/virtio_net.c | 598 +++++++++++++++++++++---- 5 files changed, 587 insertions(+), 110 deletions(-)
Quoted 3 lines
--
2.29.2
Applied to dpdk-next-virtio/main.
Thanks,
Maxime