From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mails.dpdk.org (mails.dpdk.org [217.70.189.124]) by inbox.dpdk.org (Postfix) with ESMTP id 2CBC7A09FF; Mon, 11 Jan 2021 15:25:23 +0100 (CET) Received: from [217.70.189.124] (localhost [127.0.0.1]) by mails.dpdk.org (Postfix) with ESMTP id B3C49140D62; Mon, 11 Jan 2021 15:25:22 +0100 (CET) Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [216.205.24.124]) by mails.dpdk.org (Postfix) with ESMTP id C1FE8140D47 for ; Mon, 11 Jan 2021 15:25:21 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1610375121; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=JRnGchNCVposDYspAPyjr2I9KE8LUJVRTcj+EYInNmI=; b=Nc8cUy/o+ntf2ni8wWRqbCN7v/dND7X1Toyrwya0SdQbXYDKz6AA53HK1j8VxfWSJAd3+r lEwAatSBfVfSfMgF2J5DOE+qBBJ1uRhViWkxa3DsF5dWMzdv6x6ffG0rp1JxpsOSpiMKg7 8X4H5SJm0H9dJxVUhGhlUSwop+UDOV4= Received: from mimecast-mx01.redhat.com (mimecast-mx01.redhat.com [209.132.183.4]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-307-jYLwJt-aNZur5AFjV_qIGw-1; Mon, 11 Jan 2021 09:25:19 -0500 X-MC-Unique: jYLwJt-aNZur5AFjV_qIGw-1 Received: from smtp.corp.redhat.com (int-mx08.intmail.prod.int.phx2.redhat.com [10.5.11.23]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx01.redhat.com (Postfix) with ESMTPS id 2F3B7802B53; Mon, 11 Jan 2021 14:25:18 +0000 (UTC) Received: from [10.36.110.24] (unknown [10.36.110.24]) by smtp.corp.redhat.com (Postfix) with ESMTPS id 6B1571975E; Mon, 11 Jan 2021 14:25:16 +0000 (UTC) To: Cheng Jiang , chenbo.xia@intel.com Cc: dev@dpdk.org, Jiayu.Hu@intel.com, YvonneX.Yang@intel.com, yinan.wang@intel.com References: <20201218113327.70528-1-Cheng1.jiang@intel.com> <20210111055252.35672-1-Cheng1.jiang@intel.com> <20210111055252.35672-3-Cheng1.jiang@intel.com> From: Maxime Coquelin Message-ID: <2ba7e5df-1c75-dba3-5f51-9b154658bd08@redhat.com> Date: Mon, 11 Jan 2021 15:25:14 +0100 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:78.0) Gecko/20100101 Thunderbird/78.6.0 MIME-Version: 1.0 In-Reply-To: <20210111055252.35672-3-Cheng1.jiang@intel.com> X-Scanned-By: MIMEDefang 2.84 on 10.5.11.23 Authentication-Results: relay.mimecast.com; auth=pass smtp.auth=CUSA124A263 smtp.mailfrom=maxime.coquelin@redhat.com X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Content-Type: text/plain; charset=utf-8 Content-Language: en-US Content-Transfer-Encoding: 7bit Subject: Re: [dpdk-dev] [PATCH v8 2/2] examples/vhost: refactor vhost data path X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org Sender: "dev" On 1/11/21 6:52 AM, Cheng Jiang wrote: > Change the vm2vm data path to batch enqueue for better performance. > Support latest async vhost API, refactor vhost async data path, > replace rte_atomicNN_xxx to atomic_XXX and clean some codes. Wouldn't it be better to use GCC/Clang C11 atmoic built-ins like all other code is being migrated to it? (i.e. __atomic_XXX) > Signed-off-by: Cheng Jiang > Reviewed-by: Jiayu Hu > --- > examples/vhost/ioat.h | 2 +- > examples/vhost/main.c | 226 ++++++++++++++++++++++++++++++------------ > examples/vhost/main.h | 7 +- > 3 files changed, 168 insertions(+), 67 deletions(-) > > diff --git a/examples/vhost/ioat.h b/examples/vhost/ioat.h > index d6e1e2e07..0a1dbb811 100644 > --- a/examples/vhost/ioat.h > +++ b/examples/vhost/ioat.h > @@ -11,7 +11,7 @@ > > #define MAX_VHOST_DEVICE 1024 > #define IOAT_RING_SIZE 4096 > -#define MAX_ENQUEUED_SIZE 256 > +#define MAX_ENQUEUED_SIZE 512 > > struct dma_info { > struct rte_pci_addr addr; > diff --git a/examples/vhost/main.c b/examples/vhost/main.c > index 22309977c..45976c93c 100644 > --- a/examples/vhost/main.c > +++ b/examples/vhost/main.c > @@ -179,9 +179,22 @@ struct mbuf_table { > struct rte_mbuf *m_table[MAX_PKT_BURST]; > }; > > +struct vhost_bufftable { > + uint32_t len; > + uint64_t pre_tsc; > + struct rte_mbuf *m_table[MAX_PKT_BURST]; > +}; > + > /* TX queue for each data core. */ > struct mbuf_table lcore_tx_queue[RTE_MAX_LCORE]; > > +/* > + * Vhost TX buffer for each data core. > + * Every data core maintains a TX buffer for every vhost device, > + * which is used for batch pkts enqueue for higher performance. > + */ > +struct vhost_bufftable *vhost_txbuff[RTE_MAX_LCORE * MAX_VHOST_DEVICE]; > + > #define MBUF_TABLE_DRAIN_TSC ((rte_get_tsc_hz() + US_PER_S - 1) \ > / US_PER_S * BURST_TX_DRAIN_US) > #define VLAN_HLEN 4 > @@ -804,43 +817,112 @@ unlink_vmdq(struct vhost_dev *vdev) > } > } > > +static inline void > +free_pkts(struct rte_mbuf **pkts, uint16_t n) > +{ > + while (n--) > + rte_pktmbuf_free(pkts[n]); > +} > + > static __rte_always_inline void > -virtio_xmit(struct vhost_dev *dst_vdev, struct vhost_dev *src_vdev, > +complete_async_pkts(struct vhost_dev *vdev) > +{ > + struct rte_mbuf *p_cpl[MAX_PKT_BURST]; > + uint16_t complete_count; > + > + complete_count = rte_vhost_poll_enqueue_completed(vdev->vid, > + VIRTIO_RXQ, p_cpl, MAX_PKT_BURST); > + if (complete_count) { > + atomic_fetch_sub(&vdev->nr_async_pkts, complete_count); > + free_pkts(p_cpl, complete_count); > + } > +} > + > +static __rte_always_inline void > +sync_virtio_xmit(struct vhost_dev *dst_vdev, struct vhost_dev *src_vdev, > struct rte_mbuf *m) > { > uint16_t ret; > - struct rte_mbuf *m_cpl[1], *comp_pkt; > - uint32_t nr_comp = 0; > > if (builtin_net_driver) { > ret = vs_enqueue_pkts(dst_vdev, VIRTIO_RXQ, &m, 1); > - } else if (async_vhost_driver) { > - ret = rte_vhost_submit_enqueue_burst(dst_vdev->vid, VIRTIO_RXQ, > - &m, 1, &comp_pkt, &nr_comp); > - if (nr_comp == 1) > - goto done; > - > - if (likely(ret)) > - dst_vdev->nr_async_pkts++; > - > - while (likely(dst_vdev->nr_async_pkts)) { > - if (rte_vhost_poll_enqueue_completed(dst_vdev->vid, > - VIRTIO_RXQ, m_cpl, 1)) > - dst_vdev->nr_async_pkts--; > - } > } else { > ret = rte_vhost_enqueue_burst(dst_vdev->vid, VIRTIO_RXQ, &m, 1); > } > > -done: > if (enable_stats) { > - rte_atomic64_inc(&dst_vdev->stats.rx_total_atomic); > - rte_atomic64_add(&dst_vdev->stats.rx_atomic, ret); > + atomic_fetch_add(&dst_vdev->stats.rx_total_atomic, 1); > + atomic_fetch_add(&dst_vdev->stats.rx_atomic, ret); > src_vdev->stats.tx_total++; > src_vdev->stats.tx += ret; > } > } > > +static __rte_always_inline void > +drain_vhost(struct vhost_dev *vdev) > +{ > + uint16_t ret; > + uint64_t buff_idx = rte_lcore_id() * MAX_VHOST_DEVICE + vdev->vid; > + uint16_t nr_xmit = vhost_txbuff[buff_idx]->len; > + struct rte_mbuf **m = vhost_txbuff[buff_idx]->m_table; > + > + if (builtin_net_driver) { > + ret = vs_enqueue_pkts(vdev, VIRTIO_RXQ, m, nr_xmit); > + } else if (async_vhost_driver) { > + uint32_t cpu_cpl_nr = 0; > + uint16_t enqueue_fail = 0; > + struct rte_mbuf *m_cpu_cpl[nr_xmit]; > + > + complete_async_pkts(vdev); > + ret = rte_vhost_submit_enqueue_burst(vdev->vid, VIRTIO_RXQ, > + m, nr_xmit, m_cpu_cpl, &cpu_cpl_nr); > + atomic_fetch_add(&vdev->nr_async_pkts, ret - cpu_cpl_nr); > + > + if (cpu_cpl_nr) > + free_pkts(m_cpu_cpl, cpu_cpl_nr); > + > + enqueue_fail = nr_xmit - ret; > + if (enqueue_fail) > + free_pkts(&m[ret], nr_xmit - ret); > + } else { > + ret = rte_vhost_enqueue_burst(vdev->vid, VIRTIO_RXQ, > + m, nr_xmit); > + } > + > + if (enable_stats) { > + atomic_fetch_add(&vdev->stats.rx_total_atomic, nr_xmit); > + atomic_fetch_add(&vdev->stats.rx_atomic, ret); > + } > + > + if (!async_vhost_driver) > + free_pkts(m, nr_xmit); > +} > + > +static __rte_always_inline void > +drain_vhost_table(void) > +{ > + uint16_t lcore_id = rte_lcore_id(); > + struct vhost_bufftable *vhost_txq; > + struct vhost_dev *vdev; > + uint64_t cur_tsc; > + > + TAILQ_FOREACH(vdev, &vhost_dev_list, global_vdev_entry) { > + vhost_txq = vhost_txbuff[lcore_id * MAX_VHOST_DEVICE > + + vdev->vid]; > + > + cur_tsc = rte_rdtsc(); > + if (unlikely(cur_tsc - vhost_txq->pre_tsc > + > MBUF_TABLE_DRAIN_TSC)) { > + RTE_LOG_DP(DEBUG, VHOST_DATA, > + "Vhost TX queue drained after timeout with burst size %u\n", > + vhost_txq->len); > + drain_vhost(vdev); > + vhost_txq->len = 0; > + vhost_txq->pre_tsc = cur_tsc; > + } > + } > +} > + > /* > * Check if the packet destination MAC address is for a local device. If so then put > * the packet on that devices RX queue. If not then return. > @@ -850,7 +932,8 @@ virtio_tx_local(struct vhost_dev *vdev, struct rte_mbuf *m) > { > struct rte_ether_hdr *pkt_hdr; > struct vhost_dev *dst_vdev; > - > + struct vhost_bufftable *vhost_txq; > + uint16_t lcore_id = rte_lcore_id(); > pkt_hdr = rte_pktmbuf_mtod(m, struct rte_ether_hdr *); > > dst_vdev = find_vhost_dev(&pkt_hdr->d_addr); > @@ -873,7 +956,19 @@ virtio_tx_local(struct vhost_dev *vdev, struct rte_mbuf *m) > return 0; > } > > - virtio_xmit(dst_vdev, vdev, m); > + vhost_txq = vhost_txbuff[lcore_id * MAX_VHOST_DEVICE + dst_vdev->vid]; > + vhost_txq->m_table[vhost_txq->len++] = m; > + > + if (enable_stats) { > + vdev->stats.tx_total++; > + vdev->stats.tx++; > + } > + > + if (unlikely(vhost_txq->len == MAX_PKT_BURST)) { > + drain_vhost(dst_vdev); > + vhost_txq->len = 0; > + vhost_txq->pre_tsc = rte_rdtsc(); > + } > return 0; > } > > @@ -944,13 +1039,6 @@ static void virtio_tx_offload(struct rte_mbuf *m) > tcp_hdr->cksum = get_psd_sum(l3_hdr, m->ol_flags); > } > > -static inline void > -free_pkts(struct rte_mbuf **pkts, uint16_t n) > -{ > - while (n--) > - rte_pktmbuf_free(pkts[n]); > -} > - > static __rte_always_inline void > do_drain_mbuf_table(struct mbuf_table *tx_q) > { > @@ -983,16 +1071,14 @@ virtio_tx_route(struct vhost_dev *vdev, struct rte_mbuf *m, uint16_t vlan_tag) > > TAILQ_FOREACH(vdev2, &vhost_dev_list, global_vdev_entry) { > if (vdev2 != vdev) > - virtio_xmit(vdev2, vdev, m); > + sync_virtio_xmit(vdev2, vdev, m); > } > goto queue2nic; > } > > /*check if destination is local VM*/ > - if ((vm2vm_mode == VM2VM_SOFTWARE) && (virtio_tx_local(vdev, m) == 0)) { > - rte_pktmbuf_free(m); > + if ((vm2vm_mode == VM2VM_SOFTWARE) && (virtio_tx_local(vdev, m) == 0)) > return; > - } > > if (unlikely(vm2vm_mode == VM2VM_HARDWARE)) { > if (unlikely(find_local_dest(vdev, m, &offset, > @@ -1077,32 +1163,15 @@ drain_mbuf_table(struct mbuf_table *tx_q) > } > } > > -static __rte_always_inline void > -complete_async_pkts(struct vhost_dev *vdev, uint16_t qid) > -{ > - struct rte_mbuf *p_cpl[MAX_PKT_BURST]; > - uint16_t complete_count; > - > - complete_count = rte_vhost_poll_enqueue_completed(vdev->vid, > - qid, p_cpl, MAX_PKT_BURST); > - vdev->nr_async_pkts -= complete_count; > - if (complete_count) > - free_pkts(p_cpl, complete_count); > -} > - > static __rte_always_inline void > drain_eth_rx(struct vhost_dev *vdev) > { > uint16_t rx_count, enqueue_count; > - struct rte_mbuf *pkts[MAX_PKT_BURST], *comp_pkts[MAX_PKT_BURST]; > - uint32_t nr_comp = 0; > + struct rte_mbuf *pkts[MAX_PKT_BURST]; > > rx_count = rte_eth_rx_burst(ports[0], vdev->vmdq_rx_q, > pkts, MAX_PKT_BURST); > > - while (likely(vdev->nr_async_pkts)) > - complete_async_pkts(vdev, VIRTIO_RXQ); > - > if (!rx_count) > return; > > @@ -1128,22 +1197,31 @@ drain_eth_rx(struct vhost_dev *vdev) > enqueue_count = vs_enqueue_pkts(vdev, VIRTIO_RXQ, > pkts, rx_count); > } else if (async_vhost_driver) { > + uint32_t cpu_cpl_nr = 0; > + uint16_t enqueue_fail = 0; > + struct rte_mbuf *m_cpu_cpl[MAX_PKT_BURST]; > + > + complete_async_pkts(vdev); > enqueue_count = rte_vhost_submit_enqueue_burst(vdev->vid, > - VIRTIO_RXQ, pkts, rx_count, comp_pkts, > - &nr_comp); > - if (nr_comp > 0) { > - free_pkts(comp_pkts, nr_comp); > - enqueue_count -= nr_comp; > - } > - vdev->nr_async_pkts += enqueue_count; > + VIRTIO_RXQ, pkts, rx_count, > + m_cpu_cpl, &cpu_cpl_nr); > + atomic_fetch_add(&vdev->nr_async_pkts, > + enqueue_count - cpu_cpl_nr); > + if (cpu_cpl_nr) > + free_pkts(m_cpu_cpl, cpu_cpl_nr); > + > + enqueue_fail = rx_count - enqueue_count; > + if (enqueue_fail) > + free_pkts(&pkts[enqueue_count], enqueue_fail); > + > } else { > enqueue_count = rte_vhost_enqueue_burst(vdev->vid, VIRTIO_RXQ, > pkts, rx_count); > } > > if (enable_stats) { > - rte_atomic64_add(&vdev->stats.rx_total_atomic, rx_count); > - rte_atomic64_add(&vdev->stats.rx_atomic, enqueue_count); > + atomic_fetch_add(&vdev->stats.rx_total_atomic, rx_count); > + atomic_fetch_add(&vdev->stats.rx_atomic, enqueue_count); > } > > if (!async_vhost_driver) > @@ -1212,7 +1290,7 @@ switch_worker(void *arg __rte_unused) > > while(1) { > drain_mbuf_table(tx_q); > - > + drain_vhost_table(); > /* > * Inform the configuration core that we have exited the > * linked list and that no devices are in use if requested. > @@ -1253,6 +1331,7 @@ destroy_device(int vid) > { > struct vhost_dev *vdev = NULL; > int lcore; > + uint16_t i; > > TAILQ_FOREACH(vdev, &vhost_dev_list, global_vdev_entry) { > if (vdev->vid == vid) > @@ -1266,6 +1345,9 @@ destroy_device(int vid) > rte_pause(); > } > > + for (i = 0; i < RTE_MAX_LCORE; i++) > + rte_free(vhost_txbuff[i * MAX_VHOST_DEVICE + vid]); > + > if (builtin_net_driver) > vs_vhost_net_remove(vdev); > > @@ -1308,6 +1390,7 @@ static int > new_device(int vid) > { > int lcore, core_add = 0; > + uint16_t i; > uint32_t device_num_min = num_devices; > struct vhost_dev *vdev; > vdev = rte_zmalloc("vhost device", sizeof(*vdev), RTE_CACHE_LINE_SIZE); > @@ -1319,6 +1402,19 @@ new_device(int vid) > } > vdev->vid = vid; > > + for (i = 0; i < RTE_MAX_LCORE; i++) { > + vhost_txbuff[i * MAX_VHOST_DEVICE + vid] > + = rte_zmalloc("vhost bufftable", > + sizeof(struct vhost_bufftable), > + RTE_CACHE_LINE_SIZE); > + > + if (vhost_txbuff[i * MAX_VHOST_DEVICE + vid] == NULL) { > + RTE_LOG(INFO, VHOST_DATA, > + "(%d) couldn't allocate memory for vhost TX\n", vid); > + return -1; > + } > + } > + > if (builtin_net_driver) > vs_vhost_net_setup(vdev); > > @@ -1353,12 +1449,15 @@ new_device(int vid) > if (async_vhost_driver) { > struct rte_vhost_async_features f; > struct rte_vhost_async_channel_ops channel_ops; > + > if (strncmp(dma_type, "ioat", 4) == 0) { > channel_ops.transfer_data = ioat_transfer_data_cb; > channel_ops.check_completed_copies = > ioat_check_completed_copies_cb; > + > f.async_inorder = 1; > f.async_threshold = 256; > + > return rte_vhost_async_channel_register(vid, VIRTIO_RXQ, > f.intval, &channel_ops); > } > @@ -1402,8 +1501,8 @@ print_stats(__rte_unused void *arg) > tx = vdev->stats.tx; > tx_dropped = tx_total - tx; > > - rx_total = rte_atomic64_read(&vdev->stats.rx_total_atomic); > - rx = rte_atomic64_read(&vdev->stats.rx_atomic); > + rx_total = atomic_load(&vdev->stats.rx_total_atomic); > + rx = atomic_load(&vdev->stats.rx_atomic); > rx_dropped = rx_total - rx; > > printf("Statistics for device %d\n" > @@ -1602,6 +1701,7 @@ main(int argc, char *argv[]) > /* Register vhost user driver to handle vhost messages. */ > for (i = 0; i < nb_sockets; i++) { > char *file = socket_files + i * PATH_MAX; > + > if (async_vhost_driver) > flags = flags | RTE_VHOST_USER_ASYNC_COPY; > > diff --git a/examples/vhost/main.h b/examples/vhost/main.h > index 4317b6ae8..6aa798a3e 100644 > --- a/examples/vhost/main.h > +++ b/examples/vhost/main.h > @@ -8,6 +8,7 @@ > #include > > #include > +#include > > /* Macros for printing using RTE_LOG */ > #define RTE_LOGTYPE_VHOST_CONFIG RTE_LOGTYPE_USER1 > @@ -21,8 +22,8 @@ enum {VIRTIO_RXQ, VIRTIO_TXQ, VIRTIO_QNUM}; > struct device_statistics { > uint64_t tx; > uint64_t tx_total; > - rte_atomic64_t rx_atomic; > - rte_atomic64_t rx_total_atomic; > + atomic_int_least64_t rx_atomic; > + atomic_int_least64_t rx_total_atomic; > }; > > struct vhost_queue { > @@ -51,7 +52,7 @@ struct vhost_dev { > uint64_t features; > size_t hdr_len; > uint16_t nr_vrings; > - uint16_t nr_async_pkts; > + atomic_int_least16_t nr_async_pkts; > struct rte_vhost_memory *mem; > struct device_statistics stats; > TAILQ_ENTRY(vhost_dev) global_vdev_entry; > -- > 2.29.2 >