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