get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

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

{
    "id": 17053,
    "url": "http://patches.dpdk.org/api/patches/17053/?format=api",
    "web_url": "http://patches.dpdk.org/project/dpdk/patch/1479319207-130646-8-git-send-email-harry.van.haaren@intel.com/",
    "project": {
        "id": 1,
        "url": "http://patches.dpdk.org/api/projects/1/?format=api",
        "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",
        "list_archive_url": "https://inbox.dpdk.org/dev",
        "list_archive_url_format": "https://inbox.dpdk.org/dev/{}",
        "commit_url_format": ""
    },
    "msgid": "<1479319207-130646-8-git-send-email-harry.van.haaren@intel.com>",
    "list_archive_url": "https://inbox.dpdk.org/dev/1479319207-130646-8-git-send-email-harry.van.haaren@intel.com",
    "date": "2016-11-16T18:00:07",
    "name": "[dpdk-dev,7/7] examples/eventdev_pipeline: adding example",
    "commit_ref": null,
    "pull_url": null,
    "state": "superseded",
    "archived": true,
    "hash": "071df0aeff438ba2c4377715a06d8f46a0ca17fc",
    "submitter": {
        "id": 317,
        "url": "http://patches.dpdk.org/api/people/317/?format=api",
        "name": "Van Haaren, Harry",
        "email": "harry.van.haaren@intel.com"
    },
    "delegate": null,
    "mbox": "http://patches.dpdk.org/project/dpdk/patch/1479319207-130646-8-git-send-email-harry.van.haaren@intel.com/mbox/",
    "series": [],
    "comments": "http://patches.dpdk.org/api/patches/17053/comments/",
    "check": "warning",
    "checks": "http://patches.dpdk.org/api/patches/17053/checks/",
    "tags": {},
    "related": [],
    "headers": {
        "Return-Path": "<dev-bounces@dpdk.org>",
        "X-Original-To": "patchwork@dpdk.org",
        "Delivered-To": "patchwork@dpdk.org",
        "Received": [
            "from [92.243.14.124] (localhost [IPv6:::1])\n\tby dpdk.org (Postfix) with ESMTP id 441726893;\n\tWed, 16 Nov 2016 19:01:35 +0100 (CET)",
            "from mga02.intel.com (mga02.intel.com [134.134.136.20])\n\tby dpdk.org (Postfix) with ESMTP id 84D3D567E\n\tfor <dev@dpdk.org>; Wed, 16 Nov 2016 19:00:29 +0100 (CET)",
            "from fmsmga001.fm.intel.com ([10.253.24.23])\n\tby orsmga101.jf.intel.com with ESMTP; 16 Nov 2016 10:00:28 -0800",
            "from sie-lab-212-222.ir.intel.com (HELO\n\tsilpixa00398672.ir.intel.com) ([10.237.212.222])\n\tby fmsmga001.fm.intel.com with ESMTP; 16 Nov 2016 10:00:27 -0800"
        ],
        "X-ExtLoop1": "1",
        "X-IronPort-AV": "E=Sophos; i=\"5.31,649,1473145200\"; d=\"scan'208\";\n\ta=\"1069396502\"",
        "From": "Harry van Haaren <harry.van.haaren@intel.com>",
        "To": "dev@dpdk.org",
        "Cc": "Harry van Haaren <harry.van.haaren@intel.com>,\n\tGage Eads <gage.eads@intel.com>,\n\tBruce Richardson <bruce.richardson@intel.com>",
        "Date": "Wed, 16 Nov 2016 18:00:07 +0000",
        "Message-Id": "<1479319207-130646-8-git-send-email-harry.van.haaren@intel.com>",
        "X-Mailer": "git-send-email 2.7.4",
        "In-Reply-To": "<1479319207-130646-1-git-send-email-harry.van.haaren@intel.com>",
        "References": "<1479319207-130646-1-git-send-email-harry.van.haaren@intel.com>",
        "Subject": "[dpdk-dev] [PATCH 7/7] examples/eventdev_pipeline: adding example",
        "X-BeenThere": "dev@dpdk.org",
        "X-Mailman-Version": "2.1.15",
        "Precedence": "list",
        "List-Id": "patches and discussions about DPDK <dev.dpdk.org>",
        "List-Unsubscribe": "<http://dpdk.org/ml/options/dev>,\n\t<mailto:dev-request@dpdk.org?subject=unsubscribe>",
        "List-Archive": "<http://dpdk.org/ml/archives/dev/>",
        "List-Post": "<mailto:dev@dpdk.org>",
        "List-Help": "<mailto:dev-request@dpdk.org?subject=help>",
        "List-Subscribe": "<http://dpdk.org/ml/listinfo/dev>,\n\t<mailto:dev-request@dpdk.org?subject=subscribe>",
        "Errors-To": "dev-bounces@dpdk.org",
        "Sender": "\"dev\" <dev-bounces@dpdk.org>"
    },
    "content": "This patch adds a sample app to the examples/ directory, which can be used\nas a reference application and for general testing. The application requires\ntwo ethdev ports and expects traffic to be flowing. The application must be\nrun with the --vdev flags as follows to indicate to EAL that a virtual\neventdev device called \"evdev_sw0\" is available to be used:\n\n    ./build/eventdev_pipeline --vdev evdev_sw0\n\nThe general flow of the traffic is as follows:\n\n    Rx core -> Atomic Queue => 4 worker cores => TX core\n\nA scheduler core is required to do the packet scheduling, making this\nconfiguration require 7 cores (Rx, Tx, Scheduler, and 4 workers). Finally\na master core brings the core count to 8 for this configuration. The\napplication can be configured for various numbers of flows and worker\ncores. Run the application with -h for details.\n\nSigned-off-by: Gage Eads <gage.eads@intel.com>\nSigned-off-by: Bruce Richardson <bruce.richardson@intel.com>\nSigned-off-by: Harry van Haaren <harry.van.haaren@intel.com>\n---\n examples/eventdev_pipeline/Makefile |  49 +++\n examples/eventdev_pipeline/main.c   | 718 ++++++++++++++++++++++++++++++++++++\n 2 files changed, 767 insertions(+)\n create mode 100644 examples/eventdev_pipeline/Makefile\n create mode 100644 examples/eventdev_pipeline/main.c",
    "diff": "diff --git a/examples/eventdev_pipeline/Makefile b/examples/eventdev_pipeline/Makefile\nnew file mode 100644\nindex 0000000..bab8916\n--- /dev/null\n+++ b/examples/eventdev_pipeline/Makefile\n@@ -0,0 +1,49 @@\n+#   BSD LICENSE\n+#\n+#   Copyright(c) 2016 Intel Corporation. All rights reserved.\n+#\n+#   Redistribution and use in source and binary forms, with or without\n+#   modification, are permitted provided that the following conditions\n+#   are met:\n+#\n+#     * Redistributions of source code must retain the above copyright\n+#       notice, this list of conditions and the following disclaimer.\n+#     * Redistributions in binary form must reproduce the above copyright\n+#       notice, this list of conditions and the following disclaimer in\n+#       the documentation and/or other materials provided with the\n+#       distribution.\n+#     * Neither the name of Intel Corporation nor the names of its\n+#       contributors may be used to endorse or promote products derived\n+#       from this software without specific prior written permission.\n+#\n+#   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n+#   \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n+#   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n+#   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n+#   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n+#   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n+#   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n+#   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n+#   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n+#   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n+#   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n+\n+ifeq ($(RTE_SDK),)\n+$(error \"Please define RTE_SDK environment variable\")\n+endif\n+\n+# Default target, can be overriden by command line or environment\n+RTE_TARGET ?= x86_64-native-linuxapp-gcc\n+\n+include $(RTE_SDK)/mk/rte.vars.mk\n+\n+# binary name\n+APP = eventdev_pipeline\n+\n+# all source are stored in SRCS-y\n+SRCS-y := main.c\n+\n+CFLAGS += -O3\n+CFLAGS += $(WERROR_FLAGS)\n+\n+include $(RTE_SDK)/mk/rte.extapp.mk\ndiff --git a/examples/eventdev_pipeline/main.c b/examples/eventdev_pipeline/main.c\nnew file mode 100644\nindex 0000000..6a8052c\n--- /dev/null\n+++ b/examples/eventdev_pipeline/main.c\n@@ -0,0 +1,718 @@\n+/*-\n+ *   BSD LICENSE\n+ *\n+ *   Copyright(c) 2016 Intel Corporation. All rights reserved.\n+ *\n+ *   Redistribution and use in source and binary forms, with or without\n+ *   modification, are permitted provided that the following conditions\n+ *   are met:\n+ *\n+ *     * Redistributions of source code must retain the above copyright\n+ *       notice, this list of conditions and the following disclaimer.\n+ *     * Redistributions in binary form must reproduce the above copyright\n+ *       notice, this list of conditions and the following disclaimer in\n+ *       the documentation and/or other materials provided with the\n+ *       distribution.\n+ *     * Neither the name of Intel Corporation nor the names of its\n+ *       contributors may be used to endorse or promote products derived\n+ *       from this software without specific prior written permission.\n+ *\n+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n+ *   \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n+ */\n+\n+#include <getopt.h>\n+#include <stdint.h>\n+#include <stdio.h>\n+#include <signal.h>\n+\n+#include <rte_eal.h>\n+#include <rte_mempool.h>\n+#include <rte_mbuf.h>\n+#include <rte_launch.h>\n+#include <rte_malloc.h>\n+#include <rte_cycles.h>\n+#include <rte_ethdev.h>\n+#include <rte_eventdev.h>\n+\n+#define BATCH_SIZE 32\n+\n+static unsigned int num_workers = 4;\n+static unsigned long num_packets = (1L << 25); /* do ~32M packets */\n+static unsigned int num_fids = 16;\n+static unsigned int num_priorities = 1;\n+static int sched_type = RTE_SCHED_TYPE_ATOMIC;\n+\n+struct prod_data {\n+\tuint8_t event_dev_id;\n+\tuint8_t event_port_id;\n+\tint32_t qid;\n+\tunsigned num_ports;\n+};\n+\n+struct cons_data {\n+\tuint8_t event_dev_id;\n+\tuint8_t event_port_id;\n+};\n+\n+struct worker_data {\n+\tuint8_t event_dev_id;\n+\tint event_port_id;\n+\tint32_t qid;\n+};\n+\n+static volatile int done = 0;\n+static int quiet = 0;\n+struct rte_mempool *mp;\n+\n+static int\n+worker(void *arg)\n+{\n+\tstruct rte_event rcv_events[BATCH_SIZE];\n+\n+\tstruct worker_data *data = (struct worker_data *)arg;\n+\tuint8_t event_dev_id = data->event_dev_id;\n+\tuint8_t event_port_id = data->event_port_id;\n+\tint32_t qid = data->qid;\n+\tsize_t sent = 0, received = 0;\n+\n+\twhile (!done) {\n+\t\tuint16_t i;\n+\n+\t\tuint16_t n = rte_event_dequeue_burst(event_dev_id,\n+\t\t\t\t\t\t     event_port_id,\n+\t\t\t\t\t\t     rcv_events,\n+\t\t\t\t\t\t     RTE_DIM(rcv_events),\n+\t\t\t\t\t\t     false);\n+\t\tif (n == 0){\n+\t\t\trte_pause();\n+\t\t\t/* Flush any buffered events */\n+\t\t\trte_event_dequeue(event_dev_id,\n+\t\t\t\t\t  event_port_id,\n+\t\t\t\t\t  NULL,\n+\t\t\t\t\t  false);\n+\t\t\tcontinue;\n+\t\t}\n+\t\treceived += n;\n+\n+\t\tfor (i = 0; i < n; i++) {\n+\t\t\tstruct ether_hdr *eth;\n+\t\t\tstruct ether_addr addr;\n+\t\t\tstruct rte_event *ev = &rcv_events[i];\n+\n+\t\t\tev->queue_id = qid;\n+\t\t\tev->flow_id = 0;\n+\t\t\tev->priority = 0;\n+\t\t\tev->sched_type = RTE_SCHED_TYPE_ATOMIC;\n+\t\t\tev->operation = RTE_EVENT_OP_FORWARD;\n+\n+\t\t\tuint64_t now = rte_rdtsc();\n+\t\t\twhile(now + 750 > rte_rdtsc()) {}\n+\n+\t\t\t/* change mac addresses on packet */\n+\t\t\teth = rte_pktmbuf_mtod(ev->mbuf, struct ether_hdr *);\n+\t\t\tether_addr_copy(&eth->d_addr, &addr);\n+\t\t\tether_addr_copy(&eth->s_addr, &eth->d_addr);\n+\t\t\tether_addr_copy(&addr, &eth->s_addr);\n+\t\t}\n+\t\tint ret = rte_event_enqueue_burst(event_dev_id, event_port_id,\n+\t\t\t\t\trcv_events, n, false);\n+\t\tif (ret != n)\n+\t\t\trte_panic(\"worker %u thread failed to enqueue event\\n\",\n+\t\t\t\trte_lcore_id());\n+\t}\n+\n+\t/* Flush the buffered events */\n+\trte_event_dequeue(event_dev_id, event_port_id, NULL, false);\n+\n+\tif (!quiet)\n+\t\tprintf(\"  worker %u thread done. RX=%zu TX=%zu\\n\",\n+\t\t\t\trte_lcore_id(), received, sent);\n+\n+\treturn 0;\n+}\n+\n+static int\n+scheduler(void *arg)\n+{\n+\tRTE_SET_USED(arg);\n+\tsize_t loops = 0;\n+\n+\twhile (!done) {\n+\t\t/* Assumes an event dev ID of 0 */\n+\t\trte_event_schedule(0);\n+\t\tloops++;\n+\t}\n+\n+\tprintf(\"  scheduler thread done. loops=%zu\\n\", loops);\n+\n+\treturn 0;\n+}\n+\n+static int\n+consumer(void *arg)\n+{\n+\tstruct rte_event events[BATCH_SIZE];\n+\n+\tstruct cons_data *data = (struct cons_data *)arg;\n+\tuint8_t event_dev_id = data->event_dev_id;\n+\tuint8_t event_port_id = data->event_port_id;\n+\tstruct rte_eth_dev_tx_buffer *tx_buf[RTE_MAX_ETHPORTS];\n+\tsize_t npackets = num_packets;\n+\tsize_t received = 0;\n+\tsize_t received_printed = 0; /* tracks when we last printed receive count */\n+\tuint64_t start_time = 0;\n+\tuint64_t freq_khz = rte_get_timer_hz() / 1000;\n+\tuint64_t dropped = 0;\n+\tunsigned i;\n+\n+\tfor (i = 0; i < rte_eth_dev_count(); i++) {\n+\t\ttx_buf[i] = rte_malloc(NULL, RTE_ETH_TX_BUFFER_SIZE(32), 0);\n+\t\tif (tx_buf[i] == NULL)\n+\t\t\trte_panic(\"Out of memory\\n\");\n+\t\trte_eth_tx_buffer_init(tx_buf[i], 32);\n+\t\trte_eth_tx_buffer_set_err_callback(tx_buf[i],\n+\t\t\t\trte_eth_tx_buffer_count_callback, &dropped);\n+\t}\n+\n+\twhile (!done) {\n+\t\tuint16_t i;\n+\t\tuint16_t n = rte_event_dequeue_burst(event_dev_id,\n+\t\t\t\t\t\t     event_port_id,\n+\t\t\t\t\t\t     events,\n+\t\t\t\t\t\t     RTE_DIM(events),\n+\t\t\t\t\t\t     false);\n+\n+\t\tif (n == 0){\n+\t\t\trte_pause();\n+\t\t\tcontinue;\n+\t\t}\n+\t\tif (start_time == 0)\n+\t\t\tstart_time = rte_get_timer_cycles();\n+\n+\t\treceived += n;\n+\t\tfor (i = 0; i < n; i++) {\n+\t\t\tuint8_t outport = events[i].mbuf->port;\n+\t\t\trte_eth_tx_buffer(outport, 0, tx_buf[outport], events[i].mbuf);\n+\t\t}\n+\n+\t\tif (!quiet && received >= received_printed + (1<<22)) {\n+\t\t\tprintf(\"# consumer RX=%zu, time %\"PRIu64\"ms\\n\",\n+\t\t\t\t\treceived,\n+\t\t\t\t\t(rte_get_timer_cycles() - start_time) / freq_khz);\n+\t\t\treceived_printed = received;\n+\t\t}\n+\n+\t\tif (num_packets > 0 && npackets > 0) {\n+\t\t\tnpackets -= n;\n+\t\t\tif (npackets == 0)\n+\t\t\t\tdone = 1;\n+\t\t}\n+\t}\n+\n+\tfor (i = 0; i < rte_eth_dev_count(); i++)\n+\t\trte_eth_tx_buffer_flush(i, 0, tx_buf[i]);\n+\n+\tprintf(\"  consumer done! RX=%zu, time %\"PRIu64\"ms\\n\",\n+\t\t\treceived,\n+\t\t\t(rte_get_timer_cycles() - start_time) / freq_khz);\n+\n+\treturn 0;\n+}\n+\n+static int\n+producer(void *arg)\n+{\n+\n+\tstruct prod_data *data = (struct prod_data *)arg;\n+\tsize_t npackets = num_packets;\n+\tunsigned i;\n+\tuint64_t mbuf_seqno = 0;\n+\tsize_t sent = 0;\n+\tuint8_t eth_port = 0;\n+\tuint8_t event_dev_id = data->event_dev_id;\n+\tuint8_t event_port_id = data->event_port_id;\n+\tint fid_counter = 0;\n+\n+\twhile (!done) {\n+\t\tint ret;\n+\t\tunsigned num_ports = data->num_ports;\n+\t\tint32_t qid = data->qid;\n+\t\tstruct rte_event events[BATCH_SIZE];\n+\t\tstruct rte_mbuf *mbufs[BATCH_SIZE];\n+\n+\t\tuint16_t nb_rx = rte_eth_rx_burst(eth_port, 0, mbufs, BATCH_SIZE);\n+\t\tif (++eth_port == num_ports)\n+\t\t\teth_port = 0;\n+\t\tif (nb_rx == 0) {\n+\t\t\trte_pause();\n+\t\t\t/* Flush any buffered events */\n+\t\t\trte_event_dequeue(event_dev_id,\n+\t\t\t\t\t  event_port_id,\n+\t\t\t\t\t  NULL,\n+\t\t\t\t\t  false);\n+\t\t\tcontinue;\n+\t\t}\n+\n+\t\tfor (i = 0; i < nb_rx; i++) {\n+\t\t\tstruct rte_mbuf *m = mbufs[i];\n+\t\t\tstruct rte_event *ev = &events[i];\n+\n+\t\t\tev->queue_id = qid;\n+\t\t\tev->flow_id = fid_counter++ % 6;\n+\t\t\tev->priority = 0;\n+\t\t\tm->udata64 = mbuf_seqno++;\n+\t\t\tev->mbuf = m;\n+\t\t\tev->sched_type = sched_type;\n+\t\t\tev->operation = RTE_EVENT_OP_NEW;\n+\t\t}\n+\n+\t\tdo {\n+\t\t\tret = rte_event_enqueue_burst(event_dev_id,\n+\t\t\t\t\t\t\tevent_port_id,\n+\t\t\t\t\t\t\tevents,\n+\t\t\t\t\t\t\tnb_rx,\n+\t\t\t\t\t\t\tfalse);\n+\t\t} while (ret == -ENOSPC);\n+\t\tif (ret != nb_rx)\n+\t\t\trte_panic(\"producer thread failed to enqueue *all* events\\n\");\n+\n+\t\tsent += nb_rx;\n+\n+\t\tif (num_packets > 0 && npackets > 0) {\n+\t\t\tnpackets -= nb_rx;\n+\t\t\tif (npackets == 0)\n+\t\t\t\tbreak;\n+\t\t}\n+\t}\n+\n+\t/* Flush any buffered events */\n+\twhile (!done)\n+\t\trte_event_dequeue(event_dev_id, event_port_id, NULL, false);\n+\n+\tprintf(\"  prod thread done! TX=%zu across %u flows\\n\", sent, num_fids);\n+\n+\treturn 0;\n+}\n+\n+static struct option long_options[] = {\n+\t{\"workers\", required_argument, 0, 'w'},\n+\t{\"packets\", required_argument, 0, 'n'},\n+\t{\"atomic-flows\", required_argument, 0, 'f'},\n+\t{\"priority\", required_argument, 0, 'p'},\n+\t{\"ordered\", no_argument, 0, 'o'},\n+\t{\"quiet\", no_argument, 0, 'q'},\n+\t{0, 0, 0, 0}\n+};\n+\n+static void\n+usage(void)\n+{\n+\tconst char *usage_str =\n+\t\t\"  Usage: eventdev_pipeline [options]\\n\"\n+\t\t\"  Options:\\n\"\n+\t\t\"  -w, --workers=N       Use N workers (default 4)\\n\"\n+\t\t\"  -n, --packets=N       Send N packets (default ~32M), 0 implies no limit\\n\"\n+\t\t\"  -f, --atomic-flows=N  Use N random flows from 1 to N (default 16)\\n\"\n+\t\t\"  -p, --priority=N      Use N number of priorities (default 1)\\n\"\n+\t\t\"  -o, --ordered         Use ordered scheduling\\n\"\n+\t\t\"  -q, --quiet           Minimize printed output\\n\"\n+\t\t\"\\n\";\n+\n+\tfprintf(stderr, \"%s\", usage_str);\n+\texit(1);\n+}\n+\n+static void\n+parse_app_args(int argc, char** argv)\n+{\n+\t/* Parse cli options*/\n+\tint option_index;\n+\tint c;\n+\topterr = 0;\n+\n+\tfor (;;) {\n+\t\tc = getopt_long(argc, argv, \"w:n:f:p:oq\", long_options,\n+\t\t\t\t&option_index);\n+\t\tif (c == -1)\n+\t\t\tbreak;\n+\n+\t\tswitch (c) {\n+\t\t\tcase 'w':\n+\t\t\t\tnum_workers = (unsigned int)atoi(optarg);\n+\t\t\t\tbreak;\n+\t\t\tcase 'n':\n+\t\t\t\tnum_packets = (unsigned long )atol(optarg);\n+\t\t\t\tbreak;\n+\t\t\tcase 'f':\n+\t\t\t\tnum_fids = (unsigned int)atoi(optarg);\n+\t\t\t\tbreak;\n+\t\t\tcase 'p':\n+\t\t\t\tnum_priorities = (unsigned int)atoi(optarg);\n+\t\t\t\tbreak;\n+\t\t\tcase 'o':\n+\t\t\t\tsched_type = RTE_SCHED_TYPE_ORDERED;\n+\t\t\t\tbreak;\n+\t\t\tcase 'q':\n+\t\t\t\tquiet = 1;\n+\t\t\t\tbreak;\n+\t\t\tdefault:\n+\t\t\t\tusage();\n+\t\t}\n+\t}\n+\tif (num_workers == 0)\n+\t\tusage();\n+}\n+\n+/*\n+ * Initializes a given port using global settings and with the RX buffers\n+ * coming from the mbuf_pool passed as a parameter.\n+ */\n+static inline int\n+port_init(uint8_t port, struct rte_mempool *mbuf_pool)\n+{\n+\tstatic const struct rte_eth_conf port_conf_default = {\n+\t\t.rxmode = { .max_rx_pkt_len = ETHER_MAX_LEN }\n+\t};\n+\tconst uint16_t rx_rings = 1, tx_rings = 1;\n+\tconst uint16_t rx_ring_size = 512, tx_ring_size = 512;\n+\tstruct rte_eth_conf port_conf = port_conf_default;\n+\tint retval;\n+\tuint16_t q;\n+\n+\tif (port >= rte_eth_dev_count())\n+\t\treturn -1;\n+\n+\t/* Configure the Ethernet device. */\n+\tretval = rte_eth_dev_configure(port, rx_rings, tx_rings, &port_conf);\n+\tif (retval != 0)\n+\t\treturn retval;\n+\n+\t/* Allocate and set up 1 RX queue per Ethernet port. */\n+\tfor (q = 0; q < rx_rings; q++) {\n+\t\tretval = rte_eth_rx_queue_setup(port, q, rx_ring_size,\n+\t\t\t\trte_eth_dev_socket_id(port), NULL, mbuf_pool);\n+\t\tif (retval < 0)\n+\t\t\treturn retval;\n+\t}\n+\n+\t/* Allocate and set up 1 TX queue per Ethernet port. */\n+\tfor (q = 0; q < tx_rings; q++) {\n+\t\tretval = rte_eth_tx_queue_setup(port, q, tx_ring_size,\n+\t\t\t\trte_eth_dev_socket_id(port), NULL);\n+\t\tif (retval < 0)\n+\t\t\treturn retval;\n+\t}\n+\n+\t/* Start the Ethernet port. */\n+\tretval = rte_eth_dev_start(port);\n+\tif (retval < 0)\n+\t\treturn retval;\n+\n+\t/* Display the port MAC address. */\n+\tstruct ether_addr addr;\n+\trte_eth_macaddr_get(port, &addr);\n+\tprintf(\"Port %u MAC: %02\" PRIx8 \" %02\" PRIx8 \" %02\" PRIx8\n+\t\t\t   \" %02\" PRIx8 \" %02\" PRIx8 \" %02\" PRIx8 \"\\n\",\n+\t\t\t(unsigned)port,\n+\t\t\taddr.addr_bytes[0], addr.addr_bytes[1],\n+\t\t\taddr.addr_bytes[2], addr.addr_bytes[3],\n+\t\t\taddr.addr_bytes[4], addr.addr_bytes[5]);\n+\n+\t/* Enable RX in promiscuous mode for the Ethernet device. */\n+\trte_eth_promiscuous_enable(port);\n+\n+\treturn 0;\n+}\n+\n+static int\n+init_ports(unsigned num_ports)\n+{\n+\tuint8_t portid;\n+\n+\tmp = rte_pktmbuf_pool_create(\"packet_pool\",\n+\t\t\t/* mbufs */ 16384 * num_ports,\n+\t\t\t/* cache_size */ 512,\n+\t\t\t/* priv_size*/ 0,\n+\t\t\t/* data_room_size */ RTE_MBUF_DEFAULT_BUF_SIZE,\n+\t\t\trte_socket_id());\n+\n+\tfor (portid = 0; portid < num_ports; portid++)\n+\t\tif (port_init(portid, mp) != 0)\n+\t\t\trte_exit(EXIT_FAILURE, \"Cannot init port %\"PRIu8 \"\\n\",\n+\t\t\t\t\tportid);\n+\treturn 0;\n+}\n+\n+static uint8_t\n+setup_event_dev(struct prod_data *prod_data,\n+\t\tstruct cons_data *cons_data,\n+\t\tstruct worker_data *worker_data)\n+{\n+\tstruct rte_event_dev_config config;\n+\tstruct rte_event_queue_conf queue_config;\n+\tstruct rte_event_port_conf port_config;\n+\tstruct rte_event_queue_link link;\n+\tint prod_port;\n+\tint cons_port;\n+\tint qid0;\n+\tint cons_qid;\n+\tint prod_qid;\n+\tunsigned i;\n+\tint ret;\n+\tint8_t id;\n+\n+\tconst char *dev_name = \"evdev_sw0\";\n+\tid = rte_event_dev_get_dev_id(dev_name);\n+\tif (id < 0)\n+\t\trte_panic(\"Failed to get %s device ID\\n\", dev_name);\n+\n+\tconfig.nb_event_queues = 3;\n+\tconfig.nb_event_ports = num_workers + 2;\n+\tconfig.nb_events_limit = 256;\n+\tconfig.dequeue_wait_ns = 0;\n+\n+\tret = rte_event_dev_configure(id, &config);\n+\tif (ret)\n+\t\trte_panic(\"Failed to configure the event dev\\n\");\n+\n+\t/* Create queues */\n+\tqueue_config.event_queue_cfg = RTE_EVENT_QUEUE_CFG_ATOMIC_ONLY;\n+\tqueue_config.priority = 0;\n+\n+\tqid0 = 0;\n+\tret = rte_event_queue_setup(id, qid0, &queue_config);\n+\tif (ret < 0)\n+\t\trte_panic(\"Failed to create the scheduled QID\\n\");\n+\n+\tqueue_config.event_queue_cfg = RTE_EVENT_QUEUE_CFG_SINGLE_CONSUMER;\n+\tqueue_config.priority = 0;\n+\n+\tcons_qid = 1;\n+\tret = rte_event_queue_setup(id, cons_qid, &queue_config);\n+\tif (ret < 0)\n+\t\trte_panic(\"Failed to create the cons directed QID\\n\");\n+\n+\tqueue_config.event_queue_cfg = RTE_EVENT_QUEUE_CFG_SINGLE_CONSUMER;\n+\tqueue_config.priority = 0;\n+\n+\tprod_qid = 2;\n+\tret = rte_event_queue_setup(id, prod_qid, &queue_config);\n+\tif (ret < 0)\n+\t\trte_panic(\"Failed to create the prod directed QID\\n\");\n+\n+\t/* Create ports */\n+#define LB_PORT_DEPTH 16\n+#define DIR_PORT_DEPTH 32\n+\tport_config.enqueue_queue_depth = LB_PORT_DEPTH;\n+\tport_config.dequeue_queue_depth = LB_PORT_DEPTH;\n+\tport_config.new_event_threshold = 255;\n+\n+\tprod_port = 0;\n+\tret = rte_event_port_setup(id, prod_port, &port_config);\n+\tif (ret < 0)\n+\t\trte_panic(\"Failed to create the producer port\\n\");\n+\n+\tcons_port = 1;\n+\tport_config.enqueue_queue_depth = DIR_PORT_DEPTH;\n+\tport_config.dequeue_queue_depth = DIR_PORT_DEPTH;\n+\tret = rte_event_port_setup(id, cons_port, &port_config);\n+\tif (ret < 0)\n+\t\trte_panic(\"Failed to create the consumer port\\n\");\n+\n+\tport_config.enqueue_queue_depth = LB_PORT_DEPTH;\n+\tport_config.dequeue_queue_depth = LB_PORT_DEPTH;\n+\tfor (i = 0; i < num_workers; i++) {\n+\t\tworker_data[i].event_port_id = i + 2;\n+\t\tret = rte_event_port_setup(id, worker_data[i].event_port_id, &port_config);\n+\t\tif (ret < 0)\n+\t\t\trte_panic(\"Failed to create worker port #%d\\n\", i);\n+\t}\n+\n+\t/* Map ports/qids */\n+\tfor (i = 0; i < num_workers; i++) {\n+\t\tlink.queue_id = qid0;\n+\t\tlink.priority = 0;\n+\n+\t\tret = rte_event_port_link(id, worker_data[i].event_port_id, &link, 1);\n+\t\tif (ret != 1)\n+\t\t\trte_panic(\"Failed to map worker%d port to qid0\\n\", i);\n+\t}\n+\n+\t/* Link consumer port to its QID */\n+\tlink.queue_id = cons_qid;\n+\tlink.priority = 0;\n+\n+\tret = rte_event_port_link(id, cons_port, &link, 1);\n+\tif (ret != 1)\n+\t\trte_panic(\"Failed to map consumer port to cons_qid\\n\");\n+\n+\t/* Link producer port to its QID */\n+\tlink.queue_id = prod_qid;\n+\tlink.priority = 0;\n+\n+\tret = rte_event_port_link(id, prod_port, &link, 1);\n+\tif (ret != 1)\n+\t\trte_panic(\"Failed to map producer port to prod_qid\\n\");\n+\n+\t/* Dispatch to slaves */\n+\t*prod_data = (struct prod_data){.event_dev_id = id,\n+\t\t\t\t\t.event_port_id = prod_port,\n+\t\t\t\t\t.qid = qid0};\n+\t*cons_data = (struct cons_data){.event_dev_id = id,\n+\t\t\t\t\t.event_port_id = cons_port};\n+\n+\tfor (i = 0; i < num_workers; i++) {\n+\t\tstruct worker_data *w = &worker_data[i];\n+\t\tw->event_dev_id = id;\n+\t\tw->qid = cons_qid;\n+\t}\n+\n+\tif (rte_event_dev_start(id) < 0) {\n+\t\tprintf(\"%d: Error with start call\\n\", __LINE__);\n+\t\treturn -1;\n+\t}\n+\n+\treturn (uint8_t) id;\n+}\n+\n+static void sighndlr(int sig)\n+{\n+\t/* Ctlr-Z to dump stats */\n+\tif(sig == SIGTSTP) {\n+\t\trte_mempool_dump(stdout, mp);\n+\t\trte_event_dev_dump(stdout, 0);\n+\t}\n+\t/* Ctlr-C to exit */\n+\tif(sig == SIGINT)\n+\t\trte_exit(0, \"sigint arrived, quitting\\n\");\n+}\n+\n+int\n+main(int argc, char **argv)\n+{\n+\tsignal(SIGINT , sighndlr);\n+\tsignal(SIGTSTP, sighndlr);\n+\n+\tstruct prod_data prod_data = {0};\n+\tstruct cons_data cons_data = {0};\n+\tstruct worker_data *worker_data;\n+\tunsigned nworkers = 0;\n+\tunsigned num_ports;\n+\tint lcore_id;\n+\tint err;\n+\tint has_prod = 0;\n+\tint has_cons = 0;\n+\tint has_scheduler = 0;\n+\n+\terr = rte_eal_init(argc, argv);\n+\tif (err < 0)\n+\t\trte_panic(\"Invalid EAL arguments\\n\");\n+\n+\targc -= err;\n+\targv += err;\n+\n+\t/* Parse cli options*/\n+\tparse_app_args(argc, argv);\n+\n+\tnum_ports = rte_eth_dev_count();\n+\tif (num_ports == 0)\n+\t\trte_panic(\"No ethernet ports found\\n\");\n+\n+\tif (!quiet) {\n+\t\tprintf(\"  Config:\\n\");\n+\t\tprintf(\"\\tports: %u\\n\", num_ports);\n+\t\tprintf(\"\\tworkers: %u\\n\", num_workers);\n+\t\tprintf(\"\\tpackets: %lu\\n\", num_packets);\n+\t\tprintf(\"\\tflows: %u\\n\", num_fids);\n+\t\tprintf(\"\\tpriorities: %u\\n\", num_priorities);\n+\t\tif (sched_type == RTE_SCHED_TYPE_ORDERED)\n+\t\t\tprintf(\"\\tqid0 type: ordered\\n\");\n+\t\tif (sched_type == RTE_SCHED_TYPE_ATOMIC)\n+\t\t\tprintf(\"\\tqid0 type: atomic\\n\");\n+\t\tprintf(\"\\n\");\n+\t}\n+\n+\tconst unsigned cores_needed = num_workers +\n+\t\t\t/*main*/1 +\n+\t\t\t/*sched*/1 +\n+\t\t\t/*TX*/1 +\n+\t\t\t/*RX*/1;\n+\n+\tif (!quiet) {\n+\t\tprintf(\"Number of cores available: %u\\n\", rte_lcore_count());\n+\t\tprintf(\"Number of cores to be used: %u\\n\", cores_needed);\n+\t}\n+\n+\tif (rte_lcore_count() < cores_needed)\n+\t\trte_panic(\"Too few cores\\n\");\n+\n+\tconst uint8_t ndevs = rte_event_dev_count();\n+\tif (ndevs == 0)\n+\t\trte_panic(\"No event devs found. Do you need to pass in a --vdev flag?\\n\");\n+\tif (ndevs > 1)\n+\t\tfprintf(stderr, \"Warning: More than one event dev, using idx 0\");\n+\n+\tworker_data = rte_calloc(0, num_workers, sizeof(worker_data[0]), 0);\n+\tif (worker_data == NULL)\n+\t\trte_panic(\"rte_calloc failed\\n\");\n+\n+\tuint8_t id = setup_event_dev(&prod_data, &cons_data, worker_data);\n+\tRTE_SET_USED(id);\n+\n+\tprod_data.num_ports = num_ports;\n+\tinit_ports(num_ports);\n+\n+\tRTE_LCORE_FOREACH_SLAVE(lcore_id) {\n+\t\tif (has_prod && has_cons && has_scheduler && nworkers == num_workers)\n+\t\t\tbreak;\n+\n+\t\tif (!has_scheduler) {\n+\t\t\terr = rte_eal_remote_launch(scheduler, NULL, lcore_id);\n+\t\t\tif (err)\n+\t\t\t\trte_panic(\"Failed to launch scheduler\\n\");\n+\n+\t\t\thas_scheduler = 1;\n+\t\t\tcontinue;\n+\t\t}\n+\n+\t\tif (nworkers < num_workers) {\n+\t\t\terr = rte_eal_remote_launch(worker, &worker_data[nworkers], lcore_id);\n+\t\t\tif (err)\n+\t\t\t\trte_panic(\"Failed to launch worker%d\\n\", nworkers);\n+\t\t\tnworkers++;\n+\t\t\tcontinue;\n+\t\t}\n+\n+\t\tif (!has_cons) {\n+\t\t\terr = rte_eal_remote_launch(consumer, &cons_data, lcore_id);\n+\t\t\tif (err)\n+\t\t\t\trte_panic(\"Failed to launch consumer\\n\");\n+\t\t\thas_cons = 1;\n+\t\t\tcontinue;\n+\t\t}\n+\n+\t\tif (!has_prod) {\n+\t\t\terr = rte_eal_remote_launch(producer, &prod_data, lcore_id);\n+\t\t\tif (err)\n+\t\t\t\trte_panic(\"Failed to launch producer\\n\");\n+\t\t\thas_prod = 1;\n+\t\t\tcontinue;\n+\t\t}\n+\t}\n+\n+\trte_eal_mp_wait_lcore();\n+\n+\t/* Cleanup done automatically by kernel on app exit */\n+\n+\treturn 0;\n+}\n",
    "prefixes": [
        "dpdk-dev",
        "7/7"
    ]
}