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

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

Issue 511963007: Pretenure some strings into bump-allocated block (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: Created 6 years, 3 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 | Annotate | Revision Log
« no previous file with comments | « runtime/vm/pages.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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/thread.h" 13 #include "vm/thread.h"
14 #include "vm/virtual_memory.h" 14 #include "vm/virtual_memory.h"
15 15
16 namespace dart { 16 namespace dart {
17 17
18 DEFINE_FLAG(int, heap_growth_space_ratio, 20, 18 DEFINE_FLAG(int, heap_growth_space_ratio, 20,
19 "The desired maximum percentage of free space after GC"); 19 "The desired maximum percentage of free space after GC");
20 DEFINE_FLAG(int, heap_growth_time_ratio, 3, 20 DEFINE_FLAG(int, heap_growth_time_ratio, 3,
21 "The desired maximum percentage of time spent in GC"); 21 "The desired maximum percentage of time spent in GC");
22 DEFINE_FLAG(int, heap_growth_rate, 256, 22 DEFINE_FLAG(int, heap_growth_rate, 280,
23 "The max number of pages the heap can grow at a time"); 23 "The max number of pages the heap can grow at a time");
24 DEFINE_FLAG(bool, print_free_list_before_gc, false, 24 DEFINE_FLAG(bool, print_free_list_before_gc, false,
25 "Print free list statistics before a GC"); 25 "Print free list statistics before a GC");
26 DEFINE_FLAG(bool, print_free_list_after_gc, false, 26 DEFINE_FLAG(bool, print_free_list_after_gc, false,
27 "Print free list statistics after a GC"); 27 "Print free list statistics after a GC");
28 DEFINE_FLAG(bool, collect_code, true, 28 DEFINE_FLAG(bool, collect_code, true,
29 "Attempt to GC infrequently used code."); 29 "Attempt to GC infrequently used code.");
30 DEFINE_FLAG(int, code_collection_interval_in_us, 30000000, 30 DEFINE_FLAG(int, code_collection_interval_in_us, 30000000,
31 "Time between attempts to collect unused code."); 31 "Time between attempts to collect unused code.");
32 DEFINE_FLAG(bool, log_code_drop, false, 32 DEFINE_FLAG(bool, log_code_drop, false,
33 "Emit a log message when pointers to unused code are dropped."); 33 "Emit a log message when pointers to unused code are dropped.");
34 DEFINE_FLAG(bool, always_drop_code, false, 34 DEFINE_FLAG(bool, always_drop_code, false,
35 "Always try to drop code if the function's usage counter is >= 0"); 35 "Always try to drop code if the function's usage counter is >= 0");
36 DEFINE_FLAG(bool, concurrent_sweep, false, 36 DEFINE_FLAG(bool, concurrent_sweep, false,
37 "Concurrent sweep for old generation."); 37 "Concurrent sweep for old generation.");
38 DEFINE_FLAG(bool, log_growth, false, "Log PageSpace growth policy decisions.");
38 39
39 HeapPage* HeapPage::Initialize(VirtualMemory* memory, PageType type) { 40 HeapPage* HeapPage::Initialize(VirtualMemory* memory, PageType type) {
40 ASSERT(memory->size() > VirtualMemory::PageSize()); 41 ASSERT(memory->size() > VirtualMemory::PageSize());
41 bool is_executable = (type == kExecutable); 42 bool is_executable = (type == kExecutable);
42 memory->Commit(is_executable); 43 memory->Commit(is_executable);
43 44
44 HeapPage* result = reinterpret_cast<HeapPage*>(memory->address()); 45 HeapPage* result = reinterpret_cast<HeapPage*>(memory->address());
45 result->memory_ = memory; 46 result->memory_ = memory;
46 result->next_ = NULL; 47 result->next_ = NULL;
47 result->executable_ = is_executable; 48 result->executable_ = is_executable;
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after
122 123
123 PageSpace::PageSpace(Heap* heap, intptr_t max_capacity_in_words) 124 PageSpace::PageSpace(Heap* heap, intptr_t max_capacity_in_words)
124 : freelist_(), 125 : freelist_(),
125 heap_(heap), 126 heap_(heap),
126 pages_lock_(new Mutex()), 127 pages_lock_(new Mutex()),
127 pages_(NULL), 128 pages_(NULL),
128 pages_tail_(NULL), 129 pages_tail_(NULL),
129 exec_pages_(NULL), 130 exec_pages_(NULL),
130 exec_pages_tail_(NULL), 131 exec_pages_tail_(NULL),
131 large_pages_(NULL), 132 large_pages_(NULL),
133 bump_top_(0),
134 bump_end_(0),
132 max_capacity_in_words_(max_capacity_in_words), 135 max_capacity_in_words_(max_capacity_in_words),
133 tasks_lock_(new Monitor()), 136 tasks_lock_(new Monitor()),
134 tasks_(0), 137 tasks_(0),
135 page_space_controller_(heap, 138 page_space_controller_(heap,
136 FLAG_heap_growth_space_ratio, 139 FLAG_heap_growth_space_ratio,
137 FLAG_heap_growth_rate, 140 FLAG_heap_growth_rate,
138 FLAG_heap_growth_time_ratio), 141 FLAG_heap_growth_time_ratio),
139 gc_time_micros_(0), 142 gc_time_micros_(0),
140 collections_(0) { 143 collections_(0) {
141 } 144 }
(...skipping 132 matching lines...) Expand 10 before | Expand all | Expand 10 after
274 void PageSpace::FreePages(HeapPage* pages) { 277 void PageSpace::FreePages(HeapPage* pages) {
275 HeapPage* page = pages; 278 HeapPage* page = pages;
276 while (page != NULL) { 279 while (page != NULL) {
277 HeapPage* next = page->next(); 280 HeapPage* next = page->next();
278 page->Deallocate(); 281 page->Deallocate();
279 page = next; 282 page = next;
280 } 283 }
281 } 284 }
282 285
283 286
287 uword PageSpace::TryAllocateInFreshPage(intptr_t size,
288 HeapPage::PageType type,
289 GrowthPolicy growth_policy,
290 bool is_locked) {
291 ASSERT(size < kAllocatablePageSize);
292 uword result = 0;
293 SpaceUsage after_allocation = usage_;
294 after_allocation.used_in_words += size >> kWordSizeLog2;
295 // Can we grow by one page?
296 after_allocation.capacity_in_words += kPageSizeInWords;
297 if ((growth_policy == kForceGrowth ||
298 !page_space_controller_.NeedsGarbageCollection(after_allocation)) &&
299 CanIncreaseCapacityInWords(kPageSizeInWords)) {
300 HeapPage* page = AllocatePage(type);
301 ASSERT(page != NULL);
302 // Start of the newly allocated page is the allocated object.
303 result = page->object_start();
304 usage_ = after_allocation;
305 // Enqueue the remainder in the free list.
306 uword free_start = result + size;
307 intptr_t free_size = page->object_end() - free_start;
308 if (free_size > 0) {
309 if (is_locked) {
310 freelist_[type].FreeLocked(free_start, free_size);
311 } else {
312 freelist_[type].Free(free_start, free_size);
313 }
314 }
315 }
316 return result;
317 }
318
319
284 uword PageSpace::TryAllocateInternal(intptr_t size, 320 uword PageSpace::TryAllocateInternal(intptr_t size,
285 HeapPage::PageType type, 321 HeapPage::PageType type,
286 GrowthPolicy growth_policy, 322 GrowthPolicy growth_policy,
287 bool is_protected, 323 bool is_protected,
288 bool is_locked) { 324 bool is_locked) {
289 ASSERT(size >= kObjectAlignment); 325 ASSERT(size >= kObjectAlignment);
290 ASSERT(Utils::IsAligned(size, kObjectAlignment)); 326 ASSERT(Utils::IsAligned(size, kObjectAlignment));
291 uword result = 0; 327 uword result = 0;
292 SpaceUsage after_allocation = usage_;
293 after_allocation.used_in_words += size >> kWordSizeLog2;
294 if (size < kAllocatablePageSize) { 328 if (size < kAllocatablePageSize) {
295 if (is_locked) { 329 if (is_locked) {
296 result = freelist_[type].TryAllocateLocked(size, is_protected); 330 result = freelist_[type].TryAllocateLocked(size, is_protected);
297 } else { 331 } else {
298 result = freelist_[type].TryAllocate(size, is_protected); 332 result = freelist_[type].TryAllocate(size, is_protected);
299 } 333 }
300 if (result == 0) { 334 if (result == 0) {
301 // Can we grow by one page? 335 result = TryAllocateInFreshPage(size, type, growth_policy, is_locked);
302 after_allocation.capacity_in_words += kPageSizeInWords;
303 if ((!page_space_controller_.NeedsGarbageCollection(after_allocation) ||
304 growth_policy == kForceGrowth) &&
305 CanIncreaseCapacityInWords(kPageSizeInWords)) {
306 HeapPage* page = AllocatePage(type);
307 ASSERT(page != NULL);
308 // Start of the newly allocated page is the allocated object.
309 result = page->object_start();
310 // Enqueue the remainder in the free list.
311 uword free_start = result + size;
312 intptr_t free_size = page->object_end() - free_start;
313 if (free_size > 0) {
314 if (is_locked) {
315 freelist_[type].FreeLocked(free_start, free_size);
316 } else {
317 freelist_[type].Free(free_start, free_size);
318 }
319 }
320 }
321 } 336 }
322 } else { 337 } else {
323 // Large page allocation. 338 // Large page allocation.
324 intptr_t page_size_in_words = LargePageSizeInWordsFor(size); 339 intptr_t page_size_in_words = LargePageSizeInWordsFor(size);
325 if ((page_size_in_words << kWordSizeLog2) < size) { 340 if ((page_size_in_words << kWordSizeLog2) < size) {
326 // On overflow we fail to allocate. 341 // On overflow we fail to allocate.
327 return 0; 342 return 0;
328 } 343 }
344 SpaceUsage after_allocation = usage_;
345 after_allocation.used_in_words += size >> kWordSizeLog2;
329 after_allocation.capacity_in_words += page_size_in_words; 346 after_allocation.capacity_in_words += page_size_in_words;
330 if ((!page_space_controller_.NeedsGarbageCollection(after_allocation) || 347 if ((growth_policy == kForceGrowth ||
331 growth_policy == kForceGrowth) && 348 !page_space_controller_.NeedsGarbageCollection(after_allocation)) &&
332 CanIncreaseCapacityInWords(page_size_in_words)) { 349 CanIncreaseCapacityInWords(page_size_in_words)) {
333 HeapPage* page = AllocateLargePage(size, type); 350 HeapPage* page = AllocateLargePage(size, type);
334 if (page != NULL) { 351 if (page != NULL) {
335 result = page->object_start(); 352 result = page->object_start();
353 usage_ = after_allocation;
336 } 354 }
337 } 355 }
338 } 356 }
339 if (result != 0) { 357 if (result != 0) {
340 usage_ = after_allocation;
341 if (FLAG_compiler_stats && (type == HeapPage::kExecutable)) { 358 if (FLAG_compiler_stats && (type == HeapPage::kExecutable)) {
342 CompilerStats::code_allocated += size; 359 CompilerStats::code_allocated += size;
343 } 360 }
344 } 361 }
345 ASSERT((result & kObjectAlignmentMask) == kOldObjectAlignmentOffset); 362 ASSERT((result & kObjectAlignmentMask) == kOldObjectAlignmentOffset);
346 return result; 363 return result;
347 } 364 }
348 365
349 366
350 void PageSpace::AcquireDataLock() { 367 void PageSpace::AcquireDataLock() {
(...skipping 270 matching lines...) Expand 10 before | Expand all | Expand 10 after
621 SpaceUsage usage_before = usage_; 638 SpaceUsage usage_before = usage_;
622 639
623 // Mark all reachable old-gen objects. 640 // Mark all reachable old-gen objects.
624 bool collect_code = FLAG_collect_code && ShouldCollectCode(); 641 bool collect_code = FLAG_collect_code && ShouldCollectCode();
625 GCMarker marker(heap_); 642 GCMarker marker(heap_);
626 marker.MarkObjects(isolate, this, invoke_api_callbacks, collect_code); 643 marker.MarkObjects(isolate, this, invoke_api_callbacks, collect_code);
627 usage_.used_in_words = marker.marked_words(); 644 usage_.used_in_words = marker.marked_words();
628 645
629 int64_t mid1 = OS::GetCurrentTimeMicros(); 646 int64_t mid1 = OS::GetCurrentTimeMicros();
630 647
631 // Reset the bump allocation page to unused. 648 // Abandon the remainder of the bump allocation block.
649 bump_top_ = 0;
650 bump_end_ = 0;
632 // Reset the freelists and setup sweeping. 651 // Reset the freelists and setup sweeping.
633 freelist_[HeapPage::kData].Reset(); 652 freelist_[HeapPage::kData].Reset();
634 freelist_[HeapPage::kExecutable].Reset(); 653 freelist_[HeapPage::kExecutable].Reset();
635 654
636 int64_t mid2 = OS::GetCurrentTimeMicros(); 655 int64_t mid2 = OS::GetCurrentTimeMicros();
637 int64_t mid3 = 0; 656 int64_t mid3 = 0;
638 657
639 { 658 {
640 GCSweeper sweeper(heap_); 659 GCSweeper sweeper(heap_);
641 660
(...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after
728 747
729 // Done, reset the task count. 748 // Done, reset the task count.
730 { 749 {
731 MonitorLocker ml(tasks_lock()); 750 MonitorLocker ml(tasks_lock());
732 set_tasks(tasks() - 1); 751 set_tasks(tasks() - 1);
733 ml.Notify(); 752 ml.Notify();
734 } 753 }
735 } 754 }
736 755
737 756
757 uword PageSpace::TryAllocateDataBump(intptr_t size,
758 GrowthPolicy growth_policy) {
759 ASSERT(size >= kObjectAlignment);
760 ASSERT(Utils::IsAligned(size, kObjectAlignment));
761 intptr_t remaining = bump_end_ - bump_top_;
762 if (remaining < size) {
763 // Checking this first would be logical, but needlessly slow.
764 if (size >= kAllocatablePageSize) {
765 return TryAllocate(size, HeapPage::kData, growth_policy);
766 }
767 FreeListElement* block = freelist_[HeapPage::kData].TryAllocateLarge(size);
768 if (block == NULL) {
769 // Allocating from a new page (if growth policy allows) will have the
770 // side-effect of populating the freelist with a large block. The next
771 // bump allocation request will have a chance to consume that block.
772 // TODO(koda): Could take freelist lock just once instead of twice.
773 return TryAllocateInFreshPage(size,
774 HeapPage::kData,
775 growth_policy,
776 /* is_locked = */ false);
777 }
778 intptr_t block_size = block->Size();
779 bump_top_ = reinterpret_cast<uword>(block);
780 bump_end_ = bump_top_ + block_size;
781 remaining = block_size;
782 }
783 ASSERT(remaining >= size);
784 uword result = bump_top_;
785 bump_top_ += size;
786 usage_.used_in_words += size >> kWordSizeLog2;
787 remaining -= size;
788 if (remaining > 0) {
789 FreeListElement::AsElement(bump_top_, remaining);
790 }
791 return result;
792 }
793
794
738 PageSpaceController::PageSpaceController(Heap* heap, 795 PageSpaceController::PageSpaceController(Heap* heap,
739 int heap_growth_ratio, 796 int heap_growth_ratio,
740 int heap_growth_max, 797 int heap_growth_max,
741 int garbage_collection_time_ratio) 798 int garbage_collection_time_ratio)
742 : heap_(heap), 799 : heap_(heap),
743 is_enabled_(false), 800 is_enabled_(false),
744 grow_heap_(heap_growth_max / 2), 801 grow_heap_(heap_growth_max / 2),
745 heap_growth_ratio_(heap_growth_ratio), 802 heap_growth_ratio_(heap_growth_ratio),
746 desired_utilization_((100.0 - heap_growth_ratio) / 100.0), 803 desired_utilization_((100.0 - heap_growth_ratio) / 100.0),
747 heap_growth_max_(heap_growth_max), 804 heap_growth_max_(heap_growth_max),
(...skipping 25 matching lines...) Expand all
773 // To avoid waste, the first GC should be triggered before too long. After 830 // To avoid waste, the first GC should be triggered before too long. After
774 // kInitialTimeoutSeconds, gradually lower the capacity limit. 831 // kInitialTimeoutSeconds, gradually lower the capacity limit.
775 static const double kInitialTimeoutSeconds = 1.00; 832 static const double kInitialTimeoutSeconds = 1.00;
776 if (history_.IsEmpty()) { 833 if (history_.IsEmpty()) {
777 double seconds_since_init = MicrosecondsToSeconds( 834 double seconds_since_init = MicrosecondsToSeconds(
778 OS::GetCurrentTimeMicros() - heap_->isolate()->start_time()); 835 OS::GetCurrentTimeMicros() - heap_->isolate()->start_time());
779 if (seconds_since_init > kInitialTimeoutSeconds) { 836 if (seconds_since_init > kInitialTimeoutSeconds) {
780 multiplier *= seconds_since_init / kInitialTimeoutSeconds; 837 multiplier *= seconds_since_init / kInitialTimeoutSeconds;
781 } 838 }
782 } 839 }
783 return capacity_increase_in_pages * multiplier > grow_heap_; 840 bool needs_gc = capacity_increase_in_pages * multiplier > grow_heap_;
841 if (FLAG_log_growth) {
842 OS::PrintErr("%s: %" Pd " * %f %s %" Pd "\n",
843 needs_gc ? "NEEDS GC" : "grow",
844 capacity_increase_in_pages,
845 multiplier,
846 needs_gc ? ">" : "<=",
847 grow_heap_);
848 }
849 return needs_gc;
784 } 850 }
785 851
786 852
787 void PageSpaceController::EvaluateGarbageCollection( 853 void PageSpaceController::EvaluateGarbageCollection(
788 SpaceUsage before, SpaceUsage after, int64_t start, int64_t end) { 854 SpaceUsage before, SpaceUsage after, int64_t start, int64_t end) {
789 ASSERT(end >= start); 855 ASSERT(end >= start);
790 history_.AddGarbageCollectionTime(start, end); 856 history_.AddGarbageCollectionTime(start, end);
791 int gc_time_fraction = history_.GarbageCollectionTimeFraction(); 857 int gc_time_fraction = history_.GarbageCollectionTimeFraction();
792 heap_->RecordData(PageSpace::kGCTimeFraction, gc_time_fraction); 858 heap_->RecordData(PageSpace::kGCTimeFraction, gc_time_fraction);
793 859
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after
851 return 0; 917 return 0;
852 } else { 918 } else {
853 ASSERT(total_time >= gc_time); 919 ASSERT(total_time >= gc_time);
854 int result= static_cast<int>((static_cast<double>(gc_time) / 920 int result= static_cast<int>((static_cast<double>(gc_time) /
855 static_cast<double>(total_time)) * 100); 921 static_cast<double>(total_time)) * 100);
856 return result; 922 return result;
857 } 923 }
858 } 924 }
859 925
860 } // namespace dart 926 } // namespace dart
OLDNEW
« no previous file with comments | « runtime/vm/pages.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698