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 slave_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_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 58 test_hash_readwrite_worker(__attribute__((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 (slave_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_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 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"); 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 slave_cnt = rte_lcore_count() - 1; 210 uint32_t tot_insert = 0; 211 212 rte_atomic64_init(&gcycles); 213 rte_atomic64_clear(&gcycles); 214 215 rte_atomic64_init(&ginsertions); 216 rte_atomic64_clear(&ginsertions); 217 218 if (init_params(use_ext, use_htm, use_rw_lf, use_jhash) != 0) 219 goto err; 220 221 if (use_ext) 222 tot_insert = TOTAL_INSERT_EXT; 223 else 224 tot_insert = TOTAL_INSERT; 225 226 tbl_rw_test_param.num_insert = 227 tot_insert / slave_cnt; 228 229 tbl_rw_test_param.rounded_tot_insert = 230 tbl_rw_test_param.num_insert 231 * slave_cnt; 232 233 printf("\nHTM = %d, RW-LF = %d, EXT-Table = %d\n", 234 use_htm, use_rw_lf, use_ext); 235 printf("++++++++Start function tests:+++++++++\n"); 236 237 /* Fire all threads. */ 238 rte_eal_mp_remote_launch(test_hash_readwrite_worker, 239 NULL, SKIP_MASTER); 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 296 test_rw_reader(void *arg) 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++) { 304 void *data = arg; 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 323 test_rw_writer(void *arg) 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 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; 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; 367 uint32_t iter; 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 385 if (init_params(0, use_htm, 0, use_jhash) != 0) 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++) { 436 unsigned int tot_slave_lcore = rte_lcore_count() - 1; 437 if (tot_slave_lcore < core_cnt[n] * 2) 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 */ 467 for (i = 0; i < core_cnt[n]; i++) 468 rte_eal_remote_launch(test_rw_reader, 469 (void *)(uintptr_t)read_cnt, 470 slave_core_ids[i]); 471 472 rte_eal_mp_wait_lcore(); 473 474 start_coreid = i; 475 /* Test only writer cases */ 476 for (; i < core_cnt[n] * 2; i++) 477 rte_eal_remote_launch(test_rw_writer, 478 (void *)((uintptr_t)start_coreid), 479 slave_core_ids[i]); 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 518 start_coreid = core_cnt[n]; 519 520 if (reader_faster) { 521 for (i = core_cnt[n]; i < core_cnt[n] * 2; i++) 522 rte_eal_remote_launch(test_rw_writer, 523 (void *)((uintptr_t)start_coreid), 524 slave_core_ids[i]); 525 for (i = 0; i < core_cnt[n]; i++) 526 rte_eal_remote_launch(test_rw_reader, 527 (void *)(uintptr_t)read_cnt, 528 slave_core_ids[i]); 529 } else { 530 for (i = 0; i < core_cnt[n]; i++) 531 rte_eal_remote_launch(test_rw_reader, 532 (void *)(uintptr_t)read_cnt, 533 slave_core_ids[i]); 534 for (; i < core_cnt[n] * 2; i++) 535 rte_eal_remote_launch(test_rw_writer, 536 (void *)((uintptr_t)start_coreid), 537 slave_core_ids[i]); 538 } 539 540 rte_eal_mp_wait_lcore(); 541 542 iter = 0; 543 memset(tbl_rw_test_param.found, 0, TOTAL_ENTRY); 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 612 test_hash_rw_perf_main(void) 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 */ 621 int use_htm, reader_faster; 622 unsigned int i = 0, core_id = 0; 623 624 if (rte_lcore_count() < 3) { 625 printf("Not enough cores for hash_readwrite_autotest, expecting at least 3\n"); 626 return TEST_SKIPPED; 627 } 628 629 RTE_LCORE_FOREACH_SLAVE(core_id) { 630 slave_core_ids[i] = core_id; 631 i++; 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; 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; 660 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 670 printf("================\n"); 671 printf("Results summary:\n"); 672 printf("================\n"); 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++) { 677 printf("+++ core_cnt: %u +++\n", core_cnt[i]); 678 printf("HTM:\n"); 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]); 683 684 printf("non HTM:\n"); 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", 688 non_htm_results.read_write_r[i]); 689 printf(" read-write write: %u\n", 690 non_htm_results.read_write_w[i]); 691 } 692 693 return 0; 694 } 695 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); 768