| Index: runtime/vm/heap.cc
|
| ===================================================================
|
| --- runtime/vm/heap.cc (revision 16586)
|
| +++ runtime/vm/heap.cc (working copy)
|
| @@ -23,6 +23,7 @@
|
| namespace dart {
|
|
|
| DEFINE_FLAG(bool, verbose_gc, false, "Enables verbose GC.");
|
| +DEFINE_FLAG(int, verbose_gc_hdr, 40, "Print verbose GC header interval.");
|
| DEFINE_FLAG(bool, verify_before_gc, false,
|
| "Enables heap verification before GC.");
|
| DEFINE_FLAG(bool, verify_after_gc, false,
|
| @@ -39,6 +40,7 @@
|
| (FLAG_new_gen_heap_size * MB),
|
| kNewObjectAlignmentOffset);
|
| old_space_ = new PageSpace(this, (FLAG_old_gen_heap_size * MB));
|
| + stats_.num_ = 0;
|
| heap_trace_ = new HeapTrace;
|
| }
|
|
|
| @@ -151,25 +153,27 @@
|
| bool invoke_api_callbacks = (api_callbacks == kInvokeApiCallbacks);
|
| switch (space) {
|
| case kNew: {
|
| - new_space_->Scavenge(invoke_api_callbacks,
|
| - GCReasonToString(kNewSpace));
|
| + RecordBeforeGC(kNew, kNewSpace);
|
| + new_space_->Scavenge(invoke_api_callbacks);
|
| + RecordAfterGC();
|
| + PrintStats();
|
| if (new_space_->HadPromotionFailure()) {
|
| - old_space_->MarkSweep(true,
|
| - GCReasonToString(kPromotionFailure));
|
| + CollectGarbage(kOld, api_callbacks);
|
| }
|
| break;
|
| }
|
| case kOld:
|
| - case kCode:
|
| - old_space_->MarkSweep(invoke_api_callbacks,
|
| - GCReasonToString(kOldSpace));
|
| + case kCode: {
|
| + bool promotion_failure = new_space_->HadPromotionFailure();
|
| + RecordBeforeGC(kOld, promotion_failure ? kPromotionFailure : kOldSpace);
|
| + old_space_->MarkSweep(invoke_api_callbacks);
|
| + RecordAfterGC();
|
| + PrintStats();
|
| break;
|
| + }
|
| default:
|
| UNREACHABLE();
|
| }
|
| - if (FLAG_verbose_gc) {
|
| - PrintSizes();
|
| - }
|
| }
|
|
|
|
|
| @@ -185,12 +189,14 @@
|
|
|
|
|
| void Heap::CollectAllGarbage() {
|
| - const char* gc_reason = GCReasonToString(kFull);
|
| - new_space_->Scavenge(kInvokeApiCallbacks, gc_reason);
|
| - old_space_->MarkSweep(kInvokeApiCallbacks, gc_reason);
|
| - if (FLAG_verbose_gc) {
|
| - PrintSizes();
|
| - }
|
| + RecordBeforeGC(kNew, kFull);
|
| + new_space_->Scavenge(kInvokeApiCallbacks);
|
| + RecordAfterGC();
|
| + PrintStats();
|
| + RecordBeforeGC(kOld, kFull);
|
| + old_space_->MarkSweep(kInvokeApiCallbacks);
|
| + RecordAfterGC();
|
| + PrintStats();
|
| }
|
|
|
|
|
| @@ -323,8 +329,6 @@
|
| return "promotion failure";
|
| case kOldSpace:
|
| return "old space";
|
| - case kCodeSpace:
|
| - return "code space";
|
| case kFull:
|
| return "full";
|
| case kGCAtAlloc:
|
| @@ -362,6 +366,96 @@
|
| }
|
|
|
|
|
| +void Heap::RecordBeforeGC(Space space, GCReason reason) {
|
| + stats_.num_++;
|
| + stats_.space_ = space;
|
| + stats_.reason_ = reason;
|
| + stats_.before_.micros_ = OS::GetCurrentTimeMicros();
|
| + stats_.before_.new_used_ = new_space_->in_use();
|
| + stats_.before_.new_capacity_ = new_space_->capacity();
|
| + stats_.before_.old_used_ = old_space_->in_use();
|
| + stats_.before_.old_capacity_ = old_space_->capacity();
|
| + stats_.times_[0] = 0;
|
| + stats_.times_[1] = 0;
|
| + stats_.times_[2] = 0;
|
| + stats_.times_[3] = 0;
|
| + stats_.data_[0] = 0;
|
| + stats_.data_[1] = 0;
|
| + stats_.data_[2] = 0;
|
| + stats_.data_[3] = 0;
|
| +}
|
| +
|
| +
|
| +void Heap::RecordAfterGC() {
|
| + stats_.after_.micros_ = OS::GetCurrentTimeMicros();
|
| + stats_.after_.new_used_ = new_space_->in_use();
|
| + stats_.after_.new_capacity_ = new_space_->capacity();
|
| + stats_.after_.old_used_ = old_space_->in_use();
|
| + stats_.after_.old_capacity_ = old_space_->capacity();
|
| +}
|
| +
|
| +
|
| +static intptr_t RoundToKB(intptr_t memory_size) {
|
| + return (memory_size + (KB >> 1)) >> KBLog2;
|
| +}
|
| +
|
| +
|
| +static double RoundToSecs(int64_t micros) {
|
| + const int k1M = 1000000; // Converting us to secs.
|
| + return static_cast<double>(micros + (k1M / 2)) / k1M;
|
| +}
|
| +
|
| +
|
| +static double RoundToMillis(int64_t micros) {
|
| + const int k1K = 1000; // Conversting us to ms.
|
| + return static_cast<double>(micros + (k1K / 2)) / k1K;
|
| +}
|
| +
|
| +
|
| +void Heap::PrintStats() {
|
| + if (!FLAG_verbose_gc) return;
|
| + Isolate* isolate = Isolate::Current();
|
| +
|
| + if ((FLAG_verbose_gc_hdr != 0) &&
|
| + (((stats_.num_ - 1) % FLAG_verbose_gc_hdr) == 0)) {
|
| + OS::PrintErr("[ GC | space | count | start | gc time | "
|
| + "new gen (KB) | old gen (KB) | timers | data ]\n"
|
| + "[ (isolate)| (reason)| | (s) | (ms) | "
|
| + " used , cap | used , cap | (ms) | ]\n");
|
| + }
|
| +
|
| + const char* space_str = stats_.space_ == kNew ? "Scavenge" : "Mark-Sweep";
|
| + OS::PrintErr(
|
| + "[ GC(%"Pd64"): %s(%s), " // GC(isolate), space(reason)
|
| + "%"Pd", " // count
|
| + "%.3f, " // start time
|
| + "%.3f, " // total time
|
| + "%"Pd", %"Pd", %"Pd", %"Pd", " // new gen: in use, capacity before/after
|
| + "%"Pd", %"Pd", %"Pd", %"Pd", " // old gen: in use, capacity before/after
|
| + "%.3f, %.3f, %.3f, %.3f, " // times
|
| + "%"Pd", %"Pd", %"Pd", %"Pd", " // data
|
| + "]\n", // End with a comma to make it easier to import in spreadsheets.
|
| + isolate->main_port(), space_str, GCReasonToString(stats_.reason_),
|
| + stats_.num_,
|
| + RoundToSecs(stats_.before_.micros_ - isolate->start_time()),
|
| + RoundToMillis(stats_.after_.micros_ - stats_.before_.micros_),
|
| + RoundToKB(stats_.before_.new_used_), RoundToKB(stats_.after_.new_used_),
|
| + RoundToKB(stats_.before_.new_capacity_),
|
| + RoundToKB(stats_.after_.new_capacity_),
|
| + RoundToKB(stats_.before_.old_used_), RoundToKB(stats_.after_.old_used_),
|
| + RoundToKB(stats_.before_.old_capacity_),
|
| + RoundToKB(stats_.after_.old_capacity_),
|
| + RoundToMillis(stats_.times_[0]),
|
| + RoundToMillis(stats_.times_[1]),
|
| + RoundToMillis(stats_.times_[2]),
|
| + RoundToMillis(stats_.times_[3]),
|
| + stats_.data_[0],
|
| + stats_.data_[1],
|
| + stats_.data_[2],
|
| + stats_.data_[3]);
|
| +}
|
| +
|
| +
|
| #if defined(DEBUG)
|
| NoGCScope::NoGCScope() : StackResource(Isolate::Current()) {
|
| isolate()->IncrementNoGCScopeDepth();
|
|
|