get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

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

{
    "id": 47027,
    "url": "http://patchwork.dpdk.org/api/patches/47027/?format=api",
    "web_url": "http://patchwork.dpdk.org/project/dpdk/patch/1539833881-589-6-git-send-email-honnappa.nagarahalli@arm.com/",
    "project": {
        "id": 1,
        "url": "http://patchwork.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": "<1539833881-589-6-git-send-email-honnappa.nagarahalli@arm.com>",
    "list_archive_url": "https://inbox.dpdk.org/dev/1539833881-589-6-git-send-email-honnappa.nagarahalli@arm.com",
    "date": "2018-10-18T03:38:01",
    "name": "[v4,5/5] test/hash: read-write lock-free concurrency test",
    "commit_ref": null,
    "pull_url": null,
    "state": "superseded",
    "archived": true,
    "hash": "8366a8e97d25b0d9b491c15f1c90bd58415bc785",
    "submitter": {
        "id": 1045,
        "url": "http://patchwork.dpdk.org/api/people/1045/?format=api",
        "name": "Honnappa Nagarahalli",
        "email": "honnappa.nagarahalli@arm.com"
    },
    "delegate": {
        "id": 1,
        "url": "http://patchwork.dpdk.org/api/users/1/?format=api",
        "username": "tmonjalo",
        "first_name": "Thomas",
        "last_name": "Monjalon",
        "email": "thomas@monjalon.net"
    },
    "mbox": "http://patchwork.dpdk.org/project/dpdk/patch/1539833881-589-6-git-send-email-honnappa.nagarahalli@arm.com/mbox/",
    "series": [
        {
            "id": 1967,
            "url": "http://patchwork.dpdk.org/api/series/1967/?format=api",
            "web_url": "http://patchwork.dpdk.org/project/dpdk/list/?series=1967",
            "date": "2018-10-18T03:37:56",
            "name": "Address reader-writer concurrency in rte_hash",
            "version": 4,
            "mbox": "http://patchwork.dpdk.org/series/1967/mbox/"
        }
    ],
    "comments": "http://patchwork.dpdk.org/api/patches/47027/comments/",
    "check": "success",
    "checks": "http://patchwork.dpdk.org/api/patches/47027/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 [127.0.0.1])\n\tby dpdk.org (Postfix) with ESMTP id 04A011B145;\n\tThu, 18 Oct 2018 05:38:25 +0200 (CEST)",
            "from foss.arm.com (foss.arm.com [217.140.101.70])\n\tby dpdk.org (Postfix) with ESMTP id C16241B115\n\tfor <dev@dpdk.org>; Thu, 18 Oct 2018 05:38:17 +0200 (CEST)",
            "from usa-sjc-imap-foss1.foss.arm.com (unknown [10.72.51.249])\n\tby usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id 22D11EBD;\n\tWed, 17 Oct 2018 20:38:17 -0700 (PDT)",
            "from 2p2660v4-1.austin.arm.com (2p2660v4-1.austin.arm.com\n\t[10.118.14.139])\n\tby usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id\n\t9EB083F5D3; Wed, 17 Oct 2018 20:38:16 -0700 (PDT)"
        ],
        "From": "Honnappa Nagarahalli <honnappa.nagarahalli@arm.com>",
        "To": "bruce.richardson@intel.com,\n\tpablo.de.lara.guarch@intel.com",
        "Cc": "dev@dpdk.org, yipeng1.wang@intel.com, honnappa.nagarahalli@arm.com,\n\tgavin.hu@arm.com, dharmik.thakkar@arm.com, nd@arm.com",
        "Date": "Wed, 17 Oct 2018 22:38:01 -0500",
        "Message-Id": "<1539833881-589-6-git-send-email-honnappa.nagarahalli@arm.com>",
        "X-Mailer": "git-send-email 2.7.4",
        "In-Reply-To": "<1539833881-589-1-git-send-email-honnappa.nagarahalli@arm.com>",
        "References": "<1539833881-589-1-git-send-email-honnappa.nagarahalli@arm.com>",
        "Subject": "[dpdk-dev] [PATCH v4 5/5] test/hash: read-write lock-free\n\tconcurrency test",
        "X-BeenThere": "dev@dpdk.org",
        "X-Mailman-Version": "2.1.15",
        "Precedence": "list",
        "List-Id": "DPDK patches and discussions <dev.dpdk.org>",
        "List-Unsubscribe": "<https://mails.dpdk.org/options/dev>,\n\t<mailto:dev-request@dpdk.org?subject=unsubscribe>",
        "List-Archive": "<http://mails.dpdk.org/archives/dev/>",
        "List-Post": "<mailto:dev@dpdk.org>",
        "List-Help": "<mailto:dev-request@dpdk.org?subject=help>",
        "List-Subscribe": "<https://mails.dpdk.org/listinfo/dev>,\n\t<mailto:dev-request@dpdk.org?subject=subscribe>",
        "Errors-To": "dev-bounces@dpdk.org",
        "Sender": "\"dev\" <dev-bounces@dpdk.org>"
    },
    "content": "From: Dharmik Thakkar <dharmik.thakkar@arm.com>\n\nUnit tests to check for hash lookup and bulk-lookup perf\nwith lock-free enabled and with lock-free disabled.\nUnit tests performed with readers running in parallel with writers.\n\nTests include:\n\n- hash lookup on existing keys with:\n  - hash add causing NO key-shifts of existing keys in the table\n\n- hash lookup on existing keys likely to be on shift-path with:\n  - hash add causing key-shifts of existing keys in the table\n\n- hash lookup on existing keys NOT likely to be on shift-path with:\n  - hash add causing key-shifts of existing keys in the table\n\n- hash lookup on non-existing keys with:\n  - hash add causing NO key-shifts of existing keys in the table\n  - hash add causing key-shifts of existing keys in the table\n\n- hash lookup on keys likely to be on shift-path with:\n  - multiple writers causing key-shifts of existing keys in the table\n\nSigned-off-by: Dharmik Thakkar <dharmik.thakkar@arm.com>\nReviewed-by: Honnappa Nagarahalli <honnappa.nagarahalli@arm.com>\nReviewed-by: Gavin Hu <gavin.hu@arm.com>\nReviewed-by: Yipeng Wang <yipeng1.wang@intel.com>\n---\n test/test/Makefile                 |    1 +\n test/test/meson.build              |    1 +\n test/test/test_hash_readwrite_lf.c | 1220 ++++++++++++++++++++++++++++++++++++\n 3 files changed, 1222 insertions(+)\n create mode 100644 test/test/test_hash_readwrite_lf.c",
    "diff": "diff --git a/test/test/Makefile b/test/test/Makefile\nindex 5d8b1dc..0e0e6c4 100644\n--- a/test/test/Makefile\n+++ b/test/test/Makefile\n@@ -116,6 +116,7 @@ SRCS-$(CONFIG_RTE_LIBRTE_HASH) += test_hash_functions.c\n SRCS-$(CONFIG_RTE_LIBRTE_HASH) += test_hash_scaling.c\n SRCS-$(CONFIG_RTE_LIBRTE_HASH) += test_hash_multiwriter.c\n SRCS-$(CONFIG_RTE_LIBRTE_HASH) += test_hash_readwrite.c\n+SRCS-$(CONFIG_RTE_LIBRTE_HASH) += test_hash_readwrite_lf.c\n \n SRCS-$(CONFIG_RTE_LIBRTE_LPM) += test_lpm.c\n SRCS-$(CONFIG_RTE_LIBRTE_LPM) += test_lpm_perf.c\ndiff --git a/test/test/meson.build b/test/test/meson.build\nindex d696f5e..bc3350f 100644\n--- a/test/test/meson.build\n+++ b/test/test/meson.build\n@@ -46,6 +46,7 @@ test_sources = files('commands.c',\n \t'test_hash_multiwriter.c',\n \t'test_hash_readwrite.c',\n \t'test_hash_perf.c',\n+\t'test_hash_readwrite_lf.c',\n \t'test_hash_scaling.c',\n \t'test_interrupts.c',\n \t'test_kni.c',\ndiff --git a/test/test/test_hash_readwrite_lf.c b/test/test/test_hash_readwrite_lf.c\nnew file mode 100644\nindex 0000000..7b2362c\n--- /dev/null\n+++ b/test/test/test_hash_readwrite_lf.c\n@@ -0,0 +1,1220 @@\n+/* SPDX-License-Identifier: BSD-3-Clause\n+ * Copyright(c) 2018 Arm Limited\n+ */\n+\n+#include <inttypes.h>\n+#include <locale.h>\n+\n+#include <rte_cycles.h>\n+#include <rte_hash.h>\n+#include <rte_hash_crc.h>\n+#include <rte_jhash.h>\n+#include <rte_launch.h>\n+#include <rte_malloc.h>\n+#include <rte_random.h>\n+#include <rte_spinlock.h>\n+\n+#include \"test.h\"\n+\n+#ifndef RTE_HASH_EXTRA_FLAGS_RW_CONCURRENCY_LF\n+#define RTE_HASH_EXTRA_FLAGS_RW_CONCURRENCY_LF 0\n+#endif\n+\n+#define BULK_LOOKUP_SIZE 32\n+\n+#define RUN_WITH_HTM_DISABLED 0\n+\n+#if (RUN_WITH_HTM_DISABLED)\n+\n+#define TOTAL_ENTRY (5*1024)\n+#define TOTAL_INSERT (5*1024)\n+\n+#else\n+\n+#define TOTAL_ENTRY (4*1024*1024)\n+#define TOTAL_INSERT (4*1024*1024)\n+\n+#endif\n+\n+#define READ_FAIL 1\n+#define READ_PASS_NO_KEY_SHIFTS 2\n+#define READ_PASS_SHIFT_PATH 4\n+#define READ_PASS_NON_SHIFT_PATH 8\n+#define BULK_LOOKUP 16\n+#define NUM_TEST 3\n+unsigned int rwc_core_cnt[NUM_TEST] = {1, 2, 4};\n+\n+struct rwc_perf {\n+\tuint32_t w_no_ks_r_pass[2][NUM_TEST];\n+\tuint32_t w_no_ks_r_fail[2][NUM_TEST];\n+\tuint32_t w_ks_r_pass_nsp[2][NUM_TEST];\n+\tuint32_t w_ks_r_pass_sp[2][NUM_TEST];\n+\tuint32_t w_ks_r_fail[2][NUM_TEST];\n+\tuint32_t multi_rw[NUM_TEST - 1][2][NUM_TEST];\n+};\n+\n+static struct rwc_perf rwc_lf_results, rwc_non_lf_results;\n+\n+struct {\n+\tuint32_t *keys;\n+\tuint32_t *keys_no_ks;\n+\tuint32_t *keys_ks;\n+\tuint32_t *keys_absent;\n+\tuint32_t *keys_shift_path;\n+\tuint32_t *keys_non_shift_path;\n+\tuint32_t count_keys_no_ks;\n+\tuint32_t count_keys_ks;\n+\tuint32_t count_keys_absent;\n+\tuint32_t count_keys_shift_path;\n+\tuint32_t count_keys_non_shift_path;\n+\tuint32_t single_insert;\n+\tstruct rte_hash *h;\n+} tbl_rwc_test_param;\n+\n+static rte_atomic64_t gread_cycles;\n+static rte_atomic64_t greads;\n+\n+static volatile uint8_t writer_done;\n+static volatile uint8_t multi_writer_done[4];\n+\n+uint16_t enabled_core_ids[RTE_MAX_LCORE];\n+\n+uint8_t *scanned_bkts;\n+\n+static inline int\n+get_enabled_cores_list(void)\n+{\n+\tuint32_t i = 0;\n+\tuint16_t core_id;\n+\tuint32_t max_cores = rte_lcore_count();\n+\tfor (core_id = 0; core_id < RTE_MAX_LCORE && i < max_cores; core_id++) {\n+\t\tif (rte_lcore_is_enabled(core_id)) {\n+\t\t\tenabled_core_ids[i] = core_id;\n+\t\t\ti++;\n+\t\t}\n+\t}\n+\n+\tif (i != rte_lcore_count()) {\n+\t\tprintf(\"Number of enabled cores in list is different from \"\n+\t\t\t\"number given by rte_lcore_count()\\n\");\n+\t\treturn -1;\n+\t}\n+\treturn 0;\n+}\n+\n+static inline int\n+check_bucket(uint32_t bkt_idx, uint32_t key)\n+{\n+\tuint32_t iter;\n+\tuint32_t prev_iter;\n+\tuint32_t diff;\n+\tuint32_t count = 0;\n+\tconst void *next_key;\n+\tvoid *next_data;\n+\n+\t/* Temporary bucket to hold the keys */\n+\tuint32_t keys_in_bkt[8];\n+\n+\titer = bkt_idx * 8;\n+\tprev_iter = iter;\n+\twhile (rte_hash_iterate(tbl_rwc_test_param.h,\n+\t\t\t&next_key, &next_data, &iter) >= 0) {\n+\n+\t\t/* Check for duplicate entries */\n+\t\tif (*(const uint32_t *)next_key == key)\n+\t\t\treturn 1;\n+\n+\t\t/* Identify if there is any free entry in the bucket */\n+\t\tdiff = iter - prev_iter;\n+\t\tif (diff > 1)\n+\t\t\tbreak;\n+\n+\t\tprev_iter = iter;\n+\t\tkeys_in_bkt[count] = *(const uint32_t *)next_key;\n+\t\tcount++;\n+\n+\t\t/* All entries in the bucket are occupied */\n+\t\tif (count == 8) {\n+\n+\t\t\t/*\n+\t\t\t * Check if bucket was not scanned before, to avoid\n+\t\t\t * duplicate keys.\n+\t\t\t */\n+\t\t\tif (scanned_bkts[bkt_idx] == 0) {\n+\t\t\t\t/*\n+\t\t\t\t * Since this bucket (pointed to by bkt_idx) is\n+\t\t\t\t * full, it is likely that key(s) in this\n+\t\t\t\t * bucket will be on the shift path, when\n+\t\t\t\t * collision occurs. Thus, add it to\n+\t\t\t\t * keys_shift_path.\n+\t\t\t\t */\n+\t\t\t\tmemcpy(tbl_rwc_test_param.keys_shift_path +\n+\t\t\t\t\ttbl_rwc_test_param.count_keys_shift_path\n+\t\t\t\t\t, keys_in_bkt, 32);\n+\t\t\t\ttbl_rwc_test_param.count_keys_shift_path += 8;\n+\t\t\t\tscanned_bkts[bkt_idx] = 1;\n+\t\t\t}\n+\t\t\treturn -1;\n+\t\t}\n+\t}\n+\treturn 0;\n+}\n+\n+static int\n+generate_keys(void)\n+{\n+\tuint32_t *keys = NULL;\n+\tuint32_t *keys_no_ks = NULL;\n+\tuint32_t *keys_ks = NULL;\n+\tuint32_t *keys_absent = NULL;\n+\tuint32_t *keys_non_shift_path = NULL;\n+\tuint32_t *found = NULL;\n+\tuint32_t count_keys_no_ks = 0;\n+\tuint32_t count_keys_ks = 0;\n+\tuint32_t i;\n+\n+\t/*\n+\t * keys will consist of a) keys whose addition to the hash table\n+\t * will result in shifting of the existing keys to their alternate\n+\t * locations b) keys whose addition to the hash table will not result\n+\t * in shifting of the existing keys.\n+\t */\n+\tkeys = rte_malloc(NULL, sizeof(uint32_t) * TOTAL_INSERT, 0);\n+\tif (keys == NULL) {\n+\t\tprintf(\"RTE_MALLOC failed\\n\");\n+\t\tgoto err;\n+\t}\n+\n+\t/*\n+\t * keys_no_ks (no key-shifts): Subset of 'keys' - consists of keys  that\n+\t * will NOT result in shifting of the existing keys to their alternate\n+\t * locations. Roughly around 900K keys.\n+\t */\n+\tkeys_no_ks = rte_malloc(NULL, sizeof(uint32_t) * TOTAL_INSERT, 0);\n+\tif (keys_no_ks == NULL) {\n+\t\tprintf(\"RTE_MALLOC failed\\n\");\n+\t\tgoto err;\n+\t}\n+\n+\t/*\n+\t * keys_ks (key-shifts): Subset of 'keys' - consists of keys that will\n+\t * result in shifting of the existing keys to their alternate locations.\n+\t * Roughly around 146K keys. There might be repeating keys. More code is\n+\t * required to filter out these keys which will complicate the test case\n+\t */\n+\tkeys_ks = rte_malloc(NULL, sizeof(uint32_t) * TOTAL_INSERT, 0);\n+\tif (keys_ks == NULL) {\n+\t\tprintf(\"RTE_MALLOC failed\\n\");\n+\t\tgoto err;\n+\t}\n+\n+\t/* Used to identify keys not inserted in the hash table */\n+\tfound = rte_zmalloc(NULL, sizeof(uint32_t) * TOTAL_INSERT, 0);\n+\tif (found == NULL) {\n+\t\tprintf(\"RTE_MALLOC failed\\n\");\n+\t\tgoto err;\n+\t}\n+\n+\t/*\n+\t * This consist of keys not inserted to the hash table.\n+\t * Used to test perf of lookup on keys that do not exist in the table.\n+\t */\n+\tkeys_absent = rte_malloc(NULL, sizeof(uint32_t) * TOTAL_INSERT, 0);\n+\tif (keys_absent == NULL) {\n+\t\tprintf(\"RTE_MALLOC failed\\n\");\n+\t\tgoto err;\n+\t}\n+\n+\t/*\n+\t * This consist of keys which are likely to be on the shift\n+\t * path (i.e. being moved to alternate location), when collision occurs\n+\t * on addition of a key to an already full primary bucket.\n+\t * Used to test perf of lookup on keys that are on the shift path.\n+\t */\n+\ttbl_rwc_test_param.keys_shift_path = rte_malloc(NULL, sizeof(uint32_t) *\n+\t\t\t\t\t\t\tTOTAL_INSERT, 0);\n+\tif (tbl_rwc_test_param.keys_shift_path == NULL) {\n+\t\tprintf(\"RTE_MALLOC failed\\n\");\n+\t\tgoto err;\n+\t}\n+\n+\t/*\n+\t * This consist of keys which are never on the shift\n+\t * path (i.e. being moved to alternate location), when collision occurs\n+\t * on addition of a key to an already full primary bucket.\n+\t * Used to test perf of lookup on keys that are not on the shift path.\n+\t */\n+\tkeys_non_shift_path = rte_malloc(NULL, sizeof(uint32_t) * TOTAL_INSERT,\n+\t\t\t\t\t 0);\n+\tif (keys_non_shift_path == NULL) {\n+\t\tprintf(\"RTE_MALLOC failed\\n\");\n+\t\tgoto err;\n+\t}\n+\n+\n+\thash_sig_t sig;\n+\tuint32_t prim_bucket_idx;\n+\tint ret;\n+\tuint32_t num_buckets;\n+\tuint32_t bucket_bitmask;\n+\tnum_buckets  = rte_align32pow2(TOTAL_ENTRY) / 8;\n+\tbucket_bitmask = num_buckets - 1;\n+\n+\t/*\n+\t * Used to mark bkts in which at least one key was shifted to its\n+\t * alternate location\n+\t */\n+\tscanned_bkts = rte_malloc(NULL, sizeof(uint8_t) * num_buckets, 0);\n+\tif (scanned_bkts == NULL) {\n+\t\tprintf(\"RTE_MALLOC failed\\n\");\n+\t\tgoto err;\n+\t}\n+\n+\ttbl_rwc_test_param.keys = keys;\n+\ttbl_rwc_test_param.keys_no_ks = keys_no_ks;\n+\ttbl_rwc_test_param.keys_ks = keys_ks;\n+\ttbl_rwc_test_param.keys_absent = keys_absent;\n+\ttbl_rwc_test_param.keys_non_shift_path = keys_non_shift_path;\n+\t/* Generate keys by adding previous two keys, neglect overflow */\n+\tprintf(\"Generating keys...\\n\");\n+\tkeys[0] = 0;\n+\tkeys[1] = 1;\n+\tfor (i = 2; i < TOTAL_INSERT; i++)\n+\t\tkeys[i] = keys[i-1] + keys[i-2];\n+\n+\t/* Segregate keys into keys_no_ks and keys_ks */\n+\tfor (i = 0; i < TOTAL_INSERT; i++) {\n+\t\t/* Check if primary bucket has space.*/\n+\t\tsig = rte_hash_hash(tbl_rwc_test_param.h,\n+\t\t\t\t\ttbl_rwc_test_param.keys+i);\n+\t\tprim_bucket_idx = sig & bucket_bitmask;\n+\t\tret = check_bucket(prim_bucket_idx, keys[i]);\n+\t\tif (ret < 0) {\n+\t\t\t/*\n+\t\t\t * Primary bucket is full, this key will result in\n+\t\t\t * shifting of the keys to their alternate locations.\n+\t\t\t */\n+\t\t\tkeys_ks[count_keys_ks] = keys[i];\n+\t\t\tcount_keys_ks++;\n+\t\t} else if (ret == 0) {\n+\t\t\t/*\n+\t\t\t * Primary bucket has space, this key will not result in\n+\t\t\t * shifting of the keys. Hence, add key to the table.\n+\t\t\t */\n+\t\t\tret = rte_hash_add_key_data(tbl_rwc_test_param.h,\n+\t\t\t\t\t\t\tkeys+i,\n+\t\t\t\t\t\t\t(void *)((uintptr_t)i));\n+\t\t\tif (ret < 0) {\n+\t\t\t\tprintf(\"writer failed %\"PRIu32\"\\n\", i);\n+\t\t\t\tbreak;\n+\t\t\t}\n+\t\t\tkeys_no_ks[count_keys_no_ks] = keys[i];\n+\t\t\tcount_keys_no_ks++;\n+\t\t}\n+\t}\n+\n+\tfor (i = 0; i < count_keys_no_ks; i++) {\n+\t\t/*\n+\t\t * Identify keys in keys_no_ks with value less than\n+\t\t * 4M (HTM enabled) OR 5K (HTM disabled)\n+\t\t */\n+\t\tif (keys_no_ks[i] < TOTAL_INSERT)\n+\t\t\tfound[keys_no_ks[i]]++;\n+\t}\n+\n+\tfor (i = 0; i < count_keys_ks; i++) {\n+\t\t/*\n+\t\t * Identify keys in keys_ks with value less than\n+\t\t * 4M (HTM enabled) OR 5K (HTM disabled)\n+\t\t */\n+\t\tif (keys_ks[i] < TOTAL_INSERT)\n+\t\t\tfound[keys_ks[i]]++;\n+\t}\n+\n+\tuint32_t count_keys_absent = 0;\n+\tfor (i = 0; i < TOTAL_INSERT; i++) {\n+\t\t/*\n+\t\t * Identify missing keys between 0 and\n+\t\t * 4M (HTM enabled) OR 5K (HTM disabled)\n+\t\t */\n+\t\tif (found[i] == 0)\n+\t\t\tkeys_absent[count_keys_absent++] = i;\n+\t}\n+\n+\t/* Find keys that will not be on the shift path */\n+\tuint32_t iter;\n+\tconst void *next_key;\n+\tvoid *next_data;\n+\tuint32_t count = 0;\n+\tfor (i = 0; i < num_buckets; i++) {\n+\t\t/* Check bucket for no keys shifted to alternate locations */\n+\t\tif (scanned_bkts[i] == 0) {\n+\t\t\titer = i * 8;\n+\t\t\twhile (rte_hash_iterate(tbl_rwc_test_param.h,\n+\t\t\t\t&next_key, &next_data, &iter) >= 0) {\n+\n+\t\t\t\t/* Check if key belongs to the current bucket */\n+\t\t\t\tif (i >= (iter-1)/8)\n+\t\t\t\t\tkeys_non_shift_path[count++]\n+\t\t\t\t\t\t= *(const uint32_t *)next_key;\n+\t\t\t\telse\n+\t\t\t\t\tbreak;\n+\t\t\t}\n+\t\t}\n+\t}\n+\n+\ttbl_rwc_test_param.count_keys_no_ks = count_keys_no_ks;\n+\ttbl_rwc_test_param.count_keys_ks = count_keys_ks;\n+\ttbl_rwc_test_param.count_keys_absent = count_keys_absent;\n+\ttbl_rwc_test_param.count_keys_non_shift_path = count;\n+\n+\tprintf(\"\\nCount of keys NOT causing shifting of existing keys to \"\n+\t\"alternate location: %d\\n\", tbl_rwc_test_param.count_keys_no_ks);\n+\tprintf(\"\\nCount of keys causing shifting of existing keys to alternate \"\n+\t\t\"locations: %d\\n\\n\", tbl_rwc_test_param.count_keys_ks);\n+\tprintf(\"Count of absent keys that will never be added to the hash \"\n+\t\t\"table: %d\\n\\n\", tbl_rwc_test_param.count_keys_absent);\n+\tprintf(\"Count of keys likely to be on the shift path: %d\\n\\n\",\n+\t       tbl_rwc_test_param.count_keys_shift_path);\n+\tprintf(\"Count of keys not likely to be on the shift path: %d\\n\\n\",\n+\t       tbl_rwc_test_param.count_keys_non_shift_path);\n+\n+\trte_free(found);\n+\trte_hash_free(tbl_rwc_test_param.h);\n+\treturn 0;\n+\n+err:\n+\trte_free(keys);\n+\trte_free(keys_no_ks);\n+\trte_free(keys_ks);\n+\trte_free(keys_absent);\n+\trte_free(found);\n+\trte_free(tbl_rwc_test_param.keys_shift_path);\n+\trte_free(scanned_bkts);\n+\treturn -1;\n+}\n+\n+static int\n+init_params(int rwc_lf, int use_jhash, int htm)\n+{\n+\tstruct rte_hash *handle;\n+\n+\tstruct rte_hash_parameters hash_params = {\n+\t\t.entries = TOTAL_ENTRY,\n+\t\t.key_len = sizeof(uint32_t),\n+\t\t.hash_func_init_val = 0,\n+\t\t.socket_id = rte_socket_id(),\n+\t};\n+\n+\tif (use_jhash)\n+\t\thash_params.hash_func = rte_jhash;\n+\telse\n+\t\thash_params.hash_func = rte_hash_crc;\n+\n+\tif (rwc_lf)\n+\t\thash_params.extra_flag =\n+\t\t\tRTE_HASH_EXTRA_FLAGS_RW_CONCURRENCY_LF |\n+\t\t\tRTE_HASH_EXTRA_FLAGS_MULTI_WRITER_ADD;\n+\telse if (htm)\n+\t\thash_params.extra_flag =\n+\t\t\tRTE_HASH_EXTRA_FLAGS_TRANS_MEM_SUPPORT |\n+\t\t\tRTE_HASH_EXTRA_FLAGS_RW_CONCURRENCY |\n+\t\t\tRTE_HASH_EXTRA_FLAGS_MULTI_WRITER_ADD;\n+\telse\n+\t\thash_params.extra_flag =\n+\t\t\tRTE_HASH_EXTRA_FLAGS_RW_CONCURRENCY |\n+\t\t\tRTE_HASH_EXTRA_FLAGS_MULTI_WRITER_ADD;\n+\n+\thash_params.name = \"tests\";\n+\n+\thandle = rte_hash_create(&hash_params);\n+\tif (handle == NULL) {\n+\t\tprintf(\"hash creation failed\");\n+\t\treturn -1;\n+\t}\n+\n+\ttbl_rwc_test_param.h = handle;\n+\treturn 0;\n+}\n+\n+static int\n+test_rwc_reader(__attribute__((unused)) void *arg)\n+{\n+\tuint32_t i, j;\n+\tint ret;\n+\tuint64_t begin, cycles;\n+\tuint32_t loop_cnt = 0;\n+\tuint8_t read_type = (uint8_t)((uintptr_t)arg);\n+\tuint32_t read_cnt;\n+\tuint32_t *keys;\n+\tuint32_t extra_keys;\n+\tint32_t *pos;\n+\tvoid *temp_a[BULK_LOOKUP_SIZE];\n+\n+\t/* Used to identify keys not inserted in the hash table */\n+\tpos = rte_zmalloc(NULL, sizeof(uint32_t) * BULK_LOOKUP_SIZE, 0);\n+\tif (pos == NULL) {\n+\t\tprintf(\"RTE_MALLOC failed\\n\");\n+\t\treturn -1;\n+\t}\n+\n+\tif (read_type & READ_FAIL) {\n+\t\tkeys = tbl_rwc_test_param.keys_absent;\n+\t\tread_cnt = tbl_rwc_test_param.count_keys_absent;\n+\t} else if (read_type & READ_PASS_NO_KEY_SHIFTS) {\n+\t\tkeys = tbl_rwc_test_param.keys_no_ks;\n+\t\tread_cnt = tbl_rwc_test_param.count_keys_no_ks;\n+\t} else if (read_type & READ_PASS_SHIFT_PATH) {\n+\t\tkeys = tbl_rwc_test_param.keys_shift_path;\n+\t\tread_cnt = tbl_rwc_test_param.count_keys_shift_path;\n+\t} else {\n+\t\tkeys = tbl_rwc_test_param.keys_non_shift_path;\n+\t\tread_cnt = tbl_rwc_test_param.count_keys_non_shift_path;\n+\t}\n+\n+\textra_keys = read_cnt & (BULK_LOOKUP_SIZE - 1);\n+\n+\tbegin = rte_rdtsc_precise();\n+\tdo {\n+\t\tif (read_type & BULK_LOOKUP) {\n+\t\t\tfor (i = 0; i < (read_cnt - extra_keys);\n+\t\t\t     i += BULK_LOOKUP_SIZE) {\n+\t\t\t\t/* Array of  pointer to the list of keys */\n+\t\t\t\tfor (j = 0; j < BULK_LOOKUP_SIZE; j++)\n+\t\t\t\t\ttemp_a[j] = keys + i + j;\n+\n+\t\t\t\trte_hash_lookup_bulk(tbl_rwc_test_param.h,\n+\t\t\t\t\t\t   (const void **)\n+\t\t\t\t\t\t   ((uintptr_t)temp_a),\n+\t\t\t\t\t\t   BULK_LOOKUP_SIZE, pos);\n+\t\t\t\t/* Validate lookup result */\n+\t\t\t\tfor (j = 0; j < BULK_LOOKUP_SIZE; j++)\n+\t\t\t\t\tif ((read_type & READ_FAIL &&\n+\t\t\t\t\t     pos[j] != -ENOENT) ||\n+\t\t\t\t\t    (!(read_type & READ_FAIL) &&\n+\t\t\t\t\t     pos[j] == -ENOENT)) {\n+\t\t\t\t\t\tprintf(\"lookup failed!\"\n+\t\t\t\t\t\t       \"%\"PRIu32\"\\n\",\n+\t\t\t\t\t\t       keys[i + j]);\n+\t\t\t\t\t\treturn -1;\n+\t\t\t\t\t}\n+\t\t\t}\n+\t\t\tfor (j = 0; j < extra_keys; j++)\n+\t\t\t\ttemp_a[j] = keys + i + j;\n+\n+\t\t\trte_hash_lookup_bulk(tbl_rwc_test_param.h,\n+\t\t\t\t\t   (const void **)\n+\t\t\t\t\t   ((uintptr_t)temp_a),\n+\t\t\t\t\t   extra_keys, pos);\n+\t\t\tfor (j = 0; j < extra_keys; j++)\n+\t\t\t\tif ((read_type & READ_FAIL &&\n+\t\t\t\t     pos[j] != -ENOENT) ||\n+\t\t\t\t    (!(read_type & READ_FAIL) &&\n+\t\t\t\t     pos[j] == -ENOENT)) {\n+\t\t\t\t\tprintf(\"lookup failed! %\"PRIu32\"\\n\",\n+\t\t\t\t\t       keys[i + j]);\n+\t\t\t\t\treturn -1;\n+\t\t\t\t}\n+\t\t} else {\n+\t\t\tfor (i = 0; i < read_cnt; i++) {\n+\t\t\t\tret = rte_hash_lookup\n+\t\t\t\t\t(tbl_rwc_test_param.h, keys + i);\n+\t\t\t\tif (((read_type & READ_FAIL) &&\n+\t\t\t\t     (ret != -ENOENT)) ||\n+\t\t\t\t    (!(read_type & READ_FAIL) &&\n+\t\t\t\t\tret == -ENOENT)) {\n+\t\t\t\t\tprintf(\"lookup failed! %\"PRIu32\"\\n\",\n+\t\t\t\t\t       keys[i]);\n+\t\t\t\t\treturn -1;\n+\t\t\t\t}\n+\t\t\t}\n+\t\t}\n+\t\tloop_cnt++;\n+\t} while (!writer_done);\n+\n+\tcycles = rte_rdtsc_precise() - begin;\n+\trte_atomic64_add(&gread_cycles, cycles);\n+\trte_atomic64_add(&greads, read_cnt*loop_cnt);\n+\treturn 0;\n+}\n+\n+static int\n+write_keys(uint8_t key_shift)\n+{\n+\tuint32_t i;\n+\tint ret;\n+\tuint32_t key_cnt;\n+\tuint32_t *keys;\n+\tif (key_shift) {\n+\t\tkey_cnt = tbl_rwc_test_param.count_keys_ks;\n+\t\tkeys = tbl_rwc_test_param.keys_ks;\n+\t} else {\n+\t\tkey_cnt = tbl_rwc_test_param.count_keys_no_ks;\n+\t\tkeys = tbl_rwc_test_param.keys_no_ks;\n+\t}\n+\tfor (i = 0; i < key_cnt; i++) {\n+\t\tret = rte_hash_add_key(tbl_rwc_test_param.h, keys + i);\n+\t\tif (!key_shift && ret < 0) {\n+\t\t\tprintf(\"writer failed %\"PRIu32\"\\n\", i);\n+\t\t\treturn -1;\n+\t\t}\n+\t}\n+\treturn 0;\n+}\n+\n+static int\n+test_rwc_multi_writer(__attribute__((unused)) void *arg)\n+{\n+\tuint32_t i, offset;\n+\tuint32_t pos_core = (uint32_t)((uintptr_t)arg);\n+\toffset = pos_core * tbl_rwc_test_param.single_insert;\n+\tfor (i = offset; i < offset + tbl_rwc_test_param.single_insert; i++)\n+\t\trte_hash_add_key(tbl_rwc_test_param.h,\n+\t\t\t\t tbl_rwc_test_param.keys_ks + i);\n+\tmulti_writer_done[pos_core] = 1;\n+\treturn 0;\n+}\n+\n+/*\n+ * Test lookup perf:\n+ * Reader(s) lookup keys present in the table.\n+ */\n+static int\n+test_hash_add_no_ks_lookup_pass(struct rwc_perf *rwc_perf_results, int rwc_lf,\n+\t\t\t\tint htm)\n+{\n+\tunsigned int n, m;\n+\tuint64_t i;\n+\tint use_jhash = 0;\n+\tuint8_t key_shift = 0;\n+\tuint8_t read_type = READ_PASS_NO_KEY_SHIFTS;\n+\n+\trte_atomic64_init(&greads);\n+\trte_atomic64_init(&gread_cycles);\n+\n+\tif (init_params(rwc_lf, use_jhash, htm) != 0)\n+\t\tgoto err;\n+\tprintf(\"\\nTest: Hash add - no key-shifts, read - pass\\n\");\n+\tfor (m = 0; m < 2; m++) {\n+\t\tif (m == 1) {\n+\t\t\tprintf(\"\\n** With bulk-lookup **\\n\");\n+\t\t\tread_type |= BULK_LOOKUP;\n+\t\t}\n+\t\tfor (n = 0; n < NUM_TEST; n++) {\n+\t\t\tunsigned int tot_lcore = rte_lcore_count();\n+\t\t\tif (tot_lcore < rwc_core_cnt[n] + 1)\n+\t\t\t\tgoto finish;\n+\n+\t\t\tprintf(\"\\nNumber of readers: %u\\n\", rwc_core_cnt[n]);\n+\n+\t\t\trte_atomic64_clear(&greads);\n+\t\t\trte_atomic64_clear(&gread_cycles);\n+\n+\t\t\trte_hash_reset(tbl_rwc_test_param.h);\n+\t\t\twriter_done = 0;\n+\t\t\tif (write_keys(key_shift) < 0)\n+\t\t\t\tgoto err;\n+\t\t\twriter_done = 1;\n+\t\t\tfor (i = 1; i <= rwc_core_cnt[n]; i++)\n+\t\t\t\trte_eal_remote_launch(test_rwc_reader,\n+\t\t\t\t\t\t(void *)(uintptr_t)read_type,\n+\t\t\t\t\t\t\tenabled_core_ids[i]);\n+\t\t\trte_eal_mp_wait_lcore();\n+\n+\t\t\tfor (i = 1; i <= rwc_core_cnt[n]; i++)\n+\t\t\t\tif (lcore_config[i].ret < 0)\n+\t\t\t\t\tgoto err;\n+\n+\t\t\tunsigned long long cycles_per_lookup =\n+\t\t\t\trte_atomic64_read(&gread_cycles) /\n+\t\t\t\trte_atomic64_read(&greads);\n+\t\t\trwc_perf_results->w_no_ks_r_pass[m][n]\n+\t\t\t\t\t\t= cycles_per_lookup;\n+\t\t\tprintf(\"Cycles per lookup: %llu\\n\", cycles_per_lookup);\n+\t\t}\n+\t}\n+\n+finish:\n+\trte_hash_free(tbl_rwc_test_param.h);\n+\treturn 0;\n+\n+err:\n+\trte_hash_free(tbl_rwc_test_param.h);\n+\treturn -1;\n+}\n+\n+/*\n+ * Test lookup perf:\n+ * Reader(s) lookup keys absent in the table while\n+ * 'Main' thread adds with no key-shifts.\n+ */\n+static int\n+test_hash_add_no_ks_lookup_fail(struct rwc_perf *rwc_perf_results, int rwc_lf,\n+\t\t\t\tint htm)\n+{\n+\tunsigned int n, m;\n+\tuint64_t i;\n+\tint use_jhash = 0;\n+\tuint8_t key_shift = 0;\n+\tuint8_t read_type = READ_FAIL;\n+\tint ret;\n+\n+\trte_atomic64_init(&greads);\n+\trte_atomic64_init(&gread_cycles);\n+\n+\tif (init_params(rwc_lf, use_jhash, htm) != 0)\n+\t\tgoto err;\n+\tprintf(\"\\nTest: Hash add - no key-shifts, Hash lookup - fail\\n\");\n+\tfor (m = 0; m < 2; m++) {\n+\t\tif (m == 1) {\n+\t\t\tprintf(\"\\n** With bulk-lookup **\\n\");\n+\t\t\tread_type |= BULK_LOOKUP;\n+\t\t}\n+\t\tfor (n = 0; n < NUM_TEST; n++) {\n+\t\t\tunsigned int tot_lcore = rte_lcore_count();\n+\t\t\tif (tot_lcore < rwc_core_cnt[n] + 1)\n+\t\t\t\tgoto finish;\n+\n+\t\t\tprintf(\"\\nNumber of readers: %u\\n\", rwc_core_cnt[n]);\n+\n+\t\t\trte_atomic64_clear(&greads);\n+\t\t\trte_atomic64_clear(&gread_cycles);\n+\n+\t\t\trte_hash_reset(tbl_rwc_test_param.h);\n+\t\t\twriter_done = 0;\n+\n+\t\t\tfor (i = 1; i <= rwc_core_cnt[n]; i++)\n+\t\t\t\trte_eal_remote_launch(test_rwc_reader,\n+\t\t\t\t\t\t(void *)(uintptr_t)read_type,\n+\t\t\t\t\t\t\tenabled_core_ids[i]);\n+\t\t\tret = write_keys(key_shift);\n+\t\t\twriter_done = 1;\n+\t\t\trte_eal_mp_wait_lcore();\n+\n+\t\t\tif (ret < 0)\n+\t\t\t\tgoto err;\n+\t\t\tfor (i = 1; i <= rwc_core_cnt[n]; i++)\n+\t\t\t\tif (lcore_config[i].ret < 0)\n+\t\t\t\t\tgoto err;\n+\n+\t\t\tunsigned long long cycles_per_lookup =\n+\t\t\t\trte_atomic64_read(&gread_cycles) /\n+\t\t\t\trte_atomic64_read(&greads);\n+\t\t\trwc_perf_results->w_no_ks_r_fail[m][n]\n+\t\t\t\t\t\t= cycles_per_lookup;\n+\t\t\tprintf(\"Cycles per lookup: %llu\\n\", cycles_per_lookup);\n+\t\t}\n+\t}\n+\n+finish:\n+\trte_hash_free(tbl_rwc_test_param.h);\n+\treturn 0;\n+\n+err:\n+\trte_hash_free(tbl_rwc_test_param.h);\n+\treturn -1;\n+}\n+\n+/*\n+ * Test lookup perf:\n+ * Reader(s) lookup keys present in the table and not likely to be on the\n+ * shift path  while 'Main' thread adds keys causing key-shifts.\n+ */\n+static int\n+test_hash_add_ks_lookup_pass_non_sp(struct rwc_perf *rwc_perf_results,\n+\t\t\t\t    int rwc_lf, int htm)\n+{\n+\tunsigned int n, m;\n+\tuint64_t i;\n+\tint use_jhash = 0;\n+\tint ret;\n+\tuint8_t key_shift;\n+\tuint8_t read_type = READ_PASS_NON_SHIFT_PATH;\n+\n+\trte_atomic64_init(&greads);\n+\trte_atomic64_init(&gread_cycles);\n+\n+\tif (init_params(rwc_lf, use_jhash, htm) != 0)\n+\t\tgoto err;\n+\tprintf(\"\\nTest: Hash add - key shift, Hash lookup - pass\"\n+\t       \" (non-shift-path)\\n\");\n+\tfor (m = 0; m < 2; m++) {\n+\t\tif (m == 1) {\n+\t\t\tprintf(\"\\n** With bulk-lookup **\\n\");\n+\t\t\tread_type |= BULK_LOOKUP;\n+\t\t}\n+\t\tfor (n = 0; n < NUM_TEST; n++) {\n+\t\t\tunsigned int tot_lcore = rte_lcore_count();\n+\t\t\tif (tot_lcore < rwc_core_cnt[n] + 1)\n+\t\t\t\tgoto finish;\n+\n+\t\t\tprintf(\"\\nNumber of readers: %u\\n\", rwc_core_cnt[n]);\n+\n+\t\t\trte_atomic64_clear(&greads);\n+\t\t\trte_atomic64_clear(&gread_cycles);\n+\n+\t\t\trte_hash_reset(tbl_rwc_test_param.h);\n+\t\t\twriter_done = 0;\n+\t\t\tkey_shift = 0;\n+\t\t\tif (write_keys(key_shift) < 0)\n+\t\t\t\tgoto err;\n+\t\t\tfor (i = 1; i <= rwc_core_cnt[n]; i++)\n+\t\t\t\trte_eal_remote_launch(test_rwc_reader,\n+\t\t\t\t\t\t(void *)(uintptr_t)read_type,\n+\t\t\t\t\t\t\tenabled_core_ids[i]);\n+\t\t\tkey_shift = 1;\n+\t\t\tret = write_keys(key_shift);\n+\t\t\twriter_done = 1;\n+\t\t\trte_eal_mp_wait_lcore();\n+\n+\t\t\tif (ret < 0)\n+\t\t\t\tgoto err;\n+\t\t\tfor (i = 1; i <= rwc_core_cnt[n]; i++)\n+\t\t\t\tif (lcore_config[i].ret < 0)\n+\t\t\t\t\tgoto err;\n+\n+\t\t\tunsigned long long cycles_per_lookup =\n+\t\t\t\trte_atomic64_read(&gread_cycles) /\n+\t\t\t\trte_atomic64_read(&greads);\n+\t\t\trwc_perf_results->w_ks_r_pass_nsp[m][n]\n+\t\t\t\t\t\t= cycles_per_lookup;\n+\t\t\tprintf(\"Cycles per lookup: %llu\\n\", cycles_per_lookup);\n+\t\t}\n+\t}\n+\n+finish:\n+\trte_hash_free(tbl_rwc_test_param.h);\n+\treturn 0;\n+\n+err:\n+\trte_hash_free(tbl_rwc_test_param.h);\n+\treturn -1;\n+}\n+\n+/*\n+ * Test lookup perf:\n+ * Reader(s) lookup keys present in the table and likely on the shift-path while\n+ * 'Main' thread adds keys causing key-shifts.\n+ */\n+static int\n+test_hash_add_ks_lookup_pass_sp(struct rwc_perf *rwc_perf_results, int rwc_lf,\n+\t\t\t\tint htm)\n+{\n+\tunsigned int n, m;\n+\tuint64_t i;\n+\tint use_jhash = 0;\n+\tint ret;\n+\tuint8_t key_shift;\n+\tuint8_t read_type = READ_PASS_SHIFT_PATH;\n+\n+\trte_atomic64_init(&greads);\n+\trte_atomic64_init(&gread_cycles);\n+\n+\tif (init_params(rwc_lf, use_jhash, htm) != 0)\n+\t\tgoto err;\n+\tprintf(\"\\nTest: Hash add - key shift, Hash lookup - pass (shift-path)\"\n+\t       \"\\n\");\n+\n+\tfor (m = 0; m < 2; m++) {\n+\t\tif (m == 1) {\n+\t\t\tprintf(\"\\n** With bulk-lookup **\\n\");\n+\t\t\tread_type |= BULK_LOOKUP;\n+\t\t}\n+\t\tfor (n = 0; n < NUM_TEST; n++) {\n+\t\t\tunsigned int tot_lcore = rte_lcore_count();\n+\t\t\tif (tot_lcore < rwc_core_cnt[n])\n+\t\t\t\tgoto finish;\n+\n+\t\t\tprintf(\"\\nNumber of readers: %u\\n\", rwc_core_cnt[n]);\n+\t\t\trte_atomic64_clear(&greads);\n+\t\t\trte_atomic64_clear(&gread_cycles);\n+\n+\t\t\trte_hash_reset(tbl_rwc_test_param.h);\n+\t\t\twriter_done = 0;\n+\t\t\tkey_shift = 0;\n+\t\t\tif (write_keys(key_shift) < 0)\n+\t\t\t\tgoto err;\n+\t\t\tfor (i = 1; i <= rwc_core_cnt[n]; i++)\n+\t\t\t\trte_eal_remote_launch(test_rwc_reader,\n+\t\t\t\t\t\t(void *)(uintptr_t)read_type,\n+\t\t\t\t\t\tenabled_core_ids[i]);\n+\t\t\tkey_shift = 1;\n+\t\t\tret = write_keys(key_shift);\n+\t\t\twriter_done = 1;\n+\t\t\trte_eal_mp_wait_lcore();\n+\n+\t\t\tif (ret < 0)\n+\t\t\t\tgoto err;\n+\t\t\tfor (i = 1; i <= rwc_core_cnt[n]; i++)\n+\t\t\t\tif (lcore_config[i].ret < 0)\n+\t\t\t\t\tgoto err;\n+\n+\t\t\tunsigned long long cycles_per_lookup =\n+\t\t\t\trte_atomic64_read(&gread_cycles) /\n+\t\t\t\trte_atomic64_read(&greads);\n+\t\t\trwc_perf_results->w_ks_r_pass_sp[m][n]\n+\t\t\t\t\t\t= cycles_per_lookup;\n+\t\t\tprintf(\"Cycles per lookup: %llu\\n\", cycles_per_lookup);\n+\t\t}\n+\t}\n+\n+finish:\n+\trte_hash_free(tbl_rwc_test_param.h);\n+\treturn 0;\n+\n+err:\n+\trte_hash_free(tbl_rwc_test_param.h);\n+\treturn -1;\n+}\n+\n+/*\n+ * Test lookup perf:\n+ * Reader(s) lookup keys absent in the table while\n+ * 'Main' thread adds keys causing key-shifts.\n+ */\n+static int\n+test_hash_add_ks_lookup_fail(struct rwc_perf *rwc_perf_results, int rwc_lf, int\n+\t\t\t     htm)\n+{\n+\tunsigned int n, m;\n+\tuint64_t i;\n+\tint use_jhash = 0;\n+\tint ret;\n+\tuint8_t key_shift;\n+\tuint8_t read_type = READ_FAIL;\n+\n+\trte_atomic64_init(&greads);\n+\trte_atomic64_init(&gread_cycles);\n+\n+\tif (init_params(rwc_lf, use_jhash, htm) != 0)\n+\t\tgoto err;\n+\tprintf(\"\\nTest: Hash add - key shift, Hash lookup - fail\\n\");\n+\tfor (m = 0; m < 2; m++) {\n+\t\tif (m == 1) {\n+\t\t\tprintf(\"\\n** With bulk-lookup **\\n\");\n+\t\t\tread_type |= BULK_LOOKUP;\n+\t\t}\n+\t\tfor (n = 0; n < NUM_TEST; n++) {\n+\t\t\tunsigned int tot_lcore = rte_lcore_count();\n+\t\t\tif (tot_lcore < rwc_core_cnt[n] + 1)\n+\t\t\t\tgoto finish;\n+\n+\t\t\tprintf(\"\\nNumber of readers: %u\\n\", rwc_core_cnt[n]);\n+\n+\t\t\trte_atomic64_clear(&greads);\n+\t\t\trte_atomic64_clear(&gread_cycles);\n+\n+\t\t\trte_hash_reset(tbl_rwc_test_param.h);\n+\t\t\twriter_done = 0;\n+\t\t\tkey_shift = 0;\n+\t\t\tif (write_keys(key_shift) < 0)\n+\t\t\t\tgoto err;\n+\t\t\tfor (i = 1; i <= rwc_core_cnt[n]; i++)\n+\t\t\t\trte_eal_remote_launch(test_rwc_reader,\n+\t\t\t\t\t\t(void *)(uintptr_t)read_type,\n+\t\t\t\t\t\t\tenabled_core_ids[i]);\n+\t\t\tkey_shift = 1;\n+\t\t\tret = write_keys(key_shift);\n+\t\t\twriter_done = 1;\n+\t\t\trte_eal_mp_wait_lcore();\n+\n+\t\t\tif (ret < 0)\n+\t\t\t\tgoto err;\n+\t\t\tfor (i = 1; i <= rwc_core_cnt[n]; i++)\n+\t\t\t\tif (lcore_config[i].ret < 0)\n+\t\t\t\t\tgoto err;\n+\n+\t\t\tunsigned long long cycles_per_lookup =\n+\t\t\t\trte_atomic64_read(&gread_cycles) /\n+\t\t\t\trte_atomic64_read(&greads);\n+\t\t\trwc_perf_results->w_ks_r_fail[m][n] = cycles_per_lookup;\n+\t\t\tprintf(\"Cycles per lookup: %llu\\n\", cycles_per_lookup);\n+\t\t}\n+\t}\n+\n+finish:\n+\trte_hash_free(tbl_rwc_test_param.h);\n+\treturn 0;\n+\n+err:\n+\trte_hash_free(tbl_rwc_test_param.h);\n+\treturn -1;\n+}\n+\n+/*\n+ * Test lookup perf for multi-writer:\n+ * Reader(s) lookup keys present in the table and likely on the shift-path while\n+ * Writers add keys causing key-shiftsi.\n+ * Writers are running in parallel, on different data plane cores.\n+ */\n+static int\n+test_hash_multi_add_lookup(struct rwc_perf *rwc_perf_results, int rwc_lf,\n+\t\t\t   int htm)\n+{\n+\tunsigned int n, m, k;\n+\tuint64_t i;\n+\tint use_jhash = 0;\n+\tuint8_t key_shift;\n+\tuint8_t read_type = READ_PASS_SHIFT_PATH;\n+\n+\trte_atomic64_init(&greads);\n+\trte_atomic64_init(&gread_cycles);\n+\n+\tif (init_params(rwc_lf, use_jhash, htm) != 0)\n+\t\tgoto err;\n+\tprintf(\"\\nTest: Multi-add-lookup\\n\");\n+\tuint8_t pos_core;\n+\tfor (m = 1; m < NUM_TEST; m++) {\n+\t\t/* Calculate keys added by each writer */\n+\t\ttbl_rwc_test_param.single_insert =\n+\t\t\ttbl_rwc_test_param.count_keys_ks / rwc_core_cnt[m];\n+\t\tfor (k = 0; k < 2; k++) {\n+\t\t\tif (k == 1) {\n+\t\t\t\tprintf(\"\\n** With bulk-lookup **\\n\");\n+\t\t\t\tread_type |= BULK_LOOKUP;\n+\t\t\t}\n+\t\t\tfor (n = 0; n < NUM_TEST; n++) {\n+\t\t\t\tunsigned int tot_lcore\t= rte_lcore_count();\n+\t\t\t\tif (tot_lcore < (rwc_core_cnt[n] +\n+\t\t\t\t     rwc_core_cnt[m] + 1))\n+\t\t\t\t\tgoto finish;\n+\n+\t\t\t\tprintf(\"\\nNumber of writers: %u\",\n+\t\t\t\t       rwc_core_cnt[m]);\n+\t\t\t\tprintf(\"\\nNumber of readers: %u\\n\",\n+\t\t\t\t       rwc_core_cnt[n]);\n+\n+\t\t\t\trte_atomic64_clear(&greads);\n+\t\t\t\trte_atomic64_clear(&gread_cycles);\n+\n+\t\t\t\trte_hash_reset(tbl_rwc_test_param.h);\n+\t\t\t\twriter_done = 0;\n+\t\t\t\tfor (i = 0; i < 4; i++)\n+\t\t\t\t\tmulti_writer_done[i] = 0;\n+\t\t\t\tkey_shift = 0;\n+\t\t\t\tif (write_keys(key_shift) < 0)\n+\t\t\t\t\tgoto err;\n+\n+\t\t\t\t/* Launch reader(s) */\n+\t\t\t\tfor (i = 1; i <= rwc_core_cnt[n]; i++)\n+\t\t\t\t\trte_eal_remote_launch(test_rwc_reader,\n+\t\t\t\t\t\t(void *)(uintptr_t)read_type,\n+\t\t\t\t\t\tenabled_core_ids[i]);\n+\t\t\t\tkey_shift = 1;\n+\t\t\t\tpos_core = 0;\n+\n+\t\t\t\t/* Launch writers */\n+\t\t\t\tfor (; i <= rwc_core_cnt[m]\n+\t\t\t\t     + rwc_core_cnt[n];\ti++) {\n+\t\t\t\t\trte_eal_remote_launch\n+\t\t\t\t\t\t(test_rwc_multi_writer,\n+\t\t\t\t\t\t(void *)(uintptr_t)pos_core,\n+\t\t\t\t\t\tenabled_core_ids[i]);\n+\t\t\t\t\tpos_core++;\n+\t\t\t\t}\n+\n+\t\t\t\t/* Wait for writers to complete */\n+\t\t\t\tfor (i = 0; i < rwc_core_cnt[m]; i++)\n+\t\t\t\t\twhile\n+\t\t\t\t\t\t(multi_writer_done[i] == 0);\n+\t\t\t\twriter_done = 1;\n+\n+\t\t\t\trte_eal_mp_wait_lcore();\n+\n+\t\t\t\tfor (i = 1; i <= rwc_core_cnt[n]; i++)\n+\t\t\t\t\tif (lcore_config[i].ret < 0)\n+\t\t\t\t\t\tgoto err;\n+\n+\t\t\t\tunsigned long long cycles_per_lookup =\n+\t\t\t\t\trte_atomic64_read(&gread_cycles)\n+\t\t\t\t\t/ rte_atomic64_read(&greads);\n+\t\t\t\trwc_perf_results->multi_rw[m][k][n]\n+\t\t\t\t\t= cycles_per_lookup;\n+\t\t\t\tprintf(\"Cycles per lookup: %llu\\n\",\n+\t\t\t\t       cycles_per_lookup);\n+\t\t\t}\n+\t\t}\n+\t}\n+\n+finish:\n+\trte_hash_free(tbl_rwc_test_param.h);\n+\treturn 0;\n+\n+err:\n+\trte_hash_free(tbl_rwc_test_param.h);\n+\treturn -1;\n+}\n+\n+static int\n+test_hash_readwrite_lf_main(void)\n+{\n+\t/*\n+\t * Variables used to choose different tests.\n+\t * rwc_lf indicates if read-write concurrency lock-free support is\n+\t * enabled.\n+\t * htm indicates if Hardware transactional memory support is enabled.\n+\t */\n+\tint rwc_lf = 0;\n+\tint htm;\n+\tint use_jhash = 0;\n+\tif (rte_lcore_count() == 1) {\n+\t\tprintf(\"More than one lcore is required \"\n+\t\t\t\"to do read write lock-free concurrency test\\n\");\n+\t\treturn -1;\n+\t}\n+\n+\tsetlocale(LC_NUMERIC, \"\");\n+\n+\tif (rte_tm_supported())\n+\t\thtm = 1;\n+\telse\n+\t\thtm = 0;\n+\n+\tif (init_params(rwc_lf, use_jhash, htm) != 0)\n+\t\treturn -1;\n+\tif (generate_keys() != 0)\n+\t\treturn -1;\n+\tif (get_enabled_cores_list() != 0)\n+\t\treturn -1;\n+\n+\tif (RTE_HASH_EXTRA_FLAGS_RW_CONCURRENCY_LF) {\n+\t\trwc_lf = 1;\n+\t\tprintf(\"Test lookup with read-write concurrency lock free support\"\n+\t\t       \" enabled\\n\");\n+\t\tif (test_hash_add_no_ks_lookup_pass(&rwc_lf_results, rwc_lf,\n+\t\t\t\t\t\t\thtm) < 0)\n+\t\t\treturn -1;\n+\t\tif (test_hash_add_no_ks_lookup_fail(&rwc_lf_results, rwc_lf,\n+\t\t\t\t\t\t\thtm) < 0)\n+\t\t\treturn -1;\n+\t\tif (test_hash_add_ks_lookup_pass_non_sp(&rwc_lf_results, rwc_lf,\n+\t\t\t\t\t\t\thtm) < 0)\n+\t\t\treturn -1;\n+\t\tif (test_hash_add_ks_lookup_pass_sp(&rwc_lf_results, rwc_lf,\n+\t\t\t\t\t\t\thtm) < 0)\n+\t\t\treturn -1;\n+\t\tif (test_hash_add_ks_lookup_fail(&rwc_lf_results, rwc_lf, htm)\n+\t\t\t\t\t\t\t< 0)\n+\t\t\treturn -1;\n+\t\tif (test_hash_multi_add_lookup(&rwc_lf_results, rwc_lf, htm)\n+\t\t\t\t\t\t\t< 0)\n+\t\t\treturn -1;\n+\t}\n+\tprintf(\"\\nTest lookup with read-write concurrency lock free support\"\n+\t       \" disabled\\n\");\n+\trwc_lf = 0;\n+\tif (!htm) {\n+\t\tprintf(\"With HTM Disabled\\n\");\n+\t\tif (!RUN_WITH_HTM_DISABLED) {\n+\t\t\tprintf(\"Enable RUN_WITH_HTM_DISABLED to test with\"\n+\t\t\t       \" lock-free disabled\");\n+\t\t\tgoto results;\n+\t\t}\n+\t} else\n+\t\tprintf(\"With HTM Enabled\\n\");\n+\tif (test_hash_add_no_ks_lookup_pass(&rwc_non_lf_results, rwc_lf, htm)\n+\t\t\t\t\t\t< 0)\n+\t\treturn -1;\n+\tif (test_hash_add_no_ks_lookup_fail(&rwc_non_lf_results, rwc_lf, htm)\n+\t\t\t\t\t\t< 0)\n+\t\treturn -1;\n+\tif (test_hash_add_ks_lookup_pass_non_sp(&rwc_non_lf_results, rwc_lf,\n+\t\t\t\t\t\thtm) < 0)\n+\t\treturn -1;\n+\tif (test_hash_add_ks_lookup_pass_sp(&rwc_non_lf_results, rwc_lf, htm)\n+\t\t\t\t\t\t< 0)\n+\t\treturn -1;\n+\tif (test_hash_add_ks_lookup_fail(&rwc_non_lf_results, rwc_lf, htm) < 0)\n+\t\treturn -1;\n+\tif (test_hash_multi_add_lookup(&rwc_non_lf_results, rwc_lf, htm) < 0)\n+\t\treturn -1;\n+results:\n+\tprintf(\"\\n\\t\\t\\t\\t\\t\\t********** Results summary **********\\n\\n\");\n+\tint i, j, k;\n+\tfor (j = 0; j < 2; j++) {\n+\t\tif (j == 1)\n+\t\t\tprintf(\"\\n\\t\\t\\t\\t\\t#######********** Bulk Lookup \"\n+\t\t\t       \"**********#######\\n\\n\");\n+\t\tprintf(\"_______\\t\\t_______\\t\\t_________\\t___\\t\\t_________\\t\\t\"\n+\t\t\t\"\\t\\t\\t\\t_________________\\n\");\n+\t\tprintf(\"Writers\\t\\tReaders\\t\\tLock-free\\tHTM\\t\\tTest-case\\t\\t\\t\"\n+\t\t       \"\\t\\t\\tCycles per lookup\\n\");\n+\t\tprintf(\"_______\\t\\t_______\\t\\t_________\\t___\\t\\t_________\\t\\t\\t\"\n+\t\t       \"\\t\\t\\t_________________\\n\");\n+\t\tfor (i = 0; i < NUM_TEST; i++) {\n+\t\t\tprintf(\"%u\\t\\t%u\\t\\t\", 1, rwc_core_cnt[i]);\n+\t\t\tprintf(\"Enabled\\t\\t\");\n+\t\t\tprintf(\"N/A\\t\\t\");\n+\t\t\tprintf(\"Hash add - no key-shifts, lookup - pass\\t\\t\\t\\t\"\n+\t\t\t\t\"%u\\n\\t\\t\\t\\t\\t\\t\\t\\t\",\n+\t\t\t\trwc_lf_results.w_no_ks_r_pass[j][i]);\n+\t\t\tprintf(\"Hash add - no key-shifts, lookup - fail\\t\\t\\t\\t\"\n+\t\t\t\t\"%u\\n\\t\\t\\t\\t\\t\\t\\t\\t\",\n+\t\t\t\trwc_lf_results.w_no_ks_r_fail[j][i]);\n+\t\t\tprintf(\"Hash add - key-shifts, lookup - pass\"\n+\t\t\t       \"(non-shift-path)\\t\\t%u\\n\\t\\t\\t\\t\\t\\t\\t\\t\",\n+\t\t\t       rwc_lf_results.w_ks_r_pass_nsp[j][i]);\n+\t\t\tprintf(\"Hash add - key-shifts, lookup - passi \"\n+\t\t\t       \"(shift-path)\\t\\t%u\\n\\t\\t\\t\\t\\t\\t\\t\\t\",\n+\t\t\t       rwc_lf_results.w_ks_r_pass_sp[j][i]);\n+\t\t\tprintf(\"Hash add - key-shifts, Hash lookup fail\\t\\t\\t\\t\"\n+\t\t\t\t\"%u\\n\\n\\t\\t\\t\\t\",\n+\t\t\t\trwc_lf_results.w_ks_r_fail[j][i]);\n+\n+\t\t\tprintf(\"Disabled\\t\");\n+\t\t\tif (htm)\n+\t\t\t\tprintf(\"Enabled\\t\\t\");\n+\t\t\telse\n+\t\t\t\tprintf(\"Disabled\\t\");\n+\t\t\tprintf(\"Hash add - no key-shifts, lookup - pass\\t\\t\\t\\t\"\n+\t\t\t\t\"%u\\n\\t\\t\\t\\t\\t\\t\\t\\t\",\n+\t\t\t\trwc_non_lf_results.w_no_ks_r_pass[j][i]);\n+\t\t\tprintf(\"Hash add - no key-shifts, lookup - fail\\t\\t\\t\\t\"\n+\t\t\t\t\"%u\\n\\t\\t\\t\\t\\t\\t\\t\\t\",\n+\t\t\t\trwc_non_lf_results.w_no_ks_r_fail[j][i]);\n+\t\t\tprintf(\"Hash add - key-shifts, lookup - pass \"\n+\t\t\t       \"(non-shift-path)\\t\\t%u\\n\\t\\t\\t\\t\\t\\t\\t\\t\",\n+\t\t\t       rwc_non_lf_results.w_ks_r_pass_nsp[j][i]);\n+\t\t\tprintf(\"Hash add - key-shifts, lookup - pass \"\n+\t\t\t       \"(shift-path)\\t\\t%u\\n\\t\\t\\t\\t\\t\\t\\t\\t\",\n+\t\t\t       rwc_non_lf_results.w_ks_r_pass_sp[j][i]);\n+\t\t\tprintf(\"Hash add - key-shifts, Hash lookup fail\\t\\t\\t\\t\"\n+\t\t\t       \"%u\\n\", rwc_non_lf_results.w_ks_r_fail[j][i]);\n+\n+\t\t\tprintf(\"_______\\t\\t_______\\t\\t_________\\t___\\t\\t\"\n+\t\t\t       \"_________\\t\\t\\t\\t\\t\\t_________________\\n\");\n+\t\t}\n+\n+\t\tfor (i = 1; i < NUM_TEST; i++) {\n+\t\t\tfor (k = 0; k < NUM_TEST; k++) {\n+\t\t\t\tprintf(\"%u\", rwc_core_cnt[i]);\n+\t\t\t\tprintf(\"\\t\\t%u\\t\\t\", rwc_core_cnt[k]);\n+\t\t\t\tprintf(\"Enabled\\t\\t\");\n+\t\t\t\tprintf(\"N/A\\t\\t\");\n+\t\t\t\tprintf(\"Multi-add-lookup\\t\\t\\t\\t\\t\\t%u\\n\\n\\t\\t\"\n+\t\t\t\t       \"\\t\\t\",\n+\t\t\t\t       rwc_lf_results.multi_rw[i][j][k]);\n+\t\t\t\tprintf(\"Disabled\\t\");\n+\t\t\t\tif (htm)\n+\t\t\t\t\tprintf(\"Enabled\\t\\t\");\n+\t\t\t\telse\n+\t\t\t\t\tprintf(\"Disabled\\t\");\n+\t\t\t\tprintf(\"Multi-add-lookup\\t\\t\\t\\t\\t\\t%u\\n\",\n+\t\t\t\t       rwc_non_lf_results.multi_rw[i][j][k]);\n+\n+\t\t\t\tprintf(\"_______\\t\\t_______\\t\\t_________\\t___\"\n+\t\t\t\t       \"\\t\\t_________\\t\\t\\t\\t\\t\\t\"\n+\t\t\t\t       \"_________________\\n\");\n+\t\t\t}\n+\t\t}\n+\t}\n+\trte_free(tbl_rwc_test_param.keys);\n+\trte_free(tbl_rwc_test_param.keys_no_ks);\n+\trte_free(tbl_rwc_test_param.keys_ks);\n+\trte_free(tbl_rwc_test_param.keys_absent);\n+\trte_free(tbl_rwc_test_param.keys_shift_path);\n+\trte_free(scanned_bkts);\n+\treturn 0;\n+}\n+\n+REGISTER_TEST_COMMAND(hash_readwrite_lf_autotest, test_hash_readwrite_lf_main);\n",
    "prefixes": [
        "v4",
        "5/5"
    ]
}