OLD | NEW |
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/heap.h" | 5 #include "vm/heap.h" |
6 | 6 |
7 #include "platform/assert.h" | 7 #include "platform/assert.h" |
8 #include "platform/utils.h" | 8 #include "platform/utils.h" |
9 #include "vm/flags.h" | 9 #include "vm/flags.h" |
10 #include "vm/heap_profiler.h" | 10 #include "vm/heap_profiler.h" |
11 #include "vm/heap_trace.h" | 11 #include "vm/heap_trace.h" |
12 #include "vm/isolate.h" | 12 #include "vm/isolate.h" |
13 #include "vm/object.h" | 13 #include "vm/object.h" |
14 #include "vm/object_set.h" | 14 #include "vm/object_set.h" |
15 #include "vm/os.h" | 15 #include "vm/os.h" |
16 #include "vm/pages.h" | 16 #include "vm/pages.h" |
17 #include "vm/raw_object.h" | 17 #include "vm/raw_object.h" |
18 #include "vm/scavenger.h" | 18 #include "vm/scavenger.h" |
19 #include "vm/stack_frame.h" | 19 #include "vm/stack_frame.h" |
20 #include "vm/verifier.h" | 20 #include "vm/verifier.h" |
21 #include "vm/virtual_memory.h" | 21 #include "vm/virtual_memory.h" |
22 | 22 |
23 namespace dart { | 23 namespace dart { |
24 | 24 |
25 DEFINE_FLAG(bool, verbose_gc, false, "Enables verbose GC."); | 25 DEFINE_FLAG(bool, verbose_gc, false, "Enables verbose GC."); |
| 26 DEFINE_FLAG(int, verbose_gc_hdr, 40, "Print verbose GC header interval."); |
26 DEFINE_FLAG(bool, verify_before_gc, false, | 27 DEFINE_FLAG(bool, verify_before_gc, false, |
27 "Enables heap verification before GC."); | 28 "Enables heap verification before GC."); |
28 DEFINE_FLAG(bool, verify_after_gc, false, | 29 DEFINE_FLAG(bool, verify_after_gc, false, |
29 "Enables heap verification after GC."); | 30 "Enables heap verification after GC."); |
30 DEFINE_FLAG(bool, gc_at_alloc, false, "GC at every allocation."); | 31 DEFINE_FLAG(bool, gc_at_alloc, false, "GC at every allocation."); |
31 DEFINE_FLAG(int, new_gen_heap_size, 32, "new gen heap size in MB," | 32 DEFINE_FLAG(int, new_gen_heap_size, 32, "new gen heap size in MB," |
32 "e.g: --new_gen_heap_size=64 allocates a 64MB new gen heap"); | 33 "e.g: --new_gen_heap_size=64 allocates a 64MB new gen heap"); |
33 DEFINE_FLAG(int, old_gen_heap_size, Heap::kHeapSizeInMB, | 34 DEFINE_FLAG(int, old_gen_heap_size, Heap::kHeapSizeInMB, |
34 "old gen heap size in MB," | 35 "old gen heap size in MB," |
35 "e.g: --old_gen_heap_size=1024 allocates a 1024MB old gen heap"); | 36 "e.g: --old_gen_heap_size=1024 allocates a 1024MB old gen heap"); |
36 | 37 |
37 Heap::Heap() : read_only_(false) { | 38 Heap::Heap() : read_only_(false) { |
38 new_space_ = new Scavenger(this, | 39 new_space_ = new Scavenger(this, |
39 (FLAG_new_gen_heap_size * MB), | 40 (FLAG_new_gen_heap_size * MB), |
40 kNewObjectAlignmentOffset); | 41 kNewObjectAlignmentOffset); |
41 old_space_ = new PageSpace(this, (FLAG_old_gen_heap_size * MB)); | 42 old_space_ = new PageSpace(this, (FLAG_old_gen_heap_size * MB)); |
| 43 stats_.num_ = 0; |
42 heap_trace_ = new HeapTrace; | 44 heap_trace_ = new HeapTrace; |
43 } | 45 } |
44 | 46 |
45 | 47 |
46 Heap::~Heap() { | 48 Heap::~Heap() { |
47 delete new_space_; | 49 delete new_space_; |
48 delete old_space_; | 50 delete old_space_; |
49 } | 51 } |
50 | 52 |
51 | 53 |
(...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
144 ASSERT((raw_obj == Object::null()) || | 146 ASSERT((raw_obj == Object::null()) || |
145 (raw_obj->GetClassId() == kInstructionsCid)); | 147 (raw_obj->GetClassId() == kInstructionsCid)); |
146 return reinterpret_cast<RawInstructions*>(raw_obj); | 148 return reinterpret_cast<RawInstructions*>(raw_obj); |
147 } | 149 } |
148 | 150 |
149 | 151 |
150 void Heap::CollectGarbage(Space space, ApiCallbacks api_callbacks) { | 152 void Heap::CollectGarbage(Space space, ApiCallbacks api_callbacks) { |
151 bool invoke_api_callbacks = (api_callbacks == kInvokeApiCallbacks); | 153 bool invoke_api_callbacks = (api_callbacks == kInvokeApiCallbacks); |
152 switch (space) { | 154 switch (space) { |
153 case kNew: { | 155 case kNew: { |
154 new_space_->Scavenge(invoke_api_callbacks, | 156 RecordBeforeGC(kNew, kNewSpace); |
155 GCReasonToString(kNewSpace)); | 157 new_space_->Scavenge(invoke_api_callbacks); |
| 158 RecordAfterGC(); |
| 159 PrintStats(); |
156 if (new_space_->HadPromotionFailure()) { | 160 if (new_space_->HadPromotionFailure()) { |
157 old_space_->MarkSweep(true, | 161 CollectGarbage(kOld, api_callbacks); |
158 GCReasonToString(kPromotionFailure)); | |
159 } | 162 } |
160 break; | 163 break; |
161 } | 164 } |
162 case kOld: | 165 case kOld: |
163 case kCode: | 166 case kCode: { |
164 old_space_->MarkSweep(invoke_api_callbacks, | 167 bool promotion_failure = new_space_->HadPromotionFailure(); |
165 GCReasonToString(kOldSpace)); | 168 RecordBeforeGC(kOld, promotion_failure ? kPromotionFailure : kOldSpace); |
| 169 old_space_->MarkSweep(invoke_api_callbacks); |
| 170 RecordAfterGC(); |
| 171 PrintStats(); |
166 break; | 172 break; |
| 173 } |
167 default: | 174 default: |
168 UNREACHABLE(); | 175 UNREACHABLE(); |
169 } | 176 } |
170 if (FLAG_verbose_gc) { | |
171 PrintSizes(); | |
172 } | |
173 } | 177 } |
174 | 178 |
175 | 179 |
176 void Heap::CollectGarbage(Space space) { | 180 void Heap::CollectGarbage(Space space) { |
177 ApiCallbacks api_callbacks; | 181 ApiCallbacks api_callbacks; |
178 if (space == kOld) { | 182 if (space == kOld) { |
179 api_callbacks = kInvokeApiCallbacks; | 183 api_callbacks = kInvokeApiCallbacks; |
180 } else { | 184 } else { |
181 api_callbacks = kIgnoreApiCallbacks; | 185 api_callbacks = kIgnoreApiCallbacks; |
182 } | 186 } |
183 CollectGarbage(space, api_callbacks); | 187 CollectGarbage(space, api_callbacks); |
184 } | 188 } |
185 | 189 |
186 | 190 |
187 void Heap::CollectAllGarbage() { | 191 void Heap::CollectAllGarbage() { |
188 const char* gc_reason = GCReasonToString(kFull); | 192 RecordBeforeGC(kNew, kFull); |
189 new_space_->Scavenge(kInvokeApiCallbacks, gc_reason); | 193 new_space_->Scavenge(kInvokeApiCallbacks); |
190 old_space_->MarkSweep(kInvokeApiCallbacks, gc_reason); | 194 RecordAfterGC(); |
191 if (FLAG_verbose_gc) { | 195 PrintStats(); |
192 PrintSizes(); | 196 RecordBeforeGC(kOld, kFull); |
193 } | 197 old_space_->MarkSweep(kInvokeApiCallbacks); |
| 198 RecordAfterGC(); |
| 199 PrintStats(); |
194 } | 200 } |
195 | 201 |
196 | 202 |
197 void Heap::EnableGrowthControl() { | 203 void Heap::EnableGrowthControl() { |
198 old_space_->EnableGrowthControl(); | 204 old_space_->EnableGrowthControl(); |
199 } | 205 } |
200 | 206 |
201 | 207 |
202 void Heap::WriteProtect(bool read_only) { | 208 void Heap::WriteProtect(bool read_only) { |
203 read_only_ = read_only; | 209 read_only_ = read_only; |
(...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
316 | 322 |
317 | 323 |
318 const char* Heap::GCReasonToString(GCReason gc_reason) { | 324 const char* Heap::GCReasonToString(GCReason gc_reason) { |
319 switch (gc_reason) { | 325 switch (gc_reason) { |
320 case kNewSpace: | 326 case kNewSpace: |
321 return "new space"; | 327 return "new space"; |
322 case kPromotionFailure: | 328 case kPromotionFailure: |
323 return "promotion failure"; | 329 return "promotion failure"; |
324 case kOldSpace: | 330 case kOldSpace: |
325 return "old space"; | 331 return "old space"; |
326 case kCodeSpace: | |
327 return "code space"; | |
328 case kFull: | 332 case kFull: |
329 return "full"; | 333 return "full"; |
330 case kGCAtAlloc: | 334 case kGCAtAlloc: |
331 return "debugging"; | 335 return "debugging"; |
332 case kGCTestCase: | 336 case kGCTestCase: |
333 return "test case"; | 337 return "test case"; |
334 default: | 338 default: |
335 UNREACHABLE(); | 339 UNREACHABLE(); |
336 return ""; | 340 return ""; |
337 } | 341 } |
(...skipping 17 matching lines...) Expand all Loading... |
355 ASSERT(raw_obj->IsOldObject()); | 359 ASSERT(raw_obj->IsOldObject()); |
356 return old_space_->GetPeer(raw_obj); | 360 return old_space_->GetPeer(raw_obj); |
357 } | 361 } |
358 | 362 |
359 | 363 |
360 int64_t Heap::PeerCount() const { | 364 int64_t Heap::PeerCount() const { |
361 return new_space_->PeerCount() + old_space_->PeerCount(); | 365 return new_space_->PeerCount() + old_space_->PeerCount(); |
362 } | 366 } |
363 | 367 |
364 | 368 |
| 369 void Heap::RecordBeforeGC(Space space, GCReason reason) { |
| 370 stats_.num_++; |
| 371 stats_.space_ = space; |
| 372 stats_.reason_ = reason; |
| 373 stats_.before_.micros_ = OS::GetCurrentTimeMicros(); |
| 374 stats_.before_.new_used_ = new_space_->in_use(); |
| 375 stats_.before_.new_capacity_ = new_space_->capacity(); |
| 376 stats_.before_.old_used_ = old_space_->in_use(); |
| 377 stats_.before_.old_capacity_ = old_space_->capacity(); |
| 378 stats_.times_[0] = 0; |
| 379 stats_.times_[1] = 0; |
| 380 stats_.times_[2] = 0; |
| 381 stats_.times_[3] = 0; |
| 382 stats_.data_[0] = 0; |
| 383 stats_.data_[1] = 0; |
| 384 stats_.data_[2] = 0; |
| 385 stats_.data_[3] = 0; |
| 386 } |
| 387 |
| 388 |
| 389 void Heap::RecordAfterGC() { |
| 390 stats_.after_.micros_ = OS::GetCurrentTimeMicros(); |
| 391 stats_.after_.new_used_ = new_space_->in_use(); |
| 392 stats_.after_.new_capacity_ = new_space_->capacity(); |
| 393 stats_.after_.old_used_ = old_space_->in_use(); |
| 394 stats_.after_.old_capacity_ = old_space_->capacity(); |
| 395 } |
| 396 |
| 397 |
| 398 static intptr_t RoundToKB(intptr_t memory_size) { |
| 399 return (memory_size + (KB >> 1)) >> KBLog2; |
| 400 } |
| 401 |
| 402 |
| 403 static double RoundToSecs(int64_t micros) { |
| 404 const int k1M = 1000000; // Converting us to secs. |
| 405 return static_cast<double>(micros + (k1M / 2)) / k1M; |
| 406 } |
| 407 |
| 408 |
| 409 static double RoundToMillis(int64_t micros) { |
| 410 const int k1K = 1000; // Conversting us to ms. |
| 411 return static_cast<double>(micros + (k1K / 2)) / k1K; |
| 412 } |
| 413 |
| 414 |
| 415 void Heap::PrintStats() { |
| 416 if (!FLAG_verbose_gc) return; |
| 417 Isolate* isolate = Isolate::Current(); |
| 418 |
| 419 if ((FLAG_verbose_gc_hdr != 0) && |
| 420 (((stats_.num_ - 1) % FLAG_verbose_gc_hdr) == 0)) { |
| 421 OS::PrintErr("[ GC | space | count | start | gc time | " |
| 422 "new gen (KB) | old gen (KB) | timers | data ]\n" |
| 423 "[ (isolate)| (reason)| | (s) | (ms) | " |
| 424 " used , cap | used , cap | (ms) | ]\n"); |
| 425 } |
| 426 |
| 427 const char* space_str = stats_.space_ == kNew ? "Scavenge" : "Mark-Sweep"; |
| 428 OS::PrintErr( |
| 429 "[ GC(%"Pd64"): %s(%s), " // GC(isolate), space(reason) |
| 430 "%"Pd", " // count |
| 431 "%.3f, " // start time |
| 432 "%.3f, " // total time |
| 433 "%"Pd", %"Pd", %"Pd", %"Pd", " // new gen: in use, capacity before/after |
| 434 "%"Pd", %"Pd", %"Pd", %"Pd", " // old gen: in use, capacity before/after |
| 435 "%.3f, %.3f, %.3f, %.3f, " // times |
| 436 "%"Pd", %"Pd", %"Pd", %"Pd", " // data |
| 437 "]\n", // End with a comma to make it easier to import in spreadsheets. |
| 438 isolate->main_port(), space_str, GCReasonToString(stats_.reason_), |
| 439 stats_.num_, |
| 440 RoundToSecs(stats_.before_.micros_ - isolate->start_time()), |
| 441 RoundToMillis(stats_.after_.micros_ - stats_.before_.micros_), |
| 442 RoundToKB(stats_.before_.new_used_), RoundToKB(stats_.after_.new_used_), |
| 443 RoundToKB(stats_.before_.new_capacity_), |
| 444 RoundToKB(stats_.after_.new_capacity_), |
| 445 RoundToKB(stats_.before_.old_used_), RoundToKB(stats_.after_.old_used_), |
| 446 RoundToKB(stats_.before_.old_capacity_), |
| 447 RoundToKB(stats_.after_.old_capacity_), |
| 448 RoundToMillis(stats_.times_[0]), |
| 449 RoundToMillis(stats_.times_[1]), |
| 450 RoundToMillis(stats_.times_[2]), |
| 451 RoundToMillis(stats_.times_[3]), |
| 452 stats_.data_[0], |
| 453 stats_.data_[1], |
| 454 stats_.data_[2], |
| 455 stats_.data_[3]); |
| 456 } |
| 457 |
| 458 |
365 #if defined(DEBUG) | 459 #if defined(DEBUG) |
366 NoGCScope::NoGCScope() : StackResource(Isolate::Current()) { | 460 NoGCScope::NoGCScope() : StackResource(Isolate::Current()) { |
367 isolate()->IncrementNoGCScopeDepth(); | 461 isolate()->IncrementNoGCScopeDepth(); |
368 } | 462 } |
369 | 463 |
370 | 464 |
371 NoGCScope::~NoGCScope() { | 465 NoGCScope::~NoGCScope() { |
372 isolate()->DecrementNoGCScopeDepth(); | 466 isolate()->DecrementNoGCScopeDepth(); |
373 } | 467 } |
374 #endif // defined(DEBUG) | 468 #endif // defined(DEBUG) |
375 | 469 |
376 } // namespace dart | 470 } // namespace dart |
OLD | NEW |