Add max post-gc heap usage metrics

- Add per heap max usage metrics.
- Add combined heap (max) usage metrics.

Fixes #24483

R=koda@google.com

Review URL: https://codereview.chromium.org/1384003004 .
diff --git a/runtime/vm/heap.cc b/runtime/vm/heap.cc
index 39d3478..670c868 100644
--- a/runtime/vm/heap.cc
+++ b/runtime/vm/heap.cc
@@ -453,6 +453,16 @@
 }
 
 
+void Heap::UpdateGlobalMaxUsed() {
+  ASSERT(isolate_ != NULL);
+  // We are accessing the used in words count for both new and old space
+  // without synchronizing. The value of this metric is approximate.
+  isolate_->GetHeapGlobalUsedMaxMetric()->SetValue(
+      (UsedInWords(Heap::kNew) * kWordSize) +
+      (UsedInWords(Heap::kOld) * kWordSize));
+}
+
+
 void Heap::SetGrowthControlState(bool state) {
   old_space_.SetGrowthControlState(state);
 }
@@ -568,8 +578,8 @@
 
 
 void Heap::PrintSizes() const {
-  OS::PrintErr("New space (%" Pd "k of %" Pd "k) "
-               "Old space (%" Pd "k of %" Pd "k)\n",
+  OS::PrintErr("New space (%" Pd64 "k of %" Pd64 "k) "
+               "Old space (%" Pd64 "k of %" Pd64 "k)\n",
                (UsedInWords(kNew) / KBInWords),
                (CapacityInWords(kNew) / KBInWords),
                (UsedInWords(kOld) / KBInWords),
@@ -577,21 +587,23 @@
 }
 
 
-intptr_t Heap::UsedInWords(Space space) const {
+int64_t Heap::UsedInWords(Space space) const {
   return space == kNew ? new_space_.UsedInWords() : old_space_.UsedInWords();
 }
 
 
-intptr_t Heap::CapacityInWords(Space space) const {
+int64_t Heap::CapacityInWords(Space space) const {
   return space == kNew ? new_space_.CapacityInWords() :
                          old_space_.CapacityInWords();
 }
 
-intptr_t Heap::ExternalInWords(Space space) const {
+
+int64_t Heap::ExternalInWords(Space space) const {
   return space == kNew ? new_space_.ExternalInWords() :
                          old_space_.ExternalInWords();
 }
 
+
 int64_t Heap::GCTimeInMicros(Space space) const {
   if (space == kNew) {
     return new_space_.gc_time_micros();
diff --git a/runtime/vm/heap.h b/runtime/vm/heap.h
index 496a9c8..4639c26 100644
--- a/runtime/vm/heap.h
+++ b/runtime/vm/heap.h
@@ -158,9 +158,9 @@
   void PrintSizes() const;
 
   // Return amount of memory used and capacity in a space, excluding external.
-  intptr_t UsedInWords(Space space) const;
-  intptr_t CapacityInWords(Space space) const;
-  intptr_t ExternalInWords(Space space) const;
+  int64_t UsedInWords(Space space) const;
+  int64_t CapacityInWords(Space space) const;
+  int64_t ExternalInWords(Space space) const;
   // Return the amount of GCing in microseconds.
   int64_t GCTimeInMicros(Space space) const;
 
@@ -222,6 +222,8 @@
 
   bool gc_in_progress();
 
+  void UpdateGlobalMaxUsed();
+
   static bool IsAllocatableInNewSpace(intptr_t size) {
     return size <= kNewAllocatableSize;
   }
diff --git a/runtime/vm/metrics.cc b/runtime/vm/metrics.cc
index 274a3fd..0e15c0f 100644
--- a/runtime/vm/metrics.cc
+++ b/runtime/vm/metrics.cc
@@ -276,6 +276,12 @@
 }
 
 
+int64_t MetricHeapUsed::Value() const {
+  ASSERT(isolate() == Isolate::Current());
+  return isolate()->heap()->UsedInWords(Heap::kNew) * kWordSize +
+         isolate()->heap()->UsedInWords(Heap::kOld) * kWordSize;
+}
+
 int64_t MetricIsolateCount::Value() const {
   return Isolate::IsolateListLength();
 }
diff --git a/runtime/vm/metrics.h b/runtime/vm/metrics.h
index 22f9a78..9fde2d8 100644
--- a/runtime/vm/metrics.h
+++ b/runtime/vm/metrics.h
@@ -15,13 +15,17 @@
 // Metrics for each isolate.
 #define ISOLATE_METRIC_LIST(V)                                                 \
   V(MetricHeapOldUsed, HeapOldUsed, "heap.old.used", kByte)                    \
+  V(MaxMetric, HeapOldUsedMax, "heap.old.used.max", kByte)                     \
   V(MetricHeapOldCapacity, HeapOldCapacity, "heap.old.capacity", kByte)        \
   V(MaxMetric, HeapOldCapacityMax, "heap.old.capacity.max", kByte)             \
   V(MetricHeapOldExternal, HeapOldExternal, "heap.old.external", kByte)        \
   V(MetricHeapNewUsed, HeapNewUsed, "heap.new.used", kByte)                    \
+  V(MaxMetric, HeapNewUsedMax, "heap.new.used.max", kByte)                     \
   V(MetricHeapNewCapacity, HeapNewCapacity, "heap.new.capacity", kByte)        \
   V(MaxMetric, HeapNewCapacityMax, "heap.new.capacity.max", kByte)             \
-  V(MetricHeapNewExternal, HeapNewExternal, "heap.new.external", kByte)
+  V(MetricHeapNewExternal, HeapNewExternal, "heap.new.external", kByte)        \
+  V(MetricHeapUsed, HeapGlobalUsed, "heap.global.used", kByte)                 \
+  V(MaxMetric, HeapGlobalUsedMax, "heap.global.used.max", kByte)               \
 
 #define VM_METRIC_LIST(V)                                                      \
   V(MetricIsolateCount, IsolateCount, "vm.isolate.count", kCounter)
@@ -166,6 +170,11 @@
 };
 
 
+class MetricHeapUsed : public Metric {
+ protected:
+  virtual int64_t Value() const;
+};
+
 }  // namespace dart
 
 #endif  // VM_METRICS_H_
diff --git a/runtime/vm/pages.cc b/runtime/vm/pages.cc
index 7cee6df..da7ec80 100644
--- a/runtime/vm/pages.cc
+++ b/runtime/vm/pages.cc
@@ -171,6 +171,7 @@
       collections_(0) {
   // We aren't holding the lock but no one can reference us yet.
   UpdateMaxCapacityLocked();
+  UpdateMaxUsed();
 }
 
 
@@ -547,6 +548,19 @@
 }
 
 
+void PageSpace::UpdateMaxUsed() {
+  if (heap_ == NULL) {
+    // Some unit tests.
+    return;
+  }
+  ASSERT(heap_ != NULL);
+  ASSERT(heap_->isolate() != NULL);
+  Isolate* isolate = heap_->isolate();
+  isolate->GetHeapOldUsedMaxMetric()->SetValue(
+      UsedInWords() * kWordSize);
+}
+
+
 bool PageSpace::Contains(uword addr) const {
   for (ExclusivePageIterator it(this); !it.Done(); it.Advance()) {
     if (it.page()->Contains(addr)) {
@@ -662,9 +676,9 @@
   space.AddProperty("name", "old");
   space.AddProperty("vmName", "PageSpace");
   space.AddProperty("collections", collections());
-  space.AddProperty("used", UsedInWords() * kWordSize);
-  space.AddProperty("capacity", CapacityInWords() * kWordSize);
-  space.AddProperty("external", ExternalInWords() * kWordSize);
+  space.AddProperty64("used", UsedInWords() * kWordSize);
+  space.AddProperty64("capacity", CapacityInWords() * kWordSize);
+  space.AddProperty64("external", ExternalInWords() * kWordSize);
   space.AddProperty("time", MicrosecondsToSeconds(gc_time_micros()));
   if (collections() > 0) {
     int64_t run_time = OS::GetCurrentTimeMicros() - isolate->start_time();
@@ -932,6 +946,11 @@
     freelist_[HeapPage::kExecutable].Print();
   }
 
+  UpdateMaxUsed();
+  if (heap_ != NULL) {
+    heap_->UpdateGlobalMaxUsed();
+  }
+
   isolate->thread_registry()->ResumeAllThreads();
 
   // Done, reset the task count.
diff --git a/runtime/vm/pages.h b/runtime/vm/pages.h
index 7cc123b6..39ef84e 100644
--- a/runtime/vm/pages.h
+++ b/runtime/vm/pages.h
@@ -218,8 +218,8 @@
            NeedsExternalGC();
   }
 
-  intptr_t UsedInWords() const { return usage_.used_in_words; }
-  intptr_t CapacityInWords() const {
+  int64_t UsedInWords() const { return usage_.used_in_words; }
+  int64_t CapacityInWords() const {
     MutexLocker ml(pages_lock_);
     return usage_.capacity_in_words;
   }
@@ -234,8 +234,9 @@
   }
 
   void UpdateMaxCapacityLocked();
+  void UpdateMaxUsed();
 
-  intptr_t ExternalInWords() const {
+  int64_t ExternalInWords() const {
     return usage_.external_in_words;
   }
   SpaceUsage GetCurrentUsage() const {
diff --git a/runtime/vm/scavenger.cc b/runtime/vm/scavenger.cc
index e885b98..f526af1 100644
--- a/runtime/vm/scavenger.cc
+++ b/runtime/vm/scavenger.cc
@@ -415,13 +415,18 @@
   if (to_ == NULL) {
     FATAL("Out of memory.\n");
   }
-  UpdateMaxHeapCapacity();
   // Setup local fields.
   top_ = FirstObjectStart();
   resolved_top_ = top_;
   end_ = to_->end();
 
   survivor_end_ = FirstObjectStart();
+
+  UpdateMaxHeapCapacity();
+  UpdateMaxHeapUsage();
+  if (heap_ != NULL) {
+    heap_->UpdateGlobalMaxUsed();
+  }
 }
 
 
@@ -501,6 +506,10 @@
   }
 #endif  // defined(DEBUG)
   from->Delete();
+  UpdateMaxHeapUsage();
+  if (heap_ != NULL) {
+    heap_->UpdateGlobalMaxUsed();
+  }
   if (invoke_api_callbacks && (isolate->gc_epilogue_callback() != NULL)) {
     (isolate->gc_epilogue_callback())();
   }
@@ -720,6 +729,19 @@
 }
 
 
+void Scavenger::UpdateMaxHeapUsage() {
+  if (heap_ == NULL) {
+    // Some unit tests.
+    return;
+  }
+  ASSERT(to_ != NULL);
+  ASSERT(heap_ != NULL);
+  Isolate* isolate = heap_->isolate();
+  ASSERT(isolate != NULL);
+  isolate->GetHeapNewUsedMaxMetric()->SetValue(UsedInWords() * kWordSize);
+}
+
+
 uword Scavenger::ProcessWeakProperty(RawWeakProperty* raw_weak,
                                      ScavengerVisitor* visitor) {
   // The fate of the weak property is determined by its key.
@@ -916,9 +938,9 @@
   } else {
     space.AddProperty("avgCollectionPeriodMillis", 0.0);
   }
-  space.AddProperty("used", UsedInWords() * kWordSize);
-  space.AddProperty("capacity", CapacityInWords() * kWordSize);
-  space.AddProperty("external", ExternalInWords() * kWordSize);
+  space.AddProperty64("used", UsedInWords() * kWordSize);
+  space.AddProperty64("capacity", CapacityInWords() * kWordSize);
+  space.AddProperty64("external", ExternalInWords() * kWordSize);
   space.AddProperty("time", MicrosecondsToSeconds(gc_time_micros()));
 }
 
diff --git a/runtime/vm/scavenger.h b/runtime/vm/scavenger.h
index d265ab9..af3f129 100644
--- a/runtime/vm/scavenger.h
+++ b/runtime/vm/scavenger.h
@@ -164,13 +164,13 @@
   static intptr_t top_offset() { return OFFSET_OF(Scavenger, top_); }
   static intptr_t end_offset() { return OFFSET_OF(Scavenger, end_); }
 
-  intptr_t UsedInWords() const {
+  int64_t UsedInWords() const {
     return (top_ - FirstObjectStart()) >> kWordSizeLog2;
   }
-  intptr_t CapacityInWords() const {
+  int64_t CapacityInWords() const {
     return to_->size_in_words();
   }
-  intptr_t ExternalInWords() const {
+  int64_t ExternalInWords() const {
     return external_size_ >> kWordSizeLog2;
   }
   SpaceUsage GetCurrentUsage() const {
@@ -269,6 +269,7 @@
   }
 
   void UpdateMaxHeapCapacity();
+  void UpdateMaxHeapUsage();
 
   void ProcessWeakTables();