* [dpdk-dev] [PATCH v3 0/3] net/virtio: Rx paths improvements
@ 2018-12-20 17:27 Maxime Coquelin
2018-12-20 17:27 ` [dpdk-dev] [PATCH v3 1/3] net/virtio: inline refill and offload helpers Maxime Coquelin
` (3 more replies)
0 siblings, 4 replies; 8+ messages in thread
From: Maxime Coquelin @ 2018-12-20 17:27 UTC (permalink / raw)
To: dev, jfreimann, tiwei.bie, zhihong.wang; +Cc: Maxime Coquelin
First version of this series did merge out-of-order mergeable
and non-mergeable receive paths, but Intel STV team highlighted
some performance regression when using multiqueue with two cores
enqueueing descs on host, while a single core dequeues the
two queues.
I didn't manage to close the performance gap, so I decided to
give-up this refactoring. But while trying to optimize, I reworked
the meargeable function so that it looks like the in-order one.
I.e. descriptors are now dequeued in batches, so are descriptors
refilled. Doing that, I measure a perfromance gain of 6% when doing
rxonly microbenchmark with two cores on host, one in guest.
Changes since v2:
- Rebase after Jens' packed ring series
- Break refill loop if VQ_RING_DESC_CHAIN_END (Tiwei)
- Fixup commit message
Maxime Coquelin (3):
net/virtio: inline refill and offload helpers
net/virtio: add non-mergeable support to in-order path
net/virtio: improve batching in mergeable path
drivers/net/virtio/virtio_ethdev.c | 14 +-
drivers/net/virtio/virtio_ethdev.h | 2 +-
drivers/net/virtio/virtio_rxtx.c | 257 ++++++++++++++++-------------
3 files changed, 145 insertions(+), 128 deletions(-)
--
2.17.2
^ permalink raw reply [flat|nested] 8+ messages in thread
* [dpdk-dev] [PATCH v3 1/3] net/virtio: inline refill and offload helpers
2018-12-20 17:27 [dpdk-dev] [PATCH v3 0/3] net/virtio: Rx paths improvements Maxime Coquelin
@ 2018-12-20 17:27 ` Maxime Coquelin
2018-12-20 17:27 ` [dpdk-dev] [PATCH v3 2/3] net/virtio: add non-mergeable support to in-order path Maxime Coquelin
` (2 subsequent siblings)
3 siblings, 0 replies; 8+ messages in thread
From: Maxime Coquelin @ 2018-12-20 17:27 UTC (permalink / raw)
To: dev, jfreimann, tiwei.bie, zhihong.wang; +Cc: Maxime Coquelin
Signed-off-by: Maxime Coquelin <maxime.coquelin@redhat.com>
Reviewed-by: Jens Freimann <jfreimann@redhat.com>
---
drivers/net/virtio/virtio_rxtx.c | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/drivers/net/virtio/virtio_rxtx.c b/drivers/net/virtio/virtio_rxtx.c
index 8564f18a7..95d74d000 100644
--- a/drivers/net/virtio/virtio_rxtx.c
+++ b/drivers/net/virtio/virtio_rxtx.c
@@ -980,7 +980,7 @@ virtio_dev_tx_queue_setup_finish(struct rte_eth_dev *dev,
return 0;
}
-static void
+static inline void
virtio_discard_rxbuf(struct virtqueue *vq, struct rte_mbuf *m)
{
int error;
@@ -999,7 +999,7 @@ virtio_discard_rxbuf(struct virtqueue *vq, struct rte_mbuf *m)
}
}
-static void
+static inline void
virtio_discard_rxbuf_inorder(struct virtqueue *vq, struct rte_mbuf *m)
{
int error;
@@ -1011,7 +1011,7 @@ virtio_discard_rxbuf_inorder(struct virtqueue *vq, struct rte_mbuf *m)
}
}
-static void
+static inline void
virtio_update_packet_stats(struct virtnet_stats *stats, struct rte_mbuf *mbuf)
{
uint32_t s = mbuf->pkt_len;
@@ -1054,7 +1054,7 @@ virtio_rx_stats_updated(struct virtnet_rx *rxvq, struct rte_mbuf *m)
}
/* Optionally fill offload information in structure */
-static int
+static inline int
virtio_rx_offload(struct rte_mbuf *m, struct virtio_net_hdr *hdr)
{
struct rte_net_hdr_lens hdr_lens;
--
2.17.2
^ permalink raw reply [flat|nested] 8+ messages in thread
* [dpdk-dev] [PATCH v3 2/3] net/virtio: add non-mergeable support to in-order path
2018-12-20 17:27 [dpdk-dev] [PATCH v3 0/3] net/virtio: Rx paths improvements Maxime Coquelin
2018-12-20 17:27 ` [dpdk-dev] [PATCH v3 1/3] net/virtio: inline refill and offload helpers Maxime Coquelin
@ 2018-12-20 17:27 ` Maxime Coquelin
2018-12-20 17:27 ` [dpdk-dev] [PATCH v3 3/3] net/virtio: improve batching in mergeable path Maxime Coquelin
2018-12-21 9:20 ` [dpdk-dev] [PATCH v3 0/3] net/virtio: Rx paths improvements Maxime Coquelin
3 siblings, 0 replies; 8+ messages in thread
From: Maxime Coquelin @ 2018-12-20 17:27 UTC (permalink / raw)
To: dev, jfreimann, tiwei.bie, zhihong.wang; +Cc: Maxime Coquelin
This patch adds support for in-order path when meargeable buffers
feature hasn't been negotiated.
Signed-off-by: Maxime Coquelin <maxime.coquelin@redhat.com>
Reviewed-by: Tiwei Bie <tiwei.bie@intel.com>
---
drivers/net/virtio/virtio_ethdev.c | 14 ++++----------
drivers/net/virtio/virtio_ethdev.h | 2 +-
drivers/net/virtio/virtio_rxtx.c | 10 +++++++---
3 files changed, 12 insertions(+), 14 deletions(-)
diff --git a/drivers/net/virtio/virtio_ethdev.c b/drivers/net/virtio/virtio_ethdev.c
index d0c65e375..446c338fc 100644
--- a/drivers/net/virtio/virtio_ethdev.c
+++ b/drivers/net/virtio/virtio_ethdev.c
@@ -1481,10 +1481,9 @@ set_rxtx_funcs(struct rte_eth_dev *eth_dev)
eth_dev->rx_pkt_burst = virtio_recv_pkts_vec;
} else if (hw->use_inorder_rx) {
PMD_INIT_LOG(INFO,
- "virtio: using inorder mergeable buffer Rx path on port %u",
+ "virtio: using inorder Rx path on port %u",
eth_dev->data->port_id);
- eth_dev->rx_pkt_burst =
- &virtio_recv_mergeable_pkts_inorder;
+ eth_dev->rx_pkt_burst = &virtio_recv_pkts_inorder;
} else if (vtpci_with_feature(hw, VIRTIO_NET_F_MRG_RXBUF)) {
PMD_INIT_LOG(INFO,
"virtio: using mergeable buffer Rx path on port %u",
@@ -2049,13 +2048,8 @@ virtio_dev_configure(struct rte_eth_dev *dev)
if (vtpci_with_feature(hw, VIRTIO_F_IN_ORDER)) {
hw->use_inorder_tx = 1;
- if (vtpci_with_feature(hw, VIRTIO_NET_F_MRG_RXBUF) &&
- !vtpci_packed_queue(hw)) {
- hw->use_inorder_rx = 1;
- hw->use_simple_rx = 0;
- } else {
- hw->use_inorder_rx = 0;
- }
+ hw->use_inorder_rx = 1;
+ hw->use_simple_rx = 0;
}
if (vtpci_packed_queue(hw)) {
diff --git a/drivers/net/virtio/virtio_ethdev.h b/drivers/net/virtio/virtio_ethdev.h
index 364ecbb50..f8d8a56ab 100644
--- a/drivers/net/virtio/virtio_ethdev.h
+++ b/drivers/net/virtio/virtio_ethdev.h
@@ -83,7 +83,7 @@ uint16_t virtio_recv_mergeable_pkts(void *rx_queue, struct rte_mbuf **rx_pkts,
uint16_t virtio_recv_mergeable_pkts_packed(void *rx_queue,
struct rte_mbuf **rx_pkts, uint16_t nb_pkts);
-uint16_t virtio_recv_mergeable_pkts_inorder(void *rx_queue,
+uint16_t virtio_recv_pkts_inorder(void *rx_queue,
struct rte_mbuf **rx_pkts, uint16_t nb_pkts);
uint16_t virtio_xmit_pkts(void *tx_queue, struct rte_mbuf **tx_pkts,
diff --git a/drivers/net/virtio/virtio_rxtx.c b/drivers/net/virtio/virtio_rxtx.c
index 95d74d000..58376ced3 100644
--- a/drivers/net/virtio/virtio_rxtx.c
+++ b/drivers/net/virtio/virtio_rxtx.c
@@ -1330,7 +1330,7 @@ virtio_recv_pkts_packed(void *rx_queue, struct rte_mbuf **rx_pkts,
uint16_t
-virtio_recv_mergeable_pkts_inorder(void *rx_queue,
+virtio_recv_pkts_inorder(void *rx_queue,
struct rte_mbuf **rx_pkts,
uint16_t nb_pkts)
{
@@ -1387,10 +1387,14 @@ virtio_recv_mergeable_pkts_inorder(void *rx_queue,
header = (struct virtio_net_hdr_mrg_rxbuf *)
((char *)rxm->buf_addr + RTE_PKTMBUF_HEADROOM
- hdr_size);
- seg_num = header->num_buffers;
- if (seg_num == 0)
+ if (vtpci_with_feature(hw, VIRTIO_NET_F_MRG_RXBUF)) {
+ seg_num = header->num_buffers;
+ if (seg_num == 0)
+ seg_num = 1;
+ } else {
seg_num = 1;
+ }
rxm->data_off = RTE_PKTMBUF_HEADROOM;
rxm->nb_segs = seg_num;
--
2.17.2
^ permalink raw reply [flat|nested] 8+ messages in thread
* [dpdk-dev] [PATCH v3 3/3] net/virtio: improve batching in mergeable path
2018-12-20 17:27 [dpdk-dev] [PATCH v3 0/3] net/virtio: Rx paths improvements Maxime Coquelin
2018-12-20 17:27 ` [dpdk-dev] [PATCH v3 1/3] net/virtio: inline refill and offload helpers Maxime Coquelin
2018-12-20 17:27 ` [dpdk-dev] [PATCH v3 2/3] net/virtio: add non-mergeable support to in-order path Maxime Coquelin
@ 2018-12-20 17:27 ` Maxime Coquelin
2018-12-21 6:27 ` Gavin Hu (Arm Technology China)
2018-12-21 9:20 ` [dpdk-dev] [PATCH v3 0/3] net/virtio: Rx paths improvements Maxime Coquelin
3 siblings, 1 reply; 8+ messages in thread
From: Maxime Coquelin @ 2018-12-20 17:27 UTC (permalink / raw)
To: dev, jfreimann, tiwei.bie, zhihong.wang; +Cc: Maxime Coquelin
This patch improves both descriptors dequeue and refill,
by using the same batching strategy as done in in-order path.
Signed-off-by: Maxime Coquelin <maxime.coquelin@redhat.com>
Tested-by: Jens Freimann <jfreimann@redhat.com>
Reviewed-by: Jens Freimann <jfreimann@redhat.com>
---
drivers/net/virtio/virtio_rxtx.c | 239 +++++++++++++++++--------------
1 file changed, 129 insertions(+), 110 deletions(-)
diff --git a/drivers/net/virtio/virtio_rxtx.c b/drivers/net/virtio/virtio_rxtx.c
index 58376ced3..1cfa2f0d6 100644
--- a/drivers/net/virtio/virtio_rxtx.c
+++ b/drivers/net/virtio/virtio_rxtx.c
@@ -353,41 +353,44 @@ virtqueue_enqueue_refill_inorder(struct virtqueue *vq,
}
static inline int
-virtqueue_enqueue_recv_refill(struct virtqueue *vq, struct rte_mbuf *cookie)
+virtqueue_enqueue_recv_refill(struct virtqueue *vq, struct rte_mbuf **cookie,
+ uint16_t num)
{
struct vq_desc_extra *dxp;
struct virtio_hw *hw = vq->hw;
- struct vring_desc *start_dp;
- uint16_t needed = 1;
- uint16_t head_idx, idx;
+ struct vring_desc *start_dp = vq->vq_ring.desc;
+ uint16_t idx, i;
if (unlikely(vq->vq_free_cnt == 0))
return -ENOSPC;
- if (unlikely(vq->vq_free_cnt < needed))
+ if (unlikely(vq->vq_free_cnt < num))
return -EMSGSIZE;
- head_idx = vq->vq_desc_head_idx;
- if (unlikely(head_idx >= vq->vq_nentries))
+ if (unlikely(vq->vq_desc_head_idx >= vq->vq_nentries))
return -EFAULT;
- idx = head_idx;
- dxp = &vq->vq_descx[idx];
- dxp->cookie = (void *)cookie;
- dxp->ndescs = needed;
+ for (i = 0; i < num; i++) {
+ idx = vq->vq_desc_head_idx;
+ dxp = &vq->vq_descx[idx];
+ dxp->cookie = (void *)cookie[i];
+ dxp->ndescs = 1;
- start_dp = vq->vq_ring.desc;
- start_dp[idx].addr =
- VIRTIO_MBUF_ADDR(cookie, vq) +
- RTE_PKTMBUF_HEADROOM - hw->vtnet_hdr_size;
- start_dp[idx].len =
- cookie->buf_len - RTE_PKTMBUF_HEADROOM + hw->vtnet_hdr_size;
- start_dp[idx].flags = VRING_DESC_F_WRITE;
- idx = start_dp[idx].next;
- vq->vq_desc_head_idx = idx;
- if (vq->vq_desc_head_idx == VQ_RING_DESC_CHAIN_END)
- vq->vq_desc_tail_idx = idx;
- vq->vq_free_cnt = (uint16_t)(vq->vq_free_cnt - needed);
- vq_update_avail_ring(vq, head_idx);
+ start_dp[idx].addr =
+ VIRTIO_MBUF_ADDR(cookie[i], vq) +
+ RTE_PKTMBUF_HEADROOM - hw->vtnet_hdr_size;
+ start_dp[idx].len =
+ cookie[i]->buf_len - RTE_PKTMBUF_HEADROOM +
+ hw->vtnet_hdr_size;
+ start_dp[idx].flags = VRING_DESC_F_WRITE;
+ vq->vq_desc_head_idx = start_dp[idx].next;
+ vq_update_avail_ring(vq, idx);
+ if (vq->vq_desc_head_idx == VQ_RING_DESC_CHAIN_END) {
+ vq->vq_desc_tail_idx = vq->vq_desc_head_idx;
+ break;
+ }
+ }
+
+ vq->vq_free_cnt = (uint16_t)(vq->vq_free_cnt - num);
return 0;
}
@@ -892,7 +895,8 @@ virtio_dev_rx_queue_setup_finish(struct rte_eth_dev *dev, uint16_t queue_idx)
error = virtqueue_enqueue_recv_refill_packed(vq,
&m, 1);
else
- error = virtqueue_enqueue_recv_refill(vq, m);
+ error = virtqueue_enqueue_recv_refill(vq,
+ &m, 1);
if (error) {
rte_pktmbuf_free(m);
break;
@@ -991,7 +995,7 @@ virtio_discard_rxbuf(struct virtqueue *vq, struct rte_mbuf *m)
if (vtpci_packed_queue(vq->hw))
error = virtqueue_enqueue_recv_refill_packed(vq, &m, 1);
else
- error = virtqueue_enqueue_recv_refill(vq, m);
+ error = virtqueue_enqueue_recv_refill(vq, &m, 1);
if (unlikely(error)) {
RTE_LOG(ERR, PMD, "cannot requeue discarded mbuf");
@@ -1211,7 +1215,7 @@ virtio_recv_pkts(void *rx_queue, struct rte_mbuf **rx_pkts, uint16_t nb_pkts)
dev->data->rx_mbuf_alloc_failed++;
break;
}
- error = virtqueue_enqueue_recv_refill(vq, new_mbuf);
+ error = virtqueue_enqueue_recv_refill(vq, &new_mbuf, 1);
if (unlikely(error)) {
rte_pktmbuf_free(new_mbuf);
break;
@@ -1528,19 +1532,18 @@ virtio_recv_mergeable_pkts(void *rx_queue,
struct virtnet_rx *rxvq = rx_queue;
struct virtqueue *vq = rxvq->vq;
struct virtio_hw *hw = vq->hw;
- struct rte_mbuf *rxm, *new_mbuf;
- uint16_t nb_used, num, nb_rx;
+ struct rte_mbuf *rxm;
+ struct rte_mbuf *prev;
+ uint16_t nb_used, num, nb_rx = 0;
uint32_t len[VIRTIO_MBUF_BURST_SZ];
struct rte_mbuf *rcv_pkts[VIRTIO_MBUF_BURST_SZ];
- struct rte_mbuf *prev;
int error;
- uint32_t i, nb_enqueued;
- uint32_t seg_num;
- uint16_t extra_idx;
- uint32_t seg_res;
- uint32_t hdr_size;
+ uint32_t nb_enqueued = 0;
+ uint32_t seg_num = 0;
+ uint32_t seg_res = 0;
+ uint32_t hdr_size = hw->vtnet_hdr_size;
+ int32_t i;
- nb_rx = 0;
if (unlikely(hw->started == 0))
return nb_rx;
@@ -1550,31 +1553,25 @@ virtio_recv_mergeable_pkts(void *rx_queue,
PMD_RX_LOG(DEBUG, "used:%d", nb_used);
- i = 0;
- nb_enqueued = 0;
- seg_num = 0;
- extra_idx = 0;
- seg_res = 0;
- hdr_size = hw->vtnet_hdr_size;
-
- while (i < nb_used) {
- struct virtio_net_hdr_mrg_rxbuf *header;
+ num = likely(nb_used <= nb_pkts) ? nb_used : nb_pkts;
+ if (unlikely(num > VIRTIO_MBUF_BURST_SZ))
+ num = VIRTIO_MBUF_BURST_SZ;
+ if (likely(num > DESC_PER_CACHELINE))
+ num = num - ((vq->vq_used_cons_idx + num) %
+ DESC_PER_CACHELINE);
- if (nb_rx == nb_pkts)
- break;
- num = virtqueue_dequeue_burst_rx(vq, rcv_pkts, len, 1);
- if (num != 1)
- continue;
+ num = virtqueue_dequeue_burst_rx(vq, rcv_pkts, len, num);
- i++;
+ for (i = 0; i < num; i++) {
+ struct virtio_net_hdr_mrg_rxbuf *header;
PMD_RX_LOG(DEBUG, "dequeue:%d", num);
- PMD_RX_LOG(DEBUG, "packet len:%d", len[0]);
+ PMD_RX_LOG(DEBUG, "packet len:%d", len[i]);
- rxm = rcv_pkts[0];
+ rxm = rcv_pkts[i];
- if (unlikely(len[0] < hdr_size + ETHER_HDR_LEN)) {
+ if (unlikely(len[i] < hdr_size + ETHER_HDR_LEN)) {
PMD_RX_LOG(ERR, "Packet drop");
nb_enqueued++;
virtio_discard_rxbuf(vq, rxm);
@@ -1582,10 +1579,10 @@ virtio_recv_mergeable_pkts(void *rx_queue,
continue;
}
- header = (struct virtio_net_hdr_mrg_rxbuf *)((char *)rxm->buf_addr +
- RTE_PKTMBUF_HEADROOM - hdr_size);
+ header = (struct virtio_net_hdr_mrg_rxbuf *)
+ ((char *)rxm->buf_addr + RTE_PKTMBUF_HEADROOM
+ - hdr_size);
seg_num = header->num_buffers;
-
if (seg_num == 0)
seg_num = 1;
@@ -1593,10 +1590,11 @@ virtio_recv_mergeable_pkts(void *rx_queue,
rxm->nb_segs = seg_num;
rxm->ol_flags = 0;
rxm->vlan_tci = 0;
- rxm->pkt_len = (uint32_t)(len[0] - hdr_size);
- rxm->data_len = (uint16_t)(len[0] - hdr_size);
+ rxm->pkt_len = (uint32_t)(len[i] - hdr_size);
+ rxm->data_len = (uint16_t)(len[i] - hdr_size);
rxm->port = rxvq->port_id;
+
rx_pkts[nb_rx] = rxm;
prev = rxm;
@@ -1607,75 +1605,96 @@ virtio_recv_mergeable_pkts(void *rx_queue,
continue;
}
+ if (hw->vlan_strip)
+ rte_vlan_strip(rx_pkts[nb_rx]);
+
seg_res = seg_num - 1;
- while (seg_res != 0) {
- /*
- * Get extra segments for current uncompleted packet.
- */
- uint16_t rcv_cnt =
- RTE_MIN(seg_res, RTE_DIM(rcv_pkts));
- if (likely(VIRTQUEUE_NUSED(vq) >= rcv_cnt)) {
- uint32_t rx_num =
- virtqueue_dequeue_burst_rx(vq,
- rcv_pkts, len, rcv_cnt);
- i += rx_num;
- rcv_cnt = rx_num;
- } else {
- PMD_RX_LOG(ERR,
- "No enough segments for packet.");
- nb_enqueued++;
- virtio_discard_rxbuf(vq, rxm);
- rxvq->stats.errors++;
- break;
- }
+ /* Merge remaining segments */
+ while (seg_res != 0 && i < (num - 1)) {
+ i++;
+
+ rxm = rcv_pkts[i];
+ rxm->data_off = RTE_PKTMBUF_HEADROOM - hdr_size;
+ rxm->pkt_len = (uint32_t)(len[i]);
+ rxm->data_len = (uint16_t)(len[i]);
+
+ rx_pkts[nb_rx]->pkt_len += (uint32_t)(len[i]);
+ rx_pkts[nb_rx]->data_len += (uint16_t)(len[i]);
+
+ if (prev)
+ prev->next = rxm;
+
+ prev = rxm;
+ seg_res -= 1;
+ }
+
+ if (!seg_res) {
+ virtio_rx_stats_updated(rxvq, rx_pkts[nb_rx]);
+ nb_rx++;
+ }
+ }
+
+ /* Last packet still need merge segments */
+ while (seg_res != 0) {
+ uint16_t rcv_cnt = RTE_MIN((uint16_t)seg_res,
+ VIRTIO_MBUF_BURST_SZ);
- extra_idx = 0;
+ prev = rcv_pkts[nb_rx];
+ if (likely(VIRTQUEUE_NUSED(vq) >= rcv_cnt)) {
+ num = virtqueue_dequeue_burst_rx(vq, rcv_pkts, len,
+ rcv_cnt);
+ uint16_t extra_idx = 0;
+ rcv_cnt = num;
while (extra_idx < rcv_cnt) {
rxm = rcv_pkts[extra_idx];
-
- rxm->data_off = RTE_PKTMBUF_HEADROOM - hdr_size;
+ rxm->data_off =
+ RTE_PKTMBUF_HEADROOM - hdr_size;
rxm->pkt_len = (uint32_t)(len[extra_idx]);
rxm->data_len = (uint16_t)(len[extra_idx]);
-
- if (prev)
- prev->next = rxm;
-
+ prev->next = rxm;
prev = rxm;
- rx_pkts[nb_rx]->pkt_len += rxm->pkt_len;
- extra_idx++;
+ rx_pkts[nb_rx]->pkt_len += len[extra_idx];
+ rx_pkts[nb_rx]->data_len += len[extra_idx];
+ extra_idx += 1;
};
seg_res -= rcv_cnt;
- }
-
- if (hw->vlan_strip)
- rte_vlan_strip(rx_pkts[nb_rx]);
-
- VIRTIO_DUMP_PACKET(rx_pkts[nb_rx],
- rx_pkts[nb_rx]->data_len);
- virtio_update_packet_stats(&rxvq->stats, rx_pkts[nb_rx]);
- nb_rx++;
+ if (!seg_res) {
+ virtio_rx_stats_updated(rxvq, rx_pkts[nb_rx]);
+ nb_rx++;
+ }
+ } else {
+ PMD_RX_LOG(ERR,
+ "No enough segments for packet.");
+ virtio_discard_rxbuf(vq, prev);
+ rxvq->stats.errors++;
+ break;
+ }
}
rxvq->stats.packets += nb_rx;
/* Allocate new mbuf for the used descriptor */
- while (likely(!virtqueue_full(vq))) {
- new_mbuf = rte_mbuf_raw_alloc(rxvq->mpool);
- if (unlikely(new_mbuf == NULL)) {
- struct rte_eth_dev *dev
- = &rte_eth_devices[rxvq->port_id];
- dev->data->rx_mbuf_alloc_failed++;
- break;
- }
- error = virtqueue_enqueue_recv_refill(vq, new_mbuf);
- if (unlikely(error)) {
- rte_pktmbuf_free(new_mbuf);
- break;
+ if (likely(!virtqueue_full(vq))) {
+ /* free_cnt may include mrg descs */
+ uint16_t free_cnt = vq->vq_free_cnt;
+ struct rte_mbuf *new_pkts[free_cnt];
+
+ if (!rte_pktmbuf_alloc_bulk(rxvq->mpool, new_pkts, free_cnt)) {
+ error = virtqueue_enqueue_recv_refill(vq, new_pkts,
+ free_cnt);
+ if (unlikely(error)) {
+ for (i = 0; i < free_cnt; i++)
+ rte_pktmbuf_free(new_pkts[i]);
+ }
+ nb_enqueued += free_cnt;
+ } else {
+ struct rte_eth_dev *dev =
+ &rte_eth_devices[rxvq->port_id];
+ dev->data->rx_mbuf_alloc_failed += free_cnt;
}
- nb_enqueued++;
}
if (likely(nb_enqueued)) {
--
2.17.2
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [dpdk-dev] [PATCH v3 3/3] net/virtio: improve batching in mergeable path
2018-12-20 17:27 ` [dpdk-dev] [PATCH v3 3/3] net/virtio: improve batching in mergeable path Maxime Coquelin
@ 2018-12-21 6:27 ` Gavin Hu (Arm Technology China)
2018-12-21 8:36 ` Maxime Coquelin
0 siblings, 1 reply; 8+ messages in thread
From: Gavin Hu (Arm Technology China) @ 2018-12-21 6:27 UTC (permalink / raw)
To: Maxime Coquelin, dev, jfreimann, tiwei.bie, zhihong.wang; +Cc: nd
> -----Original Message-----
> From: dev <dev-bounces@dpdk.org> On Behalf Of Maxime Coquelin
> Sent: Friday, December 21, 2018 1:27 AM
> To: dev@dpdk.org; jfreimann@redhat.com; tiwei.bie@intel.com;
> zhihong.wang@intel.com
> Cc: Maxime Coquelin <maxime.coquelin@redhat.com>
> Subject: [dpdk-dev] [PATCH v3 3/3] net/virtio: improve batching in
> mergeable path
>
> This patch improves both descriptors dequeue and refill,
> by using the same batching strategy as done in in-order path.
>
> Signed-off-by: Maxime Coquelin <maxime.coquelin@redhat.com>
> Tested-by: Jens Freimann <jfreimann@redhat.com>
> Reviewed-by: Jens Freimann <jfreimann@redhat.com>
> ---
> drivers/net/virtio/virtio_rxtx.c | 239 +++++++++++++++++--------------
> 1 file changed, 129 insertions(+), 110 deletions(-)
>
> diff --git a/drivers/net/virtio/virtio_rxtx.c b/drivers/net/virtio/virtio_rxtx.c
> index 58376ced3..1cfa2f0d6 100644
> --- a/drivers/net/virtio/virtio_rxtx.c
> +++ b/drivers/net/virtio/virtio_rxtx.c
> @@ -353,41 +353,44 @@ virtqueue_enqueue_refill_inorder(struct
> virtqueue *vq,
> }
>
> static inline int
> -virtqueue_enqueue_recv_refill(struct virtqueue *vq, struct rte_mbuf
> *cookie)
> +virtqueue_enqueue_recv_refill(struct virtqueue *vq, struct rte_mbuf
> **cookie,
> + uint16_t num)
> {
> struct vq_desc_extra *dxp;
> struct virtio_hw *hw = vq->hw;
> - struct vring_desc *start_dp;
> - uint16_t needed = 1;
> - uint16_t head_idx, idx;
> + struct vring_desc *start_dp = vq->vq_ring.desc;
> + uint16_t idx, i;
>
> if (unlikely(vq->vq_free_cnt == 0))
> return -ENOSPC;
> - if (unlikely(vq->vq_free_cnt < needed))
> + if (unlikely(vq->vq_free_cnt < num))
> return -EMSGSIZE;
>
> - head_idx = vq->vq_desc_head_idx;
> - if (unlikely(head_idx >= vq->vq_nentries))
> + if (unlikely(vq->vq_desc_head_idx >= vq->vq_nentries))
> return -EFAULT;
>
> - idx = head_idx;
> - dxp = &vq->vq_descx[idx];
> - dxp->cookie = (void *)cookie;
> - dxp->ndescs = needed;
> + for (i = 0; i < num; i++) {
> + idx = vq->vq_desc_head_idx;
> + dxp = &vq->vq_descx[idx];
> + dxp->cookie = (void *)cookie[i];
> + dxp->ndescs = 1;
>
> - start_dp = vq->vq_ring.desc;
> - start_dp[idx].addr =
> - VIRTIO_MBUF_ADDR(cookie, vq) +
> - RTE_PKTMBUF_HEADROOM - hw->vtnet_hdr_size;
> - start_dp[idx].len =
> - cookie->buf_len - RTE_PKTMBUF_HEADROOM + hw-
> >vtnet_hdr_size;
> - start_dp[idx].flags = VRING_DESC_F_WRITE;
> - idx = start_dp[idx].next;
> - vq->vq_desc_head_idx = idx;
> - if (vq->vq_desc_head_idx == VQ_RING_DESC_CHAIN_END)
> - vq->vq_desc_tail_idx = idx;
> - vq->vq_free_cnt = (uint16_t)(vq->vq_free_cnt - needed);
> - vq_update_avail_ring(vq, head_idx);
> + start_dp[idx].addr =
> + VIRTIO_MBUF_ADDR(cookie[i], vq) +
> + RTE_PKTMBUF_HEADROOM - hw->vtnet_hdr_size;
> + start_dp[idx].len =
> + cookie[i]->buf_len - RTE_PKTMBUF_HEADROOM +
> + hw->vtnet_hdr_size;
> + start_dp[idx].flags = VRING_DESC_F_WRITE;
> + vq->vq_desc_head_idx = start_dp[idx].next;
> + vq_update_avail_ring(vq, idx);
> + if (vq->vq_desc_head_idx == VQ_RING_DESC_CHAIN_END)
> {
> + vq->vq_desc_tail_idx = vq->vq_desc_head_idx;
> + break;
> + }
> + }
> +
> + vq->vq_free_cnt = (uint16_t)(vq->vq_free_cnt - num);
>
> return 0;
> }
> @@ -892,7 +895,8 @@ virtio_dev_rx_queue_setup_finish(struct
> rte_eth_dev *dev, uint16_t queue_idx)
> error =
> virtqueue_enqueue_recv_refill_packed(vq,
> &m, 1);
> else
> - error = virtqueue_enqueue_recv_refill(vq,
> m);
> + error = virtqueue_enqueue_recv_refill(vq,
> + &m, 1);
> if (error) {
> rte_pktmbuf_free(m);
> break;
> @@ -991,7 +995,7 @@ virtio_discard_rxbuf(struct virtqueue *vq, struct
> rte_mbuf *m)
> if (vtpci_packed_queue(vq->hw))
> error = virtqueue_enqueue_recv_refill_packed(vq, &m, 1);
> else
> - error = virtqueue_enqueue_recv_refill(vq, m);
> + error = virtqueue_enqueue_recv_refill(vq, &m, 1);
>
> if (unlikely(error)) {
> RTE_LOG(ERR, PMD, "cannot requeue discarded mbuf");
> @@ -1211,7 +1215,7 @@ virtio_recv_pkts(void *rx_queue, struct rte_mbuf
> **rx_pkts, uint16_t nb_pkts)
> dev->data->rx_mbuf_alloc_failed++;
> break;
> }
> - error = virtqueue_enqueue_recv_refill(vq, new_mbuf);
> + error = virtqueue_enqueue_recv_refill(vq, &new_mbuf, 1);
> if (unlikely(error)) {
> rte_pktmbuf_free(new_mbuf);
> break;
> @@ -1528,19 +1532,18 @@ virtio_recv_mergeable_pkts(void *rx_queue,
> struct virtnet_rx *rxvq = rx_queue;
> struct virtqueue *vq = rxvq->vq;
> struct virtio_hw *hw = vq->hw;
> - struct rte_mbuf *rxm, *new_mbuf;
> - uint16_t nb_used, num, nb_rx;
> + struct rte_mbuf *rxm;
> + struct rte_mbuf *prev;
> + uint16_t nb_used, num, nb_rx = 0;
> uint32_t len[VIRTIO_MBUF_BURST_SZ];
> struct rte_mbuf *rcv_pkts[VIRTIO_MBUF_BURST_SZ];
> - struct rte_mbuf *prev;
> int error;
> - uint32_t i, nb_enqueued;
> - uint32_t seg_num;
> - uint16_t extra_idx;
> - uint32_t seg_res;
> - uint32_t hdr_size;
> + uint32_t nb_enqueued = 0;
> + uint32_t seg_num = 0;
> + uint32_t seg_res = 0;
> + uint32_t hdr_size = hw->vtnet_hdr_size;
> + int32_t i;
>
> - nb_rx = 0;
> if (unlikely(hw->started == 0))
> return nb_rx;
>
> @@ -1550,31 +1553,25 @@ virtio_recv_mergeable_pkts(void *rx_queue,
>
> PMD_RX_LOG(DEBUG, "used:%d", nb_used);
>
> - i = 0;
> - nb_enqueued = 0;
> - seg_num = 0;
> - extra_idx = 0;
> - seg_res = 0;
> - hdr_size = hw->vtnet_hdr_size;
> -
> - while (i < nb_used) {
> - struct virtio_net_hdr_mrg_rxbuf *header;
> + num = likely(nb_used <= nb_pkts) ? nb_used : nb_pkts;
> + if (unlikely(num > VIRTIO_MBUF_BURST_SZ))
> + num = VIRTIO_MBUF_BURST_SZ;
> + if (likely(num > DESC_PER_CACHELINE))
> + num = num - ((vq->vq_used_cons_idx + num) %
> + DESC_PER_CACHELINE);
>
> - if (nb_rx == nb_pkts)
> - break;
>
> - num = virtqueue_dequeue_burst_rx(vq, rcv_pkts, len, 1);
> - if (num != 1)
> - continue;
> + num = virtqueue_dequeue_burst_rx(vq, rcv_pkts, len, num);
>
> - i++;
> + for (i = 0; i < num; i++) {
> + struct virtio_net_hdr_mrg_rxbuf *header;
>
> PMD_RX_LOG(DEBUG, "dequeue:%d", num);
> - PMD_RX_LOG(DEBUG, "packet len:%d", len[0]);
> + PMD_RX_LOG(DEBUG, "packet len:%d", len[i]);
>
> - rxm = rcv_pkts[0];
> + rxm = rcv_pkts[i];
>
> - if (unlikely(len[0] < hdr_size + ETHER_HDR_LEN)) {
> + if (unlikely(len[i] < hdr_size + ETHER_HDR_LEN)) {
> PMD_RX_LOG(ERR, "Packet drop");
> nb_enqueued++;
> virtio_discard_rxbuf(vq, rxm);
> @@ -1582,10 +1579,10 @@ virtio_recv_mergeable_pkts(void *rx_queue,
> continue;
> }
>
> - header = (struct virtio_net_hdr_mrg_rxbuf *)((char *)rxm-
> >buf_addr +
> - RTE_PKTMBUF_HEADROOM - hdr_size);
> + header = (struct virtio_net_hdr_mrg_rxbuf *)
> + ((char *)rxm->buf_addr +
> RTE_PKTMBUF_HEADROOM
> + - hdr_size);
> seg_num = header->num_buffers;
> -
> if (seg_num == 0)
> seg_num = 1;
>
> @@ -1593,10 +1590,11 @@ virtio_recv_mergeable_pkts(void *rx_queue,
> rxm->nb_segs = seg_num;
> rxm->ol_flags = 0;
> rxm->vlan_tci = 0;
> - rxm->pkt_len = (uint32_t)(len[0] - hdr_size);
> - rxm->data_len = (uint16_t)(len[0] - hdr_size);
> + rxm->pkt_len = (uint32_t)(len[i] - hdr_size);
> + rxm->data_len = (uint16_t)(len[i] - hdr_size);
>
> rxm->port = rxvq->port_id;
> +
> rx_pkts[nb_rx] = rxm;
> prev = rxm;
>
> @@ -1607,75 +1605,96 @@ virtio_recv_mergeable_pkts(void *rx_queue,
> continue;
> }
>
> + if (hw->vlan_strip)
> + rte_vlan_strip(rx_pkts[nb_rx]);
> +
> seg_res = seg_num - 1;
>
> - while (seg_res != 0) {
> - /*
> - * Get extra segments for current uncompleted
> packet.
> - */
> - uint16_t rcv_cnt =
> - RTE_MIN(seg_res, RTE_DIM(rcv_pkts));
> - if (likely(VIRTQUEUE_NUSED(vq) >= rcv_cnt)) {
> - uint32_t rx_num =
> - virtqueue_dequeue_burst_rx(vq,
> - rcv_pkts, len, rcv_cnt);
> - i += rx_num;
> - rcv_cnt = rx_num;
> - } else {
> - PMD_RX_LOG(ERR,
> - "No enough segments for
> packet.");
> - nb_enqueued++;
> - virtio_discard_rxbuf(vq, rxm);
> - rxvq->stats.errors++;
> - break;
> - }
> + /* Merge remaining segments */
> + while (seg_res != 0 && i < (num - 1)) {
> + i++;
> +
> + rxm = rcv_pkts[i];
> + rxm->data_off = RTE_PKTMBUF_HEADROOM -
> hdr_size;
> + rxm->pkt_len = (uint32_t)(len[i]);
> + rxm->data_len = (uint16_t)(len[i]);
> +
> + rx_pkts[nb_rx]->pkt_len += (uint32_t)(len[i]);
> + rx_pkts[nb_rx]->data_len += (uint16_t)(len[i]);
> +
> + if (prev)
> + prev->next = rxm;
> +
> + prev = rxm;
> + seg_res -= 1;
> + }
> +
> + if (!seg_res) {
> + virtio_rx_stats_updated(rxvq, rx_pkts[nb_rx]);
> + nb_rx++;
> + }
> + }
> +
> + /* Last packet still need merge segments */
> + while (seg_res != 0) {
> + uint16_t rcv_cnt = RTE_MIN((uint16_t)seg_res,
> + VIRTIO_MBUF_BURST_SZ);
>
> - extra_idx = 0;
> + prev = rcv_pkts[nb_rx];
> + if (likely(VIRTQUEUE_NUSED(vq) >= rcv_cnt)) {
> + num = virtqueue_dequeue_burst_rx(vq, rcv_pkts,
> len,
> + rcv_cnt);
> + uint16_t extra_idx = 0;
>
> + rcv_cnt = num;
> while (extra_idx < rcv_cnt) {
> rxm = rcv_pkts[extra_idx];
> -
> - rxm->data_off =
> RTE_PKTMBUF_HEADROOM - hdr_size;
> + rxm->data_off =
> + RTE_PKTMBUF_HEADROOM -
> hdr_size;
> rxm->pkt_len = (uint32_t)(len[extra_idx]);
> rxm->data_len = (uint16_t)(len[extra_idx]);
> -
> - if (prev)
> - prev->next = rxm;
> -
> + prev->next = rxm;
> prev = rxm;
> - rx_pkts[nb_rx]->pkt_len += rxm->pkt_len;
> - extra_idx++;
> + rx_pkts[nb_rx]->pkt_len += len[extra_idx];
> + rx_pkts[nb_rx]->data_len += len[extra_idx];
> + extra_idx += 1;
> };
> seg_res -= rcv_cnt;
> - }
> -
> - if (hw->vlan_strip)
> - rte_vlan_strip(rx_pkts[nb_rx]);
> -
> - VIRTIO_DUMP_PACKET(rx_pkts[nb_rx],
> - rx_pkts[nb_rx]->data_len);
>
> - virtio_update_packet_stats(&rxvq->stats, rx_pkts[nb_rx]);
> - nb_rx++;
> + if (!seg_res) {
> + virtio_rx_stats_updated(rxvq,
> rx_pkts[nb_rx]);
> + nb_rx++;
> + }
> + } else {
> + PMD_RX_LOG(ERR,
> + "No enough segments for packet.");
> + virtio_discard_rxbuf(vq, prev);
> + rxvq->stats.errors++;
> + break;
> + }
> }
>
> rxvq->stats.packets += nb_rx;
>
> /* Allocate new mbuf for the used descriptor */
> - while (likely(!virtqueue_full(vq))) {
> - new_mbuf = rte_mbuf_raw_alloc(rxvq->mpool);
> - if (unlikely(new_mbuf == NULL)) {
> - struct rte_eth_dev *dev
> - = &rte_eth_devices[rxvq->port_id];
> - dev->data->rx_mbuf_alloc_failed++;
> - break;
> - }
> - error = virtqueue_enqueue_recv_refill(vq, new_mbuf);
> - if (unlikely(error)) {
> - rte_pktmbuf_free(new_mbuf);
> - break;
> + if (likely(!virtqueue_full(vq))) {
> + /* free_cnt may include mrg descs */
> + uint16_t free_cnt = vq->vq_free_cnt;
> + struct rte_mbuf *new_pkts[free_cnt];
> +
> + if (!rte_pktmbuf_alloc_bulk(rxvq->mpool, new_pkts,
> free_cnt)) {
> + error = virtqueue_enqueue_recv_refill(vq, new_pkts,
> + free_cnt);
> + if (unlikely(error)) {
> + for (i = 0; i < free_cnt; i++)
> + rte_pktmbuf_free(new_pkts[i]);
Missing error handling here? the execution keeps going on without the mbufs?
/Gavin
> + }
> + nb_enqueued += free_cnt;
> + } else {
> + struct rte_eth_dev *dev =
> + &rte_eth_devices[rxvq->port_id];
> + dev->data->rx_mbuf_alloc_failed += free_cnt;
> }
> - nb_enqueued++;
> }
>
> if (likely(nb_enqueued)) {
> --
> 2.17.2
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [dpdk-dev] [PATCH v3 3/3] net/virtio: improve batching in mergeable path
2018-12-21 6:27 ` Gavin Hu (Arm Technology China)
@ 2018-12-21 8:36 ` Maxime Coquelin
2018-12-21 8:41 ` Gavin Hu (Arm Technology China)
0 siblings, 1 reply; 8+ messages in thread
From: Maxime Coquelin @ 2018-12-21 8:36 UTC (permalink / raw)
To: Gavin Hu (Arm Technology China), dev, jfreimann, tiwei.bie, zhihong.wang
Cc: nd
On 12/21/18 7:27 AM, Gavin Hu (Arm Technology China) wrote:
>
>
>> -----Original Message-----
>> From: dev <dev-bounces@dpdk.org> On Behalf Of Maxime Coquelin
>> Sent: Friday, December 21, 2018 1:27 AM
>> To: dev@dpdk.org; jfreimann@redhat.com; tiwei.bie@intel.com;
>> zhihong.wang@intel.com
>> Cc: Maxime Coquelin <maxime.coquelin@redhat.com>
>> Subject: [dpdk-dev] [PATCH v3 3/3] net/virtio: improve batching in
>> mergeable path
>>
>> This patch improves both descriptors dequeue and refill,
>> by using the same batching strategy as done in in-order path.
>>
>> Signed-off-by: Maxime Coquelin <maxime.coquelin@redhat.com>
>> Tested-by: Jens Freimann <jfreimann@redhat.com>
>> Reviewed-by: Jens Freimann <jfreimann@redhat.com>
>> ---
>> drivers/net/virtio/virtio_rxtx.c | 239 +++++++++++++++++--------------
>> 1 file changed, 129 insertions(+), 110 deletions(-)
>>
>> diff --git a/drivers/net/virtio/virtio_rxtx.c b/drivers/net/virtio/virtio_rxtx.c
>> index 58376ced3..1cfa2f0d6 100644
>> --- a/drivers/net/virtio/virtio_rxtx.c
>> +++ b/drivers/net/virtio/virtio_rxtx.c
>> @@ -353,41 +353,44 @@ virtqueue_enqueue_refill_inorder(struct
>> virtqueue *vq,
>> }
>>
>> static inline int
>> -virtqueue_enqueue_recv_refill(struct virtqueue *vq, struct rte_mbuf
>> *cookie)
>> +virtqueue_enqueue_recv_refill(struct virtqueue *vq, struct rte_mbuf
>> **cookie,
>> + uint16_t num)
>> {
>> struct vq_desc_extra *dxp;
>> struct virtio_hw *hw = vq->hw;
>> - struct vring_desc *start_dp;
>> - uint16_t needed = 1;
>> - uint16_t head_idx, idx;
>> + struct vring_desc *start_dp = vq->vq_ring.desc;
>> + uint16_t idx, i;
>>
>> if (unlikely(vq->vq_free_cnt == 0))
>> return -ENOSPC;
>> - if (unlikely(vq->vq_free_cnt < needed))
>> + if (unlikely(vq->vq_free_cnt < num))
>> return -EMSGSIZE;
>>
>> - head_idx = vq->vq_desc_head_idx;
>> - if (unlikely(head_idx >= vq->vq_nentries))
>> + if (unlikely(vq->vq_desc_head_idx >= vq->vq_nentries))
>> return -EFAULT;
>>
>> - idx = head_idx;
>> - dxp = &vq->vq_descx[idx];
>> - dxp->cookie = (void *)cookie;
>> - dxp->ndescs = needed;
>> + for (i = 0; i < num; i++) {
>> + idx = vq->vq_desc_head_idx;
>> + dxp = &vq->vq_descx[idx];
>> + dxp->cookie = (void *)cookie[i];
>> + dxp->ndescs = 1;
>>
>> - start_dp = vq->vq_ring.desc;
>> - start_dp[idx].addr =
>> - VIRTIO_MBUF_ADDR(cookie, vq) +
>> - RTE_PKTMBUF_HEADROOM - hw->vtnet_hdr_size;
>> - start_dp[idx].len =
>> - cookie->buf_len - RTE_PKTMBUF_HEADROOM + hw-
>>> vtnet_hdr_size;
>> - start_dp[idx].flags = VRING_DESC_F_WRITE;
>> - idx = start_dp[idx].next;
>> - vq->vq_desc_head_idx = idx;
>> - if (vq->vq_desc_head_idx == VQ_RING_DESC_CHAIN_END)
>> - vq->vq_desc_tail_idx = idx;
>> - vq->vq_free_cnt = (uint16_t)(vq->vq_free_cnt - needed);
>> - vq_update_avail_ring(vq, head_idx);
>> + start_dp[idx].addr =
>> + VIRTIO_MBUF_ADDR(cookie[i], vq) +
>> + RTE_PKTMBUF_HEADROOM - hw->vtnet_hdr_size;
>> + start_dp[idx].len =
>> + cookie[i]->buf_len - RTE_PKTMBUF_HEADROOM +
>> + hw->vtnet_hdr_size;
>> + start_dp[idx].flags = VRING_DESC_F_WRITE;
>> + vq->vq_desc_head_idx = start_dp[idx].next;
>> + vq_update_avail_ring(vq, idx);
>> + if (vq->vq_desc_head_idx == VQ_RING_DESC_CHAIN_END)
>> {
>> + vq->vq_desc_tail_idx = vq->vq_desc_head_idx;
>> + break;
>> + }
>> + }
>> +
>> + vq->vq_free_cnt = (uint16_t)(vq->vq_free_cnt - num);
>>
>> return 0;
>> }
>> @@ -892,7 +895,8 @@ virtio_dev_rx_queue_setup_finish(struct
>> rte_eth_dev *dev, uint16_t queue_idx)
>> error =
>> virtqueue_enqueue_recv_refill_packed(vq,
>> &m, 1);
>> else
>> - error = virtqueue_enqueue_recv_refill(vq,
>> m);
>> + error = virtqueue_enqueue_recv_refill(vq,
>> + &m, 1);
>> if (error) {
>> rte_pktmbuf_free(m);
>> break;
>> @@ -991,7 +995,7 @@ virtio_discard_rxbuf(struct virtqueue *vq, struct
>> rte_mbuf *m)
>> if (vtpci_packed_queue(vq->hw))
>> error = virtqueue_enqueue_recv_refill_packed(vq, &m, 1);
>> else
>> - error = virtqueue_enqueue_recv_refill(vq, m);
>> + error = virtqueue_enqueue_recv_refill(vq, &m, 1);
>>
>> if (unlikely(error)) {
>> RTE_LOG(ERR, PMD, "cannot requeue discarded mbuf");
>> @@ -1211,7 +1215,7 @@ virtio_recv_pkts(void *rx_queue, struct rte_mbuf
>> **rx_pkts, uint16_t nb_pkts)
>> dev->data->rx_mbuf_alloc_failed++;
>> break;
>> }
>> - error = virtqueue_enqueue_recv_refill(vq, new_mbuf);
>> + error = virtqueue_enqueue_recv_refill(vq, &new_mbuf, 1);
>> if (unlikely(error)) {
>> rte_pktmbuf_free(new_mbuf);
>> break;
>> @@ -1528,19 +1532,18 @@ virtio_recv_mergeable_pkts(void *rx_queue,
>> struct virtnet_rx *rxvq = rx_queue;
>> struct virtqueue *vq = rxvq->vq;
>> struct virtio_hw *hw = vq->hw;
>> - struct rte_mbuf *rxm, *new_mbuf;
>> - uint16_t nb_used, num, nb_rx;
>> + struct rte_mbuf *rxm;
>> + struct rte_mbuf *prev;
>> + uint16_t nb_used, num, nb_rx = 0;
>> uint32_t len[VIRTIO_MBUF_BURST_SZ];
>> struct rte_mbuf *rcv_pkts[VIRTIO_MBUF_BURST_SZ];
>> - struct rte_mbuf *prev;
>> int error;
>> - uint32_t i, nb_enqueued;
>> - uint32_t seg_num;
>> - uint16_t extra_idx;
>> - uint32_t seg_res;
>> - uint32_t hdr_size;
>> + uint32_t nb_enqueued = 0;
>> + uint32_t seg_num = 0;
>> + uint32_t seg_res = 0;
>> + uint32_t hdr_size = hw->vtnet_hdr_size;
>> + int32_t i;
>>
>> - nb_rx = 0;
>> if (unlikely(hw->started == 0))
>> return nb_rx;
>>
>> @@ -1550,31 +1553,25 @@ virtio_recv_mergeable_pkts(void *rx_queue,
>>
>> PMD_RX_LOG(DEBUG, "used:%d", nb_used);
>>
>> - i = 0;
>> - nb_enqueued = 0;
>> - seg_num = 0;
>> - extra_idx = 0;
>> - seg_res = 0;
>> - hdr_size = hw->vtnet_hdr_size;
>> -
>> - while (i < nb_used) {
>> - struct virtio_net_hdr_mrg_rxbuf *header;
>> + num = likely(nb_used <= nb_pkts) ? nb_used : nb_pkts;
>> + if (unlikely(num > VIRTIO_MBUF_BURST_SZ))
>> + num = VIRTIO_MBUF_BURST_SZ;
>> + if (likely(num > DESC_PER_CACHELINE))
>> + num = num - ((vq->vq_used_cons_idx + num) %
>> + DESC_PER_CACHELINE);
>>
>> - if (nb_rx == nb_pkts)
>> - break;
>>
>> - num = virtqueue_dequeue_burst_rx(vq, rcv_pkts, len, 1);
>> - if (num != 1)
>> - continue;
>> + num = virtqueue_dequeue_burst_rx(vq, rcv_pkts, len, num);
>>
>> - i++;
>> + for (i = 0; i < num; i++) {
>> + struct virtio_net_hdr_mrg_rxbuf *header;
>>
>> PMD_RX_LOG(DEBUG, "dequeue:%d", num);
>> - PMD_RX_LOG(DEBUG, "packet len:%d", len[0]);
>> + PMD_RX_LOG(DEBUG, "packet len:%d", len[i]);
>>
>> - rxm = rcv_pkts[0];
>> + rxm = rcv_pkts[i];
>>
>> - if (unlikely(len[0] < hdr_size + ETHER_HDR_LEN)) {
>> + if (unlikely(len[i] < hdr_size + ETHER_HDR_LEN)) {
>> PMD_RX_LOG(ERR, "Packet drop");
>> nb_enqueued++;
>> virtio_discard_rxbuf(vq, rxm);
>> @@ -1582,10 +1579,10 @@ virtio_recv_mergeable_pkts(void *rx_queue,
>> continue;
>> }
>>
>> - header = (struct virtio_net_hdr_mrg_rxbuf *)((char *)rxm-
>>> buf_addr +
>> - RTE_PKTMBUF_HEADROOM - hdr_size);
>> + header = (struct virtio_net_hdr_mrg_rxbuf *)
>> + ((char *)rxm->buf_addr +
>> RTE_PKTMBUF_HEADROOM
>> + - hdr_size);
>> seg_num = header->num_buffers;
>> -
>> if (seg_num == 0)
>> seg_num = 1;
>>
>> @@ -1593,10 +1590,11 @@ virtio_recv_mergeable_pkts(void *rx_queue,
>> rxm->nb_segs = seg_num;
>> rxm->ol_flags = 0;
>> rxm->vlan_tci = 0;
>> - rxm->pkt_len = (uint32_t)(len[0] - hdr_size);
>> - rxm->data_len = (uint16_t)(len[0] - hdr_size);
>> + rxm->pkt_len = (uint32_t)(len[i] - hdr_size);
>> + rxm->data_len = (uint16_t)(len[i] - hdr_size);
>>
>> rxm->port = rxvq->port_id;
>> +
>> rx_pkts[nb_rx] = rxm;
>> prev = rxm;
>>
>> @@ -1607,75 +1605,96 @@ virtio_recv_mergeable_pkts(void *rx_queue,
>> continue;
>> }
>>
>> + if (hw->vlan_strip)
>> + rte_vlan_strip(rx_pkts[nb_rx]);
>> +
>> seg_res = seg_num - 1;
>>
>> - while (seg_res != 0) {
>> - /*
>> - * Get extra segments for current uncompleted
>> packet.
>> - */
>> - uint16_t rcv_cnt =
>> - RTE_MIN(seg_res, RTE_DIM(rcv_pkts));
>> - if (likely(VIRTQUEUE_NUSED(vq) >= rcv_cnt)) {
>> - uint32_t rx_num =
>> - virtqueue_dequeue_burst_rx(vq,
>> - rcv_pkts, len, rcv_cnt);
>> - i += rx_num;
>> - rcv_cnt = rx_num;
>> - } else {
>> - PMD_RX_LOG(ERR,
>> - "No enough segments for
>> packet.");
>> - nb_enqueued++;
>> - virtio_discard_rxbuf(vq, rxm);
>> - rxvq->stats.errors++;
>> - break;
>> - }
>> + /* Merge remaining segments */
>> + while (seg_res != 0 && i < (num - 1)) {
>> + i++;
>> +
>> + rxm = rcv_pkts[i];
>> + rxm->data_off = RTE_PKTMBUF_HEADROOM -
>> hdr_size;
>> + rxm->pkt_len = (uint32_t)(len[i]);
>> + rxm->data_len = (uint16_t)(len[i]);
>> +
>> + rx_pkts[nb_rx]->pkt_len += (uint32_t)(len[i]);
>> + rx_pkts[nb_rx]->data_len += (uint16_t)(len[i]);
>> +
>> + if (prev)
>> + prev->next = rxm;
>> +
>> + prev = rxm;
>> + seg_res -= 1;
>> + }
>> +
>> + if (!seg_res) {
>> + virtio_rx_stats_updated(rxvq, rx_pkts[nb_rx]);
>> + nb_rx++;
>> + }
>> + }
>> +
>> + /* Last packet still need merge segments */
>> + while (seg_res != 0) {
>> + uint16_t rcv_cnt = RTE_MIN((uint16_t)seg_res,
>> + VIRTIO_MBUF_BURST_SZ);
>>
>> - extra_idx = 0;
>> + prev = rcv_pkts[nb_rx];
>> + if (likely(VIRTQUEUE_NUSED(vq) >= rcv_cnt)) {
>> + num = virtqueue_dequeue_burst_rx(vq, rcv_pkts,
>> len,
>> + rcv_cnt);
>> + uint16_t extra_idx = 0;
>>
>> + rcv_cnt = num;
>> while (extra_idx < rcv_cnt) {
>> rxm = rcv_pkts[extra_idx];
>> -
>> - rxm->data_off =
>> RTE_PKTMBUF_HEADROOM - hdr_size;
>> + rxm->data_off =
>> + RTE_PKTMBUF_HEADROOM -
>> hdr_size;
>> rxm->pkt_len = (uint32_t)(len[extra_idx]);
>> rxm->data_len = (uint16_t)(len[extra_idx]);
>> -
>> - if (prev)
>> - prev->next = rxm;
>> -
>> + prev->next = rxm;
>> prev = rxm;
>> - rx_pkts[nb_rx]->pkt_len += rxm->pkt_len;
>> - extra_idx++;
>> + rx_pkts[nb_rx]->pkt_len += len[extra_idx];
>> + rx_pkts[nb_rx]->data_len += len[extra_idx];
>> + extra_idx += 1;
>> };
>> seg_res -= rcv_cnt;
>> - }
>> -
>> - if (hw->vlan_strip)
>> - rte_vlan_strip(rx_pkts[nb_rx]);
>> -
>> - VIRTIO_DUMP_PACKET(rx_pkts[nb_rx],
>> - rx_pkts[nb_rx]->data_len);
>>
>> - virtio_update_packet_stats(&rxvq->stats, rx_pkts[nb_rx]);
>> - nb_rx++;
>> + if (!seg_res) {
>> + virtio_rx_stats_updated(rxvq,
>> rx_pkts[nb_rx]);
>> + nb_rx++;
>> + }
>> + } else {
>> + PMD_RX_LOG(ERR,
>> + "No enough segments for packet.");
>> + virtio_discard_rxbuf(vq, prev);
>> + rxvq->stats.errors++;
>> + break;
>> + }
>> }
>>
>> rxvq->stats.packets += nb_rx;
>>
>> /* Allocate new mbuf for the used descriptor */
>> - while (likely(!virtqueue_full(vq))) {
>> - new_mbuf = rte_mbuf_raw_alloc(rxvq->mpool);
>> - if (unlikely(new_mbuf == NULL)) {
>> - struct rte_eth_dev *dev
>> - = &rte_eth_devices[rxvq->port_id];
>> - dev->data->rx_mbuf_alloc_failed++;
>> - break;
>> - }
>> - error = virtqueue_enqueue_recv_refill(vq, new_mbuf);
>> - if (unlikely(error)) {
>> - rte_pktmbuf_free(new_mbuf);
>> - break;
>> + if (likely(!virtqueue_full(vq))) {
>> + /* free_cnt may include mrg descs */
>> + uint16_t free_cnt = vq->vq_free_cnt;
>> + struct rte_mbuf *new_pkts[free_cnt];
>> +
>> + if (!rte_pktmbuf_alloc_bulk(rxvq->mpool, new_pkts,
>> free_cnt)) {
>> + error = virtqueue_enqueue_recv_refill(vq, new_pkts,
>> + free_cnt);
>> + if (unlikely(error)) {
>> + for (i = 0; i < free_cnt; i++)
>> + rte_pktmbuf_free(new_pkts[i]);
> Missing error handling here? the execution keeps going on without the mbufs?
That's fine because if we get an error here, no descriptors were
inserted in the avail queue.
nb_enqueue is just used to know whether we should notify host descs are
available. I can set free_cnt to 0 in the error path though, so that
host isn't notified for nothing but that's not a big deal, really.
Thanks!
Maxime
> /Gavin
>
>> + }
>> + nb_enqueued += free_cnt;
>> + } else {
>> + struct rte_eth_dev *dev =
>> + &rte_eth_devices[rxvq->port_id];
>> + dev->data->rx_mbuf_alloc_failed += free_cnt;
>> }
>> - nb_enqueued++;
>> }
>>
>> if (likely(nb_enqueued)) {
>> --
>> 2.17.2
>
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [dpdk-dev] [PATCH v3 3/3] net/virtio: improve batching in mergeable path
2018-12-21 8:36 ` Maxime Coquelin
@ 2018-12-21 8:41 ` Gavin Hu (Arm Technology China)
0 siblings, 0 replies; 8+ messages in thread
From: Gavin Hu (Arm Technology China) @ 2018-12-21 8:41 UTC (permalink / raw)
To: Maxime Coquelin, dev, jfreimann, tiwei.bie, zhihong.wang; +Cc: nd, nd
> -----Original Message-----
> From: Maxime Coquelin <maxime.coquelin@redhat.com>
> Sent: Friday, December 21, 2018 4:36 PM
> To: Gavin Hu (Arm Technology China) <Gavin.Hu@arm.com>;
> dev@dpdk.org; jfreimann@redhat.com; tiwei.bie@intel.com;
> zhihong.wang@intel.com
> Cc: nd <nd@arm.com>
> Subject: Re: [dpdk-dev] [PATCH v3 3/3] net/virtio: improve batching in
> mergeable path
>
>
>
> On 12/21/18 7:27 AM, Gavin Hu (Arm Technology China) wrote:
> >
> >
> >> -----Original Message-----
> >> From: dev <dev-bounces@dpdk.org> On Behalf Of Maxime Coquelin
> >> Sent: Friday, December 21, 2018 1:27 AM
> >> To: dev@dpdk.org; jfreimann@redhat.com; tiwei.bie@intel.com;
> >> zhihong.wang@intel.com
> >> Cc: Maxime Coquelin <maxime.coquelin@redhat.com>
> >> Subject: [dpdk-dev] [PATCH v3 3/3] net/virtio: improve batching in
> >> mergeable path
> >>
> >> This patch improves both descriptors dequeue and refill,
> >> by using the same batching strategy as done in in-order path.
> >>
> >> Signed-off-by: Maxime Coquelin <maxime.coquelin@redhat.com>
> >> Tested-by: Jens Freimann <jfreimann@redhat.com>
> >> Reviewed-by: Jens Freimann <jfreimann@redhat.com>
> >> ---
> >> drivers/net/virtio/virtio_rxtx.c | 239 +++++++++++++++++--------------
> >> 1 file changed, 129 insertions(+), 110 deletions(-)
> >>
> >> diff --git a/drivers/net/virtio/virtio_rxtx.c
> b/drivers/net/virtio/virtio_rxtx.c
> >> index 58376ced3..1cfa2f0d6 100644
> >> --- a/drivers/net/virtio/virtio_rxtx.c
> >> +++ b/drivers/net/virtio/virtio_rxtx.c
> >> @@ -353,41 +353,44 @@ virtqueue_enqueue_refill_inorder(struct
> >> virtqueue *vq,
> >> }
> >>
> >> static inline int
> >> -virtqueue_enqueue_recv_refill(struct virtqueue *vq, struct rte_mbuf
> >> *cookie)
> >> +virtqueue_enqueue_recv_refill(struct virtqueue *vq, struct rte_mbuf
> >> **cookie,
> >> + uint16_t num)
> >> {
> >> struct vq_desc_extra *dxp;
> >> struct virtio_hw *hw = vq->hw;
> >> - struct vring_desc *start_dp;
> >> - uint16_t needed = 1;
> >> - uint16_t head_idx, idx;
> >> + struct vring_desc *start_dp = vq->vq_ring.desc;
> >> + uint16_t idx, i;
> >>
> >> if (unlikely(vq->vq_free_cnt == 0))
> >> return -ENOSPC;
> >> - if (unlikely(vq->vq_free_cnt < needed))
> >> + if (unlikely(vq->vq_free_cnt < num))
> >> return -EMSGSIZE;
> >>
> >> - head_idx = vq->vq_desc_head_idx;
> >> - if (unlikely(head_idx >= vq->vq_nentries))
> >> + if (unlikely(vq->vq_desc_head_idx >= vq->vq_nentries))
> >> return -EFAULT;
> >>
> >> - idx = head_idx;
> >> - dxp = &vq->vq_descx[idx];
> >> - dxp->cookie = (void *)cookie;
> >> - dxp->ndescs = needed;
> >> + for (i = 0; i < num; i++) {
> >> + idx = vq->vq_desc_head_idx;
> >> + dxp = &vq->vq_descx[idx];
> >> + dxp->cookie = (void *)cookie[i];
> >> + dxp->ndescs = 1;
> >>
> >> - start_dp = vq->vq_ring.desc;
> >> - start_dp[idx].addr =
> >> - VIRTIO_MBUF_ADDR(cookie, vq) +
> >> - RTE_PKTMBUF_HEADROOM - hw->vtnet_hdr_size;
> >> - start_dp[idx].len =
> >> - cookie->buf_len - RTE_PKTMBUF_HEADROOM + hw-
> >>> vtnet_hdr_size;
> >> - start_dp[idx].flags = VRING_DESC_F_WRITE;
> >> - idx = start_dp[idx].next;
> >> - vq->vq_desc_head_idx = idx;
> >> - if (vq->vq_desc_head_idx == VQ_RING_DESC_CHAIN_END)
> >> - vq->vq_desc_tail_idx = idx;
> >> - vq->vq_free_cnt = (uint16_t)(vq->vq_free_cnt - needed);
> >> - vq_update_avail_ring(vq, head_idx);
> >> + start_dp[idx].addr =
> >> + VIRTIO_MBUF_ADDR(cookie[i], vq) +
> >> + RTE_PKTMBUF_HEADROOM - hw->vtnet_hdr_size;
> >> + start_dp[idx].len =
> >> + cookie[i]->buf_len - RTE_PKTMBUF_HEADROOM +
> >> + hw->vtnet_hdr_size;
> >> + start_dp[idx].flags = VRING_DESC_F_WRITE;
> >> + vq->vq_desc_head_idx = start_dp[idx].next;
> >> + vq_update_avail_ring(vq, idx);
> >> + if (vq->vq_desc_head_idx == VQ_RING_DESC_CHAIN_END)
> >> {
> >> + vq->vq_desc_tail_idx = vq->vq_desc_head_idx;
> >> + break;
> >> + }
> >> + }
> >> +
> >> + vq->vq_free_cnt = (uint16_t)(vq->vq_free_cnt - num);
> >>
> >> return 0;
> >> }
> >> @@ -892,7 +895,8 @@ virtio_dev_rx_queue_setup_finish(struct
> >> rte_eth_dev *dev, uint16_t queue_idx)
> >> error =
> >> virtqueue_enqueue_recv_refill_packed(vq,
> >> &m, 1);
> >> else
> >> - error = virtqueue_enqueue_recv_refill(vq,
> >> m);
> >> + error = virtqueue_enqueue_recv_refill(vq,
> >> + &m, 1);
> >> if (error) {
> >> rte_pktmbuf_free(m);
> >> break;
> >> @@ -991,7 +995,7 @@ virtio_discard_rxbuf(struct virtqueue *vq, struct
> >> rte_mbuf *m)
> >> if (vtpci_packed_queue(vq->hw))
> >> error = virtqueue_enqueue_recv_refill_packed(vq, &m, 1);
> >> else
> >> - error = virtqueue_enqueue_recv_refill(vq, m);
> >> + error = virtqueue_enqueue_recv_refill(vq, &m, 1);
> >>
> >> if (unlikely(error)) {
> >> RTE_LOG(ERR, PMD, "cannot requeue discarded mbuf");
> >> @@ -1211,7 +1215,7 @@ virtio_recv_pkts(void *rx_queue, struct
> rte_mbuf
> >> **rx_pkts, uint16_t nb_pkts)
> >> dev->data->rx_mbuf_alloc_failed++;
> >> break;
> >> }
> >> - error = virtqueue_enqueue_recv_refill(vq, new_mbuf);
> >> + error = virtqueue_enqueue_recv_refill(vq, &new_mbuf, 1);
> >> if (unlikely(error)) {
> >> rte_pktmbuf_free(new_mbuf);
> >> break;
> >> @@ -1528,19 +1532,18 @@ virtio_recv_mergeable_pkts(void
> *rx_queue,
> >> struct virtnet_rx *rxvq = rx_queue;
> >> struct virtqueue *vq = rxvq->vq;
> >> struct virtio_hw *hw = vq->hw;
> >> - struct rte_mbuf *rxm, *new_mbuf;
> >> - uint16_t nb_used, num, nb_rx;
> >> + struct rte_mbuf *rxm;
> >> + struct rte_mbuf *prev;
> >> + uint16_t nb_used, num, nb_rx = 0;
> >> uint32_t len[VIRTIO_MBUF_BURST_SZ];
> >> struct rte_mbuf *rcv_pkts[VIRTIO_MBUF_BURST_SZ];
> >> - struct rte_mbuf *prev;
> >> int error;
> >> - uint32_t i, nb_enqueued;
> >> - uint32_t seg_num;
> >> - uint16_t extra_idx;
> >> - uint32_t seg_res;
> >> - uint32_t hdr_size;
> >> + uint32_t nb_enqueued = 0;
> >> + uint32_t seg_num = 0;
> >> + uint32_t seg_res = 0;
> >> + uint32_t hdr_size = hw->vtnet_hdr_size;
> >> + int32_t i;
> >>
> >> - nb_rx = 0;
> >> if (unlikely(hw->started == 0))
> >> return nb_rx;
> >>
> >> @@ -1550,31 +1553,25 @@ virtio_recv_mergeable_pkts(void
> *rx_queue,
> >>
> >> PMD_RX_LOG(DEBUG, "used:%d", nb_used);
> >>
> >> - i = 0;
> >> - nb_enqueued = 0;
> >> - seg_num = 0;
> >> - extra_idx = 0;
> >> - seg_res = 0;
> >> - hdr_size = hw->vtnet_hdr_size;
> >> -
> >> - while (i < nb_used) {
> >> - struct virtio_net_hdr_mrg_rxbuf *header;
> >> + num = likely(nb_used <= nb_pkts) ? nb_used : nb_pkts;
> >> + if (unlikely(num > VIRTIO_MBUF_BURST_SZ))
> >> + num = VIRTIO_MBUF_BURST_SZ;
> >> + if (likely(num > DESC_PER_CACHELINE))
> >> + num = num - ((vq->vq_used_cons_idx + num) %
> >> + DESC_PER_CACHELINE);
> >>
> >> - if (nb_rx == nb_pkts)
> >> - break;
> >>
> >> - num = virtqueue_dequeue_burst_rx(vq, rcv_pkts, len, 1);
> >> - if (num != 1)
> >> - continue;
> >> + num = virtqueue_dequeue_burst_rx(vq, rcv_pkts, len, num);
> >>
> >> - i++;
> >> + for (i = 0; i < num; i++) {
> >> + struct virtio_net_hdr_mrg_rxbuf *header;
> >>
> >> PMD_RX_LOG(DEBUG, "dequeue:%d", num);
> >> - PMD_RX_LOG(DEBUG, "packet len:%d", len[0]);
> >> + PMD_RX_LOG(DEBUG, "packet len:%d", len[i]);
> >>
> >> - rxm = rcv_pkts[0];
> >> + rxm = rcv_pkts[i];
> >>
> >> - if (unlikely(len[0] < hdr_size + ETHER_HDR_LEN)) {
> >> + if (unlikely(len[i] < hdr_size + ETHER_HDR_LEN)) {
> >> PMD_RX_LOG(ERR, "Packet drop");
> >> nb_enqueued++;
> >> virtio_discard_rxbuf(vq, rxm);
> >> @@ -1582,10 +1579,10 @@ virtio_recv_mergeable_pkts(void
> *rx_queue,
> >> continue;
> >> }
> >>
> >> - header = (struct virtio_net_hdr_mrg_rxbuf *)((char *)rxm-
> >>> buf_addr +
> >> - RTE_PKTMBUF_HEADROOM - hdr_size);
> >> + header = (struct virtio_net_hdr_mrg_rxbuf *)
> >> + ((char *)rxm->buf_addr +
> >> RTE_PKTMBUF_HEADROOM
> >> + - hdr_size);
> >> seg_num = header->num_buffers;
> >> -
> >> if (seg_num == 0)
> >> seg_num = 1;
> >>
> >> @@ -1593,10 +1590,11 @@ virtio_recv_mergeable_pkts(void
> *rx_queue,
> >> rxm->nb_segs = seg_num;
> >> rxm->ol_flags = 0;
> >> rxm->vlan_tci = 0;
> >> - rxm->pkt_len = (uint32_t)(len[0] - hdr_size);
> >> - rxm->data_len = (uint16_t)(len[0] - hdr_size);
> >> + rxm->pkt_len = (uint32_t)(len[i] - hdr_size);
> >> + rxm->data_len = (uint16_t)(len[i] - hdr_size);
> >>
> >> rxm->port = rxvq->port_id;
> >> +
> >> rx_pkts[nb_rx] = rxm;
> >> prev = rxm;
> >>
> >> @@ -1607,75 +1605,96 @@ virtio_recv_mergeable_pkts(void
> *rx_queue,
> >> continue;
> >> }
> >>
> >> + if (hw->vlan_strip)
> >> + rte_vlan_strip(rx_pkts[nb_rx]);
> >> +
> >> seg_res = seg_num - 1;
> >>
> >> - while (seg_res != 0) {
> >> - /*
> >> - * Get extra segments for current uncompleted
> >> packet.
> >> - */
> >> - uint16_t rcv_cnt =
> >> - RTE_MIN(seg_res, RTE_DIM(rcv_pkts));
> >> - if (likely(VIRTQUEUE_NUSED(vq) >= rcv_cnt)) {
> >> - uint32_t rx_num =
> >> - virtqueue_dequeue_burst_rx(vq,
> >> - rcv_pkts, len, rcv_cnt);
> >> - i += rx_num;
> >> - rcv_cnt = rx_num;
> >> - } else {
> >> - PMD_RX_LOG(ERR,
> >> - "No enough segments for
> >> packet.");
> >> - nb_enqueued++;
> >> - virtio_discard_rxbuf(vq, rxm);
> >> - rxvq->stats.errors++;
> >> - break;
> >> - }
> >> + /* Merge remaining segments */
> >> + while (seg_res != 0 && i < (num - 1)) {
> >> + i++;
> >> +
> >> + rxm = rcv_pkts[i];
> >> + rxm->data_off = RTE_PKTMBUF_HEADROOM -
> >> hdr_size;
> >> + rxm->pkt_len = (uint32_t)(len[i]);
> >> + rxm->data_len = (uint16_t)(len[i]);
> >> +
> >> + rx_pkts[nb_rx]->pkt_len += (uint32_t)(len[i]);
> >> + rx_pkts[nb_rx]->data_len += (uint16_t)(len[i]);
> >> +
> >> + if (prev)
> >> + prev->next = rxm;
> >> +
> >> + prev = rxm;
> >> + seg_res -= 1;
> >> + }
> >> +
> >> + if (!seg_res) {
> >> + virtio_rx_stats_updated(rxvq, rx_pkts[nb_rx]);
> >> + nb_rx++;
> >> + }
> >> + }
> >> +
> >> + /* Last packet still need merge segments */
> >> + while (seg_res != 0) {
> >> + uint16_t rcv_cnt = RTE_MIN((uint16_t)seg_res,
> >> + VIRTIO_MBUF_BURST_SZ);
> >>
> >> - extra_idx = 0;
> >> + prev = rcv_pkts[nb_rx];
> >> + if (likely(VIRTQUEUE_NUSED(vq) >= rcv_cnt)) {
> >> + num = virtqueue_dequeue_burst_rx(vq, rcv_pkts,
> >> len,
> >> + rcv_cnt);
> >> + uint16_t extra_idx = 0;
> >>
> >> + rcv_cnt = num;
> >> while (extra_idx < rcv_cnt) {
> >> rxm = rcv_pkts[extra_idx];
> >> -
> >> - rxm->data_off =
> >> RTE_PKTMBUF_HEADROOM - hdr_size;
> >> + rxm->data_off =
> >> + RTE_PKTMBUF_HEADROOM -
> >> hdr_size;
> >> rxm->pkt_len = (uint32_t)(len[extra_idx]);
> >> rxm->data_len = (uint16_t)(len[extra_idx]);
> >> -
> >> - if (prev)
> >> - prev->next = rxm;
> >> -
> >> + prev->next = rxm;
> >> prev = rxm;
> >> - rx_pkts[nb_rx]->pkt_len += rxm->pkt_len;
> >> - extra_idx++;
> >> + rx_pkts[nb_rx]->pkt_len += len[extra_idx];
> >> + rx_pkts[nb_rx]->data_len += len[extra_idx];
> >> + extra_idx += 1;
> >> };
> >> seg_res -= rcv_cnt;
> >> - }
> >> -
> >> - if (hw->vlan_strip)
> >> - rte_vlan_strip(rx_pkts[nb_rx]);
> >> -
> >> - VIRTIO_DUMP_PACKET(rx_pkts[nb_rx],
> >> - rx_pkts[nb_rx]->data_len);
> >>
> >> - virtio_update_packet_stats(&rxvq->stats, rx_pkts[nb_rx]);
> >> - nb_rx++;
> >> + if (!seg_res) {
> >> + virtio_rx_stats_updated(rxvq,
> >> rx_pkts[nb_rx]);
> >> + nb_rx++;
> >> + }
> >> + } else {
> >> + PMD_RX_LOG(ERR,
> >> + "No enough segments for packet.");
> >> + virtio_discard_rxbuf(vq, prev);
> >> + rxvq->stats.errors++;
> >> + break;
> >> + }
> >> }
> >>
> >> rxvq->stats.packets += nb_rx;
> >>
> >> /* Allocate new mbuf for the used descriptor */
> >> - while (likely(!virtqueue_full(vq))) {
> >> - new_mbuf = rte_mbuf_raw_alloc(rxvq->mpool);
> >> - if (unlikely(new_mbuf == NULL)) {
> >> - struct rte_eth_dev *dev
> >> - = &rte_eth_devices[rxvq->port_id];
> >> - dev->data->rx_mbuf_alloc_failed++;
> >> - break;
> >> - }
> >> - error = virtqueue_enqueue_recv_refill(vq, new_mbuf);
> >> - if (unlikely(error)) {
> >> - rte_pktmbuf_free(new_mbuf);
> >> - break;
> >> + if (likely(!virtqueue_full(vq))) {
> >> + /* free_cnt may include mrg descs */
> >> + uint16_t free_cnt = vq->vq_free_cnt;
> >> + struct rte_mbuf *new_pkts[free_cnt];
> >> +
> >> + if (!rte_pktmbuf_alloc_bulk(rxvq->mpool, new_pkts,
> >> free_cnt)) {
> >> + error = virtqueue_enqueue_recv_refill(vq, new_pkts,
> >> + free_cnt);
> >> + if (unlikely(error)) {
> >> + for (i = 0; i < free_cnt; i++)
> >> + rte_pktmbuf_free(new_pkts[i]);
> > Missing error handling here? the execution keeps going on without the
> mbufs?
>
> That's fine because if we get an error here, no descriptors were
> inserted in the avail queue.
>
> nb_enqueue is just used to know whether we should notify host descs are
> available. I can set free_cnt to 0 in the error path though, so that
> host isn't notified for nothing but that's not a big deal, really.
>
> Thanks!
> Maxime
>
> > /Gavin
> >
> >> + }
> >> + nb_enqueued += free_cnt;
> >> + } else {
> >> + struct rte_eth_dev *dev =
> >> + &rte_eth_devices[rxvq->port_id];
> >> + dev->data->rx_mbuf_alloc_failed += free_cnt;
> >> }
> >> - nb_enqueued++;
> >> }
> >>
> >> if (likely(nb_enqueued)) {
> >> --
> >> 2.17.2
> >
Thanks for explanation, then
Reviewed-by: Gavin Hu <gavin.hu@arm.com>
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [dpdk-dev] [PATCH v3 0/3] net/virtio: Rx paths improvements
2018-12-20 17:27 [dpdk-dev] [PATCH v3 0/3] net/virtio: Rx paths improvements Maxime Coquelin
` (2 preceding siblings ...)
2018-12-20 17:27 ` [dpdk-dev] [PATCH v3 3/3] net/virtio: improve batching in mergeable path Maxime Coquelin
@ 2018-12-21 9:20 ` Maxime Coquelin
3 siblings, 0 replies; 8+ messages in thread
From: Maxime Coquelin @ 2018-12-21 9:20 UTC (permalink / raw)
To: dev, jfreimann, tiwei.bie, zhihong.wang
On 12/20/18 6:27 PM, Maxime Coquelin wrote:
> First version of this series did merge out-of-order mergeable
> and non-mergeable receive paths, but Intel STV team highlighted
> some performance regression when using multiqueue with two cores
> enqueueing descs on host, while a single core dequeues the
> two queues.
>
> I didn't manage to close the performance gap, so I decided to
> give-up this refactoring. But while trying to optimize, I reworked
> the meargeable function so that it looks like the in-order one.
> I.e. descriptors are now dequeued in batches, so are descriptors
> refilled. Doing that, I measure a perfromance gain of 6% when doing
> rxonly microbenchmark with two cores on host, one in guest.
>
>
> Changes since v2:
> - Rebase after Jens' packed ring series
> - Break refill loop if VQ_RING_DESC_CHAIN_END (Tiwei)
> - Fixup commit message
>
> Maxime Coquelin (3):
> net/virtio: inline refill and offload helpers
> net/virtio: add non-mergeable support to in-order path
> net/virtio: improve batching in mergeable path
>
> drivers/net/virtio/virtio_ethdev.c | 14 +-
> drivers/net/virtio/virtio_ethdev.h | 2 +-
> drivers/net/virtio/virtio_rxtx.c | 257 ++++++++++++++++-------------
> 3 files changed, 145 insertions(+), 128 deletions(-)
>
Applied to dpdk-next-virtio
Maxime
^ permalink raw reply [flat|nested] 8+ messages in thread
end of thread, other threads:[~2018-12-21 9:20 UTC | newest]
Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-12-20 17:27 [dpdk-dev] [PATCH v3 0/3] net/virtio: Rx paths improvements Maxime Coquelin
2018-12-20 17:27 ` [dpdk-dev] [PATCH v3 1/3] net/virtio: inline refill and offload helpers Maxime Coquelin
2018-12-20 17:27 ` [dpdk-dev] [PATCH v3 2/3] net/virtio: add non-mergeable support to in-order path Maxime Coquelin
2018-12-20 17:27 ` [dpdk-dev] [PATCH v3 3/3] net/virtio: improve batching in mergeable path Maxime Coquelin
2018-12-21 6:27 ` Gavin Hu (Arm Technology China)
2018-12-21 8:36 ` Maxime Coquelin
2018-12-21 8:41 ` Gavin Hu (Arm Technology China)
2018-12-21 9:20 ` [dpdk-dev] [PATCH v3 0/3] net/virtio: Rx paths improvements Maxime Coquelin
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).