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