4 * Copyright(c) 2016 Intel Corporation. All rights reserved.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
11 * * Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * * Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in
15 * the documentation and/or other materials provided with the
17 * * Neither the name of Intel Corporation nor the names of its
18 * contributors may be used to endorse or promote products derived
19 * from this software without specific prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36 #include <rte_cycles.h>
38 #include <rte_hash_crc.h>
39 #include <rte_launch.h>
40 #include <rte_malloc.h>
41 #include <rte_random.h>
42 #include <rte_spinlock.h>
47 * Check condition and return an error if true. Assumes that "handle" is the
48 * name of the hash structure pointer to be freed.
50 #define RETURN_IF_ERROR(cond, str, ...) do { \
52 printf("ERROR line %d: " str "\n", __LINE__, \
55 rte_hash_free(handle); \
60 #define RTE_APP_TEST_HASH_MULTIWRITER_FAILED 0
65 uint32_t nb_tsx_insertion;
67 } tbl_multiwriter_test_params;
69 const uint32_t nb_entries = 16*1024*1024;
70 const uint32_t nb_total_tsx_insertion = 15*1024*1024;
71 uint32_t rounded_nb_total_tsx_insertion;
73 static rte_atomic64_t gcycles;
74 static rte_atomic64_t ginsertions;
79 test_hash_multiwriter_worker(void *arg)
83 uint32_t lcore_id = rte_lcore_id();
84 uint64_t begin, cycles;
85 uint16_t *enabled_core_ids = (uint16_t *)arg;
87 for (pos_core = 0; pos_core < rte_lcore_count(); pos_core++) {
88 if (enabled_core_ids[pos_core] == lcore_id)
93 * Calculate offset for entries based on the position of the
94 * logical core, from the master core (not counting not enabled cores)
96 offset = pos_core * tbl_multiwriter_test_params.nb_tsx_insertion;
98 printf("Core #%d inserting %d: %'"PRId64" - %'"PRId64"\n",
99 lcore_id, tbl_multiwriter_test_params.nb_tsx_insertion,
101 offset + tbl_multiwriter_test_params.nb_tsx_insertion - 1);
103 begin = rte_rdtsc_precise();
106 i < offset + tbl_multiwriter_test_params.nb_tsx_insertion;
108 if (rte_hash_add_key(tbl_multiwriter_test_params.h,
109 tbl_multiwriter_test_params.keys + i) < 0)
113 cycles = rte_rdtsc_precise() - begin;
114 rte_atomic64_add(&gcycles, cycles);
115 rte_atomic64_add(&ginsertions, i - offset);
117 for (; i < offset + tbl_multiwriter_test_params.nb_tsx_insertion; i++)
118 tbl_multiwriter_test_params.keys[i]
119 = RTE_APP_TEST_HASH_MULTIWRITER_FAILED;
126 test_hash_multiwriter(void)
128 unsigned int i, rounded_nb_total_tsx_insertion;
129 static unsigned calledCount = 1;
130 uint16_t enabled_core_ids[RTE_MAX_LCORE];
136 struct rte_hash_parameters hash_params = {
137 .entries = nb_entries,
138 .key_len = sizeof(uint32_t),
139 .hash_func = rte_hash_crc,
140 .hash_func_init_val = 0,
141 .socket_id = rte_socket_id(),
144 hash_params.extra_flag =
145 RTE_HASH_EXTRA_FLAGS_TRANS_MEM_SUPPORT
146 | RTE_HASH_EXTRA_FLAGS_MULTI_WRITER_ADD;
148 hash_params.extra_flag =
149 RTE_HASH_EXTRA_FLAGS_MULTI_WRITER_ADD;
151 struct rte_hash *handle;
152 char name[RTE_HASH_NAMESIZE];
154 const void *next_key;
158 uint32_t duplicated_keys = 0;
159 uint32_t lost_keys = 0;
161 snprintf(name, 32, "test%u", calledCount++);
162 hash_params.name = name;
164 handle = rte_hash_create(&hash_params);
165 RETURN_IF_ERROR(handle == NULL, "hash creation failed");
167 tbl_multiwriter_test_params.h = handle;
168 tbl_multiwriter_test_params.nb_tsx_insertion =
169 nb_total_tsx_insertion / rte_lcore_count();
171 rounded_nb_total_tsx_insertion = (nb_total_tsx_insertion /
172 tbl_multiwriter_test_params.nb_tsx_insertion)
173 * tbl_multiwriter_test_params.nb_tsx_insertion;
175 rte_srand(rte_rdtsc());
177 keys = rte_malloc(NULL, sizeof(uint32_t) * nb_entries, 0);
180 printf("RTE_MALLOC failed\n");
184 for (i = 0; i < nb_entries; i++)
187 tbl_multiwriter_test_params.keys = keys;
189 found = rte_zmalloc(NULL, sizeof(uint32_t) * nb_entries, 0);
191 printf("RTE_ZMALLOC failed\n");
195 tbl_multiwriter_test_params.found = found;
197 rte_atomic64_init(&gcycles);
198 rte_atomic64_clear(&gcycles);
200 rte_atomic64_init(&ginsertions);
201 rte_atomic64_clear(&ginsertions);
203 /* Get list of enabled cores */
205 for (core_id = 0; core_id < RTE_MAX_LCORE; core_id++) {
206 if (i == rte_lcore_count())
209 if (rte_lcore_is_enabled(core_id)) {
210 enabled_core_ids[i] = core_id;
215 if (i != rte_lcore_count()) {
216 printf("Number of enabled cores in list is different from "
217 "number given by rte_lcore_count()\n");
221 /* Fire all threads. */
222 rte_eal_mp_remote_launch(test_hash_multiwriter_worker,
223 enabled_core_ids, CALL_MASTER);
224 rte_eal_mp_wait_lcore();
226 while (rte_hash_iterate(handle, &next_key, &next_data, &iter) >= 0) {
227 /* Search for the key in the list of keys added .*/
228 i = *(const uint32_t *)next_key;
229 tbl_multiwriter_test_params.found[i]++;
232 for (i = 0; i < rounded_nb_total_tsx_insertion; i++) {
233 if (tbl_multiwriter_test_params.keys[i]
234 != RTE_APP_TEST_HASH_MULTIWRITER_FAILED) {
235 if (tbl_multiwriter_test_params.found[i] > 1) {
239 if (tbl_multiwriter_test_params.found[i] == 0) {
241 printf("key %d is lost\n", i);
247 if (duplicated_keys > 0) {
248 printf("%d key duplicated\n", duplicated_keys);
253 printf("%d key lost\n", lost_keys);
257 printf("No key corrupted during multiwriter insertion.\n");
259 unsigned long long int cycles_per_insertion =
260 rte_atomic64_read(&gcycles)/
261 rte_atomic64_read(&ginsertions);
263 printf(" cycles per insertion: %llu\n", cycles_per_insertion);
265 rte_free(tbl_multiwriter_test_params.found);
266 rte_free(tbl_multiwriter_test_params.keys);
267 rte_hash_free(handle);
271 rte_free(tbl_multiwriter_test_params.found);
273 rte_free(tbl_multiwriter_test_params.keys);
275 rte_hash_free(handle);
280 test_hash_multiwriter_main(void)
282 if (rte_lcore_count() == 1) {
283 printf("More than one lcore is required to do multiwriter test\n");
288 setlocale(LC_NUMERIC, "");
291 if (!rte_tm_supported()) {
292 printf("Hardware transactional memory (lock elision) "
293 "is NOT supported\n");
295 printf("Hardware transactional memory (lock elision) "
298 printf("Test multi-writer with Hardware transactional memory\n");
301 if (test_hash_multiwriter() < 0)
305 printf("Test multi-writer without Hardware transactional memory\n");
307 if (test_hash_multiwriter() < 0)
313 REGISTER_TEST_COMMAND(hash_multiwriter_autotest, test_hash_multiwriter_main);