Show a patch.

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

{
    "id": 73436,
    "url": "https://patches.dpdk.org/api/patches/73436/",
    "web_url": "https://patches.dpdk.org/patch/73436/",
    "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": "<20200707144041.35498-4-ruifeng.wang@arm.com>",
    "date": "2020-07-07T14:40:40",
    "name": "[v6,3/3] test/lpm: add RCU integration performance tests",
    "commit_ref": null,
    "pull_url": null,
    "state": "superseded",
    "archived": true,
    "hash": "c1cd49ab2142eb6348f6fe25b7461166d521d3e5",
    "submitter": {
        "id": 1198,
        "url": "https://patches.dpdk.org/api/people/1198/",
        "name": "Ruifeng Wang",
        "email": "ruifeng.wang@arm.com"
    },
    "delegate": {
        "id": 24651,
        "url": "https://patches.dpdk.org/api/users/24651/",
        "username": "dmarchand",
        "first_name": "David",
        "last_name": "Marchand",
        "email": "david.marchand@redhat.com"
    },
    "mbox": "https://patches.dpdk.org/patch/73436/mbox/",
    "series": [
        {
            "id": 10852,
            "url": "https://patches.dpdk.org/api/series/10852/",
            "web_url": "https://patches.dpdk.org/project/dpdk/list/?series=10852",
            "date": "2020-07-07T14:40:37",
            "name": "RCU integration with LPM library",
            "version": 6,
            "mbox": "https://patches.dpdk.org/series/10852/mbox/"
        }
    ],
    "comments": "https://patches.dpdk.org/api/patches/73436/comments/",
    "check": "warning",
    "checks": "https://patches.dpdk.org/api/patches/73436/checks/",
    "tags": {},
    "headers": {
        "List-Archive": "<http://mails.dpdk.org/archives/dev/>",
        "Return-Path": "<dev-bounces@dpdk.org>",
        "Message-Id": "<20200707144041.35498-4-ruifeng.wang@arm.com>",
        "X-Mailer": "git-send-email 2.17.1",
        "To": "Bruce Richardson <bruce.richardson@intel.com>,\n Vladimir Medvedkin <vladimir.medvedkin@intel.com>",
        "Cc": "dev@dpdk.org, mdr@ashroe.eu, konstantin.ananyev@intel.com,\n honnappa.nagarahalli@arm.com, nd@arm.com",
        "X-BeenThere": "dev@dpdk.org",
        "Received": [
            "from dpdk.org (dpdk.org [92.243.14.124])\n\tby inbox.dpdk.org (Postfix) with ESMTP id 7CE26A00BE;\n\tTue,  7 Jul 2020 16:41:56 +0200 (CEST)",
            "from [92.243.14.124] (localhost [127.0.0.1])\n\tby dpdk.org (Postfix) with ESMTP id 5C3E31DE47;\n\tTue,  7 Jul 2020 16:41:56 +0200 (CEST)",
            "from foss.arm.com (foss.arm.com [217.140.110.172])\n by dpdk.org (Postfix) with ESMTP id 7705A1DE62\n for <dev@dpdk.org>; Tue,  7 Jul 2020 16:41:54 +0200 (CEST)",
            "from usa-sjc-imap-foss1.foss.arm.com (unknown [10.121.207.14])\n by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id 0D2C7D6E;\n Tue,  7 Jul 2020 07:41:54 -0700 (PDT)",
            "from net-arm-thunderx2-02.shanghai.arm.com\n (net-arm-thunderx2-02.shanghai.arm.com [10.169.210.119])\n by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPA id 6E3603F68F;\n Tue,  7 Jul 2020 07:41:51 -0700 (PDT)"
        ],
        "Subject": "[dpdk-dev] [PATCH v6 3/3] test/lpm: add RCU integration performance\n\ttests",
        "List-Unsubscribe": "<https://mails.dpdk.org/options/dev>,\n <mailto:dev-request@dpdk.org?subject=unsubscribe>",
        "List-Id": "DPDK patches and discussions <dev.dpdk.org>",
        "List-Post": "<mailto:dev@dpdk.org>",
        "In-Reply-To": "<20200707144041.35498-1-ruifeng.wang@arm.com>",
        "Precedence": "list",
        "From": "Ruifeng Wang <ruifeng.wang@arm.com>",
        "References": "<20190906094534.36060-1-ruifeng.wang@arm.com>\n <20200707144041.35498-1-ruifeng.wang@arm.com>",
        "X-Original-To": "patchwork@inbox.dpdk.org",
        "Sender": "\"dev\" <dev-bounces@dpdk.org>",
        "Errors-To": "dev-bounces@dpdk.org",
        "List-Help": "<mailto:dev-request@dpdk.org?subject=help>",
        "Delivered-To": "patchwork@inbox.dpdk.org",
        "Date": "Tue,  7 Jul 2020 22:40:40 +0800",
        "X-Mailman-Version": "2.1.15",
        "List-Subscribe": "<https://mails.dpdk.org/listinfo/dev>,\n <mailto:dev-request@dpdk.org?subject=subscribe>"
    },
    "content": "From: Honnappa Nagarahalli <honnappa.nagarahalli@arm.com>\n\nAdd performance tests for RCU integration. The performance\ndifference with and without RCU integration is very small\n(~1% to ~2%) on both Arm and x86 platforms.\n\nSigned-off-by: Honnappa Nagarahalli <honnappa.nagarahalli@arm.com>\nReviewed-by: Gavin Hu <gavin.hu@arm.com>\nReviewed-by: Ruifeng Wang <ruifeng.wang@arm.com>\n---\n app/test/test_lpm_perf.c | 492 ++++++++++++++++++++++++++++++++++++++-\n 1 file changed, 489 insertions(+), 3 deletions(-)",
    "diff": "diff --git a/app/test/test_lpm_perf.c b/app/test/test_lpm_perf.c\nindex 489719c40..dfe186426 100644\n--- a/app/test/test_lpm_perf.c\n+++ b/app/test/test_lpm_perf.c\n@@ -1,5 +1,6 @@\n /* SPDX-License-Identifier: BSD-3-Clause\n  * Copyright(c) 2010-2014 Intel Corporation\n+ * Copyright(c) 2020 Arm Limited\n  */\n \n #include <stdio.h>\n@@ -10,12 +11,27 @@\n #include <rte_cycles.h>\n #include <rte_random.h>\n #include <rte_branch_prediction.h>\n+#include <rte_malloc.h>\n #include <rte_ip.h>\n #include <rte_lpm.h>\n \n #include \"test.h\"\n #include \"test_xmmt_ops.h\"\n \n+struct rte_lpm *lpm;\n+static struct rte_rcu_qsbr *rv;\n+static volatile uint8_t writer_done;\n+static volatile uint32_t thr_id;\n+static uint64_t gwrite_cycles;\n+static uint64_t gwrites;\n+/* LPM APIs are not thread safe, use mutex to provide thread safety */\n+static pthread_mutex_t lpm_mutex = PTHREAD_MUTEX_INITIALIZER;\n+\n+/* Report quiescent state interval every 1024 lookups. Larger critical\n+ * sections in reader will result in writer polling multiple times.\n+ */\n+#define QSBR_REPORTING_INTERVAL 1024\n+\n #define TEST_LPM_ASSERT(cond) do {                                            \\\n \tif (!(cond)) {                                                        \\\n \t\tprintf(\"Error at line %d: \\n\", __LINE__);                     \\\n@@ -24,6 +40,7 @@\n } while(0)\n \n #define ITERATIONS (1 << 10)\n+#define RCU_ITERATIONS 10\n #define BATCH_SIZE (1 << 12)\n #define BULK_SIZE 32\n \n@@ -35,9 +52,13 @@ struct route_rule {\n };\n \n static struct route_rule large_route_table[MAX_RULE_NUM];\n+/* Route table for routes with depth > 24 */\n+struct route_rule large_ldepth_route_table[MAX_RULE_NUM];\n \n static uint32_t num_route_entries;\n+static uint32_t num_ldepth_route_entries;\n #define NUM_ROUTE_ENTRIES num_route_entries\n+#define NUM_LDEPTH_ROUTE_ENTRIES num_ldepth_route_entries\n \n enum {\n \tIP_CLASS_A,\n@@ -191,7 +212,7 @@ static void generate_random_rule_prefix(uint32_t ip_class, uint8_t depth)\n \tuint32_t ip_head_mask;\n \tuint32_t rule_num;\n \tuint32_t k;\n-\tstruct route_rule *ptr_rule;\n+\tstruct route_rule *ptr_rule, *ptr_ldepth_rule;\n \n \tif (ip_class == IP_CLASS_A) {        /* IP Address class A */\n \t\tfixed_bit_num = IP_HEAD_BIT_NUM_A;\n@@ -236,10 +257,20 @@ static void generate_random_rule_prefix(uint32_t ip_class, uint8_t depth)\n \t */\n \tstart = lrand48() & mask;\n \tptr_rule = &large_route_table[num_route_entries];\n+\tptr_ldepth_rule = &large_ldepth_route_table[num_ldepth_route_entries];\n \tfor (k = 0; k < rule_num; k++) {\n \t\tptr_rule->ip = (start << (RTE_LPM_MAX_DEPTH - depth))\n \t\t\t| ip_head_mask;\n \t\tptr_rule->depth = depth;\n+\t\t/* If the depth of the route is more than 24, store it\n+\t\t * in another table as well.\n+\t\t */\n+\t\tif (depth > 24) {\n+\t\t\tptr_ldepth_rule->ip = ptr_rule->ip;\n+\t\t\tptr_ldepth_rule->depth = ptr_rule->depth;\n+\t\t\tptr_ldepth_rule++;\n+\t\t\tnum_ldepth_route_entries++;\n+\t\t}\n \t\tptr_rule++;\n \t\tstart = (start + step) & mask;\n \t}\n@@ -273,6 +304,7 @@ static void generate_large_route_rule_table(void)\n \tuint8_t  depth;\n \n \tnum_route_entries = 0;\n+\tnum_ldepth_route_entries = 0;\n \tmemset(large_route_table, 0, sizeof(large_route_table));\n \n \tfor (ip_class = IP_CLASS_A; ip_class <= IP_CLASS_C; ip_class++) {\n@@ -316,10 +348,460 @@ print_route_distribution(const struct route_rule *table, uint32_t n)\n \tprintf(\"\\n\");\n }\n \n+/* Check condition and return an error if true. */\n+static uint16_t enabled_core_ids[RTE_MAX_LCORE];\n+static unsigned int num_cores;\n+\n+/* Simple way to allocate thread ids in 0 to RTE_MAX_LCORE space */\n+static inline uint32_t\n+alloc_thread_id(void)\n+{\n+\tuint32_t tmp_thr_id;\n+\n+\ttmp_thr_id = __atomic_fetch_add(&thr_id, 1, __ATOMIC_RELAXED);\n+\tif (tmp_thr_id >= RTE_MAX_LCORE)\n+\t\tprintf(\"Invalid thread id %u\\n\", tmp_thr_id);\n+\n+\treturn tmp_thr_id;\n+}\n+\n+/*\n+ * Reader thread using rte_lpm data structure without RCU.\n+ */\n+static int\n+test_lpm_reader(void *arg)\n+{\n+\tint i;\n+\tuint32_t ip_batch[QSBR_REPORTING_INTERVAL];\n+\tuint32_t next_hop_return = 0;\n+\n+\tRTE_SET_USED(arg);\n+\tdo {\n+\t\tfor (i = 0; i < QSBR_REPORTING_INTERVAL; i++)\n+\t\t\tip_batch[i] = rte_rand();\n+\n+\t\tfor (i = 0; i < QSBR_REPORTING_INTERVAL; i++)\n+\t\t\trte_lpm_lookup(lpm, ip_batch[i], &next_hop_return);\n+\n+\t} while (!writer_done);\n+\n+\treturn 0;\n+}\n+\n+/*\n+ * Reader thread using rte_lpm data structure with RCU.\n+ */\n+static int\n+test_lpm_rcu_qsbr_reader(void *arg)\n+{\n+\tint i;\n+\tuint32_t thread_id = alloc_thread_id();\n+\tuint32_t ip_batch[QSBR_REPORTING_INTERVAL];\n+\tuint32_t next_hop_return = 0;\n+\n+\tRTE_SET_USED(arg);\n+\t/* Register this thread to report quiescent state */\n+\trte_rcu_qsbr_thread_register(rv, thread_id);\n+\trte_rcu_qsbr_thread_online(rv, thread_id);\n+\n+\tdo {\n+\t\tfor (i = 0; i < QSBR_REPORTING_INTERVAL; i++)\n+\t\t\tip_batch[i] = rte_rand();\n+\n+\t\tfor (i = 0; i < QSBR_REPORTING_INTERVAL; i++)\n+\t\t\trte_lpm_lookup(lpm, ip_batch[i], &next_hop_return);\n+\n+\t\t/* Update quiescent state */\n+\t\trte_rcu_qsbr_quiescent(rv, thread_id);\n+\t} while (!writer_done);\n+\n+\trte_rcu_qsbr_thread_offline(rv, thread_id);\n+\trte_rcu_qsbr_thread_unregister(rv, thread_id);\n+\n+\treturn 0;\n+}\n+\n+/*\n+ * Writer thread using rte_lpm data structure with RCU.\n+ */\n+static int\n+test_lpm_rcu_qsbr_writer(void *arg)\n+{\n+\tunsigned int i, j, si, ei;\n+\tuint64_t begin, total_cycles;\n+\tuint8_t core_id = (uint8_t)((uintptr_t)arg);\n+\tuint32_t next_hop_add = 0xAA;\n+\n+\tRTE_SET_USED(arg);\n+\t/* 2 writer threads are used */\n+\tif (core_id % 2 == 0) {\n+\t\tsi = 0;\n+\t\tei = NUM_LDEPTH_ROUTE_ENTRIES / 2;\n+\t} else {\n+\t\tsi = NUM_LDEPTH_ROUTE_ENTRIES / 2;\n+\t\tei = NUM_LDEPTH_ROUTE_ENTRIES;\n+\t}\n+\n+\t/* Measure add/delete. */\n+\tbegin = rte_rdtsc_precise();\n+\tfor (i = 0; i < RCU_ITERATIONS; i++) {\n+\t\t/* Add all the entries */\n+\t\tfor (j = si; j < ei; j++) {\n+\t\t\tpthread_mutex_lock(&lpm_mutex);\n+\t\t\tif (rte_lpm_add(lpm, large_ldepth_route_table[j].ip,\n+\t\t\t\t\tlarge_ldepth_route_table[j].depth,\n+\t\t\t\t\tnext_hop_add) != 0) {\n+\t\t\t\tprintf(\"Failed to add iteration %d, route# %d\\n\",\n+\t\t\t\t\ti, j);\n+\t\t\t}\n+\t\t\tpthread_mutex_unlock(&lpm_mutex);\n+\t\t}\n+\n+\t\t/* Delete all the entries */\n+\t\tfor (j = si; j < ei; j++) {\n+\t\t\tpthread_mutex_lock(&lpm_mutex);\n+\t\t\tif (rte_lpm_delete(lpm, large_ldepth_route_table[j].ip,\n+\t\t\t\tlarge_ldepth_route_table[j].depth) != 0) {\n+\t\t\t\tprintf(\"Failed to delete iteration %d, route# %d\\n\",\n+\t\t\t\t\ti, j);\n+\t\t\t}\n+\t\t\tpthread_mutex_unlock(&lpm_mutex);\n+\t\t}\n+\t}\n+\n+\ttotal_cycles = rte_rdtsc_precise() - begin;\n+\n+\t__atomic_fetch_add(&gwrite_cycles, total_cycles, __ATOMIC_RELAXED);\n+\t__atomic_fetch_add(&gwrites,\n+\t\t\t2 * NUM_LDEPTH_ROUTE_ENTRIES * RCU_ITERATIONS,\n+\t\t\t__ATOMIC_RELAXED);\n+\n+\treturn 0;\n+}\n+\n+/*\n+ * Functional test:\n+ * 2 writers, rest are readers\n+ */\n+static int\n+test_lpm_rcu_perf_multi_writer(void)\n+{\n+\tstruct rte_lpm_config config;\n+\tsize_t sz;\n+\tunsigned int i;\n+\tuint16_t core_id;\n+\tstruct rte_lpm_rcu_config rcu_cfg = {0};\n+\n+\tif (rte_lcore_count() < 3) {\n+\t\tprintf(\"Not enough cores for lpm_rcu_perf_autotest, expecting at least 3\\n\");\n+\t\treturn TEST_SKIPPED;\n+\t}\n+\n+\tnum_cores = 0;\n+\tRTE_LCORE_FOREACH_SLAVE(core_id) {\n+\t\tenabled_core_ids[num_cores] = core_id;\n+\t\tnum_cores++;\n+\t}\n+\n+\tprintf(\"\\nPerf test: 2 writers, %d readers, RCU integration enabled\\n\",\n+\t\tnum_cores - 2);\n+\n+\t/* Create LPM table */\n+\tconfig.max_rules = NUM_LDEPTH_ROUTE_ENTRIES;\n+\tconfig.number_tbl8s = NUM_LDEPTH_ROUTE_ENTRIES;\n+\tconfig.flags = 0;\n+\tlpm = rte_lpm_create(__func__, SOCKET_ID_ANY, &config);\n+\tTEST_LPM_ASSERT(lpm != NULL);\n+\n+\t/* Init RCU variable */\n+\tsz = rte_rcu_qsbr_get_memsize(num_cores);\n+\trv = (struct rte_rcu_qsbr *)rte_zmalloc(\"rcu0\", sz,\n+\t\t\t\t\t\tRTE_CACHE_LINE_SIZE);\n+\trte_rcu_qsbr_init(rv, num_cores);\n+\n+\trcu_cfg.v = rv;\n+\t/* Assign the RCU variable to LPM */\n+\tif (rte_lpm_rcu_qsbr_add(lpm, &rcu_cfg, NULL) != 0) {\n+\t\tprintf(\"RCU variable assignment failed\\n\");\n+\t\tgoto error;\n+\t}\n+\n+\twriter_done = 0;\n+\t__atomic_store_n(&gwrite_cycles, 0, __ATOMIC_RELAXED);\n+\t__atomic_store_n(&gwrites, 0, __ATOMIC_RELAXED);\n+\n+\t__atomic_store_n(&thr_id, 0, __ATOMIC_SEQ_CST);\n+\n+\t/* Launch reader threads */\n+\tfor (i = 2; i < num_cores; i++)\n+\t\trte_eal_remote_launch(test_lpm_rcu_qsbr_reader, NULL,\n+\t\t\t\t\tenabled_core_ids[i]);\n+\n+\t/* Launch writer threads */\n+\tfor (i = 0; i < 2; i++)\n+\t\trte_eal_remote_launch(test_lpm_rcu_qsbr_writer,\n+\t\t\t\t\t(void *)(uintptr_t)i,\n+\t\t\t\t\tenabled_core_ids[i]);\n+\n+\t/* Wait for writer threads */\n+\tfor (i = 0; i < 2; i++)\n+\t\tif (rte_eal_wait_lcore(enabled_core_ids[i]) < 0)\n+\t\t\tgoto error;\n+\n+\tprintf(\"Total LPM Adds: %d\\n\",\n+\t\t2 * ITERATIONS * NUM_LDEPTH_ROUTE_ENTRIES);\n+\tprintf(\"Total LPM Deletes: %d\\n\",\n+\t\t2 * ITERATIONS * NUM_LDEPTH_ROUTE_ENTRIES);\n+\tprintf(\"Average LPM Add/Del: %\"PRIu64\" cycles\\n\",\n+\t\t__atomic_load_n(&gwrite_cycles, __ATOMIC_RELAXED) /\n+\t\t\t__atomic_load_n(&gwrites, __ATOMIC_RELAXED)\n+\t\t);\n+\n+\t/* Wait and check return value from reader threads */\n+\twriter_done = 1;\n+\tfor (i = 2; i < num_cores; i++)\n+\t\tif (rte_eal_wait_lcore(enabled_core_ids[i]) < 0)\n+\t\t\tgoto error;\n+\n+\trte_lpm_free(lpm);\n+\trte_free(rv);\n+\tlpm = NULL;\n+\trv = NULL;\n+\n+\t/* Test without RCU integration */\n+\tprintf(\"\\nPerf test: 2 writers, %d readers, RCU integration disabled\\n\",\n+\t\tnum_cores - 2);\n+\n+\t/* Create LPM table */\n+\tconfig.max_rules = NUM_LDEPTH_ROUTE_ENTRIES;\n+\tconfig.number_tbl8s = NUM_LDEPTH_ROUTE_ENTRIES;\n+\tconfig.flags = 0;\n+\tlpm = rte_lpm_create(__func__, SOCKET_ID_ANY, &config);\n+\tTEST_LPM_ASSERT(lpm != NULL);\n+\n+\twriter_done = 0;\n+\t__atomic_store_n(&gwrite_cycles, 0, __ATOMIC_RELAXED);\n+\t__atomic_store_n(&gwrites, 0, __ATOMIC_RELAXED);\n+\t__atomic_store_n(&thr_id, 0, __ATOMIC_SEQ_CST);\n+\n+\t/* Launch reader threads */\n+\tfor (i = 2; i < num_cores; i++)\n+\t\trte_eal_remote_launch(test_lpm_reader, NULL,\n+\t\t\t\t\tenabled_core_ids[i]);\n+\n+\t/* Launch writer threads */\n+\tfor (i = 0; i < 2; i++)\n+\t\trte_eal_remote_launch(test_lpm_rcu_qsbr_writer,\n+\t\t\t\t\t(void *)(uintptr_t)i,\n+\t\t\t\t\tenabled_core_ids[i]);\n+\n+\t/* Wait for writer threads */\n+\tfor (i = 0; i < 2; i++)\n+\t\tif (rte_eal_wait_lcore(enabled_core_ids[i]) < 0)\n+\t\t\tgoto error;\n+\n+\tprintf(\"Total LPM Adds: %d\\n\",\n+\t\t2 * ITERATIONS * NUM_LDEPTH_ROUTE_ENTRIES);\n+\tprintf(\"Total LPM Deletes: %d\\n\",\n+\t\t2 * ITERATIONS * NUM_LDEPTH_ROUTE_ENTRIES);\n+\tprintf(\"Average LPM Add/Del: %\"PRIu64\" cycles\\n\",\n+\t\t__atomic_load_n(&gwrite_cycles, __ATOMIC_RELAXED) /\n+\t\t\t__atomic_load_n(&gwrites, __ATOMIC_RELAXED)\n+\t\t);\n+\n+\twriter_done = 1;\n+\t/* Wait and check return value from reader threads */\n+\tfor (i = 2; i < num_cores; i++)\n+\t\tif (rte_eal_wait_lcore(enabled_core_ids[i]) < 0)\n+\t\t\tgoto error;\n+\n+\trte_lpm_free(lpm);\n+\n+\treturn 0;\n+\n+error:\n+\twriter_done = 1;\n+\t/* Wait until all readers have exited */\n+\trte_eal_mp_wait_lcore();\n+\n+\trte_lpm_free(lpm);\n+\trte_free(rv);\n+\n+\treturn -1;\n+}\n+\n+/*\n+ * Functional test:\n+ * Single writer, rest are readers\n+ */\n+static int\n+test_lpm_rcu_perf(void)\n+{\n+\tstruct rte_lpm_config config;\n+\tuint64_t begin, total_cycles;\n+\tsize_t sz;\n+\tunsigned int i, j;\n+\tuint16_t core_id;\n+\tuint32_t next_hop_add = 0xAA;\n+\tstruct rte_lpm_rcu_config rcu_cfg = {0};\n+\n+\tif (rte_lcore_count() < 2) {\n+\t\tprintf(\"Not enough cores for lpm_rcu_perf_autotest, expecting at least 2\\n\");\n+\t\treturn TEST_SKIPPED;\n+\t}\n+\n+\tnum_cores = 0;\n+\tRTE_LCORE_FOREACH_SLAVE(core_id) {\n+\t\tenabled_core_ids[num_cores] = core_id;\n+\t\tnum_cores++;\n+\t}\n+\n+\tprintf(\"\\nPerf test: 1 writer, %d readers, RCU integration enabled\\n\",\n+\t\tnum_cores);\n+\n+\t/* Create LPM table */\n+\tconfig.max_rules = NUM_LDEPTH_ROUTE_ENTRIES;\n+\tconfig.number_tbl8s = NUM_LDEPTH_ROUTE_ENTRIES;\n+\tconfig.flags = 0;\n+\tlpm = rte_lpm_create(__func__, SOCKET_ID_ANY, &config);\n+\tTEST_LPM_ASSERT(lpm != NULL);\n+\n+\t/* Init RCU variable */\n+\tsz = rte_rcu_qsbr_get_memsize(num_cores);\n+\trv = (struct rte_rcu_qsbr *)rte_zmalloc(\"rcu0\", sz,\n+\t\t\t\t\t\tRTE_CACHE_LINE_SIZE);\n+\trte_rcu_qsbr_init(rv, num_cores);\n+\n+\trcu_cfg.v = rv;\n+\t/* Assign the RCU variable to LPM */\n+\tif (rte_lpm_rcu_qsbr_add(lpm, &rcu_cfg, NULL) != 0) {\n+\t\tprintf(\"RCU variable assignment failed\\n\");\n+\t\tgoto error;\n+\t}\n+\n+\twriter_done = 0;\n+\t__atomic_store_n(&thr_id, 0, __ATOMIC_SEQ_CST);\n+\n+\t/* Launch reader threads */\n+\tfor (i = 0; i < num_cores; i++)\n+\t\trte_eal_remote_launch(test_lpm_rcu_qsbr_reader, NULL,\n+\t\t\t\t\tenabled_core_ids[i]);\n+\n+\t/* Measure add/delete. */\n+\tbegin = rte_rdtsc_precise();\n+\tfor (i = 0; i < RCU_ITERATIONS; i++) {\n+\t\t/* Add all the entries */\n+\t\tfor (j = 0; j < NUM_LDEPTH_ROUTE_ENTRIES; j++)\n+\t\t\tif (rte_lpm_add(lpm, large_ldepth_route_table[j].ip,\n+\t\t\t\t\tlarge_ldepth_route_table[j].depth,\n+\t\t\t\t\tnext_hop_add) != 0) {\n+\t\t\t\tprintf(\"Failed to add iteration %d, route# %d\\n\",\n+\t\t\t\t\ti, j);\n+\t\t\t\tgoto error;\n+\t\t\t}\n+\n+\t\t/* Delete all the entries */\n+\t\tfor (j = 0; j < NUM_LDEPTH_ROUTE_ENTRIES; j++)\n+\t\t\tif (rte_lpm_delete(lpm, large_ldepth_route_table[j].ip,\n+\t\t\t\tlarge_ldepth_route_table[j].depth) != 0) {\n+\t\t\t\tprintf(\"Failed to delete iteration %d, route# %d\\n\",\n+\t\t\t\t\ti, j);\n+\t\t\t\tgoto error;\n+\t\t\t}\n+\t}\n+\ttotal_cycles = rte_rdtsc_precise() - begin;\n+\n+\tprintf(\"Total LPM Adds: %d\\n\", ITERATIONS * NUM_LDEPTH_ROUTE_ENTRIES);\n+\tprintf(\"Total LPM Deletes: %d\\n\",\n+\t\tITERATIONS * NUM_LDEPTH_ROUTE_ENTRIES);\n+\tprintf(\"Average LPM Add/Del: %g cycles\\n\",\n+\t\t(double)total_cycles / (NUM_LDEPTH_ROUTE_ENTRIES * ITERATIONS));\n+\n+\twriter_done = 1;\n+\t/* Wait and check return value from reader threads */\n+\tfor (i = 0; i < num_cores; i++)\n+\t\tif (rte_eal_wait_lcore(enabled_core_ids[i]) < 0)\n+\t\t\tgoto error;\n+\n+\trte_lpm_free(lpm);\n+\trte_free(rv);\n+\tlpm = NULL;\n+\trv = NULL;\n+\n+\t/* Test without RCU integration */\n+\tprintf(\"\\nPerf test: 1 writer, %d readers, RCU integration disabled\\n\",\n+\t\tnum_cores);\n+\n+\t/* Create LPM table */\n+\tconfig.max_rules = NUM_LDEPTH_ROUTE_ENTRIES;\n+\tconfig.number_tbl8s = NUM_LDEPTH_ROUTE_ENTRIES;\n+\tconfig.flags = 0;\n+\tlpm = rte_lpm_create(__func__, SOCKET_ID_ANY, &config);\n+\tTEST_LPM_ASSERT(lpm != NULL);\n+\n+\twriter_done = 0;\n+\t__atomic_store_n(&thr_id, 0, __ATOMIC_SEQ_CST);\n+\n+\t/* Launch reader threads */\n+\tfor (i = 0; i < num_cores; i++)\n+\t\trte_eal_remote_launch(test_lpm_reader, NULL,\n+\t\t\t\t\tenabled_core_ids[i]);\n+\n+\t/* Measure add/delete. */\n+\tbegin = rte_rdtsc_precise();\n+\tfor (i = 0; i < RCU_ITERATIONS; i++) {\n+\t\t/* Add all the entries */\n+\t\tfor (j = 0; j < NUM_LDEPTH_ROUTE_ENTRIES; j++)\n+\t\t\tif (rte_lpm_add(lpm, large_ldepth_route_table[j].ip,\n+\t\t\t\t\tlarge_ldepth_route_table[j].depth,\n+\t\t\t\t\tnext_hop_add) != 0) {\n+\t\t\t\tprintf(\"Failed to add iteration %d, route# %d\\n\",\n+\t\t\t\t\ti, j);\n+\t\t\t\tgoto error;\n+\t\t\t}\n+\n+\t\t/* Delete all the entries */\n+\t\tfor (j = 0; j < NUM_LDEPTH_ROUTE_ENTRIES; j++)\n+\t\t\tif (rte_lpm_delete(lpm, large_ldepth_route_table[j].ip,\n+\t\t\t\tlarge_ldepth_route_table[j].depth) != 0) {\n+\t\t\t\tprintf(\"Failed to delete iteration %d, route# %d\\n\",\n+\t\t\t\t\ti, j);\n+\t\t\t\tgoto error;\n+\t\t\t}\n+\t}\n+\ttotal_cycles = rte_rdtsc_precise() - begin;\n+\n+\tprintf(\"Total LPM Adds: %d\\n\", ITERATIONS * NUM_LDEPTH_ROUTE_ENTRIES);\n+\tprintf(\"Total LPM Deletes: %d\\n\",\n+\t\tITERATIONS * NUM_LDEPTH_ROUTE_ENTRIES);\n+\tprintf(\"Average LPM Add/Del: %g cycles\\n\",\n+\t\t(double)total_cycles / (NUM_LDEPTH_ROUTE_ENTRIES * ITERATIONS));\n+\n+\twriter_done = 1;\n+\t/* Wait and check return value from reader threads */\n+\tfor (i = 0; i < num_cores; i++)\n+\t\tif (rte_eal_wait_lcore(enabled_core_ids[i]) < 0)\n+\t\t\tprintf(\"Warning: lcore %u not finished.\\n\",\n+\t\t\t\tenabled_core_ids[i]);\n+\n+\trte_lpm_free(lpm);\n+\n+\treturn 0;\n+\n+error:\n+\twriter_done = 1;\n+\t/* Wait until all readers have exited */\n+\trte_eal_mp_wait_lcore();\n+\n+\trte_lpm_free(lpm);\n+\trte_free(rv);\n+\n+\treturn -1;\n+}\n+\n static int\n test_lpm_perf(void)\n {\n-\tstruct rte_lpm *lpm = NULL;\n \tstruct rte_lpm_config config;\n \n \tconfig.max_rules = 2000000;\n@@ -343,7 +825,7 @@ test_lpm_perf(void)\n \tlpm = rte_lpm_create(__func__, SOCKET_ID_ANY, &config);\n \tTEST_LPM_ASSERT(lpm != NULL);\n \n-\t/* Measue add. */\n+\t/* Measure add. */\n \tbegin = rte_rdtsc();\n \n \tfor (i = 0; i < NUM_ROUTE_ENTRIES; i++) {\n@@ -478,6 +960,10 @@ test_lpm_perf(void)\n \trte_lpm_delete_all(lpm);\n \trte_lpm_free(lpm);\n \n+\ttest_lpm_rcu_perf();\n+\n+\ttest_lpm_rcu_perf_multi_writer();\n+\n \treturn 0;\n }\n \n",
    "prefixes": [
        "v6",
        "3/3"
    ]
}