• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2020 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "src/heap/cppgc/heap-growing.h"
6 
7 #include <cmath>
8 #include <memory>
9 
10 #include "include/cppgc/platform.h"
11 #include "src/base/macros.h"
12 #include "src/heap/cppgc/globals.h"
13 #include "src/heap/cppgc/heap.h"
14 #include "src/heap/cppgc/incremental-marking-schedule.h"
15 #include "src/heap/cppgc/stats-collector.h"
16 #include "src/heap/cppgc/task-handle.h"
17 
18 namespace cppgc {
19 namespace internal {
20 
21 namespace {
22 // Minimum ratio between limit for incremental GC and limit for atomic GC
23 // (to guarantee that limits are not to close to each other).
24 constexpr double kMaximumLimitRatioForIncrementalGC = 0.9;
25 // Minimum ratio between limit for incremental GC and limit for atomic GC
26 // (to guarantee that limit is not too close to current allocated size).
27 constexpr double kMinimumLimitRatioForIncrementalGC = 0.5;
28 }  // namespace
29 
30 class HeapGrowing::HeapGrowingImpl final
31     : public StatsCollector::AllocationObserver {
32  public:
33   HeapGrowingImpl(GarbageCollector*, StatsCollector*,
34                   cppgc::Heap::ResourceConstraints, cppgc::Heap::MarkingType,
35                   cppgc::Heap::SweepingType);
36   ~HeapGrowingImpl();
37 
38   HeapGrowingImpl(const HeapGrowingImpl&) = delete;
39   HeapGrowingImpl& operator=(const HeapGrowingImpl&) = delete;
40 
41   void AllocatedObjectSizeIncreased(size_t) final;
42   // Only trigger GC on growing.
AllocatedObjectSizeDecreased(size_t)43   void AllocatedObjectSizeDecreased(size_t) final {}
44   void ResetAllocatedObjectSize(size_t) final;
45 
limit_for_atomic_gc() const46   size_t limit_for_atomic_gc() const { return limit_for_atomic_gc_; }
limit_for_incremental_gc() const47   size_t limit_for_incremental_gc() const { return limit_for_incremental_gc_; }
48 
49   void DisableForTesting();
50 
51  private:
52   void ConfigureLimit(size_t allocated_object_size);
53 
54   GarbageCollector* collector_;
55   StatsCollector* stats_collector_;
56   // Allow 1 MB heap by default;
57   size_t initial_heap_size_ = 1 * kMB;
58   size_t limit_for_atomic_gc_ = 0;       // See ConfigureLimit().
59   size_t limit_for_incremental_gc_ = 0;  // See ConfigureLimit().
60 
61   SingleThreadedHandle gc_task_handle_;
62 
63   bool disabled_for_testing_ = false;
64 
65   const cppgc::Heap::MarkingType marking_support_;
66   const cppgc::Heap::SweepingType sweeping_support_;
67 };
68 
HeapGrowingImpl(GarbageCollector * collector,StatsCollector * stats_collector,cppgc::Heap::ResourceConstraints constraints,cppgc::Heap::MarkingType marking_support,cppgc::Heap::SweepingType sweeping_support)69 HeapGrowing::HeapGrowingImpl::HeapGrowingImpl(
70     GarbageCollector* collector, StatsCollector* stats_collector,
71     cppgc::Heap::ResourceConstraints constraints,
72     cppgc::Heap::MarkingType marking_support,
73     cppgc::Heap::SweepingType sweeping_support)
74     : collector_(collector),
75       stats_collector_(stats_collector),
76       gc_task_handle_(SingleThreadedHandle::NonEmptyTag{}),
77       marking_support_(marking_support),
78       sweeping_support_(sweeping_support) {
79   if (constraints.initial_heap_size_bytes > 0) {
80     initial_heap_size_ = constraints.initial_heap_size_bytes;
81   }
82   constexpr size_t kNoAllocatedBytes = 0;
83   ConfigureLimit(kNoAllocatedBytes);
84   stats_collector->RegisterObserver(this);
85 }
86 
~HeapGrowingImpl()87 HeapGrowing::HeapGrowingImpl::~HeapGrowingImpl() {
88   stats_collector_->UnregisterObserver(this);
89 }
90 
AllocatedObjectSizeIncreased(size_t)91 void HeapGrowing::HeapGrowingImpl::AllocatedObjectSizeIncreased(size_t) {
92   if (disabled_for_testing_) return;
93   size_t allocated_object_size = stats_collector_->allocated_object_size();
94   if (allocated_object_size > limit_for_atomic_gc_) {
95     collector_->CollectGarbage(
96         {GarbageCollector::Config::CollectionType::kMajor,
97          GarbageCollector::Config::StackState::kMayContainHeapPointers,
98          GarbageCollector::Config::MarkingType::kAtomic, sweeping_support_});
99   } else if (allocated_object_size > limit_for_incremental_gc_) {
100     if (marking_support_ == cppgc::Heap::MarkingType::kAtomic) return;
101     collector_->StartIncrementalGarbageCollection(
102         {GarbageCollector::Config::CollectionType::kMajor,
103          GarbageCollector::Config::StackState::kMayContainHeapPointers,
104          marking_support_, sweeping_support_});
105   }
106 }
107 
ResetAllocatedObjectSize(size_t allocated_object_size)108 void HeapGrowing::HeapGrowingImpl::ResetAllocatedObjectSize(
109     size_t allocated_object_size) {
110   ConfigureLimit(allocated_object_size);
111 }
112 
ConfigureLimit(size_t allocated_object_size)113 void HeapGrowing::HeapGrowingImpl::ConfigureLimit(
114     size_t allocated_object_size) {
115   const size_t size = std::max(allocated_object_size, initial_heap_size_);
116   limit_for_atomic_gc_ = std::max(static_cast<size_t>(size * kGrowingFactor),
117                                   size + kMinLimitIncrease);
118   // Estimate when to start incremental GC based on current allocation speed.
119   // Ideally we start incremental GC such that it is ready to finalize no
120   // later than when we reach |limit_for_atomic_gc_|. However, we need to cap
121   // |limit_for_incremental_gc_| within a range to prevent:
122   // 1) |limit_for_incremental_gc_| being too close to |limit_for_atomic_gc_|
123   //    such that incremental gc gets nothing done before reaching
124   //    |limit_for_atomic_gc_| (in case where the allocation rate is very low).
125   // 2) |limit_for_incremental_gc_| being too close to |size| such that GC is
126   //    essentially always running and write barriers are always active (in
127   //    case allocation rate is very high).
128   size_t estimated_bytes_allocated_during_incremental_gc =
129       std::ceil(IncrementalMarkingSchedule::kEstimatedMarkingTimeMs *
130                 stats_collector_->GetRecentAllocationSpeedInBytesPerMs());
131   size_t limit_incremental_gc_based_on_allocation_rate =
132       limit_for_atomic_gc_ - estimated_bytes_allocated_during_incremental_gc;
133   size_t maximum_limit_incremental_gc =
134       size + (limit_for_atomic_gc_ - size) * kMaximumLimitRatioForIncrementalGC;
135   size_t minimum_limit_incremental_gc =
136       size + (limit_for_atomic_gc_ - size) * kMinimumLimitRatioForIncrementalGC;
137   limit_for_incremental_gc_ =
138       std::max(minimum_limit_incremental_gc,
139                std::min(maximum_limit_incremental_gc,
140                         limit_incremental_gc_based_on_allocation_rate));
141 }
142 
DisableForTesting()143 void HeapGrowing::HeapGrowingImpl::DisableForTesting() {
144   disabled_for_testing_ = true;
145 }
146 
HeapGrowing(GarbageCollector * collector,StatsCollector * stats_collector,cppgc::Heap::ResourceConstraints constraints,cppgc::Heap::MarkingType marking_support,cppgc::Heap::SweepingType sweeping_support)147 HeapGrowing::HeapGrowing(GarbageCollector* collector,
148                          StatsCollector* stats_collector,
149                          cppgc::Heap::ResourceConstraints constraints,
150                          cppgc::Heap::MarkingType marking_support,
151                          cppgc::Heap::SweepingType sweeping_support)
152     : impl_(std::make_unique<HeapGrowing::HeapGrowingImpl>(
153           collector, stats_collector, constraints, marking_support,
154           sweeping_support)) {}
155 
156 HeapGrowing::~HeapGrowing() = default;
157 
limit_for_atomic_gc() const158 size_t HeapGrowing::limit_for_atomic_gc() const {
159   return impl_->limit_for_atomic_gc();
160 }
limit_for_incremental_gc() const161 size_t HeapGrowing::limit_for_incremental_gc() const {
162   return impl_->limit_for_incremental_gc();
163 }
164 
DisableForTesting()165 void HeapGrowing::DisableForTesting() { impl_->DisableForTesting(); }
166 
167 // static
168 constexpr double HeapGrowing::kGrowingFactor;
169 
170 }  // namespace internal
171 }  // namespace cppgc
172