Changes in kernel/test/synch/rcu1.c [1b20da0:a35b458] in mainline
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
kernel/test/synch/rcu1.c
r1b20da0 ra35b458 67 67 TPRINTF("."); 68 68 } 69 69 70 70 if (!p->exited) { 71 71 *presult = ETIMEOUT; … … 81 81 { 82 82 assert(thread[k] == NULL); 83 83 84 84 thread[k] = thread_create(func, arg, TASK, THREAD_FLAG_NONE, 85 85 "test-rcu-thread"); 86 86 87 87 if(thread[k]) { 88 88 /* Distribute evenly. */ … … 95 95 { 96 96 size_t thread_cnt = get_thread_cnt(); 97 97 98 98 one_idx = 0; 99 99 100 100 for (size_t i = 0; i < thread_cnt; ++i) { 101 101 run_thread(i, func, NULL); … … 106 106 { 107 107 size_t thread_cnt = get_thread_cnt(); 108 108 109 109 one_idx = 0; 110 110 111 111 for (size_t i = 0; i < thread_cnt; ++i) { 112 112 if (thread[i]) { … … 115 115 errno_t ret = thread_join_timeout(thread[i], 5 * 1000 * 1000, 0); 116 116 joined = (ret != ETIMEOUT); 117 117 118 118 if (ret == EOK) { 119 119 TPRINTF("%zu threads remain\n", thread_cnt - i - 1); 120 120 } 121 121 } while (!joined); 122 122 123 123 thread_detach(thread[i]); 124 124 thread[i] = NULL; … … 140 140 141 141 --one_idx; 142 142 143 143 if (thread[one_idx]) { 144 144 thread_join(thread[one_idx]); … … 154 154 { 155 155 size_t nop_iters = (size_t)arg; 156 156 157 157 TPRINTF("Enter nop-reader\n"); 158 158 159 159 for (size_t i = 0; i < nop_iters; ++i) { 160 160 rcu_read_lock(); 161 161 rcu_read_unlock(); 162 162 } 163 163 164 164 TPRINTF("Exit nop-reader\n"); 165 165 } … … 169 169 assert(0 < steps && from <= to && 0 < to); 170 170 size_t inc = (to - from) / (steps - 1); 171 171 172 172 for (size_t i = 0; i < steps - 1; ++i) { 173 173 seq[i] = i * inc + from; 174 174 } 175 175 176 176 seq[steps - 1] = to; 177 177 } … … 181 181 size_t seq[MAX_THREADS] = {0}; 182 182 get_seq(100, 100000, get_thread_cnt(), seq); 183 183 184 184 TPRINTF("\nRun %zu thr: repeat empty no-op reader sections\n", get_thread_cnt()); 185 185 186 186 for (size_t k = 0; k < get_thread_cnt(); ++k) 187 187 run_one(nop_reader, (void*)seq[k]); 188 188 189 189 TPRINTF("\nJoining %zu no-op readers\n", get_thread_cnt()); 190 190 join_all(); 191 191 192 192 return true; 193 193 } … … 202 202 size_t nop_iters = (size_t)arg; 203 203 size_t outer_iters = iter_cnt / nop_iters; 204 204 205 205 TPRINTF("Enter long-reader\n"); 206 206 207 207 for (size_t i = 0; i < outer_iters; ++i) { 208 208 rcu_read_lock(); 209 209 210 210 for (volatile size_t k = 0; k < nop_iters; ++k) { 211 211 /* nop, but increment volatile k */ 212 212 } 213 213 214 214 rcu_read_unlock(); 215 215 } 216 216 217 217 TPRINTF("Exit long-reader\n"); 218 218 } … … 222 222 size_t seq[MAX_THREADS] = {0}; 223 223 get_seq(10, 1000 * 1000, get_thread_cnt(), seq); 224 224 225 225 TPRINTF("\nRun %zu thr: repeat long reader sections, will preempt, no cbs.\n", 226 226 get_thread_cnt()); 227 227 228 228 for (size_t k = 0; k < get_thread_cnt(); ++k) 229 229 run_one(long_reader, (void*)seq[k]); 230 230 231 231 TPRINTF("\nJoining %zu readers with long reader sections.\n", get_thread_cnt()); 232 232 join_all(); 233 233 234 234 return true; 235 235 } … … 253 253 rcu_item_t *a = malloc(sizeof(rcu_item_t), FRAME_ATOMIC); 254 254 rcu_item_t *b = malloc(sizeof(rcu_item_t), FRAME_ATOMIC); 255 255 256 256 if (a && b) { 257 257 rcu_call(a, count_cb); … … 272 272 size_t exp_cnt = nop_updater_iters * get_thread_cnt(); 273 273 size_t max_used_mem = sizeof(rcu_item_t) * exp_cnt; 274 274 275 275 TPRINTF("\nRun %zu thr: post %zu no-op callbacks (%zu B used), no readers.\n", 276 276 get_thread_cnt(), exp_cnt, max_used_mem); 277 277 278 278 run_all(nop_updater); 279 279 TPRINTF("\nJoining %zu no-op callback threads\n", get_thread_cnt()); 280 280 join_all(); 281 281 282 282 size_t loop_cnt = 0, max_loops = 15; 283 283 … … 287 287 thread_sleep(1); 288 288 } 289 289 290 290 return loop_cnt < max_loops; 291 291 } … … 312 312 { 313 313 TPRINTF("Enter one-cb-reader\n"); 314 315 rcu_read_lock(); 316 314 315 rcu_read_lock(); 316 317 317 item_w_cookie_t *item = malloc(sizeof(item_w_cookie_t), FRAME_ATOMIC); 318 318 319 319 if (item) { 320 320 item->cookie = magic_cookie; … … 323 323 TPRINTF("\n[out-of-mem]\n"); 324 324 } 325 325 326 326 thread_sleep(1); 327 327 328 328 rcu_read_unlock(); 329 329 330 330 TPRINTF("Exit one-cb-reader\n"); 331 331 } … … 334 334 { 335 335 one_cb_is_done = 0; 336 336 337 337 TPRINTF("\nRun a single reader that posts one callback.\n"); 338 338 run_one(one_cb_reader, NULL); 339 339 join_one(); 340 340 341 341 TPRINTF("\nJoined one-cb reader, wait for callback.\n"); 342 342 size_t loop_cnt = 0; 343 343 size_t max_loops = 4; /* 200 ms total */ 344 344 345 345 while (!one_cb_is_done && loop_cnt < max_loops) { 346 346 thread_usleep(50 * 1000); 347 347 ++loop_cnt; 348 348 } 349 349 350 350 return one_cb_is_done; 351 351 } … … 373 373 { 374 374 seq_item_t *item = member_to_inst(rcu_item, seq_item_t, rcu); 375 375 376 376 /* Racy but errs to the conservative side, so it is ok. */ 377 377 if (max_upd_done_time < item->start_time) { 378 378 max_upd_done_time = item->start_time; 379 379 380 380 /* Make updated time visible */ 381 381 memory_barrier(); … … 393 393 #ifndef KARCH_riscv64 394 394 seq_work_t *work = (seq_work_t*)arg; 395 395 396 396 /* Alternate between reader and updater roles. */ 397 397 for (size_t k = 0; k < work->iters; ++k) { … … 400 400 rcu_read_lock(); 401 401 atomic_count_t start_time = atomic_postinc(&cur_time); 402 402 403 403 for (volatile size_t d = 0; d < 10 * i; ++d ){ 404 404 /* no-op */ 405 405 } 406 406 407 407 /* Get most recent max_upd_done_time. */ 408 408 memory_barrier(); 409 409 410 410 if (start_time < max_upd_done_time) { 411 411 seq_test_result = ERACE; 412 412 } 413 413 414 414 rcu_read_unlock(); 415 415 416 416 if (seq_test_result != EOK) 417 417 return; 418 418 } 419 419 420 420 /* Updater */ 421 421 for (size_t i = 0; i < work->update_cnt; ++i) { 422 422 seq_item_t *a = malloc(sizeof(seq_item_t), FRAME_ATOMIC); 423 423 seq_item_t *b = malloc(sizeof(seq_item_t), FRAME_ATOMIC); 424 424 425 425 if (a && b) { 426 426 a->start_time = atomic_postinc(&cur_time); 427 427 rcu_call(&a->rcu, seq_cb); 428 428 429 429 b->start_time = atomic_postinc(&cur_time); 430 430 rcu_call(&b->rcu, seq_cb); … … 437 437 } 438 438 } 439 439 440 440 } 441 441 #else … … 454 454 size_t read_cnt[MAX_THREADS] = {0}; 455 455 seq_work_t item[MAX_THREADS]; 456 456 457 457 size_t total_cbs = 0; 458 458 size_t max_used_mem = 0; 459 459 460 460 get_seq(0, total_cnt, get_thread_cnt(), read_cnt); 461 461 462 462 463 463 for (size_t i = 0; i < get_thread_cnt(); ++i) { … … 465 465 item[i].read_cnt = read_cnt[i]; 466 466 item[i].iters = iters; 467 467 468 468 total_cbs += 2 * iters * item[i].update_cnt; 469 469 } 470 470 471 471 max_used_mem = total_cbs * sizeof(seq_item_t); 472 472 … … 474 474 uint64_t mem_units; 475 475 bin_order_suffix(max_used_mem, &mem_units, &mem_suffix, false); 476 476 477 477 TPRINTF("\nRun %zu th: check callback completion time in readers. " 478 478 "%zu callbacks total (max %" PRIu64 " %s used). Be patient.\n", 479 479 get_thread_cnt(), total_cbs, mem_units, mem_suffix); 480 480 481 481 for (size_t i = 0; i < get_thread_cnt(); ++i) { 482 482 run_one(seq_func, &item[i]); 483 483 } 484 484 485 485 TPRINTF("\nJoining %zu seq-threads\n", get_thread_cnt()); 486 486 join_all(); 487 487 488 488 if (seq_test_result == ENOMEM) { 489 489 TPRINTF("\nErr: out-of mem\n"); … … 491 491 TPRINTF("\nERROR: race detected!!\n"); 492 492 } 493 493 494 494 return seq_test_result == EOK; 495 495 } … … 510 510 rcu_read_lock(); 511 511 rcu_read_unlock(); 512 512 513 513 rcu_call((rcu_item_t*)arg, reader_unlocked); 514 515 rcu_read_lock(); 516 rcu_read_lock(); 517 514 515 rcu_read_lock(); 516 rcu_read_lock(); 517 518 518 /* Exit without unlocking the rcu reader section. */ 519 519 } … … 522 522 { 523 523 TPRINTF("\nReader exits thread with rcu_lock\n"); 524 524 525 525 exited_t *p = malloc(sizeof(exited_t), FRAME_ATOMIC); 526 526 if (!p) { … … 528 528 return false; 529 529 } 530 530 531 531 p->exited = false; 532 532 533 533 run_one(reader_exit, p); 534 534 join_one(); 535 535 536 536 errno_t result = EOK; 537 537 wait_for_cb_exit(2 /* secs */, p, &result); 538 538 539 539 if (result != EOK) { 540 540 TPRINTF("Err: RCU locked up after exiting from within a reader\n"); … … 543 543 free(p); 544 544 } 545 545 546 546 return result == EOK; 547 547 } … … 570 570 571 571 TPRINTF("reader_prev{ "); 572 572 573 573 rcu_read_lock(); 574 574 scheduler(); … … 588 588 preempt_t *p = (preempt_t*)arg; 589 589 assert(!p->e.exited); 590 590 591 591 TPRINTF("reader_inside_cur{ "); 592 592 /* … … 613 613 preempt_t *p = (preempt_t*)arg; 614 614 assert(!p->e.exited); 615 615 616 616 TPRINTF("reader_cur{ "); 617 617 rcu_read_lock(); … … 622 622 /* Preempt while cur GP detection is running */ 623 623 thread_sleep(1); 624 624 625 625 /* Err: exited before this reader completed. */ 626 626 if (p->e.exited) … … 635 635 preempt_t *p = (preempt_t*)arg; 636 636 assert(!p->e.exited); 637 637 638 638 TPRINTF("reader_next1{ "); 639 639 rcu_read_lock(); … … 641 641 /* Preempt before cur GP detection starts. */ 642 642 scheduler(); 643 643 644 644 /* Start GP. */ 645 645 rcu_call(&p->e.rcu, preempted_unlocked); … … 657 657 preempt_t *p = (preempt_t*)arg; 658 658 assert(!p->e.exited); 659 659 660 660 TPRINTF("reader_next2{ "); 661 661 rcu_read_lock(); … … 663 663 /* Preempt before cur GP detection starts. */ 664 664 scheduler(); 665 665 666 666 /* Start GP. */ 667 667 rcu_call(&p->e.rcu, preempted_unlocked); … … 691 691 return false; 692 692 } 693 693 694 694 p->e.exited = false; 695 695 p->result = EOK; 696 696 697 697 run_one(f, p); 698 698 join_one(); 699 699 700 700 /* Wait at most 4 secs. */ 701 701 wait_for_cb_exit(4, &p->e, &p->result); 702 702 703 703 if (p->result == EOK) { 704 704 free(p); … … 714 714 { 715 715 TPRINTF("\nReaders will be preempted.\n"); 716 716 717 717 bool success = true; 718 718 bool ok = true; 719 719 720 720 ok = do_one_reader_preempt(preempted_reader_prev, 721 721 "Err: preempted_reader_prev()\n"); 722 722 success = success && ok; 723 723 724 724 ok = do_one_reader_preempt(preempted_reader_inside_cur, 725 725 "Err: preempted_reader_inside_cur()\n"); 726 726 success = success && ok; 727 727 728 728 ok = do_one_reader_preempt(preempted_reader_cur, 729 729 "Err: preempted_reader_cur()\n"); 730 730 success = success && ok; 731 731 732 732 ok = do_one_reader_preempt(preempted_reader_next1, 733 733 "Err: preempted_reader_next1()\n"); … … 737 737 "Err: preempted_reader_next2()\n"); 738 738 success = success && ok; 739 739 740 740 return success; 741 741 } … … 751 751 { 752 752 synch_t *synch = (synch_t *) arg; 753 753 754 754 rcu_read_lock(); 755 755 756 756 /* Order accesses of synch after the reader section begins. */ 757 757 memory_barrier(); 758 758 759 759 synch->reader_running = true; 760 760 761 761 while (!synch->synch_running) { 762 762 /* 0.5 sec */ 763 763 delay(500 * 1000); 764 764 } 765 765 766 766 /* Run for 1 sec */ 767 767 delay(1000 * 1000); 768 768 /* thread_join() propagates done to do_synch() */ 769 769 synch->reader_done = true; 770 770 771 771 rcu_read_unlock(); 772 772 } … … 776 776 { 777 777 TPRINTF("\nSynchronize with long reader\n"); 778 778 779 779 synch_t *synch = malloc(sizeof(synch_t), FRAME_ATOMIC); 780 780 781 781 if (!synch) { 782 782 TPRINTF("[out-of-mem]\n"); 783 783 return false; 784 784 } 785 785 786 786 synch->reader_done = false; 787 787 synch->reader_running = false; 788 788 synch->synch_running = false; 789 789 790 790 run_one(synch_reader, synch); 791 791 792 792 /* Wait for the reader to enter its critical section. */ 793 793 scheduler(); … … 795 795 thread_usleep(500 * 1000); 796 796 } 797 797 798 798 synch->synch_running = true; 799 799 800 800 rcu_synchronize(); 801 801 join_one(); 802 803 802 803 804 804 if (synch->reader_done) { 805 805 free(synch); … … 827 827 { 828 828 TPRINTF("\nrcu_barrier: Wait for outstanding rcu callbacks to complete\n"); 829 829 830 830 barrier_t *barrier = malloc(sizeof(barrier_t), FRAME_ATOMIC); 831 831 832 832 if (!barrier) { 833 833 TPRINTF("[out-of-mem]\n"); 834 834 return false; 835 835 } 836 836 837 837 atomic_set(&barrier->done, 0); 838 838 839 839 rcu_call(&barrier->rcu_item, barrier_callback); 840 840 rcu_barrier(); 841 841 842 842 if (1 == atomic_get(&barrier->done)) { 843 843 free(barrier); … … 861 861 { 862 862 bool *done = (bool*) arg; 863 863 864 864 while (!*done) { 865 865 rcu_read_lock(); 866 866 rcu_read_unlock(); 867 867 868 868 /* 869 869 * Do some work outside of the reader section so we are not always … … 884 884 { 885 885 stress_t *s = (stress_t *)arg; 886 886 887 887 for (size_t i = 0; i < s->iters; ++i) { 888 888 rcu_item_t *item = malloc(sizeof(rcu_item_t), FRAME_ATOMIC); 889 889 890 890 if (item) { 891 891 rcu_call(item, stress_cb); … … 894 894 return; 895 895 } 896 896 897 897 /* Print a dot if we make a progress of 1% */ 898 898 if (s->master && 0 == (i % (s->iters/100))) … … 907 907 stress_t master = { .iters = cb_per_thread, .master = true }; 908 908 stress_t worker = { .iters = cb_per_thread, .master = false }; 909 909 910 910 size_t thread_cnt = min(MAX_THREADS / 2, config.cpu_active); 911 911 /* Each cpu has one reader and one updater. */ 912 912 size_t reader_cnt = thread_cnt; 913 913 size_t updater_cnt = thread_cnt; 914 914 915 915 size_t exp_upd_calls = updater_cnt * cb_per_thread; 916 916 size_t max_used_mem = exp_upd_calls * sizeof(rcu_item_t); 917 917 918 918 const char *mem_suffix; 919 919 uint64_t mem_units; … … 923 923 " total (max %" PRIu64 " %s used). Be very patient.\n", 924 924 reader_cnt, updater_cnt, exp_upd_calls, mem_units, mem_suffix); 925 925 926 926 for (size_t k = 0; k < reader_cnt; ++k) { 927 927 run_one(stress_reader, &done); … … 931 931 run_one(stress_updater, k > 0 ? &worker : &master); 932 932 } 933 933 934 934 TPRINTF("\nJoining %zu stress updaters.\n", updater_cnt); 935 935 936 936 for (size_t k = 0; k < updater_cnt; ++k) { 937 937 join_one(); 938 938 } 939 939 940 940 done = true; 941 941 942 942 TPRINTF("\nJoining %zu stress nop-readers.\n", reader_cnt); 943 943 944 944 join_all(); 945 945 return true; … … 957 957 { 958 958 expedite_t *e = (expedite_t *)arg; 959 959 960 960 if (1 < e->count_down) { 961 961 --e->count_down; 962 962 963 963 if (0 == (e->count_down % (e->total_cnt/100))) { 964 964 TPRINTF("*"); 965 965 } 966 966 967 967 _rcu_call(e->expedite, &e->r, expedite_cb); 968 968 } else { … … 979 979 e.count_down = cnt; 980 980 e.expedite = exp; 981 981 982 982 _rcu_call(e.expedite, &e.r, expedite_cb); 983 983 984 984 while (0 < e.count_down) { 985 985 thread_sleep(1); … … 992 992 size_t exp_cnt = 1000 * 1000; 993 993 size_t normal_cnt = 1 * 1000; 994 994 995 995 TPRINTF("Expedited: sequence of %zu rcu_calls\n", exp_cnt); 996 996 run_expedite(true, exp_cnt); … … 1024 1024 { 0, NULL, NULL } 1025 1025 }; 1026 1026 1027 1027 bool success = true; 1028 1028 bool ok = true; 1029 1029 uint64_t completed_gps = rcu_completed_gps(); 1030 1030 uint64_t delta_gps = 0; 1031 1031 1032 1032 for (int i = 0; test_func[i].func; ++i) { 1033 1033 if (!test_func[i].include) { … … 1037 1037 TPRINTF("\nRunning subtest %s.\n", test_func[i].desc); 1038 1038 } 1039 1039 1040 1040 ok = test_func[i].func(); 1041 1041 success = success && ok; 1042 1042 1043 1043 delta_gps = rcu_completed_gps() - completed_gps; 1044 1044 completed_gps += delta_gps;
Note:
See TracChangeset
for help on using the changeset viewer.