Flutter Engine
The Flutter Engine
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
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 }
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; }
171 usage.used_in_words = UsedInWords();
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
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 PruneNew();
240 void PruneDeferred();
241 void Forward(MarkingStackBlock* blocks);
242 void ForwardDeferred();
243 void PruneWeak(GCLinkedLists* delayed);
244 template <typename Type, typename PtrType>
246
247 private:
248 // Ids for time and data records in Heap::GCStats.
249 enum {
250 // Time
251 kDummyScavengeTime = 0,
252 kSafePoint = 1,
253 kVisitIsolateRoots = 2,
254 kIterateStoreBuffers = 3,
255 kProcessToSpace = 4,
256 kIterateWeaks = 5,
257 };
258
259 uword TryAllocateFromTLAB(Thread* thread, intptr_t size) {
261 ASSERT(heap_ != Dart::vm_isolate_group()->heap());
262
263 const uword result = thread->top();
264 const intptr_t remaining = static_cast<intptr_t>(thread->end()) - result;
265 ASSERT(remaining >= 0);
266 if (UNLIKELY(remaining < size)) {
267 return 0;
268 }
269 ASSERT(to_->Contains(result));
271 thread->set_top(result + size);
272 return result;
273 }
274 void TryAllocateNewTLAB(Thread* thread, intptr_t size, bool can_safepoint);
275
276 SemiSpace* Prologue(GCReason reason);
277 intptr_t ParallelScavenge(SemiSpace* from);
278 intptr_t SerialScavenge(SemiSpace* from);
279 void ReverseScavenge(SemiSpace** from);
280 void IterateIsolateRoots(ObjectPointerVisitor* visitor);
281 template <bool parallel>
282 void IterateStoreBuffers(ScavengerVisitorBase<parallel>* visitor);
283 template <bool parallel>
284 void IterateRememberedCards(ScavengerVisitorBase<parallel>* visitor);
285 void IterateObjectIdTable(ObjectPointerVisitor* visitor);
286 template <bool parallel>
287 void IterateRoots(ScavengerVisitorBase<parallel>* visitor);
288 void IterateWeak();
289 void MournWeakHandles();
290 void MournWeakTables();
291 void Epilogue(SemiSpace* from);
292
293 void VerifyStoreBuffers(const char* msg);
294
295 void UpdateMaxHeapCapacity();
296 void UpdateMaxHeapUsage();
297
298 intptr_t NewSizeInWords(intptr_t old_size_in_words, GCReason reason) const;
299
300 Heap* heap_;
301
302 SemiSpace* to_;
303
304 PromotionStack promotion_stack_;
305
306 intptr_t max_semi_capacity_in_words_;
307
308 // Keep track whether a scavenge is currently running.
309 bool scavenging_ = false;
310 bool early_tenure_ = false;
311 RelaxedAtomic<intptr_t> root_slices_started_ = {0};
312 RelaxedAtomic<intptr_t> weak_slices_started_ = {0};
313 StoreBufferBlock* blocks_ = nullptr;
314 MarkingStackBlock* new_blocks_ = nullptr;
315 MarkingStackBlock* deferred_blocks_ = nullptr;
316
317 int64_t gc_time_micros_ = 0;
318 intptr_t collections_ = 0;
319 static constexpr int kStatsHistoryCapacity = 4;
320 RingBuffer<ScavengeStats, kStatsHistoryCapacity> stats_history_;
321
322 intptr_t scavenge_words_per_micro_;
323 intptr_t idle_scavenge_threshold_in_words_ = 0;
324
325 // The total size of external data associated with objects in this scavenger.
326 RelaxedAtomic<intptr_t> external_size_ = {0};
327 intptr_t freed_in_words_ = 0;
328
329 RelaxedAtomic<bool> failed_to_promote_ = {false};
330 RelaxedAtomic<bool> abort_ = {false};
331
332 // Protects new space during the allocation of new TLABs
333 mutable Mutex space_lock_;
334
335 template <bool>
337
339};
340
341} // namespace dart
342
343#endif // RUNTIME_VM_HEAP_SCAVENGER_H_
GLenum type
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)
Definition: scavenger.cc:1901
bool Contains(uword addr) const
Definition: scavenger.h:136
void ForwardDeferred()
Definition: scavenger.cc:1575
static intptr_t MaxMutatorThreadCount()
Definition: scavenger.h:228
intptr_t ExternalInWords() const
Definition: scavenger.h:168
void VisitObjects(ObjectVisitor *visitor) const
Definition: scavenger.cc:1784
void VisitObjectPointers(ObjectPointerVisitor *visitor) const
Definition: scavenger.cc:1775
void PruneDeferred()
Definition: scavenger.cc:1662
void PruneWeak(GCLinkedLists *delayed)
Definition: scavenger.cc:1700
void AddGCTime(int64_t micros)
Definition: scavenger.h:187
void WriteProtect(bool read_only)
Definition: scavenger.cc:2126
void AbandonRemainingTLABForDebugging(Thread *thread)
Definition: scavenger.cc:1850
bool ShouldPerformIdleScavenge(int64_t deadline)
Definition: scavenger.cc:1170
uword TryAllocate(Thread *thread, intptr_t size)
Definition: scavenger.h:138
void AddRegionsToObjectSet(ObjectSet *set) const
Definition: scavenger.cc:1793
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)
Definition: scavenger.cc:1863
intptr_t ThresholdInWords() const
Definition: scavenger.h:176
Scavenger(Heap *heap, intptr_t max_semi_capacity_in_words)
Definition: scavenger.cc:824
uword TryAllocateNoSafepoint(Thread *thread, intptr_t size)
Definition: scavenger.h:146
intptr_t collections() const
Definition: scavenger.h:193
void Forward(MarkingStackBlock *blocks)
Definition: scavenger.cc:1524
void PrintToJSONObject(JSONObject *object) const
Definition: scavenger.cc:2132
Page * head() const
Definition: scavenger.h:57
void AddList(Page *head, Page *tail)
Definition: scavenger.cc:805
void WriteProtect(bool read_only)
Definition: scavenger.cc:799
intptr_t gc_threshold_in_words() const
Definition: scavenger.h:55
Page * TryAllocatePageLocked(bool link)
Definition: scavenger.cc:772
bool Contains(uword addr) const
Definition: scavenger.cc:792
intptr_t capacity_in_words() const
Definition: scavenger.h:54
intptr_t used_in_words() const
Definition: scavenger.h:47
SemiSpace(intptr_t gc_threshold_in_words)
Definition: scavenger.cc:760
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:92
#define ASSERT(E)
uint8_t value
GAsyncResult * result
def link(from_root, to_root)
Definition: dart_pkg.py:44
Definition: dart_vm.cc:33
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
it will be possible to load the file into Perfetto s trace viewer disable asset Prevents usage of any non test fonts unless they were explicitly Loaded via prefetched default font Indicates whether the embedding started a prefetch of the default font manager before creating the engine run In non interactive keep the shell running after the Dart script has completed enable serial On low power devices with low core running concurrent GC tasks on threads can cause them to contend with the UI thread which could potentially lead to jank This option turns off all concurrent GC activities domain network JSON encoded network policy per domain This overrides the DisallowInsecureConnections switch Embedder can specify whether to allow or disallow insecure connections at a domain level old gen heap size
Definition: switches.h:259
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot The VM snapshot data that will be memory mapped as read only SnapshotAssetPath must be present isolate snapshot The isolate snapshot data that will be memory mapped as read only SnapshotAssetPath must be present cache dir Path to the cache directory This is different from the persistent_cache_path in embedder which is used for Skia shader cache icu native lib Path to the library file that exports the ICU data vm service The hostname IP address on which the Dart VM Service should be served If not set
Definition: switches.h:76
#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)