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