[ VM / Service ] Added `getMemoryUsage` RPC and `MemoryUsage` object to service protocol
Change-Id: If15e49d7aab93382c15529a738b492552faf5376
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/95489
Commit-Queue: Ben Konyi <bkonyi@google.com>
Reviewed-by: Ryan Macnak <rmacnak@google.com>
diff --git a/runtime/observatory/tests/service/get_memory_usage.dart b/runtime/observatory/tests/service/get_memory_usage.dart
new file mode 100644
index 0000000..96832c2
--- /dev/null
+++ b/runtime/observatory/tests/service/get_memory_usage.dart
@@ -0,0 +1,49 @@
+// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:observatory/service_io.dart';
+import 'package:unittest/unittest.dart';
+
+import 'test_helper.dart';
+
+var tests = <VMTest>[
+ (VM vm) async {
+ var params = {
+ 'isolateId': vm.isolates.first.id,
+ };
+ var result = await vm.invokeRpcNoUpgrade('getMemoryUsage', params);
+ expect(result['type'], equals('MemoryUsage'));
+ expect(result['heapUsage'], isPositive);
+ expect(result['heapCapacity'], isPositive);
+ expect(result['externalUsage'], isPositive);
+ },
+ (VM vm) async {
+ var params = {
+ 'isolateId': 'badid',
+ };
+ bool caughtException;
+ try {
+ await vm.invokeRpcNoUpgrade('getMemoryUsage', params);
+ expect(false, isTrue, reason: 'Unreachable');
+ } on ServerRpcException catch (e) {
+ caughtException = true;
+ expect(e.code, equals(ServerRpcException.kInvalidParams));
+ expect(e.message, "getMemoryUsage: invalid 'isolateId' parameter: badid");
+ }
+ expect(caughtException, isTrue);
+ },
+
+ // Plausible isolate id, not found.
+ (VM vm) async {
+ var params = {
+ 'isolateId': 'isolates/9999999999',
+ };
+ var result = await vm.invokeRpcNoUpgrade('getMemoryUsage', params);
+ expect(result['type'], equals('Sentinel'));
+ expect(result['kind'], equals('Collected'));
+ expect(result['valueAsString'], equals('<collected>'));
+ },
+];
+
+main(args) async => runVMTests(args, tests);
diff --git a/runtime/vm/heap/heap.cc b/runtime/vm/heap/heap.cc
index 35675f4..a7220d1 100644
--- a/runtime/vm/heap/heap.cc
+++ b/runtime/vm/heap/heap.cc
@@ -727,6 +727,18 @@
: old_space_.ExternalInWords();
}
+int64_t Heap::TotalUsedInWords() const {
+ return UsedInWords(kNew) + UsedInWords(kOld);
+}
+
+int64_t Heap::TotalCapacityInWords() const {
+ return CapacityInWords(kNew) + CapacityInWords(kOld);
+}
+
+int64_t Heap::TotalExternalInWords() const {
+ return ExternalInWords(kNew) + ExternalInWords(kOld);
+}
+
int64_t Heap::GCTimeInMicros(Space space) const {
if (space == kNew) {
return new_space_.gc_time_micros();
@@ -851,6 +863,14 @@
old_space_.PrintToJSONObject(object);
}
}
+
+void Heap::PrintMemoryUsageJSON(JSONStream* stream) const {
+ JSONObject jsobj(stream);
+ jsobj.AddProperty("type", "MemoryUsage");
+ jsobj.AddProperty64("heapUsage", TotalUsedInWords() * kWordSize);
+ jsobj.AddProperty64("heapCapacity", TotalCapacityInWords() * kWordSize);
+ jsobj.AddProperty64("externalUsage", TotalExternalInWords() * kWordSize);
+}
#endif // PRODUCT
void Heap::RecordBeforeGC(GCType type, GCReason reason) {
diff --git a/runtime/vm/heap/heap.h b/runtime/vm/heap/heap.h
index 5ae4083..628ab15 100644
--- a/runtime/vm/heap/heap.h
+++ b/runtime/vm/heap/heap.h
@@ -180,6 +180,10 @@
int64_t UsedInWords(Space space) const;
int64_t CapacityInWords(Space space) const;
int64_t ExternalInWords(Space space) const;
+
+ int64_t TotalUsedInWords() const;
+ int64_t TotalCapacityInWords() const;
+ int64_t TotalExternalInWords() const;
// Return the amount of GCing in microseconds.
int64_t GCTimeInMicros(Space space) const;
@@ -268,6 +272,10 @@
#ifndef PRODUCT
void PrintToJSONObject(Space space, JSONObject* object) const;
+ // Returns a JSON object with total memory usage statistics for both new and
+ // old space combined.
+ void PrintMemoryUsageJSON(JSONStream* stream) const;
+
// The heap map contains the sizes and class ids for the objects in each page.
void PrintHeapMapToJSONStream(Isolate* isolate, JSONStream* stream) {
old_space_.PrintHeapMapToJSONStream(isolate, stream);
diff --git a/runtime/vm/isolate.cc b/runtime/vm/isolate.cc
index 6be1715..ce8ed3f 100644
--- a/runtime/vm/isolate.cc
+++ b/runtime/vm/isolate.cc
@@ -2288,6 +2288,14 @@
jsobj.AddProperty("_threads", thread_registry_);
}
+
+void Isolate::PrintMemoryUsageJSON(JSONStream* stream) {
+ if (!FLAG_support_service) {
+ return;
+ }
+ heap()->PrintMemoryUsageJSON(stream);
+}
+
#endif
void Isolate::set_tag_table(const GrowableObjectArray& value) {
diff --git a/runtime/vm/isolate.h b/runtime/vm/isolate.h
index 7f003d3..40f0c6f 100644
--- a/runtime/vm/isolate.h
+++ b/runtime/vm/isolate.h
@@ -515,6 +515,10 @@
#ifndef PRODUCT
void PrintJSON(JSONStream* stream, bool ref = true);
+
+ // Creates an object with the total heap memory usage statistics for this
+ // isolate.
+ void PrintMemoryUsageJSON(JSONStream* stream);
#endif
#if !defined(PRODUCT)
diff --git a/runtime/vm/service.cc b/runtime/vm/service.cc
index 2284222..f08dc42 100644
--- a/runtime/vm/service.cc
+++ b/runtime/vm/service.cc
@@ -1377,6 +1377,16 @@
return true;
}
+static const MethodParameter* get_memory_usage_params[] = {
+ ISOLATE_PARAMETER,
+ NULL,
+};
+
+static bool GetMemoryUsage(Thread* thread, JSONStream* js) {
+ thread->isolate()->PrintMemoryUsageJSON(js);
+ return true;
+}
+
static const MethodParameter* get_scripts_params[] = {
RUNNABLE_ISOLATE_PARAMETER,
NULL,
@@ -4876,6 +4886,8 @@
get_instances_params },
{ "getIsolate", GetIsolate,
get_isolate_params },
+ { "getMemoryUsage", GetMemoryUsage,
+ get_memory_usage_params },
{ "_getIsolateMetric", GetIsolateMetric,
get_isolate_metric_params },
{ "_getIsolateMetricList", GetIsolateMetricList,
diff --git a/runtime/vm/service/service.md b/runtime/vm/service/service.md
index 46cec8e..0040087 100644
--- a/runtime/vm/service/service.md
+++ b/runtime/vm/service/service.md
@@ -1,8 +1,8 @@
-# Dart VM Service Protocol 3.15
+# Dart VM Service Protocol 3.16
> Please post feedback to the [observatory-discuss group][discuss-list]
-This document describes of _version 3.15_ of the Dart VM Service Protocol. This
+This document describes of _version 3.16_ of the Dart VM Service Protocol. This
protocol is used to communicate with a running Dart Virtual Machine.
To use the Service Protocol, start the VM with the *--observe* flag.
@@ -31,6 +31,7 @@
- [evaluateInFrame](#evaluateinframe)
- [getFlagList](#getflaglist)
- [getIsolate](#getisolate)
+ - [getMemoryUsage](#getmemoryusage)
- [getScripts](#getscripts)
- [getObject](#getobject)
- [getSourceReport](#getsourcereport)
@@ -75,6 +76,7 @@
- [Library](#library)
- [LibraryDependency](#librarydependency)
- [MapAssociation](#mapassociation)
+ - [MemoryUsage](#memoryusage)
- [Message](#message)
- [Null](#null)
- [Object](#object)
@@ -610,6 +612,20 @@
See [Isolate](#isolate).
+### getMemoryUsage
+
+```
+MemoryUsage|Sentinel getMemoryUsage(string isolateId)
+```
+
+The _getMemoryUsage_ RPC is used to lookup an isolate's memory usage
+statistics by its _id_.
+
+If _isolateId_ refers to an isolate which has exited, then the
+_Collected_ [Sentinel](#sentinel) is returned.
+
+See [Isolate](#isolate).
+
### getScripts
```
@@ -2207,6 +2223,31 @@
}
```
+### MemoryUsage
+
+```
+class MemoryUsage extends Response {
+ // The amount of non-Dart memory that is retained by Dart objects. For
+ // example, memory associated with Dart objects through APIs such as
+ // Dart_NewWeakPersistentHandle and Dart_NewExternalTypedData. This usage is
+ // only as accurate as the values supplied to these APIs from the VM embedder or
+ // native extensions. This external memory applies GC pressure, but is separate
+ // from heapUsage and heapCapacity.
+ int externalUsage;
+
+ // The total capacity of the heap in bytes. This is the amount of memory used
+ // by the Dart heap from the perspective of the operating system.
+ int heapCapacity;
+
+ // The current heap memory usage in bytes. Heap usage is always less than or
+ // equal to the heap capacity.
+ int heapUsage;
+}
+```
+
+An _MemoryUsage_ object provides heap usage information for a specific
+isolate at a given point in time.
+
### Message
```
@@ -2765,5 +2806,6 @@
3.13 | Class 'mixin' field now properly set for kernel transformed mixin applications.
3.14 | Flag 'profile_period' can now be set at runtime, allowing for the profiler sample rate to be changed while the program is running.
3.15 | Added `disableBreakpoints` parameter to `invoke`, `evaluate`, and `evaluateInFrame`.
+3.16 | Add 'getMemoryUsage' RPC and 'MemoryUsage' object.
[discuss-list]: https://groups.google.com/a/dartlang.org/forum/#!forum/observatory-discuss
diff --git a/runtime/vm/service/service_dev.md b/runtime/vm/service/service_dev.md
index 2fe0098..a440425 100644
--- a/runtime/vm/service/service_dev.md
+++ b/runtime/vm/service/service_dev.md
@@ -1,8 +1,8 @@
-# Dart VM Service Protocol 3.16-dev
+# Dart VM Service Protocol 3.17-dev
> Please post feedback to the [observatory-discuss group][discuss-list]
-This document describes of _version 3.16-dev_ of the Dart VM Service Protocol. This
+This document describes of _version 3.17-dev_ of the Dart VM Service Protocol. This
protocol is used to communicate with a running Dart Virtual Machine.
To use the Service Protocol, start the VM with the *--observe* flag.
@@ -31,6 +31,7 @@
- [evaluateInFrame](#evaluateinframe)
- [getFlagList](#getflaglist)
- [getIsolate](#getisolate)
+ - [getMemoryUsage](#getmemoryusage)
- [getScripts](#getscripts)
- [getObject](#getobject)
- [getSourceReport](#getsourcereport)
@@ -75,6 +76,7 @@
- [Library](#library)
- [LibraryDependency](#librarydependency)
- [MapAssociation](#mapassociation)
+ - [MemoryUsage](#memoryusage)
- [Message](#message)
- [Null](#null)
- [Object](#object)
@@ -610,6 +612,20 @@
See [Isolate](#isolate).
+### getMemoryUsage
+
+```
+MemoryUsage|Sentinel getMemoryUsage(string isolateId)
+```
+
+The _getMemoryUsage_ RPC is used to lookup an isolate's memory usage
+statistics by its _id_.
+
+If _isolateId_ refers to an isolate which has exited, then the
+_Collected_ [Sentinel](#sentinel) is returned.
+
+See [Isolate](#isolate).
+
### getScripts
```
@@ -2207,6 +2223,31 @@
}
```
+### MemoryUsage
+
+```
+class MemoryUsage extends Response {
+ // The amount of non-Dart memory that is retained by Dart objects. For
+ // example, memory associated with Dart objects through APIs such as
+ // Dart_NewWeakPersistentHandle and Dart_NewExternalTypedData. This usage is
+ // only as accurate as the values supplied to these APIs from the VM embedder or
+ // native extensions. This external memory applies GC pressure, but is separate
+ // from heapUsage and heapCapacity.
+ int externalUsage;
+
+ // The total capacity of the heap in bytes. This is the amount of memory used
+ // by the Dart heap from the perspective of the operating system.
+ int heapCapacity;
+
+ // The current heap memory usage in bytes. Heap usage is always less than or
+ // equal to the heap capacity.
+ int heapUsage;
+}
+```
+
+An _MemoryUsage_ object provides heap usage information for a specific
+isolate at a given point in time.
+
### Message
```
@@ -2765,5 +2806,6 @@
3.13 | Class 'mixin' field now properly set for kernel transformed mixin applications.
3.14 | Flag 'profile_period' can now be set at runtime, allowing for the profiler sample rate to be changed while the program is running.
3.15 | Added `disableBreakpoints` parameter to `invoke`, `evaluate`, and `evaluateInFrame`.
+3.16 | Add 'getMemoryUsage' RPC and 'MemoryUsage' object.
[discuss-list]: https://groups.google.com/a/dartlang.org/forum/#!forum/observatory-discuss