Changeset a35b458 in mainline for uspace/app/rcutest/rcutest.c
- Timestamp:
- 2018-03-02T20:10:49Z (7 years ago)
- Branches:
- lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
- Children:
- f1380b7
- Parents:
- 3061bc1
- git-author:
- Jiří Zárevúcky <zarevucky.jiri@…> (2018-02-28 17:38:31)
- git-committer:
- Jiří Zárevúcky <zarevucky.jiri@…> (2018-03-02 20:10:49)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/app/rcutest/rcutest.c
r3061bc1 ra35b458 174 174 { 175 175 fid_t fid = fibril_create(func, arg); 176 176 177 177 if (0 == fid) { 178 178 printf("Failed to create a fibril!\n"); 179 179 return false; 180 180 } 181 181 182 182 fibril_add_ready(fid); 183 183 return true; … … 190 190 size_t failed_cnt = 0; 191 191 size_t ok_cnt = 0; 192 192 193 193 for (size_t i = 0; i < test_desc_cnt; ++i) { 194 194 test_desc_t *t = &test_desc[i]; 195 195 196 196 if (t->func && !t->aggregate && include_filter(t)) { 197 197 printf("Running \'%s\'...\n", t->name); 198 198 bool ok = test_desc[i].func(info); 199 199 200 200 if (ok) { 201 201 ++ok_cnt; … … 207 207 } 208 208 } 209 209 210 210 printf("\n"); 211 211 … … 215 215 printf("%zu tests failed\n", failed_cnt); 216 216 } 217 217 218 218 return 0 == failed_cnt; 219 219 } … … 273 273 /* nop */ 274 274 rcu_read_unlock(); 275 275 276 276 rcu_synchronize(); 277 277 … … 284 284 fibril_yield(); 285 285 rcu_read_unlock(); 286 286 287 287 fibril_yield(); 288 288 rcu_synchronize(); 289 289 rcu_synchronize(); 290 290 291 291 rcu_read_lock(); 292 292 /* nop */ … … 295 295 296 296 rcu_read_unlock(); 297 297 298 298 return !rcu_read_locked(); 299 299 } … … 312 312 { 313 313 rcu_register_fibril(); 314 314 315 315 printf("lock{"); 316 316 rcu_read_lock(); … … 324 324 ++arg->done_sleeps_cnt; 325 325 printf("}"); 326 326 327 327 if (arg->synched) { 328 328 arg->failed = 1; 329 329 printf("Error: rcu_sync exited prematurely.\n"); 330 330 } 331 331 332 332 arg->exited_cs = true; 333 333 rcu_read_unlock(); 334 334 printf("}"); 335 335 336 336 rcu_deregister_fibril(); 337 337 return 0; … … 341 341 { 342 342 one_reader_info_t info = { 0 }; 343 343 344 344 if (!create_fibril((fibril_func_t) sleeping_reader, &info)) 345 345 return false; 346 346 347 347 /* 1 sec, waits for the reader to enter its critical section and sleep. */ 348 348 async_usleep(1 * USECS_PER_SEC); 349 349 350 350 if (!info.entered_cs || info.exited_cs) { 351 351 printf("Error: reader is unexpectedly outside of critical section.\n"); 352 352 return false; 353 353 } 354 354 355 355 info.synching = true; 356 356 printf("sync["); … … 361 361 /* Load info.exited_cs */ 362 362 memory_barrier(); 363 363 364 364 if (!info.exited_cs || info.failed) { 365 365 printf("Error: rcu_sync() returned before the reader exited its CS.\n"); … … 394 394 { 395 395 rcu_register_fibril(); 396 396 397 397 printf("old-lock{"); 398 398 rcu_read_lock(); 399 399 arg->old_entered_cs = true; 400 400 401 401 printf("wait-for-sync{"); 402 402 /* Wait for rcu_sync() to start waiting for us. */ … … 405 405 } 406 406 printf(" }"); 407 407 408 408 /* A new reader starts while rcu_sync() is in progress. */ 409 409 410 410 printf("wait-for-new-R{"); 411 411 /* Wait for the new reader to enter its reader section. */ … … 414 414 } 415 415 printf(" }"); 416 416 417 417 arg->old_exited_cs = true; 418 418 419 419 assert(!arg->new_exited_cs); 420 420 421 421 if (arg->synched) { 422 422 arg->failed = 1; 423 423 printf("Error: rcu_sync() did not wait for preexisting reader.\n"); 424 424 } 425 425 426 426 rcu_read_unlock(); 427 427 printf(" }"); 428 428 429 429 rcu_deregister_fibril(); 430 430 return 0; … … 434 434 { 435 435 rcu_register_fibril(); 436 436 437 437 /* Wait until rcu_sync() starts. */ 438 438 while (!arg->synching) { 439 439 async_usleep(WAIT_STEP_US); 440 440 } 441 441 442 442 /* 443 443 * synching is set when rcu_sync() is about to be entered so wait … … 445 445 */ 446 446 async_usleep(WAIT_STEP_US); 447 447 448 448 printf("new-lock("); 449 449 rcu_read_lock(); … … 454 454 async_usleep(WAIT_STEP_US); 455 455 } 456 456 457 457 arg->new_exited_cs = true; 458 458 /* Write new_exited_cs before exiting reader section. */ 459 459 memory_barrier(); 460 460 461 461 /* 462 462 * Preexisting reader should have exited by now, so rcu_synchronize() … … 467 467 printf("Error: preexisting reader should have exited by now!\n"); 468 468 } 469 469 470 470 rcu_read_unlock(); 471 471 printf(")"); … … 478 478 { 479 479 two_reader_info_t info = { 0 }; 480 480 481 481 if (!create_fibril((fibril_func_t) preexisting_reader, &info)) 482 482 return false; … … 484 484 if (!create_fibril((fibril_func_t) new_reader, &info)) 485 485 return false; 486 486 487 487 /* Waits for the preexisting_reader to enter its CS.*/ 488 488 while (!info.old_entered_cs) { 489 489 async_usleep(WAIT_STEP_US); 490 490 } 491 491 492 492 assert(!info.old_exited_cs); 493 493 assert(!info.new_entered_cs); 494 494 assert(!info.new_exited_cs); 495 495 496 496 printf("sync["); 497 497 info.synching = true; 498 498 rcu_synchronize(); 499 499 printf(" ]"); 500 500 501 501 /* Load info.exited_cs */ 502 502 memory_barrier(); 503 503 504 504 if (!info.old_exited_cs) { 505 505 printf("Error: rcu_sync() returned before preexisting reader exited.\n"); 506 506 info.failed = 1; 507 507 } 508 508 509 509 bool new_outside_cs = !info.new_entered_cs || info.new_exited_cs; 510 510 511 511 /* Test if new reader is waiting in CS before setting synched. */ 512 512 compiler_barrier(); 513 513 info.synched = true; 514 514 515 515 if (new_outside_cs) { 516 516 printf("Error: new reader CS held up rcu_sync(). (4)\n"); … … 519 519 /* Wait for the new reader. */ 520 520 rcu_synchronize(); 521 521 522 522 if (!info.new_exited_cs) { 523 523 printf("Error: 2nd rcu_sync() returned before new reader exited.\n"); 524 524 info.failed = 1; 525 525 } 526 526 527 527 printf("\n"); 528 528 } 529 529 530 530 if (info.failed) { 531 531 /* … … 535 535 async_usleep(WAIT_STEP_US); 536 536 } 537 537 538 538 return 0 == info.failed; 539 539 } … … 555 555 { 556 556 rcu_register_fibril(); 557 557 558 558 printf("old-lock{"); 559 559 rcu_read_lock(); … … 561 561 rcu_read_lock(); 562 562 arg->entered_cs = true; 563 563 564 564 printf("wait-for-sync{"); 565 565 /* Wait for rcu_sync() to start waiting for us. */ … … 568 568 } 569 569 printf(" }"); 570 570 571 571 rcu_read_unlock(); 572 572 printf(" }"); … … 575 575 /* Store exited_cs before unlocking reader section in deregister. */ 576 576 memory_barrier(); 577 577 578 578 /* Deregister forcefully unlocks the reader section. */ 579 579 rcu_deregister_fibril(); … … 585 585 { 586 586 exit_reader_info_t info = { 0 }; 587 587 588 588 if (!create_fibril((fibril_func_t) exiting_locked_reader, &info)) 589 589 return false; 590 590 591 591 /* Waits for the preexisting_reader to enter its CS.*/ 592 592 while (!info.entered_cs) { 593 593 async_usleep(WAIT_STEP_US); 594 594 } 595 595 596 596 assert(!info.exited_cs); 597 597 598 598 printf("sync["); 599 599 info.synching = true; … … 601 601 info.synched = true; 602 602 printf(" ]\n"); 603 603 604 604 /* Load info.exited_cs */ 605 605 memory_barrier(); 606 606 607 607 if (!info.exited_cs) { 608 608 printf("Error: rcu_deregister_fibril did not unlock the CS.\n"); 609 609 return false; 610 610 } 611 611 612 612 return true; 613 613 } … … 621 621 atomic_t time; 622 622 atomic_t max_start_time_of_done_sync; 623 623 624 624 size_t total_workers; 625 625 size_t done_reader_cnt; … … 630 630 size_t read_iters; 631 631 size_t upd_iters; 632 632 633 633 atomic_t seed; 634 634 int failed; … … 640 640 fibril_mutex_lock(&arg->done_cnt_mtx); 641 641 ++*cnt; 642 642 643 643 if (arg->total_workers == arg->done_reader_cnt + arg->done_updater_cnt) { 644 644 fibril_condvar_signal(&arg->done_cnt_changed); 645 645 } 646 646 647 647 fibril_mutex_unlock(&arg->done_cnt_mtx); 648 648 } … … 651 651 { 652 652 rcu_register_fibril(); 653 653 654 654 size_t seed = (size_t) atomic_preinc(&arg->seed); 655 655 bool first = (seed == 1); 656 656 657 657 for (size_t k = 0; k < arg->read_iters; ++k) { 658 658 /* Print progress if the first reader fibril. */ … … 660 660 printf("."); 661 661 } 662 662 663 663 rcu_read_lock(); 664 664 atomic_count_t start_time = atomic_preinc(&arg->time); 665 665 666 666 /* Do some work. */ 667 667 seed = next_rand(seed); 668 668 size_t idle_iters = seed % 8; 669 669 670 670 for (size_t i = 0; i < idle_iters; ++i) { 671 671 fibril_yield(); 672 672 } 673 673 674 674 /* 675 675 * Check if the most recently started rcu_sync of the already … … 681 681 arg->failed = 1; 682 682 } 683 683 684 684 rcu_read_unlock(); 685 685 } 686 686 687 687 rcu_deregister_fibril(); 688 688 … … 694 694 { 695 695 rcu_register_fibril(); 696 696 697 697 for (size_t k = 0; k < arg->upd_iters; ++k) { 698 698 atomic_count_t start_time = atomic_get(&arg->time); 699 699 rcu_synchronize(); 700 700 701 701 /* This is prone to a race but if it happens it errs to the safe side.*/ 702 702 if (atomic_get(&arg->max_start_time_of_done_sync) < start_time) { … … 704 704 } 705 705 } 706 706 707 707 rcu_deregister_fibril(); 708 708 709 709 signal_seq_fibril_done(arg, &arg->done_updater_cnt); 710 710 return 0; … … 715 715 size_t reader_cnt = test_info->thread_cnt; 716 716 size_t updater_cnt = test_info->thread_cnt; 717 717 718 718 seq_test_info_t info = { 719 719 .time = {0}, … … 729 729 .failed = 0, 730 730 }; 731 731 732 732 /* Create and start worker fibrils. */ 733 733 for (size_t k = 0; k + k < reader_cnt + updater_cnt; ++k) { 734 734 bool ok = create_fibril((fibril_func_t) seq_reader, &info); 735 735 ok = ok && create_fibril((fibril_func_t) seq_updater, &info); 736 736 737 737 if (!ok) { 738 738 /* Let the already created fibrils corrupt the stack. */ … … 740 740 } 741 741 } 742 742 743 743 /* Wait for all worker fibrils to complete their work. */ 744 744 fibril_mutex_lock(&info.done_cnt_mtx); 745 745 746 746 while (info.total_workers != info.done_reader_cnt + info.done_updater_cnt) { 747 747 fibril_condvar_wait(&info.done_cnt_changed, &info.done_cnt_mtx); 748 748 } 749 749 750 750 fibril_mutex_unlock(&info.done_cnt_mtx); 751 751 752 752 if (info.failed) { 753 753 printf("Error: rcu_sync() did not wait for a preexisting reader."); 754 754 } 755 755 756 756 return 0 == info.failed; 757 757 } … … 772 772 /* Sanity check. */ 773 773 assert(cnt < 1024); 774 774 775 775 /* Keep this mutex locked so that dummy fibrils never exit. */ 776 776 bool success = fibril_mutex_trylock(&blocking_mtx); 777 777 assert(success); 778 778 779 779 for (size_t k = 0; k < cnt; ++k) { 780 780 thread_id_t tid; 781 781 782 782 errno_t ret = thread_create(dummy_fibril, NULL, "urcu-test-worker", &tid); 783 783 if (EOK != ret) { … … 786 786 } 787 787 } 788 788 789 789 return true; 790 790 } … … 796 796 for (size_t k = 0; k < test_desc_cnt; ++k) { 797 797 test_desc_t *t = &test_desc[k]; 798 798 799 799 if (t->func && 0 == str_cmp(t->name, name)) 800 800 return t; 801 801 } 802 802 803 803 /* Try to match the test number. */ 804 804 uint32_t test_num = 0; 805 805 806 806 if (EOK == str_uint32_t(name, NULL, 0, true, &test_num)) { 807 807 if (test_num < test_desc_cnt && test_desc[test_num].func) { … … 809 809 } 810 810 } 811 811 812 812 return NULL; 813 813 } … … 816 816 { 817 817 printf("Available tests: \n"); 818 818 819 819 for (size_t i = 0; i < test_desc_cnt; ++i) { 820 820 test_desc_t *t = &test_desc[i]; 821 821 822 822 if (!t->func) 823 823 continue; 824 824 825 825 const char *type = ""; 826 826 827 827 if (t->type == T_SANITY) 828 828 type = " (sanity)"; … … 839 839 printf("Usage: rcutest [test_name|test_number] {number_of_threads}\n"); 840 840 list_tests(); 841 841 842 842 printf("\nExample usage:\n"); 843 843 printf("\trcutest *\n"); … … 852 852 return false; 853 853 } 854 854 855 855 info->desc = find_test(argv[1]); 856 856 … … 860 860 return false; 861 861 } 862 862 863 863 if (argc == 3) { 864 864 uint32_t thread_cnt = 0; 865 865 errno_t ret = str_uint32_t(argv[2], NULL, 0, true, &thread_cnt); 866 866 867 867 if (ret == EOK && 1 <= thread_cnt && thread_cnt <= 64) { 868 868 info->thread_cnt = thread_cnt; … … 874 874 info->thread_cnt = 1; 875 875 } 876 876 877 877 return true; 878 878 } … … 881 881 { 882 882 rcu_register_fibril(); 883 883 884 884 test_info_t info; 885 885 886 886 bool ok = parse_cmd_line(argc, argv, &info); 887 887 ok = ok && create_threads(info.thread_cnt - 1); 888 888 889 889 if (ok) { 890 890 assert(1 <= info.thread_cnt); 891 891 test_desc_t *t = info.desc; 892 892 893 893 printf("Running '%s' (in %zu threads)...\n", t->name, info.thread_cnt); 894 894 ok = t->func(&info); … … 897 897 898 898 rcu_deregister_fibril(); 899 899 900 900 /* Let the kernel clean up the created background threads. */ 901 901 return ok ? 0 : 1;
Note:
See TracChangeset
for help on using the changeset viewer.