Show a patch.

GET /api/patches/73506/
HTTP 200 OK
Allow: GET, PUT, PATCH, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept

{
    "id": 73506,
    "url": "https://patches.dpdk.org/api/patches/73506/",
    "web_url": "https://patches.dpdk.org/patch/73506/",
    "project": {
        "id": 1,
        "url": "https://patches.dpdk.org/api/projects/1/",
        "name": "DPDK",
        "link_name": "dpdk",
        "list_id": "dev.dpdk.org",
        "list_email": "dev@dpdk.org",
        "web_url": "http://core.dpdk.org",
        "scm_url": "git://dpdk.org/dpdk",
        "webscm_url": "http://git.dpdk.org/dpdk"
    },
    "msgid": "<20200708072645.39031-1-Cheng1.jiang@intel.com>",
    "date": "2020-07-08T07:26:45",
    "name": "[RFC,v2] example/vhost: add support for vhost async data path",
    "commit_ref": null,
    "pull_url": null,
    "state": "superseded",
    "archived": false,
    "hash": "0d1bbe5269f035729b016d2feeb9cc581d9261c5",
    "submitter": {
        "id": 1530,
        "url": "https://patches.dpdk.org/api/people/1530/",
        "name": "Cheng Jiang",
        "email": "Cheng1.jiang@intel.com"
    },
    "delegate": {
        "id": 2642,
        "url": "https://patches.dpdk.org/api/users/2642/",
        "username": "mcoquelin",
        "first_name": "Maxime",
        "last_name": "Coquelin",
        "email": "maxime.coquelin@redhat.com"
    },
    "mbox": "https://patches.dpdk.org/patch/73506/mbox/",
    "series": [
        {
            "id": 10878,
            "url": "https://patches.dpdk.org/api/series/10878/",
            "web_url": "https://patches.dpdk.org/project/dpdk/list/?series=10878",
            "date": "2020-07-08T07:26:45",
            "name": "[RFC,v2] example/vhost: add support for vhost async data path",
            "version": 2,
            "mbox": "https://patches.dpdk.org/series/10878/mbox/"
        }
    ],
    "comments": "https://patches.dpdk.org/api/patches/73506/comments/",
    "check": "fail",
    "checks": "https://patches.dpdk.org/api/patches/73506/checks/",
    "tags": {},
    "headers": {
        "X-Mailman-Version": "2.1.15",
        "X-ExtLoop1": "1",
        "Errors-To": "dev-bounces@dpdk.org",
        "X-Amp-Result": "SKIPPED(no attachment in message)",
        "X-Mailer": "git-send-email 2.27.0",
        "Received": [
            "from dpdk.org (dpdk.org [92.243.14.124])\n\tby inbox.dpdk.org (Postfix) with ESMTP id 61799A00BE;\n\tWed,  8 Jul 2020 09:32:17 +0200 (CEST)",
            "from [92.243.14.124] (localhost [127.0.0.1])\n\tby dpdk.org (Postfix) with ESMTP id 1BFCE1D9C4;\n\tWed,  8 Jul 2020 09:32:15 +0200 (CEST)",
            "from mga02.intel.com (mga02.intel.com [134.134.136.20])\n by dpdk.org (Postfix) with ESMTP id 8D74D1D9C3\n for <dev@dpdk.org>; Wed,  8 Jul 2020 09:32:12 +0200 (CEST)",
            "from orsmga004.jf.intel.com ([10.7.209.38])\n by orsmga101.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384;\n 08 Jul 2020 00:32:11 -0700",
            "from dpdk_jiangcheng.sh.intel.com ([10.67.119.112])\n by orsmga004.jf.intel.com with ESMTP; 08 Jul 2020 00:32:09 -0700"
        ],
        "References": "<20200622025914.85175-1-Cheng1.jiang@intel.com>",
        "X-Amp-File-Uploaded": "False",
        "MIME-Version": "1.0",
        "Message-Id": "<20200708072645.39031-1-Cheng1.jiang@intel.com>",
        "X-IronPort-AV": [
            "E=McAfee;i=\"6000,8403,9675\"; a=\"135986603\"",
            "E=Sophos;i=\"5.75,327,1589266800\"; d=\"scan'208\";a=\"135986603\"",
            "E=Sophos;i=\"5.75,327,1589266800\"; d=\"scan'208\";a=\"427748829\""
        ],
        "Delivered-To": "patchwork@inbox.dpdk.org",
        "Content-Transfer-Encoding": "8bit",
        "From": "Cheng Jiang <Cheng1.jiang@intel.com>",
        "X-Original-To": "patchwork@inbox.dpdk.org",
        "Content-Type": "text/plain; charset=UTF-8",
        "List-Post": "<mailto:dev@dpdk.org>",
        "Return-Path": "<dev-bounces@dpdk.org>",
        "Sender": "\"dev\" <dev-bounces@dpdk.org>",
        "List-Help": "<mailto:dev-request@dpdk.org?subject=help>",
        "In-Reply-To": "<20200622025914.85175-1-Cheng1.jiang@intel.com>",
        "List-Subscribe": "<https://mails.dpdk.org/listinfo/dev>,\n <mailto:dev-request@dpdk.org?subject=subscribe>",
        "To": "maxime.coquelin@redhat.com, chenbo.xia@intel.com, zhihong.wang@intel.com",
        "IronPort-SDR": [
            "\n DMZTrqWzDbM8Qt9M0QfevPHcH5z2u00PRfgXuszNr55ea03NfJaDjzAluJ24veLdE4xIg1PS11\n K49YGgIbMZLQ==",
            "\n lFThSv2AT6fDkvu/h8TqC2vmmQSAHW+4L7a4GgPsYUSQnL9Akiob1yrrAMvoK3hPzt7EQ9ybaR\n KLn4raCqJaOg=="
        ],
        "Precedence": "list",
        "List-Id": "DPDK patches and discussions <dev.dpdk.org>",
        "List-Unsubscribe": "<https://mails.dpdk.org/options/dev>,\n <mailto:dev-request@dpdk.org?subject=unsubscribe>",
        "X-BeenThere": "dev@dpdk.org",
        "Date": "Wed,  8 Jul 2020 07:26:45 +0000",
        "Cc": "dev@dpdk.org, patrick.fu@intel.com, cunming.liang@intel.com,\n Cheng Jiang <Cheng1.jiang@intel.com>",
        "List-Archive": "<http://mails.dpdk.org/archives/dev/>",
        "Subject": "[dpdk-dev] [RFC v2] example/vhost: add support for vhost async data\n\tpath"
    },
    "content": "This patch makes vhost-vswitch be able to use vhost asynchronous\napi for enqueue operations. Demonstrated how the application\nleverage IOAT DMA channel with vhost async api. Since this is an\nearly preview patch, the performance has not been fully\noptimized and it's not suggested to use this patch as a tool for\nbenchmark.\n\nWe introduce two parameters to enable DMA acceleration for Tx\noperations of queues:\n–async_vhost_driver Async vhost-user net driver which demonstrates\nhow to use the async vhost APIs will be used when this option is\ngiven. It is disabled by default.\n\n-dmas This parameter is used to specify the assigned DMA device of\na queue.\n\nThis patch depends on following patch set:\nhttp://patches.dpdk.org/cover/73359/\n\nSigned-off-by: Cheng Jiang <Cheng1.jiang@intel.com>\n---\nv2:\n* updated some variable names based on the latest async vhost patch\n* fixed a bug in virtio_xmit function\n* fixed a hardcode\n* fixed a typo\n---\n examples/vhost/main.c | 248 +++++++++++++++++++++++++++++++++++++++++-\n examples/vhost/main.h |   1 +\n 2 files changed, 245 insertions(+), 4 deletions(-)\n\n--\n2.27.0",
    "diff": "diff --git a/examples/vhost/main.c b/examples/vhost/main.c\nindex 312829e8b..72135a3df 100644\n--- a/examples/vhost/main.c\n+++ b/examples/vhost/main.c\n@@ -24,11 +24,15 @@\n #include <rte_ip.h>\n #include <rte_tcp.h>\n #include <rte_pause.h>\n+#include <rte_vhost_async.h>\n+#include <rte_rawdev.h>\n+#include <rte_ioat_rawdev.h>\n+#include <rte_pci.h>\n\n #include \"main.h\"\n\n #ifndef MAX_QUEUES\n-#define MAX_QUEUES 128\n+#define MAX_QUEUES 512\n #endif\n\n /* the maximum number of external ports supported */\n@@ -58,6 +62,12 @@\n /* Maximum long option length for option parsing. */\n #define MAX_LONG_OPT_SZ 64\n\n+#define IOAT_RING_SIZE 4096\n+\n+#define MAX_ENQUEUED_SIZE 2048\n+\n+#define MAX_VHOST_DEVICE 1024\n+\n /* mask of enabled ports */\n static uint32_t enabled_port_mask = 0;\n\n@@ -96,6 +106,20 @@ static int dequeue_zero_copy;\n\n static int builtin_net_driver;\n\n+static int async_vhost_driver;\n+\n+struct dma_info {\n+\tstruct rte_pci_addr addr;\n+\tuint16_t dev_id;\n+\tbool is_valid;\n+};\n+\n+struct dma_info_input {\n+\tstruct dma_info dmas[RTE_MAX_QUEUES_PER_PORT * 2];\n+\tuint16_t nr;\n+};\n+\n+static struct dma_info_input dma_bind[MAX_VHOST_DEVICE];\n /* Specify timeout (in useconds) between retries on RX. */\n static uint32_t burst_rx_delay_time = BURST_RX_WAIT_US;\n /* Specify the number of retries on RX. */\n@@ -141,6 +165,61 @@ static struct rte_eth_conf vmdq_conf_default = {\n \t},\n };\n\n+static int\n+ioat_transfer_data_cb(int vid, uint16_t queue_id, struct rte_vhost_async_desc *descs,\n+\t\tstruct rte_vhost_async_status *opaque_data, uint16_t count)\n+{\n+\tint ret;\n+\tuint16_t i_desc;\n+\n+\tstruct rte_vhost_iov_iter *src = NULL;\n+\tstruct rte_vhost_iov_iter *dst = NULL;\n+\tunsigned long i_seg;\n+\n+\tint dev_id = dma_bind[vid].dmas[queue_id * 2 + VIRTIO_RXQ].dev_id;\n+\tif (likely(!opaque_data)) {\n+\t\tfor (i_desc = 0; i_desc < count; i_desc++) {\n+\t\t\tsrc = descs[i_desc].src;\n+\t\t\tdst = descs[i_desc].dst;\n+\t\t\ti_seg = 0;\n+\t\t\twhile (i_seg < src->nr_segs) {\n+\t\t\t\tret = rte_ioat_enqueue_copy(dev_id,\n+\t\t\t\t\t(uintptr_t)(src->iov[i_seg].iov_base)\n+\t\t\t\t\t\t+ src->offset,\n+\t\t\t\t\t(uintptr_t)(dst->iov[i_seg].iov_base)\n+\t\t\t\t\t\t+ dst->offset,\n+\t\t\t\t\tsrc->iov[i_seg].iov_len,\n+\t\t\t\t\t0,\n+\t\t\t\t\t0,\n+\t\t\t\t\t0);\n+\t\t\t\tif (ret != 1)\n+\t\t\t\t\tbreak;\n+\t\t\t\ti_seg++;\n+\t\t\t}\n+\t\t}\n+\t} else {\n+\t\t/* Opaque data is not supported */\n+\t\treturn -1;\n+\t}\n+\t/* ring the doorbell */\n+\trte_ioat_do_copies(dev_id);\n+\treturn i_desc;\n+}\n+\n+static int\n+ioat_check_completed_copies_cb(int vid, uint16_t queue_id,\n+\t\tstruct rte_vhost_async_status *opaque_data,\n+\t\tuint16_t max_packets __rte_unused)\n+{\n+\tif (!opaque_data) {\n+\t\tuintptr_t dump[255];\n+\t\treturn rte_ioat_completed_copies(dma_bind[vid].dmas[queue_id * 2\n+\t\t\t+ VIRTIO_RXQ].dev_id, 255, dump, dump);\n+\t} else {\n+\t\t/* Opaque data is not supported */\n+\t\treturn -1;\n+\t}\n+}\n\n static unsigned lcore_ids[RTE_MAX_LCORE];\n static uint16_t ports[RTE_MAX_ETHPORTS];\n@@ -186,6 +265,94 @@ struct mbuf_table lcore_tx_queue[RTE_MAX_LCORE];\n  * Builds up the correct configuration for VMDQ VLAN pool map\n  * according to the pool & queue limits.\n  */\n+\n+static inline int\n+open_dma(const char *value, void *dma_bind_info)\n+{\n+\tstruct dma_info_input *dma_info = dma_bind_info;\n+\tchar *input = strndup(value, strlen(value) + 1);\n+\tchar *addrs = input;\n+\tchar *ptrs[2];\n+\tchar *start, *end, *substr;\n+\tint64_t qid, vring_id;\n+\tstruct rte_ioat_rawdev_config config;\n+\tstruct rte_rawdev_info info = { .dev_private = &config };\n+\tchar name[32];\n+\tint dev_id;\n+\tint ret = 0;\n+\n+\twhile (isblank(*addrs))\n+\t\taddrs++;\n+\tif (*addrs == '\\0') {\n+\t\tret = -1;\n+\t\tgoto out;\n+\t}\n+\n+\t/* process DMA devices within bracket. */\n+\taddrs++;\n+\tsubstr = strtok(addrs, \";]\");\n+\tif (!substr) {\n+\t\tret = -1;\n+\t\tgoto out;\n+\t}\n+\n+\tdo {\n+\t\trte_strsplit(substr, strlen(substr), ptrs, 2, '@');\n+\n+\t\tstart = strstr(ptrs[0], \"txq\");\n+\t\tif (start == NULL) {\n+\t\t\tret = -1;\n+\t\t\tgoto out;\n+\t\t}\n+\n+\t\tstart += 3;\n+\t\tqid = strtol(start, &end, 0);\n+\t\tif (end == start) {\n+\t\t\tret = -1;\n+\t\t\tgoto out;\n+\t\t}\n+\n+\t\tvring_id = qid * 2 + VIRTIO_RXQ;\n+\t\tif (rte_pci_addr_parse(ptrs[1],\n+\t\t\t\t       &dma_info->dmas[vring_id].addr) < 0) {\n+\t\t\tret = -1;\n+\t\t\tgoto out;\n+\t\t}\n+\n+\t\trte_pci_device_name(&dma_info->dmas[vring_id].addr,\n+\t\t\t\t    name, sizeof(name));\n+\t\tdev_id = rte_rawdev_get_dev_id(name);\n+\t\tif (dev_id == (uint16_t)(-ENODEV) ||\n+\t\t    dev_id == (uint16_t)(-EINVAL)) {\n+\t\t\tret = -1;\n+\t\t\tgoto out;\n+\t\t}\n+\n+\t\tif (rte_rawdev_info_get(dev_id, &info) < 0 ||\n+\t\t    strstr(info.driver_name, \"ioat\") == NULL) {\n+\t\t\tret = -1;\n+\t\t\tgoto out;\n+\t\t}\n+\n+\t\tdma_info->dmas[vring_id].dev_id = dev_id;\n+\t\tdma_info->dmas[vring_id].is_valid = true;\n+\t\tconfig.ring_size = IOAT_RING_SIZE;\n+\t\tif (rte_rawdev_configure(dev_id, &info) < 0) {\n+\t\t\tret = -1;\n+\t\t\tgoto out;\n+\t\t}\n+\t\trte_rawdev_start(dev_id);\n+\n+\t\tdma_info->nr++;\n+\n+\t\tsubstr = strtok(NULL, \";]\");\n+\t} while (substr);\n+\n+out:\n+\tfree(input);\n+\treturn ret;\n+}\n+\n static inline int\n get_eth_conf(struct rte_eth_conf *eth_conf, uint32_t num_devices)\n {\n@@ -488,6 +655,8 @@ us_vhost_parse_args(int argc, char **argv)\n \t\t{\"client\", no_argument, &client_mode, 1},\n \t\t{\"dequeue-zero-copy\", no_argument, &dequeue_zero_copy, 1},\n \t\t{\"builtin-net-driver\", no_argument, &builtin_net_driver, 1},\n+\t\t{\"async_vhost_driver\", no_argument, &async_vhost_driver, 1},\n+\t\t{\"dmas\", required_argument, NULL, 0},\n \t\t{NULL, 0, 0, 0},\n \t};\n\n@@ -623,13 +792,25 @@ us_vhost_parse_args(int argc, char **argv)\n \t\t\t\t\t\t\"socket-file\", MAX_LONG_OPT_SZ)) {\n \t\t\t\tif (us_vhost_parse_socket_path(optarg) == -1) {\n \t\t\t\t\tRTE_LOG(INFO, VHOST_CONFIG,\n-\t\t\t\t\t\"Invalid argument for socket name (Max %d characters)\\n\",\n-\t\t\t\t\tPATH_MAX);\n+\t\t\t\t\t\t\"Invalid argument for socket name (Max %d characters)\\n\",\n+\t\t\t\t\t\tPATH_MAX);\n \t\t\t\t\tus_vhost_usage(prgname);\n \t\t\t\t\treturn -1;\n \t\t\t\t}\n \t\t\t}\n\n+\t\t\tif (!strncmp(long_option[option_index].name,\n+\t\t\t\t\t\t\"dmas\", MAX_LONG_OPT_SZ)) {\n+\t\t\t\tif (open_dma(optarg, &(dma_bind[0])) == -1) {\n+\t\t\t\t\tif (*optarg == -1) {\n+\t\t\t\t\t\tRTE_LOG(INFO, VHOST_CONFIG,\n+\t\t\t\t\t\t\t\"Wrong DMA args\\n\");\n+\t\t\t\t\t\tus_vhost_usage(prgname);\n+\t\t\t\t\t\treturn -1;\n+\t\t\t\t\t}\n+\t\t\t\t}\n+\t\t\t}\n+\n \t\t\tbreak;\n\n \t\t\t/* Invalid option - print options. */\n@@ -785,9 +966,26 @@ virtio_xmit(struct vhost_dev *dst_vdev, struct vhost_dev *src_vdev,\n \t    struct rte_mbuf *m)\n {\n \tuint16_t ret;\n+\tstruct rte_mbuf *m_cpl[1];\n\n \tif (builtin_net_driver) {\n \t\tret = vs_enqueue_pkts(dst_vdev, VIRTIO_RXQ, &m, 1);\n+\t} else if (async_vhost_driver) {\n+\t\tret = rte_vhost_submit_enqueue_burst(dst_vdev->vid, VIRTIO_RXQ,\n+\t\t\t\t\t\t&m, 1);\n+\n+\t\tif (likely(ret)) {\n+\t\t\tdst_vdev->nr_async_pkts++;\n+\t\t\trte_mbuf_refcnt_update(m, 1);\n+\t\t}\n+\n+\t\twhile (likely(dst_vdev->nr_async_pkts)) {\n+\t\t\tif (rte_vhost_poll_enqueue_completed(dst_vdev->vid,\n+\t\t\t\t\tVIRTIO_RXQ, m_cpl, 1)) {\n+\t\t\t\tdst_vdev->nr_async_pkts--;\n+\t\t\t\trte_pktmbuf_free(*m_cpl);\n+\t\t\t}\n+\t\t}\n \t} else {\n \t\tret = rte_vhost_enqueue_burst(dst_vdev->vid, VIRTIO_RXQ, &m, 1);\n \t}\n@@ -1036,6 +1234,19 @@ drain_mbuf_table(struct mbuf_table *tx_q)\n \t}\n }\n\n+static __rte_always_inline void\n+complete_async_pkts(struct vhost_dev *vdev, uint16_t qid)\n+{\n+\tstruct rte_mbuf *p_cpl[MAX_PKT_BURST];\n+\tuint16_t complete_count;\n+\n+\tcomplete_count = rte_vhost_poll_enqueue_completed(vdev->vid,\n+\t\t\t\t\t\tqid, p_cpl, MAX_PKT_BURST);\n+\tvdev->nr_async_pkts -= complete_count;\n+\tif (complete_count)\n+\t\tfree_pkts(p_cpl, complete_count);\n+}\n+\n static __rte_always_inline void\n drain_eth_rx(struct vhost_dev *vdev)\n {\n@@ -1044,6 +1255,10 @@ drain_eth_rx(struct vhost_dev *vdev)\n\n \trx_count = rte_eth_rx_burst(ports[0], vdev->vmdq_rx_q,\n \t\t\t\t    pkts, MAX_PKT_BURST);\n+\n+\twhile (likely(vdev->nr_async_pkts))\n+\t\tcomplete_async_pkts(vdev, VIRTIO_RXQ);\n+\n \tif (!rx_count)\n \t\treturn;\n\n@@ -1068,16 +1283,22 @@ drain_eth_rx(struct vhost_dev *vdev)\n \tif (builtin_net_driver) {\n \t\tenqueue_count = vs_enqueue_pkts(vdev, VIRTIO_RXQ,\n \t\t\t\t\t\tpkts, rx_count);\n+\t} else if (async_vhost_driver) {\n+\t\tenqueue_count = rte_vhost_submit_enqueue_burst(vdev->vid,\n+\t\t\t\t\tVIRTIO_RXQ, pkts, rx_count);\n+\t\tvdev->nr_async_pkts += enqueue_count;\n \t} else {\n \t\tenqueue_count = rte_vhost_enqueue_burst(vdev->vid, VIRTIO_RXQ,\n \t\t\t\t\t\tpkts, rx_count);\n \t}\n+\n \tif (enable_stats) {\n \t\trte_atomic64_add(&vdev->stats.rx_total_atomic, rx_count);\n \t\trte_atomic64_add(&vdev->stats.rx_atomic, enqueue_count);\n \t}\n\n-\tfree_pkts(pkts, rx_count);\n+\tif (!async_vhost_driver)\n+\t\tfree_pkts(pkts, rx_count);\n }\n\n static __rte_always_inline void\n@@ -1224,6 +1445,9 @@ destroy_device(int vid)\n \t\t\"(%d) device has been removed from data core\\n\",\n \t\tvdev->vid);\n\n+\tif (async_vhost_driver)\n+\t\trte_vhost_async_channel_unregister(vid, VIRTIO_RXQ);\n+\n \trte_free(vdev);\n }\n\n@@ -1238,6 +1462,12 @@ new_device(int vid)\n \tuint32_t device_num_min = num_devices;\n \tstruct vhost_dev *vdev;\n\n+\tstruct rte_vhost_async_channel_ops channel_ops = {\n+\t\t.transfer_data = ioat_transfer_data_cb,\n+\t\t.check_completed_copies = ioat_check_completed_copies_cb\n+\t};\n+\tstruct rte_vhost_async_features f;\n+\n \tvdev = rte_zmalloc(\"vhost device\", sizeof(*vdev), RTE_CACHE_LINE_SIZE);\n \tif (vdev == NULL) {\n \t\tRTE_LOG(INFO, VHOST_DATA,\n@@ -1278,6 +1508,13 @@ new_device(int vid)\n \t\t\"(%d) device has been added to data core %d\\n\",\n \t\tvid, vdev->coreid);\n\n+\tif (async_vhost_driver) {\n+\t\tf.async_inorder = 1;\n+\t\tf.async_threshold = 256;\n+\t\treturn rte_vhost_async_channel_register(vid, VIRTIO_RXQ,\n+\t\t\tf.intval, &channel_ops);\n+\t}\n+\n \treturn 0;\n }\n\n@@ -1519,6 +1756,9 @@ main(int argc, char *argv[])\n \t/* Register vhost user driver to handle vhost messages. */\n \tfor (i = 0; i < nb_sockets; i++) {\n \t\tchar *file = socket_files + i * PATH_MAX;\n+\t\tif (async_vhost_driver)\n+\t\t\tflags = flags | RTE_VHOST_USER_ASYNC_COPY;\n+\n \t\tret = rte_vhost_driver_register(file, flags);\n \t\tif (ret != 0) {\n \t\t\tunregister_drivers(i);\ndiff --git a/examples/vhost/main.h b/examples/vhost/main.h\nindex 7cba0edbf..4317b6ae8 100644\n--- a/examples/vhost/main.h\n+++ b/examples/vhost/main.h\n@@ -51,6 +51,7 @@ struct vhost_dev {\n \tuint64_t features;\n \tsize_t hdr_len;\n \tuint16_t nr_vrings;\n+\tuint16_t nr_async_pkts;\n \tstruct rte_vhost_memory *mem;\n \tstruct device_statistics stats;\n \tTAILQ_ENTRY(vhost_dev) global_vdev_entry;\n",
    "prefixes": [
        "RFC",
        "v2"
    ]
}