14418919fSjohnjiang /* SPDX-License-Identifier: BSD-3-Clause
24418919fSjohnjiang * Copyright(c) 2016 Intel Corporation
34418919fSjohnjiang */
44418919fSjohnjiang
54418919fSjohnjiang #include <inttypes.h>
64418919fSjohnjiang #include <locale.h>
74418919fSjohnjiang
84418919fSjohnjiang #include <rte_cycles.h>
94418919fSjohnjiang #include <rte_hash.h>
104418919fSjohnjiang #include <rte_hash_crc.h>
114418919fSjohnjiang #include <rte_launch.h>
124418919fSjohnjiang #include <rte_malloc.h>
134418919fSjohnjiang #include <rte_random.h>
144418919fSjohnjiang #include <rte_spinlock.h>
154418919fSjohnjiang #include <rte_jhash.h>
164418919fSjohnjiang
174418919fSjohnjiang #include "test.h"
184418919fSjohnjiang
194418919fSjohnjiang /*
204418919fSjohnjiang * Check condition and return an error if true. Assumes that "handle" is the
214418919fSjohnjiang * name of the hash structure pointer to be freed.
224418919fSjohnjiang */
234418919fSjohnjiang #define RETURN_IF_ERROR(cond, str, ...) do { \
244418919fSjohnjiang if (cond) { \
254418919fSjohnjiang printf("ERROR line %d: " str "\n", __LINE__, \
264418919fSjohnjiang ##__VA_ARGS__); \
274418919fSjohnjiang if (handle) \
284418919fSjohnjiang rte_hash_free(handle); \
294418919fSjohnjiang return -1; \
304418919fSjohnjiang } \
314418919fSjohnjiang } while (0)
324418919fSjohnjiang
334418919fSjohnjiang #define RTE_APP_TEST_HASH_MULTIWRITER_FAILED 0
344418919fSjohnjiang
354418919fSjohnjiang struct {
364418919fSjohnjiang uint32_t *keys;
374418919fSjohnjiang uint32_t *found;
384418919fSjohnjiang uint32_t nb_tsx_insertion;
394418919fSjohnjiang struct rte_hash *h;
404418919fSjohnjiang } tbl_multiwriter_test_params;
414418919fSjohnjiang
424418919fSjohnjiang const uint32_t nb_entries = 5*1024*1024;
434418919fSjohnjiang const uint32_t nb_total_tsx_insertion = 4.5*1024*1024;
444418919fSjohnjiang uint32_t rounded_nb_total_tsx_insertion;
454418919fSjohnjiang
464418919fSjohnjiang static rte_atomic64_t gcycles;
474418919fSjohnjiang static rte_atomic64_t ginsertions;
484418919fSjohnjiang
494418919fSjohnjiang static int use_htm;
504418919fSjohnjiang
514418919fSjohnjiang static int
test_hash_multiwriter_worker(void * arg)524418919fSjohnjiang test_hash_multiwriter_worker(void *arg)
534418919fSjohnjiang {
544418919fSjohnjiang uint64_t i, offset;
554418919fSjohnjiang uint16_t pos_core;
564418919fSjohnjiang uint32_t lcore_id = rte_lcore_id();
574418919fSjohnjiang uint64_t begin, cycles;
584418919fSjohnjiang uint16_t *enabled_core_ids = (uint16_t *)arg;
594418919fSjohnjiang
604418919fSjohnjiang for (pos_core = 0; pos_core < rte_lcore_count(); pos_core++) {
614418919fSjohnjiang if (enabled_core_ids[pos_core] == lcore_id)
624418919fSjohnjiang break;
634418919fSjohnjiang }
644418919fSjohnjiang
654418919fSjohnjiang /*
664418919fSjohnjiang * Calculate offset for entries based on the position of the
67*2d9fd380Sjfb8856606 * logical core, from the main core (not counting not enabled cores)
684418919fSjohnjiang */
694418919fSjohnjiang offset = pos_core * tbl_multiwriter_test_params.nb_tsx_insertion;
704418919fSjohnjiang
714418919fSjohnjiang printf("Core #%d inserting %d: %'"PRId64" - %'"PRId64"\n",
724418919fSjohnjiang lcore_id, tbl_multiwriter_test_params.nb_tsx_insertion,
734418919fSjohnjiang offset,
744418919fSjohnjiang offset + tbl_multiwriter_test_params.nb_tsx_insertion - 1);
754418919fSjohnjiang
764418919fSjohnjiang begin = rte_rdtsc_precise();
774418919fSjohnjiang
784418919fSjohnjiang for (i = offset;
794418919fSjohnjiang i < offset + tbl_multiwriter_test_params.nb_tsx_insertion;
804418919fSjohnjiang i++) {
814418919fSjohnjiang if (rte_hash_add_key(tbl_multiwriter_test_params.h,
824418919fSjohnjiang tbl_multiwriter_test_params.keys + i) < 0)
834418919fSjohnjiang break;
844418919fSjohnjiang }
854418919fSjohnjiang
864418919fSjohnjiang cycles = rte_rdtsc_precise() - begin;
874418919fSjohnjiang rte_atomic64_add(&gcycles, cycles);
884418919fSjohnjiang rte_atomic64_add(&ginsertions, i - offset);
894418919fSjohnjiang
904418919fSjohnjiang for (; i < offset + tbl_multiwriter_test_params.nb_tsx_insertion; i++)
914418919fSjohnjiang tbl_multiwriter_test_params.keys[i]
924418919fSjohnjiang = RTE_APP_TEST_HASH_MULTIWRITER_FAILED;
934418919fSjohnjiang
944418919fSjohnjiang return 0;
954418919fSjohnjiang }
964418919fSjohnjiang
974418919fSjohnjiang
984418919fSjohnjiang static int
test_hash_multiwriter(void)994418919fSjohnjiang test_hash_multiwriter(void)
1004418919fSjohnjiang {
1014418919fSjohnjiang unsigned int i, rounded_nb_total_tsx_insertion;
1024418919fSjohnjiang static unsigned calledCount = 1;
1034418919fSjohnjiang uint16_t enabled_core_ids[RTE_MAX_LCORE];
1044418919fSjohnjiang uint16_t core_id;
1054418919fSjohnjiang
1064418919fSjohnjiang uint32_t *keys;
1074418919fSjohnjiang uint32_t *found;
1084418919fSjohnjiang
1094418919fSjohnjiang struct rte_hash_parameters hash_params = {
1104418919fSjohnjiang .entries = nb_entries,
1114418919fSjohnjiang .key_len = sizeof(uint32_t),
1124418919fSjohnjiang .hash_func = rte_jhash,
1134418919fSjohnjiang .hash_func_init_val = 0,
1144418919fSjohnjiang .socket_id = rte_socket_id(),
1154418919fSjohnjiang };
1164418919fSjohnjiang if (use_htm)
1174418919fSjohnjiang hash_params.extra_flag =
1184418919fSjohnjiang RTE_HASH_EXTRA_FLAGS_TRANS_MEM_SUPPORT
1194418919fSjohnjiang | RTE_HASH_EXTRA_FLAGS_MULTI_WRITER_ADD;
1204418919fSjohnjiang else
1214418919fSjohnjiang hash_params.extra_flag =
1224418919fSjohnjiang RTE_HASH_EXTRA_FLAGS_MULTI_WRITER_ADD;
1234418919fSjohnjiang
1244418919fSjohnjiang struct rte_hash *handle;
1254418919fSjohnjiang char name[RTE_HASH_NAMESIZE];
1264418919fSjohnjiang
1274418919fSjohnjiang const void *next_key;
1284418919fSjohnjiang void *next_data;
1294418919fSjohnjiang uint32_t iter = 0;
1304418919fSjohnjiang
1314418919fSjohnjiang uint32_t duplicated_keys = 0;
1324418919fSjohnjiang uint32_t lost_keys = 0;
1334418919fSjohnjiang uint32_t count;
1344418919fSjohnjiang
1354418919fSjohnjiang snprintf(name, 32, "test%u", calledCount++);
1364418919fSjohnjiang hash_params.name = name;
1374418919fSjohnjiang
1384418919fSjohnjiang handle = rte_hash_create(&hash_params);
1394418919fSjohnjiang RETURN_IF_ERROR(handle == NULL, "hash creation failed");
1404418919fSjohnjiang
1414418919fSjohnjiang tbl_multiwriter_test_params.h = handle;
1424418919fSjohnjiang tbl_multiwriter_test_params.nb_tsx_insertion =
1434418919fSjohnjiang nb_total_tsx_insertion / rte_lcore_count();
1444418919fSjohnjiang
1454418919fSjohnjiang rounded_nb_total_tsx_insertion = (nb_total_tsx_insertion /
1464418919fSjohnjiang tbl_multiwriter_test_params.nb_tsx_insertion)
1474418919fSjohnjiang * tbl_multiwriter_test_params.nb_tsx_insertion;
1484418919fSjohnjiang
1494418919fSjohnjiang rte_srand(rte_rdtsc());
1504418919fSjohnjiang
1514418919fSjohnjiang keys = rte_malloc(NULL, sizeof(uint32_t) * nb_entries, 0);
1524418919fSjohnjiang
1534418919fSjohnjiang if (keys == NULL) {
1544418919fSjohnjiang printf("RTE_MALLOC failed\n");
1554418919fSjohnjiang goto err1;
1564418919fSjohnjiang }
1574418919fSjohnjiang
1584418919fSjohnjiang for (i = 0; i < nb_entries; i++)
1594418919fSjohnjiang keys[i] = i;
1604418919fSjohnjiang
1614418919fSjohnjiang tbl_multiwriter_test_params.keys = keys;
1624418919fSjohnjiang
1634418919fSjohnjiang found = rte_zmalloc(NULL, sizeof(uint32_t) * nb_entries, 0);
1644418919fSjohnjiang if (found == NULL) {
1654418919fSjohnjiang printf("RTE_ZMALLOC failed\n");
1664418919fSjohnjiang goto err2;
1674418919fSjohnjiang }
1684418919fSjohnjiang
1694418919fSjohnjiang tbl_multiwriter_test_params.found = found;
1704418919fSjohnjiang
1714418919fSjohnjiang rte_atomic64_init(&gcycles);
1724418919fSjohnjiang rte_atomic64_clear(&gcycles);
1734418919fSjohnjiang
1744418919fSjohnjiang rte_atomic64_init(&ginsertions);
1754418919fSjohnjiang rte_atomic64_clear(&ginsertions);
1764418919fSjohnjiang
1774418919fSjohnjiang /* Get list of enabled cores */
1784418919fSjohnjiang i = 0;
1794418919fSjohnjiang for (core_id = 0; core_id < RTE_MAX_LCORE; core_id++) {
1804418919fSjohnjiang if (i == rte_lcore_count())
1814418919fSjohnjiang break;
1824418919fSjohnjiang
1834418919fSjohnjiang if (rte_lcore_is_enabled(core_id)) {
1844418919fSjohnjiang enabled_core_ids[i] = core_id;
1854418919fSjohnjiang i++;
1864418919fSjohnjiang }
1874418919fSjohnjiang }
1884418919fSjohnjiang
1894418919fSjohnjiang if (i != rte_lcore_count()) {
1904418919fSjohnjiang printf("Number of enabled cores in list is different from "
1914418919fSjohnjiang "number given by rte_lcore_count()\n");
1924418919fSjohnjiang goto err3;
1934418919fSjohnjiang }
1944418919fSjohnjiang
1954418919fSjohnjiang /* Fire all threads. */
1964418919fSjohnjiang rte_eal_mp_remote_launch(test_hash_multiwriter_worker,
197*2d9fd380Sjfb8856606 enabled_core_ids, CALL_MAIN);
1984418919fSjohnjiang rte_eal_mp_wait_lcore();
1994418919fSjohnjiang
2004418919fSjohnjiang count = rte_hash_count(handle);
2014418919fSjohnjiang if (count != rounded_nb_total_tsx_insertion) {
2024418919fSjohnjiang printf("rte_hash_count returned wrong value %u, %d\n",
2034418919fSjohnjiang rounded_nb_total_tsx_insertion, count);
2044418919fSjohnjiang goto err3;
2054418919fSjohnjiang }
2064418919fSjohnjiang
2074418919fSjohnjiang while (rte_hash_iterate(handle, &next_key, &next_data, &iter) >= 0) {
2084418919fSjohnjiang /* Search for the key in the list of keys added .*/
2094418919fSjohnjiang i = *(const uint32_t *)next_key;
2104418919fSjohnjiang tbl_multiwriter_test_params.found[i]++;
2114418919fSjohnjiang }
2124418919fSjohnjiang
2134418919fSjohnjiang for (i = 0; i < rounded_nb_total_tsx_insertion; i++) {
2144418919fSjohnjiang if (tbl_multiwriter_test_params.keys[i]
2154418919fSjohnjiang != RTE_APP_TEST_HASH_MULTIWRITER_FAILED) {
2164418919fSjohnjiang if (tbl_multiwriter_test_params.found[i] > 1) {
2174418919fSjohnjiang duplicated_keys++;
2184418919fSjohnjiang break;
2194418919fSjohnjiang }
2204418919fSjohnjiang if (tbl_multiwriter_test_params.found[i] == 0) {
2214418919fSjohnjiang lost_keys++;
2224418919fSjohnjiang printf("key %d is lost\n", i);
2234418919fSjohnjiang break;
2244418919fSjohnjiang }
2254418919fSjohnjiang }
2264418919fSjohnjiang }
2274418919fSjohnjiang
2284418919fSjohnjiang if (duplicated_keys > 0) {
2294418919fSjohnjiang printf("%d key duplicated\n", duplicated_keys);
2304418919fSjohnjiang goto err3;
2314418919fSjohnjiang }
2324418919fSjohnjiang
2334418919fSjohnjiang if (lost_keys > 0) {
2344418919fSjohnjiang printf("%d key lost\n", lost_keys);
2354418919fSjohnjiang goto err3;
2364418919fSjohnjiang }
2374418919fSjohnjiang
2384418919fSjohnjiang printf("No key corrupted during multiwriter insertion.\n");
2394418919fSjohnjiang
2404418919fSjohnjiang unsigned long long int cycles_per_insertion =
2414418919fSjohnjiang rte_atomic64_read(&gcycles)/
2424418919fSjohnjiang rte_atomic64_read(&ginsertions);
2434418919fSjohnjiang
2444418919fSjohnjiang printf(" cycles per insertion: %llu\n", cycles_per_insertion);
2454418919fSjohnjiang
2464418919fSjohnjiang rte_free(tbl_multiwriter_test_params.found);
2474418919fSjohnjiang rte_free(tbl_multiwriter_test_params.keys);
2484418919fSjohnjiang rte_hash_free(handle);
2494418919fSjohnjiang return 0;
2504418919fSjohnjiang
2514418919fSjohnjiang err3:
2524418919fSjohnjiang rte_free(tbl_multiwriter_test_params.found);
2534418919fSjohnjiang err2:
2544418919fSjohnjiang rte_free(tbl_multiwriter_test_params.keys);
2554418919fSjohnjiang err1:
2564418919fSjohnjiang rte_hash_free(handle);
2574418919fSjohnjiang return -1;
2584418919fSjohnjiang }
2594418919fSjohnjiang
2604418919fSjohnjiang static int
test_hash_multiwriter_main(void)2614418919fSjohnjiang test_hash_multiwriter_main(void)
2624418919fSjohnjiang {
2634418919fSjohnjiang if (rte_lcore_count() < 2) {
2644418919fSjohnjiang printf("Not enough cores for distributor_autotest, expecting at least 2\n");
2654418919fSjohnjiang return TEST_SKIPPED;
2664418919fSjohnjiang }
2674418919fSjohnjiang
2684418919fSjohnjiang setlocale(LC_NUMERIC, "");
2694418919fSjohnjiang
2704418919fSjohnjiang
2714418919fSjohnjiang if (!rte_tm_supported()) {
2724418919fSjohnjiang printf("Hardware transactional memory (lock elision) "
2734418919fSjohnjiang "is NOT supported\n");
2744418919fSjohnjiang } else {
2754418919fSjohnjiang printf("Hardware transactional memory (lock elision) "
2764418919fSjohnjiang "is supported\n");
2774418919fSjohnjiang
2784418919fSjohnjiang printf("Test multi-writer with Hardware transactional memory\n");
2794418919fSjohnjiang
2804418919fSjohnjiang use_htm = 1;
2814418919fSjohnjiang if (test_hash_multiwriter() < 0)
2824418919fSjohnjiang return -1;
2834418919fSjohnjiang }
2844418919fSjohnjiang
2854418919fSjohnjiang printf("Test multi-writer without Hardware transactional memory\n");
2864418919fSjohnjiang use_htm = 0;
2874418919fSjohnjiang if (test_hash_multiwriter() < 0)
2884418919fSjohnjiang return -1;
2894418919fSjohnjiang
2904418919fSjohnjiang return 0;
2914418919fSjohnjiang }
2924418919fSjohnjiang
2934418919fSjohnjiang REGISTER_TEST_COMMAND(hash_multiwriter_autotest, test_hash_multiwriter_main);
294