Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(362)

Side by Side Diff: runtime/vm/pages.cc

Issue 1541073002: Implement safepointing of threads (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: self-review-comments Created 4 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 #include "vm/pages.h" 5 #include "vm/pages.h"
6 6
7 #include "platform/assert.h" 7 #include "platform/assert.h"
8 #include "vm/compiler_stats.h" 8 #include "vm/compiler_stats.h"
9 #include "vm/gc_marker.h" 9 #include "vm/gc_marker.h"
10 #include "vm/gc_sweeper.h" 10 #include "vm/gc_sweeper.h"
11 #include "vm/lockers.h" 11 #include "vm/lockers.h"
12 #include "vm/object.h" 12 #include "vm/object.h"
13 #include "vm/os_thread.h" 13 #include "vm/os_thread.h"
14 #include "vm/thread_registry.h" 14 #include "vm/safepoint.h"
15 #include "vm/verified_memory.h" 15 #include "vm/verified_memory.h"
16 #include "vm/virtual_memory.h" 16 #include "vm/virtual_memory.h"
17 17
18 namespace dart { 18 namespace dart {
19 19
20 DEFINE_FLAG(int, heap_growth_rate, 0, 20 DEFINE_FLAG(int, heap_growth_rate, 0,
21 "The max number of pages the heap can grow at a time"); 21 "The max number of pages the heap can grow at a time");
22 DEFINE_FLAG(int, old_gen_growth_space_ratio, 20, 22 DEFINE_FLAG(int, old_gen_growth_space_ratio, 20,
23 "The desired maximum percentage of free space after old gen GC"); 23 "The desired maximum percentage of free space after old gen GC");
24 DEFINE_FLAG(int, old_gen_growth_time_ratio, 3, 24 DEFINE_FLAG(int, old_gen_growth_time_ratio, 3,
(...skipping 759 matching lines...) Expand 10 before | Expand all | Expand 10 after
784 if (page->type() == HeapPage::kExecutable) { 784 if (page->type() == HeapPage::kExecutable) {
785 page->WriteProtect(read_only); 785 page->WriteProtect(read_only);
786 } 786 }
787 page = page->next(); 787 page = page->next();
788 } 788 }
789 } 789 }
790 } 790 }
791 791
792 792
793 void PageSpace::MarkSweep(bool invoke_api_callbacks) { 793 void PageSpace::MarkSweep(bool invoke_api_callbacks) {
794 Thread* thread = Thread::Current();
794 Isolate* isolate = heap_->isolate(); 795 Isolate* isolate = heap_->isolate();
795 ASSERT(isolate == Isolate::Current()); 796 ASSERT(isolate == Isolate::Current());
796 797
797 // Wait for pending tasks to complete and then account for the driver task. 798 // Wait for pending tasks to complete and then account for the driver task.
798 { 799 {
799 MonitorLocker locker(tasks_lock()); 800 MonitorLocker locker(tasks_lock());
800 while (tasks() > 0) { 801 while (tasks() > 0) {
801 locker.Wait(); 802 locker.WaitWithSafepointCheck(thread);
802 } 803 }
803 set_tasks(1); 804 set_tasks(1);
804 } 805 }
805 // Ensure that all threads for this isolate are at a safepoint (either stopped 806 // Ensure that all threads for this isolate are at a safepoint (either
806 // or in native code). If two threads are racing at this point, the loser 807 // stopped or in native code). If two threads are racing at this point, the
807 // will continue with its collection after waiting for the winner to complete. 808 // loser will continue with its collection after waiting for the winner to
809 // complete.
808 // TODO(koda): Consider moving SafepointThreads into allocation failure/retry 810 // TODO(koda): Consider moving SafepointThreads into allocation failure/retry
zra 2016/01/08 23:32:07 Remove TODO?
siva 2016/01/12 21:26:22 Done.
809 // logic to avoid needless collections. 811 // logic to avoid needless collections.
810 isolate->thread_registry()->SafepointThreads(); 812 {
813 SafepointOperationScope safepoint_scope(thread);
811 814
812 // Perform various cleanup that relies on no tasks interfering. 815 // Perform various cleanup that relies on no tasks interfering.
813 isolate->class_table()->FreeOldTables(); 816 isolate->class_table()->FreeOldTables();
814 817
815 NoSafepointScope no_safepoints; 818 NoSafepointScope no_safepoints;
816 819
817 if (FLAG_print_free_list_before_gc) { 820 if (FLAG_print_free_list_before_gc) {
818 OS::Print("Data Freelist (before GC):\n"); 821 OS::Print("Data Freelist (before GC):\n");
819 freelist_[HeapPage::kData].Print(); 822 freelist_[HeapPage::kData].Print();
820 OS::Print("Executable Freelist (before GC):\n"); 823 OS::Print("Executable Freelist (before GC):\n");
821 freelist_[HeapPage::kExecutable].Print(); 824 freelist_[HeapPage::kExecutable].Print();
822 } 825 }
823 826
824 if (FLAG_verify_before_gc) {
825 OS::PrintErr("Verifying before marking...");
826 heap_->VerifyGC();
827 OS::PrintErr(" done.\n");
828 }
829
830 const int64_t start = OS::GetCurrentTimeMicros();
831
832 // Make code pages writable.
833 WriteProtectCode(false);
834
835 // Save old value before GCMarker visits the weak persistent handles.
836 SpaceUsage usage_before = GetCurrentUsage();
837
838 // Mark all reachable old-gen objects.
839 bool collect_code = FLAG_collect_code && ShouldCollectCode();
840 GCMarker marker(heap_);
841 marker.MarkObjects(isolate, this, invoke_api_callbacks, collect_code);
842 usage_.used_in_words = marker.marked_words();
843
844 int64_t mid1 = OS::GetCurrentTimeMicros();
845
846 // Abandon the remainder of the bump allocation block.
847 AbandonBumpAllocation();
848 // Reset the freelists and setup sweeping.
849 freelist_[HeapPage::kData].Reset();
850 freelist_[HeapPage::kExecutable].Reset();
851
852 int64_t mid2 = OS::GetCurrentTimeMicros();
853 int64_t mid3 = 0;
854
855 {
856 if (FLAG_verify_before_gc) { 827 if (FLAG_verify_before_gc) {
857 OS::PrintErr("Verifying before sweeping..."); 828 OS::PrintErr("Verifying before marking...");
858 heap_->VerifyGC(kAllowMarked); 829 heap_->VerifyGC();
859 OS::PrintErr(" done.\n"); 830 OS::PrintErr(" done.\n");
860 } 831 }
861 GCSweeper sweeper;
862 832
863 // During stop-the-world phases we should use bulk lock when adding elements 833 const int64_t start = OS::GetCurrentTimeMicros();
864 // to the free list.
865 MutexLocker mld(freelist_[HeapPage::kData].mutex());
866 MutexLocker mle(freelist_[HeapPage::kExecutable].mutex());
867 834
868 // Large and executable pages are always swept immediately. 835 // Make code pages writable.
869 HeapPage* prev_page = NULL; 836 WriteProtectCode(false);
870 HeapPage* page = large_pages_; 837
871 while (page != NULL) { 838 // Save old value before GCMarker visits the weak persistent handles.
872 HeapPage* next_page = page->next(); 839 SpaceUsage usage_before = GetCurrentUsage();
873 const intptr_t words_to_end = sweeper.SweepLargePage(page); 840
874 if (words_to_end == 0) { 841 // Mark all reachable old-gen objects.
875 FreeLargePage(page, prev_page); 842 bool collect_code = FLAG_collect_code && ShouldCollectCode();
876 } else { 843 GCMarker marker(heap_);
877 TruncateLargePage(page, words_to_end << kWordSizeLog2); 844 marker.MarkObjects(isolate, this, invoke_api_callbacks, collect_code);
878 prev_page = page; 845 usage_.used_in_words = marker.marked_words();
846
847 int64_t mid1 = OS::GetCurrentTimeMicros();
848
849 // Abandon the remainder of the bump allocation block.
850 AbandonBumpAllocation();
851 // Reset the freelists and setup sweeping.
852 freelist_[HeapPage::kData].Reset();
853 freelist_[HeapPage::kExecutable].Reset();
854
855 int64_t mid2 = OS::GetCurrentTimeMicros();
856 int64_t mid3 = 0;
857
858 {
859 if (FLAG_verify_before_gc) {
860 OS::PrintErr("Verifying before sweeping...");
861 heap_->VerifyGC(kAllowMarked);
862 OS::PrintErr(" done.\n");
879 } 863 }
880 // Advance to the next page. 864 GCSweeper sweeper;
881 page = next_page;
882 }
883 865
884 prev_page = NULL; 866 // During stop-the-world phases we should use bulk lock when adding
885 page = exec_pages_; 867 // elements to the free list.
886 FreeList* freelist = &freelist_[HeapPage::kExecutable]; 868 MutexLocker mld(freelist_[HeapPage::kData].mutex());
887 while (page != NULL) { 869 MutexLocker mle(freelist_[HeapPage::kExecutable].mutex());
888 HeapPage* next_page = page->next();
889 bool page_in_use = sweeper.SweepPage(page, freelist, true);
890 if (page_in_use) {
891 prev_page = page;
892 } else {
893 FreePage(page, prev_page);
894 }
895 // Advance to the next page.
896 page = next_page;
897 }
898 870
899 mid3 = OS::GetCurrentTimeMicros(); 871 // Large and executable pages are always swept immediately.
900 872 HeapPage* prev_page = NULL;
901 if (!FLAG_concurrent_sweep) { 873 HeapPage* page = large_pages_;
902 // Sweep all regular sized pages now.
903 prev_page = NULL;
904 page = pages_;
905 while (page != NULL) { 874 while (page != NULL) {
906 HeapPage* next_page = page->next(); 875 HeapPage* next_page = page->next();
907 bool page_in_use = sweeper.SweepPage( 876 const intptr_t words_to_end = sweeper.SweepLargePage(page);
908 page, &freelist_[page->type()], true); 877 if (words_to_end == 0) {
878 FreeLargePage(page, prev_page);
879 } else {
880 TruncateLargePage(page, words_to_end << kWordSizeLog2);
881 prev_page = page;
882 }
883 // Advance to the next page.
884 page = next_page;
885 }
886
887 prev_page = NULL;
888 page = exec_pages_;
889 FreeList* freelist = &freelist_[HeapPage::kExecutable];
890 while (page != NULL) {
891 HeapPage* next_page = page->next();
892 bool page_in_use = sweeper.SweepPage(page, freelist, true);
909 if (page_in_use) { 893 if (page_in_use) {
910 prev_page = page; 894 prev_page = page;
911 } else { 895 } else {
912 FreePage(page, prev_page); 896 FreePage(page, prev_page);
913 } 897 }
914 // Advance to the next page. 898 // Advance to the next page.
915 page = next_page; 899 page = next_page;
916 } 900 }
917 if (FLAG_verify_after_gc) { 901
918 OS::PrintErr("Verifying after sweeping..."); 902 mid3 = OS::GetCurrentTimeMicros();
919 heap_->VerifyGC(kForbidMarked); 903
920 OS::PrintErr(" done.\n"); 904 if (!FLAG_concurrent_sweep) {
905 // Sweep all regular sized pages now.
906 prev_page = NULL;
907 page = pages_;
908 while (page != NULL) {
909 HeapPage* next_page = page->next();
910 bool page_in_use = sweeper.SweepPage(
911 page, &freelist_[page->type()], true);
912 if (page_in_use) {
913 prev_page = page;
914 } else {
915 FreePage(page, prev_page);
916 }
917 // Advance to the next page.
918 page = next_page;
919 }
920 if (FLAG_verify_after_gc) {
921 OS::PrintErr("Verifying after sweeping...");
922 heap_->VerifyGC(kForbidMarked);
923 OS::PrintErr(" done.\n");
924 }
925 } else {
926 // Start the concurrent sweeper task now.
927 GCSweeper::SweepConcurrent(
928 isolate, pages_, pages_tail_, &freelist_[HeapPage::kData]);
921 } 929 }
922 } else { 930 }
923 // Start the concurrent sweeper task now. 931
924 GCSweeper::SweepConcurrent( 932 // Make code pages read-only.
925 isolate, pages_, pages_tail_, &freelist_[HeapPage::kData]); 933 WriteProtectCode(true);
934
935 int64_t end = OS::GetCurrentTimeMicros();
936
937 // Record signals for growth control. Include size of external allocations.
938 page_space_controller_.EvaluateGarbageCollection(usage_before,
939 GetCurrentUsage(),
940 start, end);
941
942 heap_->RecordTime(kMarkObjects, mid1 - start);
943 heap_->RecordTime(kResetFreeLists, mid2 - mid1);
944 heap_->RecordTime(kSweepPages, mid3 - mid2);
945 heap_->RecordTime(kSweepLargePages, end - mid3);
946
947 if (FLAG_print_free_list_after_gc) {
948 OS::Print("Data Freelist (after GC):\n");
949 freelist_[HeapPage::kData].Print();
950 OS::Print("Executable Freelist (after GC):\n");
951 freelist_[HeapPage::kExecutable].Print();
952 }
953
954 UpdateMaxUsed();
955 if (heap_ != NULL) {
956 heap_->UpdateGlobalMaxUsed();
926 } 957 }
927 } 958 }
928 959
929 // Make code pages read-only.
930 WriteProtectCode(true);
931
932 int64_t end = OS::GetCurrentTimeMicros();
933
934 // Record signals for growth control. Include size of external allocations.
935 page_space_controller_.EvaluateGarbageCollection(usage_before,
936 GetCurrentUsage(),
937 start, end);
938
939 heap_->RecordTime(kMarkObjects, mid1 - start);
940 heap_->RecordTime(kResetFreeLists, mid2 - mid1);
941 heap_->RecordTime(kSweepPages, mid3 - mid2);
942 heap_->RecordTime(kSweepLargePages, end - mid3);
943
944 if (FLAG_print_free_list_after_gc) {
945 OS::Print("Data Freelist (after GC):\n");
946 freelist_[HeapPage::kData].Print();
947 OS::Print("Executable Freelist (after GC):\n");
948 freelist_[HeapPage::kExecutable].Print();
949 }
950
951 UpdateMaxUsed();
952 if (heap_ != NULL) {
953 heap_->UpdateGlobalMaxUsed();
954 }
955
956 isolate->thread_registry()->ResumeAllThreads();
957
958 // Done, reset the task count. 960 // Done, reset the task count.
959 { 961 {
960 MonitorLocker ml(tasks_lock()); 962 MonitorLocker ml(tasks_lock());
961 set_tasks(tasks() - 1); 963 set_tasks(tasks() - 1);
962 ml.Notify(); 964 ml.Notify();
963 } 965 }
964 } 966 }
965 967
966 968
967 uword PageSpace::TryAllocateDataBumpInternal(intptr_t size, 969 uword PageSpace::TryAllocateDataBumpInternal(intptr_t size,
(...skipping 247 matching lines...) Expand 10 before | Expand all | Expand 10 after
1215 return 0; 1217 return 0;
1216 } else { 1218 } else {
1217 ASSERT(total_time >= gc_time); 1219 ASSERT(total_time >= gc_time);
1218 int result = static_cast<int>((static_cast<double>(gc_time) / 1220 int result = static_cast<int>((static_cast<double>(gc_time) /
1219 static_cast<double>(total_time)) * 100); 1221 static_cast<double>(total_time)) * 100);
1220 return result; 1222 return result;
1221 } 1223 }
1222 } 1224 }
1223 1225
1224 } // namespace dart 1226 } // namespace dart
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698