Exposes VM and Isolate Metrics in the API.

This change allows devs embedding the VM in e.g. a server to e.g. export VM metrics as part of their server health metrics.

Change-Id: I7a86a3ad98b900d30d9b7f5d19fa77f1705610c6
Reviewed-on: https://dart-review.googlesource.com/c/74723
Reviewed-by: Zach Anderson <zra@google.com>
Commit-Queue: Clement Skau <cskau@google.com>
diff --git a/runtime/include/dart_tools_api.h b/runtime/include/dart_tools_api.h
index 707f726..4ee47ef 100644
--- a/runtime/include/dart_tools_api.h
+++ b/runtime/include/dart_tools_api.h
@@ -442,4 +442,48 @@
     Dart_EmbedderTimelineStartRecording start_recording,
     Dart_EmbedderTimelineStopRecording stop_recording);
 
+/*
+ * =======
+ * Metrics
+ * =======
+ */
+
+/**
+ * Return metrics gathered for the VM and individual isolates.
+ *
+ * NOTE: Metrics are not available in PRODUCT builds of Dart.
+ * Calling the metric functions on a PRODUCT build might return invalid metrics.
+ */
+DART_EXPORT int64_t Dart_VMIsolateCountMetric();  // Counter
+DART_EXPORT int64_t Dart_VMCurrentRSSMetric();    // Byte
+DART_EXPORT int64_t Dart_VMPeakRSSMetric();       // Byte
+DART_EXPORT int64_t
+Dart_IsolateHeapOldUsedMetric(Dart_Isolate isolate);  // Byte
+DART_EXPORT int64_t
+Dart_IsolateHeapOldUsedMaxMetric(Dart_Isolate isolate);  // Byte
+DART_EXPORT int64_t
+Dart_IsolateHeapOldCapacityMetric(Dart_Isolate isolate);  // Byte
+DART_EXPORT int64_t
+Dart_IsolateHeapOldCapacityMaxMetric(Dart_Isolate isolate);  // Byte
+DART_EXPORT int64_t
+Dart_IsolateHeapOldExternalMetric(Dart_Isolate isolate);  // Byte
+DART_EXPORT int64_t
+Dart_IsolateHeapNewUsedMetric(Dart_Isolate isolate);  // Byte
+DART_EXPORT int64_t
+Dart_IsolateHeapNewUsedMaxMetric(Dart_Isolate isolate);  // Byte
+DART_EXPORT int64_t
+Dart_IsolateHeapNewCapacityMetric(Dart_Isolate isolate);  // Byte
+DART_EXPORT int64_t
+Dart_IsolateHeapNewCapacityMaxMetric(Dart_Isolate isolate);  // Byte
+DART_EXPORT int64_t
+Dart_IsolateHeapNewExternalMetric(Dart_Isolate isolate);  // Byte
+DART_EXPORT int64_t
+Dart_IsolateHeapGlobalUsedMetric(Dart_Isolate isolate);  // Byte
+DART_EXPORT int64_t
+Dart_IsolateHeapGlobalUsedMaxMetric(Dart_Isolate isolate);  // Byte
+DART_EXPORT int64_t
+Dart_IsolateRunnableLatencyMetric(Dart_Isolate isolate);  // Microsecond
+DART_EXPORT int64_t
+Dart_IsolateRunnableHeapSizeMetric(Dart_Isolate isolate);  // Byte
+
 #endif  // RUNTIME_INCLUDE_DART_TOOLS_API_H_
diff --git a/runtime/vm/dart_api_impl.cc b/runtime/vm/dart_api_impl.cc
index a31abce..b2055ad 100644
--- a/runtime/vm/dart_api_impl.cc
+++ b/runtime/vm/dart_api_impl.cc
@@ -1022,6 +1022,37 @@
   return Flags::IsSet(flag_name);
 }
 
+#if !defined(PRODUCT)
+#define VM_METRIC_API(type, variable, name, unit)                              \
+  DART_EXPORT int64_t Dart_VM##variable##Metric() {                            \
+    return vm_metric_##variable##_.value();                                    \
+  }
+VM_METRIC_LIST(VM_METRIC_API);
+#undef VM_METRIC_API
+
+#define ISOLATE_METRIC_API(type, variable, name, unit)                         \
+  DART_EXPORT int64_t Dart_Isolate##variable##Metric(Dart_Isolate isolate) {   \
+    if (isolate == NULL) {                                                     \
+      FATAL1("%s expects argument 'isolate' to be non-null.", CURRENT_FUNC);   \
+    }                                                                          \
+    Isolate* iso = reinterpret_cast<Isolate*>(isolate);                        \
+    return iso->Get##variable##Metric()->value();                              \
+  }
+ISOLATE_METRIC_LIST(ISOLATE_METRIC_API);
+#undef ISOLATE_METRIC_API
+#else  // !defined(PRODUCT)
+#define VM_METRIC_API(type, variable, name, unit)                              \
+  DART_EXPORT int64_t Dart_VM##variable##Metric() { return -1; }
+VM_METRIC_LIST(VM_METRIC_API);
+#undef VM_METRIC_API
+
+#define ISOLATE_METRIC_API(type, variable, name, unit)                         \
+  DART_EXPORT int64_t Dart_Isolate##variable##Metric(Dart_Isolate isolate) {   \
+    return -1;                                                                 \
+  }
+ISOLATE_METRIC_LIST(ISOLATE_METRIC_API);
+#endif  // !defined(PRODUCT)
+
 // --- Isolates ---
 
 static char* BuildIsolateName(const char* script_uri, const char* main) {
diff --git a/runtime/vm/metrics.cc b/runtime/vm/metrics.cc
index f00d991..99bc372 100644
--- a/runtime/vm/metrics.cc
+++ b/runtime/vm/metrics.cc
@@ -303,11 +303,6 @@
   return Service::MaxRSS();
 }
 
-#define VM_METRIC_VARIABLE(type, variable, name, unit)                         \
-  static type vm_metric_##variable##_;
-VM_METRIC_LIST(VM_METRIC_VARIABLE);
-#undef VM_METRIC_VARIABLE
-
 void Metric::Init() {
 #define VM_METRIC_INIT(type, variable, name, unit)                             \
   vm_metric_##variable##_.InitInstance(name, NULL, Metric::unit);
diff --git a/runtime/vm/metrics.h b/runtime/vm/metrics.h
index fab74b9..75f0781 100644
--- a/runtime/vm/metrics.h
+++ b/runtime/vm/metrics.h
@@ -180,6 +180,13 @@
   virtual int64_t Value() const;
 };
 
+#if !defined(PRODUCT)
+#define VM_METRIC_VARIABLE(type, variable, name, unit)                         \
+  static type vm_metric_##variable##_;
+VM_METRIC_LIST(VM_METRIC_VARIABLE);
+#undef VM_METRIC_VARIABLE
+#endif  // !defined(PRODUCT)
+
 }  // namespace dart
 
 #endif  // RUNTIME_VM_METRICS_H_