]>
Commit | Line | Data |
---|---|---|
11fdf7f2 TL |
1 | /* SPDX-License-Identifier: BSD-3-Clause |
2 | * Copyright(c) 2018 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_jhash.h> | |
12 | #include <rte_launch.h> | |
13 | #include <rte_malloc.h> | |
14 | #include <rte_random.h> | |
15 | #include <rte_spinlock.h> | |
16 | ||
17 | #include "test.h" | |
18 | ||
19 | #define RTE_RWTEST_FAIL 0 | |
20 | ||
9f95a23c TL |
21 | #define TOTAL_ENTRY (5*1024*1024) |
22 | #define TOTAL_INSERT (4.5*1024*1024) | |
23 | #define TOTAL_INSERT_EXT (5*1024*1024) | |
11fdf7f2 TL |
24 | |
25 | #define NUM_TEST 3 | |
26 | unsigned int core_cnt[NUM_TEST] = {2, 4, 8}; | |
27 | ||
9f95a23c | 28 | unsigned int slave_core_ids[RTE_MAX_LCORE]; |
11fdf7f2 TL |
29 | struct perf { |
30 | uint32_t single_read; | |
31 | uint32_t single_write; | |
32 | uint32_t read_only[NUM_TEST]; | |
33 | uint32_t write_only[NUM_TEST]; | |
34 | uint32_t read_write_r[NUM_TEST]; | |
35 | uint32_t read_write_w[NUM_TEST]; | |
36 | }; | |
37 | ||
38 | static struct perf htm_results, non_htm_results; | |
39 | ||
40 | struct { | |
41 | uint32_t *keys; | |
9f95a23c | 42 | uint8_t *found; |
11fdf7f2 TL |
43 | uint32_t num_insert; |
44 | uint32_t rounded_tot_insert; | |
45 | struct rte_hash *h; | |
46 | } tbl_rw_test_param; | |
47 | ||
48 | static rte_atomic64_t gcycles; | |
49 | static rte_atomic64_t ginsertions; | |
50 | ||
51 | static rte_atomic64_t gread_cycles; | |
52 | static rte_atomic64_t gwrite_cycles; | |
53 | ||
54 | static rte_atomic64_t greads; | |
55 | static rte_atomic64_t gwrites; | |
56 | ||
57 | static int | |
f67539c2 | 58 | test_hash_readwrite_worker(__rte_unused void *arg) |
11fdf7f2 TL |
59 | { |
60 | uint64_t i, offset; | |
61 | uint32_t lcore_id = rte_lcore_id(); | |
62 | uint64_t begin, cycles; | |
9f95a23c | 63 | int *ret; |
11fdf7f2 | 64 | |
9f95a23c TL |
65 | ret = rte_malloc(NULL, sizeof(int) * |
66 | tbl_rw_test_param.num_insert, 0); | |
67 | for (i = 0; i < rte_lcore_count(); i++) { | |
68 | if (slave_core_ids[i] == lcore_id) | |
69 | break; | |
70 | } | |
71 | offset = tbl_rw_test_param.num_insert * i; | |
11fdf7f2 TL |
72 | |
73 | printf("Core #%d inserting and reading %d: %'"PRId64" - %'"PRId64"\n", | |
74 | lcore_id, tbl_rw_test_param.num_insert, | |
9f95a23c | 75 | offset, offset + tbl_rw_test_param.num_insert - 1); |
11fdf7f2 TL |
76 | |
77 | begin = rte_rdtsc_precise(); | |
78 | ||
79 | for (i = offset; i < offset + tbl_rw_test_param.num_insert; i++) { | |
80 | ||
81 | if (rte_hash_lookup(tbl_rw_test_param.h, | |
82 | tbl_rw_test_param.keys + i) > 0) | |
83 | break; | |
84 | ||
9f95a23c | 85 | ret[i - offset] = rte_hash_add_key(tbl_rw_test_param.h, |
11fdf7f2 | 86 | tbl_rw_test_param.keys + i); |
9f95a23c | 87 | if (ret[i - offset] < 0) |
11fdf7f2 TL |
88 | break; |
89 | ||
9f95a23c TL |
90 | /* lookup a random key */ |
91 | uint32_t rand = rte_rand() % (i + 1 - offset); | |
92 | ||
11fdf7f2 | 93 | if (rte_hash_lookup(tbl_rw_test_param.h, |
9f95a23c TL |
94 | tbl_rw_test_param.keys + rand) != ret[rand]) |
95 | break; | |
96 | ||
97 | ||
98 | if (rte_hash_del_key(tbl_rw_test_param.h, | |
99 | tbl_rw_test_param.keys + rand) != ret[rand]) | |
100 | break; | |
101 | ||
102 | ret[rand] = rte_hash_add_key(tbl_rw_test_param.h, | |
103 | tbl_rw_test_param.keys + rand); | |
104 | if (ret[rand] < 0) | |
105 | break; | |
106 | ||
107 | if (rte_hash_lookup(tbl_rw_test_param.h, | |
108 | tbl_rw_test_param.keys + rand) != ret[rand]) | |
11fdf7f2 TL |
109 | break; |
110 | } | |
111 | ||
112 | cycles = rte_rdtsc_precise() - begin; | |
113 | rte_atomic64_add(&gcycles, cycles); | |
114 | rte_atomic64_add(&ginsertions, i - offset); | |
115 | ||
116 | for (; i < offset + tbl_rw_test_param.num_insert; i++) | |
117 | tbl_rw_test_param.keys[i] = RTE_RWTEST_FAIL; | |
118 | ||
9f95a23c | 119 | rte_free(ret); |
11fdf7f2 TL |
120 | return 0; |
121 | } | |
122 | ||
123 | static int | |
f67539c2 | 124 | init_params(int use_ext, int use_htm, int rw_lf, int use_jhash) |
11fdf7f2 TL |
125 | { |
126 | unsigned int i; | |
127 | ||
128 | uint32_t *keys = NULL; | |
9f95a23c | 129 | uint8_t *found = NULL; |
11fdf7f2 TL |
130 | struct rte_hash *handle; |
131 | ||
132 | struct rte_hash_parameters hash_params = { | |
133 | .entries = TOTAL_ENTRY, | |
134 | .key_len = sizeof(uint32_t), | |
135 | .hash_func_init_val = 0, | |
136 | .socket_id = rte_socket_id(), | |
137 | }; | |
138 | if (use_jhash) | |
139 | hash_params.hash_func = rte_jhash; | |
140 | else | |
141 | hash_params.hash_func = rte_hash_crc; | |
142 | ||
f67539c2 | 143 | hash_params.extra_flag = RTE_HASH_EXTRA_FLAGS_MULTI_WRITER_ADD; |
11fdf7f2 | 144 | if (use_htm) |
f67539c2 TL |
145 | hash_params.extra_flag |= |
146 | RTE_HASH_EXTRA_FLAGS_TRANS_MEM_SUPPORT; | |
147 | if (rw_lf) | |
148 | hash_params.extra_flag |= | |
149 | RTE_HASH_EXTRA_FLAGS_RW_CONCURRENCY_LF; | |
11fdf7f2 | 150 | else |
f67539c2 TL |
151 | hash_params.extra_flag |= |
152 | RTE_HASH_EXTRA_FLAGS_RW_CONCURRENCY; | |
9f95a23c TL |
153 | |
154 | if (use_ext) | |
155 | hash_params.extra_flag |= | |
156 | RTE_HASH_EXTRA_FLAGS_EXT_TABLE; | |
157 | else | |
158 | hash_params.extra_flag &= | |
159 | ~RTE_HASH_EXTRA_FLAGS_EXT_TABLE; | |
11fdf7f2 TL |
160 | |
161 | hash_params.name = "tests"; | |
162 | ||
163 | handle = rte_hash_create(&hash_params); | |
164 | if (handle == NULL) { | |
165 | printf("hash creation failed"); | |
166 | return -1; | |
167 | } | |
168 | ||
169 | tbl_rw_test_param.h = handle; | |
170 | keys = rte_malloc(NULL, sizeof(uint32_t) * TOTAL_ENTRY, 0); | |
171 | ||
172 | if (keys == NULL) { | |
173 | printf("RTE_MALLOC failed\n"); | |
174 | goto err; | |
175 | } | |
176 | ||
9f95a23c | 177 | found = rte_zmalloc(NULL, sizeof(uint8_t) * TOTAL_ENTRY, 0); |
11fdf7f2 TL |
178 | if (found == NULL) { |
179 | printf("RTE_ZMALLOC failed\n"); | |
180 | goto err; | |
181 | } | |
182 | ||
183 | tbl_rw_test_param.keys = keys; | |
184 | tbl_rw_test_param.found = found; | |
185 | ||
186 | for (i = 0; i < TOTAL_ENTRY; i++) | |
187 | keys[i] = i; | |
188 | ||
189 | return 0; | |
190 | ||
191 | err: | |
192 | rte_free(keys); | |
193 | rte_hash_free(handle); | |
194 | ||
195 | return -1; | |
196 | } | |
197 | ||
198 | static int | |
f67539c2 | 199 | test_hash_readwrite_functional(int use_htm, int use_rw_lf, int use_ext) |
11fdf7f2 TL |
200 | { |
201 | unsigned int i; | |
202 | const void *next_key; | |
203 | void *next_data; | |
204 | uint32_t iter = 0; | |
205 | ||
206 | uint32_t duplicated_keys = 0; | |
207 | uint32_t lost_keys = 0; | |
208 | int use_jhash = 1; | |
9f95a23c TL |
209 | int slave_cnt = rte_lcore_count() - 1; |
210 | uint32_t tot_insert = 0; | |
11fdf7f2 TL |
211 | |
212 | rte_atomic64_init(&gcycles); | |
213 | rte_atomic64_clear(&gcycles); | |
214 | ||
215 | rte_atomic64_init(&ginsertions); | |
216 | rte_atomic64_clear(&ginsertions); | |
217 | ||
f67539c2 | 218 | if (init_params(use_ext, use_htm, use_rw_lf, use_jhash) != 0) |
11fdf7f2 TL |
219 | goto err; |
220 | ||
9f95a23c TL |
221 | if (use_ext) |
222 | tot_insert = TOTAL_INSERT_EXT; | |
223 | else | |
224 | tot_insert = TOTAL_INSERT; | |
225 | ||
11fdf7f2 | 226 | tbl_rw_test_param.num_insert = |
9f95a23c | 227 | tot_insert / slave_cnt; |
11fdf7f2 TL |
228 | |
229 | tbl_rw_test_param.rounded_tot_insert = | |
230 | tbl_rw_test_param.num_insert | |
9f95a23c | 231 | * slave_cnt; |
11fdf7f2 | 232 | |
f67539c2 TL |
233 | printf("\nHTM = %d, RW-LF = %d, EXT-Table = %d\n", |
234 | use_htm, use_rw_lf, use_ext); | |
11fdf7f2 TL |
235 | printf("++++++++Start function tests:+++++++++\n"); |
236 | ||
237 | /* Fire all threads. */ | |
238 | rte_eal_mp_remote_launch(test_hash_readwrite_worker, | |
9f95a23c | 239 | NULL, SKIP_MASTER); |
11fdf7f2 TL |
240 | rte_eal_mp_wait_lcore(); |
241 | ||
242 | while (rte_hash_iterate(tbl_rw_test_param.h, &next_key, | |
243 | &next_data, &iter) >= 0) { | |
244 | /* Search for the key in the list of keys added .*/ | |
245 | i = *(const uint32_t *)next_key; | |
246 | tbl_rw_test_param.found[i]++; | |
247 | } | |
248 | ||
249 | for (i = 0; i < tbl_rw_test_param.rounded_tot_insert; i++) { | |
250 | if (tbl_rw_test_param.keys[i] != RTE_RWTEST_FAIL) { | |
251 | if (tbl_rw_test_param.found[i] > 1) { | |
252 | duplicated_keys++; | |
253 | break; | |
254 | } | |
255 | if (tbl_rw_test_param.found[i] == 0) { | |
256 | lost_keys++; | |
257 | printf("key %d is lost\n", i); | |
258 | break; | |
259 | } | |
260 | } | |
261 | } | |
262 | ||
263 | if (duplicated_keys > 0) { | |
264 | printf("%d key duplicated\n", duplicated_keys); | |
265 | goto err_free; | |
266 | } | |
267 | ||
268 | if (lost_keys > 0) { | |
269 | printf("%d key lost\n", lost_keys); | |
270 | goto err_free; | |
271 | } | |
272 | ||
273 | printf("No key corrupted during read-write test.\n"); | |
274 | ||
275 | unsigned long long int cycles_per_insertion = | |
276 | rte_atomic64_read(&gcycles) / | |
277 | rte_atomic64_read(&ginsertions); | |
278 | ||
279 | printf("cycles per insertion and lookup: %llu\n", cycles_per_insertion); | |
280 | ||
281 | rte_free(tbl_rw_test_param.found); | |
282 | rte_free(tbl_rw_test_param.keys); | |
283 | rte_hash_free(tbl_rw_test_param.h); | |
284 | printf("+++++++++Complete function tests+++++++++\n"); | |
285 | return 0; | |
286 | ||
287 | err_free: | |
288 | rte_free(tbl_rw_test_param.found); | |
289 | rte_free(tbl_rw_test_param.keys); | |
290 | rte_hash_free(tbl_rw_test_param.h); | |
291 | err: | |
292 | return -1; | |
293 | } | |
294 | ||
295 | static int | |
9f95a23c | 296 | test_rw_reader(void *arg) |
11fdf7f2 TL |
297 | { |
298 | uint64_t i; | |
299 | uint64_t begin, cycles; | |
300 | uint64_t read_cnt = (uint64_t)((uintptr_t)arg); | |
301 | ||
302 | begin = rte_rdtsc_precise(); | |
303 | for (i = 0; i < read_cnt; i++) { | |
f67539c2 | 304 | void *data = arg; |
11fdf7f2 TL |
305 | rte_hash_lookup_data(tbl_rw_test_param.h, |
306 | tbl_rw_test_param.keys + i, | |
307 | &data); | |
308 | if (i != (uint64_t)(uintptr_t)data) { | |
309 | printf("lookup find wrong value %"PRIu64"," | |
310 | "%"PRIu64"\n", i, | |
311 | (uint64_t)(uintptr_t)data); | |
312 | break; | |
313 | } | |
314 | } | |
315 | ||
316 | cycles = rte_rdtsc_precise() - begin; | |
317 | rte_atomic64_add(&gread_cycles, cycles); | |
318 | rte_atomic64_add(&greads, i); | |
319 | return 0; | |
320 | } | |
321 | ||
322 | static int | |
9f95a23c | 323 | test_rw_writer(void *arg) |
11fdf7f2 TL |
324 | { |
325 | uint64_t i; | |
326 | uint32_t lcore_id = rte_lcore_id(); | |
327 | uint64_t begin, cycles; | |
328 | int ret; | |
329 | uint64_t start_coreid = (uint64_t)(uintptr_t)arg; | |
330 | uint64_t offset; | |
331 | ||
9f95a23c TL |
332 | for (i = 0; i < rte_lcore_count(); i++) { |
333 | if (slave_core_ids[i] == lcore_id) | |
334 | break; | |
335 | } | |
336 | ||
337 | offset = TOTAL_INSERT / 2 + (i - (start_coreid)) * | |
338 | tbl_rw_test_param.num_insert; | |
11fdf7f2 TL |
339 | begin = rte_rdtsc_precise(); |
340 | for (i = offset; i < offset + tbl_rw_test_param.num_insert; i++) { | |
341 | ret = rte_hash_add_key_data(tbl_rw_test_param.h, | |
342 | tbl_rw_test_param.keys + i, | |
343 | (void *)((uintptr_t)i)); | |
344 | if (ret < 0) { | |
345 | printf("writer failed %"PRIu64"\n", i); | |
346 | break; | |
347 | } | |
348 | } | |
349 | ||
350 | cycles = rte_rdtsc_precise() - begin; | |
351 | rte_atomic64_add(&gwrite_cycles, cycles); | |
352 | rte_atomic64_add(&gwrites, tbl_rw_test_param.num_insert); | |
353 | return 0; | |
354 | } | |
355 | ||
356 | static int | |
357 | test_hash_readwrite_perf(struct perf *perf_results, int use_htm, | |
358 | int reader_faster) | |
359 | { | |
360 | unsigned int n; | |
361 | int ret; | |
362 | int start_coreid; | |
363 | uint64_t i, read_cnt; | |
364 | ||
365 | const void *next_key; | |
366 | void *next_data; | |
9f95a23c | 367 | uint32_t iter; |
11fdf7f2 TL |
368 | int use_jhash = 0; |
369 | ||
370 | uint32_t duplicated_keys = 0; | |
371 | uint32_t lost_keys = 0; | |
372 | ||
373 | uint64_t start = 0, end = 0; | |
374 | ||
375 | rte_atomic64_init(&greads); | |
376 | rte_atomic64_init(&gwrites); | |
377 | rte_atomic64_clear(&gwrites); | |
378 | rte_atomic64_clear(&greads); | |
379 | ||
380 | rte_atomic64_init(&gread_cycles); | |
381 | rte_atomic64_clear(&gread_cycles); | |
382 | rte_atomic64_init(&gwrite_cycles); | |
383 | rte_atomic64_clear(&gwrite_cycles); | |
384 | ||
f67539c2 | 385 | if (init_params(0, use_htm, 0, use_jhash) != 0) |
11fdf7f2 TL |
386 | goto err; |
387 | ||
388 | /* | |
389 | * Do a readers finish faster or writers finish faster test. | |
390 | * When readers finish faster, we timing the readers, and when writers | |
391 | * finish faster, we timing the writers. | |
392 | * Divided by 10 or 2 is just experimental values to vary the workload | |
393 | * of readers. | |
394 | */ | |
395 | if (reader_faster) { | |
396 | printf("++++++Start perf test: reader++++++++\n"); | |
397 | read_cnt = TOTAL_INSERT / 10; | |
398 | } else { | |
399 | printf("++++++Start perf test: writer++++++++\n"); | |
400 | read_cnt = TOTAL_INSERT / 2; | |
401 | } | |
402 | ||
403 | /* We first test single thread performance */ | |
404 | start = rte_rdtsc_precise(); | |
405 | /* Insert half of the keys */ | |
406 | for (i = 0; i < TOTAL_INSERT / 2; i++) { | |
407 | ret = rte_hash_add_key_data(tbl_rw_test_param.h, | |
408 | tbl_rw_test_param.keys + i, | |
409 | (void *)((uintptr_t)i)); | |
410 | if (ret < 0) { | |
411 | printf("Failed to insert half of keys\n"); | |
412 | goto err_free; | |
413 | } | |
414 | } | |
415 | end = rte_rdtsc_precise() - start; | |
416 | perf_results->single_write = end / i; | |
417 | ||
418 | start = rte_rdtsc_precise(); | |
419 | ||
420 | for (i = 0; i < read_cnt; i++) { | |
421 | void *data; | |
422 | rte_hash_lookup_data(tbl_rw_test_param.h, | |
423 | tbl_rw_test_param.keys + i, | |
424 | &data); | |
425 | if (i != (uint64_t)(uintptr_t)data) { | |
426 | printf("lookup find wrong value" | |
427 | " %"PRIu64",%"PRIu64"\n", i, | |
428 | (uint64_t)(uintptr_t)data); | |
429 | break; | |
430 | } | |
431 | } | |
432 | end = rte_rdtsc_precise() - start; | |
433 | perf_results->single_read = end / i; | |
434 | ||
435 | for (n = 0; n < NUM_TEST; n++) { | |
9f95a23c TL |
436 | unsigned int tot_slave_lcore = rte_lcore_count() - 1; |
437 | if (tot_slave_lcore < core_cnt[n] * 2) | |
11fdf7f2 TL |
438 | goto finish; |
439 | ||
440 | rte_atomic64_clear(&greads); | |
441 | rte_atomic64_clear(&gread_cycles); | |
442 | rte_atomic64_clear(&gwrites); | |
443 | rte_atomic64_clear(&gwrite_cycles); | |
444 | ||
445 | rte_hash_reset(tbl_rw_test_param.h); | |
446 | ||
447 | tbl_rw_test_param.num_insert = TOTAL_INSERT / 2 / core_cnt[n]; | |
448 | tbl_rw_test_param.rounded_tot_insert = TOTAL_INSERT / 2 + | |
449 | tbl_rw_test_param.num_insert * | |
450 | core_cnt[n]; | |
451 | ||
452 | for (i = 0; i < TOTAL_INSERT / 2; i++) { | |
453 | ret = rte_hash_add_key_data(tbl_rw_test_param.h, | |
454 | tbl_rw_test_param.keys + i, | |
455 | (void *)((uintptr_t)i)); | |
456 | if (ret < 0) { | |
457 | printf("Failed to insert half of keys\n"); | |
458 | goto err_free; | |
459 | } | |
460 | } | |
461 | ||
462 | /* Then test multiple thread case but only all reads or | |
463 | * all writes | |
464 | */ | |
465 | ||
466 | /* Test only reader cases */ | |
9f95a23c | 467 | for (i = 0; i < core_cnt[n]; i++) |
11fdf7f2 | 468 | rte_eal_remote_launch(test_rw_reader, |
9f95a23c TL |
469 | (void *)(uintptr_t)read_cnt, |
470 | slave_core_ids[i]); | |
11fdf7f2 TL |
471 | |
472 | rte_eal_mp_wait_lcore(); | |
473 | ||
474 | start_coreid = i; | |
475 | /* Test only writer cases */ | |
9f95a23c | 476 | for (; i < core_cnt[n] * 2; i++) |
11fdf7f2 | 477 | rte_eal_remote_launch(test_rw_writer, |
9f95a23c TL |
478 | (void *)((uintptr_t)start_coreid), |
479 | slave_core_ids[i]); | |
11fdf7f2 TL |
480 | |
481 | rte_eal_mp_wait_lcore(); | |
482 | ||
483 | if (reader_faster) { | |
484 | unsigned long long int cycles_per_insertion = | |
485 | rte_atomic64_read(&gread_cycles) / | |
486 | rte_atomic64_read(&greads); | |
487 | perf_results->read_only[n] = cycles_per_insertion; | |
488 | printf("Reader only: cycles per lookup: %llu\n", | |
489 | cycles_per_insertion); | |
490 | } | |
491 | ||
492 | else { | |
493 | unsigned long long int cycles_per_insertion = | |
494 | rte_atomic64_read(&gwrite_cycles) / | |
495 | rte_atomic64_read(&gwrites); | |
496 | perf_results->write_only[n] = cycles_per_insertion; | |
497 | printf("Writer only: cycles per writes: %llu\n", | |
498 | cycles_per_insertion); | |
499 | } | |
500 | ||
501 | rte_atomic64_clear(&greads); | |
502 | rte_atomic64_clear(&gread_cycles); | |
503 | rte_atomic64_clear(&gwrites); | |
504 | rte_atomic64_clear(&gwrite_cycles); | |
505 | ||
506 | rte_hash_reset(tbl_rw_test_param.h); | |
507 | ||
508 | for (i = 0; i < TOTAL_INSERT / 2; i++) { | |
509 | ret = rte_hash_add_key_data(tbl_rw_test_param.h, | |
510 | tbl_rw_test_param.keys + i, | |
511 | (void *)((uintptr_t)i)); | |
512 | if (ret < 0) { | |
513 | printf("Failed to insert half of keys\n"); | |
514 | goto err_free; | |
515 | } | |
516 | } | |
517 | ||
9f95a23c | 518 | start_coreid = core_cnt[n]; |
11fdf7f2 TL |
519 | |
520 | if (reader_faster) { | |
9f95a23c | 521 | for (i = core_cnt[n]; i < core_cnt[n] * 2; i++) |
11fdf7f2 | 522 | rte_eal_remote_launch(test_rw_writer, |
9f95a23c TL |
523 | (void *)((uintptr_t)start_coreid), |
524 | slave_core_ids[i]); | |
525 | for (i = 0; i < core_cnt[n]; i++) | |
11fdf7f2 | 526 | rte_eal_remote_launch(test_rw_reader, |
9f95a23c TL |
527 | (void *)(uintptr_t)read_cnt, |
528 | slave_core_ids[i]); | |
11fdf7f2 | 529 | } else { |
9f95a23c | 530 | for (i = 0; i < core_cnt[n]; i++) |
11fdf7f2 | 531 | rte_eal_remote_launch(test_rw_reader, |
9f95a23c TL |
532 | (void *)(uintptr_t)read_cnt, |
533 | slave_core_ids[i]); | |
534 | for (; i < core_cnt[n] * 2; i++) | |
11fdf7f2 | 535 | rte_eal_remote_launch(test_rw_writer, |
9f95a23c TL |
536 | (void *)((uintptr_t)start_coreid), |
537 | slave_core_ids[i]); | |
11fdf7f2 TL |
538 | } |
539 | ||
540 | rte_eal_mp_wait_lcore(); | |
541 | ||
9f95a23c TL |
542 | iter = 0; |
543 | memset(tbl_rw_test_param.found, 0, TOTAL_ENTRY); | |
11fdf7f2 TL |
544 | while (rte_hash_iterate(tbl_rw_test_param.h, |
545 | &next_key, &next_data, &iter) >= 0) { | |
546 | /* Search for the key in the list of keys added .*/ | |
547 | i = *(const uint32_t *)next_key; | |
548 | tbl_rw_test_param.found[i]++; | |
549 | } | |
550 | ||
551 | for (i = 0; i < tbl_rw_test_param.rounded_tot_insert; i++) { | |
552 | if (tbl_rw_test_param.keys[i] != RTE_RWTEST_FAIL) { | |
553 | if (tbl_rw_test_param.found[i] > 1) { | |
554 | duplicated_keys++; | |
555 | break; | |
556 | } | |
557 | if (tbl_rw_test_param.found[i] == 0) { | |
558 | lost_keys++; | |
559 | printf("key %"PRIu64" is lost\n", i); | |
560 | break; | |
561 | } | |
562 | } | |
563 | } | |
564 | ||
565 | if (duplicated_keys > 0) { | |
566 | printf("%d key duplicated\n", duplicated_keys); | |
567 | goto err_free; | |
568 | } | |
569 | ||
570 | if (lost_keys > 0) { | |
571 | printf("%d key lost\n", lost_keys); | |
572 | goto err_free; | |
573 | } | |
574 | ||
575 | printf("No key corrupted during read-write test.\n"); | |
576 | ||
577 | if (reader_faster) { | |
578 | unsigned long long int cycles_per_insertion = | |
579 | rte_atomic64_read(&gread_cycles) / | |
580 | rte_atomic64_read(&greads); | |
581 | perf_results->read_write_r[n] = cycles_per_insertion; | |
582 | printf("Read-write cycles per lookup: %llu\n", | |
583 | cycles_per_insertion); | |
584 | } | |
585 | ||
586 | else { | |
587 | unsigned long long int cycles_per_insertion = | |
588 | rte_atomic64_read(&gwrite_cycles) / | |
589 | rte_atomic64_read(&gwrites); | |
590 | perf_results->read_write_w[n] = cycles_per_insertion; | |
591 | printf("Read-write cycles per writes: %llu\n", | |
592 | cycles_per_insertion); | |
593 | } | |
594 | } | |
595 | ||
596 | finish: | |
597 | rte_free(tbl_rw_test_param.found); | |
598 | rte_free(tbl_rw_test_param.keys); | |
599 | rte_hash_free(tbl_rw_test_param.h); | |
600 | return 0; | |
601 | ||
602 | err_free: | |
603 | rte_free(tbl_rw_test_param.found); | |
604 | rte_free(tbl_rw_test_param.keys); | |
605 | rte_hash_free(tbl_rw_test_param.h); | |
606 | ||
607 | err: | |
608 | return -1; | |
609 | } | |
610 | ||
611 | static int | |
f67539c2 | 612 | test_hash_rw_perf_main(void) |
11fdf7f2 TL |
613 | { |
614 | /* | |
615 | * Variables used to choose different tests. | |
616 | * use_htm indicates if hardware transactional memory should be used. | |
617 | * reader_faster indicates if the reader threads should finish earlier | |
618 | * than writer threads. This is to timing either reader threads or | |
619 | * writer threads for performance numbers. | |
620 | */ | |
f67539c2 | 621 | int use_htm, reader_faster; |
9f95a23c | 622 | unsigned int i = 0, core_id = 0; |
11fdf7f2 | 623 | |
f67539c2 TL |
624 | if (rte_lcore_count() < 3) { |
625 | printf("Not enough cores for hash_readwrite_autotest, expecting at least 3\n"); | |
626 | return TEST_SKIPPED; | |
9f95a23c TL |
627 | } |
628 | ||
629 | RTE_LCORE_FOREACH_SLAVE(core_id) { | |
630 | slave_core_ids[i] = core_id; | |
631 | i++; | |
11fdf7f2 TL |
632 | } |
633 | ||
634 | setlocale(LC_NUMERIC, ""); | |
635 | ||
636 | if (rte_tm_supported()) { | |
637 | printf("Hardware transactional memory (lock elision) " | |
638 | "is supported\n"); | |
639 | ||
640 | printf("Test read-write with Hardware transactional memory\n"); | |
641 | ||
642 | use_htm = 1; | |
11fdf7f2 TL |
643 | |
644 | reader_faster = 1; | |
645 | if (test_hash_readwrite_perf(&htm_results, use_htm, | |
646 | reader_faster) < 0) | |
647 | return -1; | |
648 | ||
649 | reader_faster = 0; | |
650 | if (test_hash_readwrite_perf(&htm_results, use_htm, | |
651 | reader_faster) < 0) | |
652 | return -1; | |
653 | } else { | |
654 | printf("Hardware transactional memory (lock elision) " | |
655 | "is NOT supported\n"); | |
656 | } | |
657 | ||
658 | printf("Test read-write without Hardware transactional memory\n"); | |
659 | use_htm = 0; | |
9f95a23c | 660 | |
11fdf7f2 TL |
661 | reader_faster = 1; |
662 | if (test_hash_readwrite_perf(&non_htm_results, use_htm, | |
663 | reader_faster) < 0) | |
664 | return -1; | |
665 | reader_faster = 0; | |
666 | if (test_hash_readwrite_perf(&non_htm_results, use_htm, | |
667 | reader_faster) < 0) | |
668 | return -1; | |
669 | ||
9f95a23c | 670 | printf("================\n"); |
11fdf7f2 | 671 | printf("Results summary:\n"); |
9f95a23c | 672 | printf("================\n"); |
11fdf7f2 TL |
673 | |
674 | printf("single read: %u\n", htm_results.single_read); | |
675 | printf("single write: %u\n", htm_results.single_write); | |
676 | for (i = 0; i < NUM_TEST; i++) { | |
9f95a23c | 677 | printf("+++ core_cnt: %u +++\n", core_cnt[i]); |
11fdf7f2 | 678 | printf("HTM:\n"); |
9f95a23c TL |
679 | printf(" read only: %u\n", htm_results.read_only[i]); |
680 | printf(" write only: %u\n", htm_results.write_only[i]); | |
681 | printf(" read-write read: %u\n", htm_results.read_write_r[i]); | |
682 | printf(" read-write write: %u\n", htm_results.read_write_w[i]); | |
11fdf7f2 TL |
683 | |
684 | printf("non HTM:\n"); | |
9f95a23c TL |
685 | printf(" read only: %u\n", non_htm_results.read_only[i]); |
686 | printf(" write only: %u\n", non_htm_results.write_only[i]); | |
687 | printf(" read-write read: %u\n", | |
11fdf7f2 | 688 | non_htm_results.read_write_r[i]); |
9f95a23c | 689 | printf(" read-write write: %u\n", |
11fdf7f2 TL |
690 | non_htm_results.read_write_w[i]); |
691 | } | |
692 | ||
693 | return 0; | |
694 | } | |
695 | ||
f67539c2 TL |
696 | static int |
697 | test_hash_rw_func_main(void) | |
698 | { | |
699 | /* | |
700 | * Variables used to choose different tests. | |
701 | * use_htm indicates if hardware transactional memory should be used. | |
702 | * reader_faster indicates if the reader threads should finish earlier | |
703 | * than writer threads. This is to timing either reader threads or | |
704 | * writer threads for performance numbers. | |
705 | */ | |
706 | unsigned int i = 0, core_id = 0; | |
707 | ||
708 | if (rte_lcore_count() < 3) { | |
709 | printf("Not enough cores for hash_readwrite_autotest, expecting at least 3\n"); | |
710 | return TEST_SKIPPED; | |
711 | } | |
712 | ||
713 | RTE_LCORE_FOREACH_SLAVE(core_id) { | |
714 | slave_core_ids[i] = core_id; | |
715 | i++; | |
716 | } | |
717 | ||
718 | setlocale(LC_NUMERIC, ""); | |
719 | ||
720 | if (rte_tm_supported()) { | |
721 | printf("Hardware transactional memory (lock elision) " | |
722 | "is supported\n"); | |
723 | ||
724 | printf("Test read-write with Hardware transactional memory\n"); | |
725 | ||
726 | /* htm = 1, rw_lf = 0, ext = 0 */ | |
727 | if (test_hash_readwrite_functional(1, 0, 0) < 0) | |
728 | return -1; | |
729 | ||
730 | /* htm = 1, rw_lf = 1, ext = 0 */ | |
731 | if (test_hash_readwrite_functional(1, 1, 0) < 0) | |
732 | return -1; | |
733 | ||
734 | /* htm = 1, rw_lf = 0, ext = 1 */ | |
735 | if (test_hash_readwrite_functional(1, 0, 1) < 0) | |
736 | return -1; | |
737 | ||
738 | /* htm = 1, rw_lf = 1, ext = 1 */ | |
739 | if (test_hash_readwrite_functional(1, 1, 1) < 0) | |
740 | return -1; | |
741 | } else { | |
742 | printf("Hardware transactional memory (lock elision) " | |
743 | "is NOT supported\n"); | |
744 | } | |
745 | ||
746 | printf("Test read-write without Hardware transactional memory\n"); | |
747 | /* htm = 0, rw_lf = 0, ext = 0 */ | |
748 | if (test_hash_readwrite_functional(0, 0, 0) < 0) | |
749 | return -1; | |
750 | ||
751 | /* htm = 0, rw_lf = 1, ext = 0 */ | |
752 | if (test_hash_readwrite_functional(0, 1, 0) < 0) | |
753 | return -1; | |
754 | ||
755 | /* htm = 0, rw_lf = 0, ext = 1 */ | |
756 | if (test_hash_readwrite_functional(0, 0, 1) < 0) | |
757 | return -1; | |
758 | ||
759 | /* htm = 0, rw_lf = 1, ext = 1 */ | |
760 | if (test_hash_readwrite_functional(0, 1, 1) < 0) | |
761 | return -1; | |
762 | ||
763 | return 0; | |
764 | } | |
765 | ||
766 | REGISTER_TEST_COMMAND(hash_readwrite_func_autotest, test_hash_rw_func_main); | |
767 | REGISTER_TEST_COMMAND(hash_readwrite_perf_autotest, test_hash_rw_perf_main); |