Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
scavenger.h
Go to the documentation of this 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
3// BSD-style license that can be found in the LICENSE file.
4
5#ifndef RUNTIME_VM_HEAP_SCAVENGER_H_
6#define RUNTIME_VM_HEAP_SCAVENGER_H_
7
8#include "platform/assert.h"
9#include "platform/utils.h"
10
11#include "vm/dart.h"
12#include "vm/flags.h"
13#include "vm/globals.h"
14#include "vm/heap/page.h"
15#include "vm/heap/spaces.h"
16#include "vm/isolate.h"
17#include "vm/lockers.h"
18#include "vm/raw_object.h"
19#include "vm/ring_buffer.h"
20#include "vm/virtual_memory.h"
21#include "vm/visitor.h"
22
23namespace dart {
24
25// Forward declarations.
26class Heap;
27class Isolate;
28class JSONObject;
29class ObjectSet;
30template <bool parallel>
31class ScavengerVisitorBase;
32class GCMarker;
33template <typename Type, typename PtrType>
34class GCLinkedList;
35struct GCLinkedLists;
36
37class SemiSpace {
38 public:
39 explicit SemiSpace(intptr_t gc_threshold_in_words);
40 ~SemiSpace();
41
42 Page* TryAllocatePageLocked(bool link);
43
44 bool Contains(uword addr) const;
45 void WriteProtect(bool read_only);
46
47 intptr_t used_in_words() const {
48 intptr_t size = 0;
49 for (const Page* p = head_; p != nullptr; p = p->next()) {
50 size += p->used();
51 }
52 return size >> kWordSizeLog2;
53 }
54 intptr_t capacity_in_words() const { return capacity_in_words_; }
55 intptr_t gc_threshold_in_words() const { return gc_threshold_in_words_; }
56
57 Page* head() const { return head_; }
58
59 void AddList(Page* head, Page* tail);
60
61 private:
62 // Size of Pages in this semi-space.
63 intptr_t capacity_in_words_ = 0;
64
65 // Size of Pages before we trigger a scavenge. Compare old-space's
66 // hard_gc_threshold_in_words_.
67 intptr_t gc_threshold_in_words_;
68
69 Page* head_ = nullptr;
70 Page* tail_ = nullptr;
71};
72
73// Statistics for a particular scavenge.
75 public:
77 ScavengeStats(int64_t start_micros,
78 int64_t end_micros,
79 SpaceUsage before,
80 SpaceUsage after,
81 intptr_t promo_candidates_in_words,
82 intptr_t promoted_in_words,
83 intptr_t abandoned_in_words)
84 : start_micros_(start_micros),
85 end_micros_(end_micros),
86 before_(before),
87 after_(after),
88 promo_candidates_in_words_(promo_candidates_in_words),
89 promoted_in_words_(promoted_in_words),
90 abandoned_in_words_(abandoned_in_words) {}
91
92 // Of all data before scavenge, what fraction was found to be garbage?
93 // If this scavenge included growth, assume the extra capacity would become
94 // garbage to give the scavenger a chance to stabilize at the new capacity.
95 double ExpectedGarbageFraction(intptr_t old_threshold_in_words) const {
96 double work =
97 after_.used_in_words + promoted_in_words_ + abandoned_in_words_;
98 return 1.0 - (work / old_threshold_in_words);
99 }
100
101 // Fraction of promotion candidates that survived and was thereby promoted.
102 // Returns zero if there were no promotion candidates.
104 return promo_candidates_in_words_ > 0
105 ? promoted_in_words_ /
106 static_cast<double>(promo_candidates_in_words_)
107 : 0.0;
108 }
109
110 intptr_t UsedBeforeInWords() const { return before_.used_in_words; }
111
112 int64_t DurationMicros() const { return end_micros_ - start_micros_; }
113
114 private:
115 int64_t start_micros_;
116 int64_t end_micros_;
117 SpaceUsage before_;
118 SpaceUsage after_;
119 intptr_t promo_candidates_in_words_;
120 intptr_t promoted_in_words_;
121 intptr_t abandoned_in_words_;
122};
123
125 private:
126 static constexpr intptr_t kTLABSize = 512 * KB;
127
128 public:
129 Scavenger(Heap* heap, intptr_t max_semi_capacity_in_words);
130 ~Scavenger();
131
132 // Check whether this Scavenger contains this address.
133 // During scavenging both the to and from spaces contain "legal" objects.
134 // During a scavenge this function only returns true for addresses that will
135 // be part of the surviving objects.
136 bool Contains(uword addr) const { return to_->Contains(addr); }
137
138 uword TryAllocate(Thread* thread, intptr_t size) {
139 uword addr = TryAllocateFromTLAB(thread, size);
140 if (LIKELY(addr != 0)) {
141 return addr;
142 }
143 TryAllocateNewTLAB(thread, size, true);
144 return TryAllocateFromTLAB(thread, size);
145 }
146 uword TryAllocateNoSafepoint(Thread* thread, intptr_t size) {
147 uword addr = TryAllocateFromTLAB(thread, size);
148 if (LIKELY(addr != 0)) {
149 return addr;
150 }
151 TryAllocateNewTLAB(thread, size, false);
152 return TryAllocateFromTLAB(thread, size);
153 }
154 intptr_t AbandonRemainingTLAB(Thread* thread);
156
157 // Collect the garbage in this scavenger.
158 void Scavenge(Thread* thread, GCType type, GCReason reason);
159
160 intptr_t UsedInWords() const {
161 MutexLocker ml(&space_lock_);
162 return to_->used_in_words() - freed_in_words_;
163 }
164 intptr_t CapacityInWords() const {
165 MutexLocker ml(&space_lock_);
166 return to_->capacity_in_words();
167 }
168 intptr_t ExternalInWords() const { return external_size_ >> kWordSizeLog2; }
172 usage.capacity_in_words = CapacityInWords();
173 usage.external_in_words = ExternalInWords();
174 return usage;
175 }
176 intptr_t ThresholdInWords() const { return to_->gc_threshold_in_words(); }
177
178 void VisitObjects(ObjectVisitor* visitor) const;
179 void VisitObjectPointers(ObjectPointerVisitor* visitor) const;
180
181 void AddRegionsToObjectSet(ObjectSet* set) const;
182
183 void WriteProtect(bool read_only);
184
185 bool ShouldPerformIdleScavenge(int64_t deadline);
186
187 void AddGCTime(int64_t micros) { gc_time_micros_ += micros; }
188
189 int64_t gc_time_micros() const { return gc_time_micros_; }
190
191 void IncrementCollections() { collections_++; }
192
193 intptr_t collections() const { return collections_; }
194
195#ifndef PRODUCT
196 void PrintToJSONObject(JSONObject* object) const;
197#endif // !PRODUCT
198
199 // Tracks an external allocation by incrementing the new space's total
200 // external size tracker. Returns false without incrementing the tracker if
201 // this allocation will make it exceed kMaxAddrSpaceInWords.
202 bool AllocatedExternal(intptr_t size) {
203 ASSERT(size >= 0);
204 intptr_t expected = external_size_.load();
205 intptr_t desired;
206 do {
207 intptr_t next_external_size_in_words =
208 (external_size_ >> kWordSizeLog2) + (size >> kWordSizeLog2);
209 if (next_external_size_in_words < 0 ||
210 next_external_size_in_words > kMaxAddrSpaceInWords) {
211 return false;
212 }
213 desired = expected + size;
214 ASSERT(desired >= 0);
215 } while (!external_size_.compare_exchange_weak(expected, desired));
216 return true;
217 }
218 void FreedExternal(intptr_t size) {
219 ASSERT(size >= 0);
220 external_size_ -= size;
221 ASSERT(external_size_ >= 0);
222 }
223
224 void set_freed_in_words(intptr_t value) { freed_in_words_ = value; }
225
226 // The maximum number of Dart mutator threads we allow to execute at the same
227 // time.
228 static intptr_t MaxMutatorThreadCount() {
229 // With a max new-space of 16 MB and 512kb TLABs we would allow up to 8
230 // mutator threads to run at the same time.
231 const intptr_t max_parallel_tlab_usage =
232 (FLAG_new_gen_semi_max_size * MB) / Scavenger::kTLABSize;
233 const intptr_t max_pool_size = max_parallel_tlab_usage / 4;
234 return max_pool_size > 0 ? max_pool_size : 1;
235 }
236
237 Page* head() const { return to_->head(); }
238
239 void Prune(MarkingStackBlock** from, MarkingStack* to);
240 void Forward(MarkingStack* stack);
241 void PruneWeak(GCLinkedLists* delayed);
242 template <typename Type, typename PtrType>
244
245 private:
246 // Ids for time and data records in Heap::GCStats.
247 enum {
248 // Time
249 kDummyScavengeTime = 0,
250 kSafePoint = 1,
251 kVisitIsolateRoots = 2,
252 kIterateStoreBuffers = 3,
253 kProcessToSpace = 4,
254 kIterateWeaks = 5,
255 };
256
257 uword TryAllocateFromTLAB(Thread* thread, intptr_t size) {
259 ASSERT(heap_ != Dart::vm_isolate_group()->heap());
260
261 const uword result = thread->top();
262 const intptr_t remaining = static_cast<intptr_t>(thread->end()) - result;
263 ASSERT(remaining >= 0);
264 if (UNLIKELY(remaining < size)) {
265 return 0;
266 }
267 ASSERT(to_->Contains(result));
269 thread->set_top(result + size);
270 return result;
271 }
272 void TryAllocateNewTLAB(Thread* thread, intptr_t size, bool can_safepoint);
273
274 SemiSpace* Prologue(GCReason reason);
275 intptr_t ParallelScavenge(SemiSpace* from);
276 intptr_t SerialScavenge(SemiSpace* from);
277 void ReverseScavenge(SemiSpace** from);
278 void IterateIsolateRoots(ObjectPointerVisitor* visitor);
279 template <bool parallel>
280 void IterateStoreBuffers(ScavengerVisitorBase<parallel>* visitor);
281 template <bool parallel>
282 void IterateRememberedCards(ScavengerVisitorBase<parallel>* visitor);
283 void IterateObjectIdTable(ObjectPointerVisitor* visitor);
284 template <bool parallel>
285 void IterateRoots(ScavengerVisitorBase<parallel>* visitor);
286 void IterateWeak();
287 void MournWeakHandles();
288 void MournWeakTables();
289 void Epilogue(SemiSpace* from);
290
291 void VerifyStoreBuffers(const char* msg);
292
293 void UpdateMaxHeapCapacity();
294 void UpdateMaxHeapUsage();
295
296 intptr_t NewSizeInWords(intptr_t old_size_in_words, GCReason reason) const;
297
298 Heap* heap_;
299
300 SemiSpace* to_;
301
302 PromotionStack promotion_stack_;
303
304 intptr_t max_semi_capacity_in_words_;
305
306 // Keep track whether a scavenge is currently running.
307 bool scavenging_ = false;
308 bool early_tenure_ = false;
309 RelaxedAtomic<intptr_t> root_slices_started_ = {0};
310 RelaxedAtomic<intptr_t> weak_slices_started_ = {0};
311 StoreBufferBlock* blocks_ = nullptr;
312 MarkingStackBlock* mark_blocks_ = nullptr;
313 MarkingStackBlock* new_blocks_ = nullptr;
314 MarkingStackBlock* deferred_blocks_ = nullptr;
315
316 int64_t gc_time_micros_ = 0;
317 intptr_t collections_ = 0;
318 static constexpr int kStatsHistoryCapacity = 4;
319 RingBuffer<ScavengeStats, kStatsHistoryCapacity> stats_history_;
320
321 intptr_t scavenge_words_per_micro_;
322 intptr_t idle_scavenge_threshold_in_words_ = 0;
323
324 // The total size of external data associated with objects in this scavenger.
325 RelaxedAtomic<intptr_t> external_size_ = {0};
326 intptr_t freed_in_words_ = 0;
327
328 RelaxedAtomic<bool> failed_to_promote_ = {false};
329 RelaxedAtomic<bool> abort_ = {false};
330
331 // Protects new space during the allocation of new TLABs
332 mutable Mutex space_lock_;
333
334 template <bool>
336
338};
339
340} // namespace dart
341
342#endif // RUNTIME_VM_HEAP_SCAVENGER_H_
static IsolateGroup * vm_isolate_group()
Definition dart.h:69
T load(std::memory_order order=std::memory_order_relaxed) const
Definition atomic.h:21
bool compare_exchange_weak(T &expected, T desired, std::memory_order order=std::memory_order_relaxed)
Definition atomic.h:52
ScavengeStats(int64_t start_micros, int64_t end_micros, SpaceUsage before, SpaceUsage after, intptr_t promo_candidates_in_words, intptr_t promoted_in_words, intptr_t abandoned_in_words)
Definition scavenger.h:77
intptr_t UsedBeforeInWords() const
Definition scavenger.h:110
double ExpectedGarbageFraction(intptr_t old_threshold_in_words) const
Definition scavenger.h:95
int64_t DurationMicros() const
Definition scavenger.h:112
double PromoCandidatesSuccessFraction() const
Definition scavenger.h:103
void Scavenge(Thread *thread, GCType type, GCReason reason)
bool Contains(uword addr) const
Definition scavenger.h:136
void Prune(MarkingStackBlock **from, MarkingStack *to)
static intptr_t MaxMutatorThreadCount()
Definition scavenger.h:228
intptr_t ExternalInWords() const
Definition scavenger.h:168
void VisitObjects(ObjectVisitor *visitor) const
void VisitObjectPointers(ObjectPointerVisitor *visitor) const
void PruneWeak(GCLinkedLists *delayed)
void AddGCTime(int64_t micros)
Definition scavenger.h:187
void WriteProtect(bool read_only)
void AbandonRemainingTLABForDebugging(Thread *thread)
bool ShouldPerformIdleScavenge(int64_t deadline)
uword TryAllocate(Thread *thread, intptr_t size)
Definition scavenger.h:138
void AddRegionsToObjectSet(ObjectSet *set) const
void set_freed_in_words(intptr_t value)
Definition scavenger.h:224
intptr_t CapacityInWords() const
Definition scavenger.h:164
intptr_t UsedInWords() const
Definition scavenger.h:160
SpaceUsage GetCurrentUsage() const
Definition scavenger.h:169
bool AllocatedExternal(intptr_t size)
Definition scavenger.h:202
Page * head() const
Definition scavenger.h:237
void FreedExternal(intptr_t size)
Definition scavenger.h:218
int64_t gc_time_micros() const
Definition scavenger.h:189
void IncrementCollections()
Definition scavenger.h:191
intptr_t AbandonRemainingTLAB(Thread *thread)
intptr_t ThresholdInWords() const
Definition scavenger.h:176
uword TryAllocateNoSafepoint(Thread *thread, intptr_t size)
Definition scavenger.h:146
intptr_t collections() const
Definition scavenger.h:193
void PrintToJSONObject(JSONObject *object) const
void Forward(MarkingStack *stack)
Page * head() const
Definition scavenger.h:57
void AddList(Page *head, Page *tail)
Definition scavenger.cc:754
void WriteProtect(bool read_only)
Definition scavenger.cc:748
intptr_t gc_threshold_in_words() const
Definition scavenger.h:55
Page * TryAllocatePageLocked(bool link)
Definition scavenger.cc:721
bool Contains(uword addr) const
Definition scavenger.cc:741
intptr_t capacity_in_words() const
Definition scavenger.h:54
intptr_t used_in_words() const
Definition scavenger.h:47
RelaxedAtomic< intptr_t > used_in_words
Definition spaces.h:21
static constexpr bool IsAligned(T x, uintptr_t alignment, uintptr_t offset=0)
Definition utils.h:77
#define ASSERT(E)
uint8_t value
GAsyncResult * result
constexpr intptr_t MB
Definition globals.h:530
StoreBuffer::Block StoreBufferBlock
static constexpr intptr_t kNewObjectAlignmentOffset
GCType
Definition spaces.h:32
MarkingStack::Block MarkingStackBlock
constexpr intptr_t kWordSizeLog2
Definition globals.h:507
constexpr intptr_t KB
Definition globals.h:528
uintptr_t uword
Definition globals.h:501
GCReason
Definition spaces.h:40
static constexpr intptr_t kObjectAlignmentMask
static constexpr intptr_t kObjectAlignment
const intptr_t kMaxAddrSpaceInWords
Definition globals.h:50
#define LIKELY(cond)
Definition globals.h:260
#define UNLIKELY(cond)
Definition globals.h:261
#define DISALLOW_COPY_AND_ASSIGN(TypeName)
Definition globals.h:581
static void usage(char *argv0)