dpdk/app/test/test_hash_multiwriter.c
<<
>>
Prefs
   1/* SPDX-License-Identifier: BSD-3-Clause
   2 * Copyright(c) 2016 Intel Corporation
   3 */
   4
   5#include <inttypes.h>
   6#include <locale.h>
   7
   8#include <rte_cycles.h>
   9#include <rte_hash.h>
  10#include <rte_hash_crc.h>
  11#include <rte_launch.h>
  12#include <rte_malloc.h>
  13#include <rte_random.h>
  14#include <rte_spinlock.h>
  15#include <rte_jhash.h>
  16
  17#include "test.h"
  18
  19/*
  20 * Check condition and return an error if true. Assumes that "handle" is the
  21 * name of the hash structure pointer to be freed.
  22 */
  23#define RETURN_IF_ERROR(cond, str, ...) do {                            \
  24        if (cond) {                                                     \
  25                printf("ERROR line %d: " str "\n", __LINE__,            \
  26                                                        ##__VA_ARGS__); \
  27                if (handle)                                             \
  28                        rte_hash_free(handle);                          \
  29                return -1;                                              \
  30        }                                                               \
  31} while (0)
  32
  33#define RTE_APP_TEST_HASH_MULTIWRITER_FAILED 0
  34
  35struct {
  36        uint32_t *keys;
  37        uint32_t *found;
  38        uint32_t nb_tsx_insertion;
  39        struct rte_hash *h;
  40} tbl_multiwriter_test_params;
  41
  42const uint32_t nb_entries = 5*1024*1024;
  43const uint32_t nb_total_tsx_insertion = 4.5*1024*1024;
  44uint32_t rounded_nb_total_tsx_insertion;
  45
  46static uint64_t gcycles;
  47static uint64_t ginsertions;
  48
  49static int use_htm;
  50
  51static int
  52test_hash_multiwriter_worker(void *arg)
  53{
  54        uint64_t i, offset;
  55        uint16_t pos_core;
  56        uint32_t lcore_id = rte_lcore_id();
  57        uint64_t begin, cycles;
  58        uint16_t *enabled_core_ids = (uint16_t *)arg;
  59
  60        for (pos_core = 0; pos_core < rte_lcore_count(); pos_core++) {
  61                if (enabled_core_ids[pos_core] == lcore_id)
  62                        break;
  63        }
  64
  65        /*
  66         * Calculate offset for entries based on the position of the
  67         * logical core, from the main core (not counting not enabled cores)
  68         */
  69        offset = pos_core * tbl_multiwriter_test_params.nb_tsx_insertion;
  70
  71        printf("Core #%d inserting %d: %'"PRId64" - %'"PRId64"\n",
  72               lcore_id, tbl_multiwriter_test_params.nb_tsx_insertion,
  73               offset,
  74               offset + tbl_multiwriter_test_params.nb_tsx_insertion - 1);
  75
  76        begin = rte_rdtsc_precise();
  77
  78        for (i = offset;
  79             i < offset + tbl_multiwriter_test_params.nb_tsx_insertion;
  80             i++) {
  81                if (rte_hash_add_key(tbl_multiwriter_test_params.h,
  82                                     tbl_multiwriter_test_params.keys + i) < 0)
  83                        break;
  84        }
  85
  86        cycles = rte_rdtsc_precise() - begin;
  87        __atomic_fetch_add(&gcycles, cycles, __ATOMIC_RELAXED);
  88        __atomic_fetch_add(&ginsertions, i - offset, __ATOMIC_RELAXED);
  89
  90        for (; i < offset + tbl_multiwriter_test_params.nb_tsx_insertion; i++)
  91                tbl_multiwriter_test_params.keys[i]
  92                        = RTE_APP_TEST_HASH_MULTIWRITER_FAILED;
  93
  94        return 0;
  95}
  96
  97
  98static int
  99test_hash_multiwriter(void)
 100{
 101        unsigned int i, rounded_nb_total_tsx_insertion;
 102        static unsigned calledCount = 1;
 103        uint16_t enabled_core_ids[RTE_MAX_LCORE];
 104        uint16_t core_id;
 105
 106        uint32_t *keys;
 107        uint32_t *found;
 108
 109        struct rte_hash_parameters hash_params = {
 110                .entries = nb_entries,
 111                .key_len = sizeof(uint32_t),
 112                .hash_func = rte_jhash,
 113                .hash_func_init_val = 0,
 114                .socket_id = rte_socket_id(),
 115        };
 116        if (use_htm)
 117                hash_params.extra_flag =
 118                        RTE_HASH_EXTRA_FLAGS_TRANS_MEM_SUPPORT
 119                                | RTE_HASH_EXTRA_FLAGS_MULTI_WRITER_ADD;
 120        else
 121                hash_params.extra_flag =
 122                        RTE_HASH_EXTRA_FLAGS_MULTI_WRITER_ADD;
 123
 124        struct rte_hash *handle;
 125        char name[RTE_HASH_NAMESIZE];
 126
 127        const void *next_key;
 128        void *next_data;
 129        uint32_t iter = 0;
 130
 131        uint32_t duplicated_keys = 0;
 132        uint32_t lost_keys = 0;
 133        uint32_t count;
 134
 135        snprintf(name, 32, "test%u", calledCount++);
 136        hash_params.name = name;
 137
 138        handle = rte_hash_create(&hash_params);
 139        RETURN_IF_ERROR(handle == NULL, "hash creation failed");
 140
 141        tbl_multiwriter_test_params.h = handle;
 142        tbl_multiwriter_test_params.nb_tsx_insertion =
 143                nb_total_tsx_insertion / rte_lcore_count();
 144
 145        rounded_nb_total_tsx_insertion = (nb_total_tsx_insertion /
 146                tbl_multiwriter_test_params.nb_tsx_insertion)
 147                * tbl_multiwriter_test_params.nb_tsx_insertion;
 148
 149        rte_srand(rte_rdtsc());
 150
 151        keys = rte_malloc(NULL, sizeof(uint32_t) * nb_entries, 0);
 152
 153        if (keys == NULL) {
 154                printf("RTE_MALLOC failed\n");
 155                goto err1;
 156        }
 157
 158        for (i = 0; i < nb_entries; i++)
 159                keys[i] = i;
 160
 161        tbl_multiwriter_test_params.keys = keys;
 162
 163        found = rte_zmalloc(NULL, sizeof(uint32_t) * nb_entries, 0);
 164        if (found == NULL) {
 165                printf("RTE_ZMALLOC failed\n");
 166                goto err2;
 167        }
 168
 169        tbl_multiwriter_test_params.found = found;
 170
 171        __atomic_store_n(&gcycles, 0, __ATOMIC_RELAXED);
 172        __atomic_store_n(&ginsertions, 0, __ATOMIC_RELAXED);
 173
 174        /* Get list of enabled cores */
 175        i = 0;
 176        for (core_id = 0; core_id < RTE_MAX_LCORE; core_id++) {
 177                if (i == rte_lcore_count())
 178                        break;
 179
 180                if (rte_lcore_is_enabled(core_id)) {
 181                        enabled_core_ids[i] = core_id;
 182                        i++;
 183                }
 184        }
 185
 186        if (i != rte_lcore_count()) {
 187                printf("Number of enabled cores in list is different from "
 188                                "number given by rte_lcore_count()\n");
 189                goto err3;
 190        }
 191
 192        /* Fire all threads. */
 193        rte_eal_mp_remote_launch(test_hash_multiwriter_worker,
 194                                 enabled_core_ids, CALL_MAIN);
 195        rte_eal_mp_wait_lcore();
 196
 197        count = rte_hash_count(handle);
 198        if (count != rounded_nb_total_tsx_insertion) {
 199                printf("rte_hash_count returned wrong value %u, %d\n",
 200                                rounded_nb_total_tsx_insertion, count);
 201                goto err3;
 202        }
 203
 204        while (rte_hash_iterate(handle, &next_key, &next_data, &iter) >= 0) {
 205                /* Search for the key in the list of keys added .*/
 206                i = *(const uint32_t *)next_key;
 207                tbl_multiwriter_test_params.found[i]++;
 208        }
 209
 210        for (i = 0; i < rounded_nb_total_tsx_insertion; i++) {
 211                if (tbl_multiwriter_test_params.keys[i]
 212                    != RTE_APP_TEST_HASH_MULTIWRITER_FAILED) {
 213                        if (tbl_multiwriter_test_params.found[i] > 1) {
 214                                duplicated_keys++;
 215                                break;
 216                        }
 217                        if (tbl_multiwriter_test_params.found[i] == 0) {
 218                                lost_keys++;
 219                                printf("key %d is lost\n", i);
 220                                break;
 221                        }
 222                }
 223        }
 224
 225        if (duplicated_keys > 0) {
 226                printf("%d key duplicated\n", duplicated_keys);
 227                goto err3;
 228        }
 229
 230        if (lost_keys > 0) {
 231                printf("%d key lost\n", lost_keys);
 232                goto err3;
 233        }
 234
 235        printf("No key corrupted during multiwriter insertion.\n");
 236
 237        unsigned long long int cycles_per_insertion =
 238                __atomic_load_n(&gcycles, __ATOMIC_RELAXED)/
 239                __atomic_load_n(&ginsertions, __ATOMIC_RELAXED);
 240
 241        printf(" cycles per insertion: %llu\n", cycles_per_insertion);
 242
 243        rte_free(tbl_multiwriter_test_params.found);
 244        rte_free(tbl_multiwriter_test_params.keys);
 245        rte_hash_free(handle);
 246        return 0;
 247
 248err3:
 249        rte_free(tbl_multiwriter_test_params.found);
 250err2:
 251        rte_free(tbl_multiwriter_test_params.keys);
 252err1:
 253        rte_hash_free(handle);
 254        return -1;
 255}
 256
 257static int
 258test_hash_multiwriter_main(void)
 259{
 260        if (rte_lcore_count() < 2) {
 261                printf("Not enough cores for distributor_autotest, expecting at least 2\n");
 262                return TEST_SKIPPED;
 263        }
 264
 265        setlocale(LC_NUMERIC, "");
 266
 267
 268        if (!rte_tm_supported()) {
 269                printf("Hardware transactional memory (lock elision) "
 270                        "is NOT supported\n");
 271        } else {
 272                printf("Hardware transactional memory (lock elision) "
 273                        "is supported\n");
 274
 275                printf("Test multi-writer with Hardware transactional memory\n");
 276
 277                use_htm = 1;
 278                if (test_hash_multiwriter() < 0)
 279                        return -1;
 280        }
 281
 282        printf("Test multi-writer without Hardware transactional memory\n");
 283        use_htm = 0;
 284        if (test_hash_multiwriter() < 0)
 285                return -1;
 286
 287        return 0;
 288}
 289
 290REGISTER_TEST_COMMAND(hash_multiwriter_autotest, test_hash_multiwriter_main);
 291