Skip to content

Commit

Permalink
[vm/service] Introduce IsolateGroup entity to vm service api.
Browse files Browse the repository at this point in the history
This is to enable vm clients to ask how much memory is consumed by isolate group.

Issue #36097

Change-Id: I4f1c499bf02c20b80e9802d8ad60e7ea65cfb375
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/119724
Commit-Queue: Alexander Aprelev <aam@google.com>
Reviewed-by: Ryan Macnak <rmacnak@google.com>
Reviewed-by: Martin Kustermann <kustermann@google.com>
  • Loading branch information
aam authored and commit-bot@chromium.org committed Oct 16, 2019
1 parent 2c94e56 commit f219e51
Show file tree
Hide file tree
Showing 29 changed files with 906 additions and 48 deletions.
28 changes: 28 additions & 0 deletions pkg/vm_service/example/vm_service_assert.dart
Original file line number Diff line number Diff line change
Expand Up @@ -672,6 +672,33 @@ vms.Isolate assertIsolate(vms.Isolate obj) {
return obj;
}

vms.IsolateGroupRef assertIsolateGroupRef(vms.IsolateGroupRef obj) {
assertNotNull(obj);
assertString(obj.type);
assertString(obj.id);
assertString(obj.number);
assertString(obj.name);
return obj;
}

List<vms.IsolateGroupRef> assertListOfIsolateGroupRef(
List<vms.IsolateGroupRef> list) {
for (vms.IsolateGroupRef elem in list) {
assertIsolateGroupRef(elem);
}
return list;
}

vms.IsolateGroup assertIsolateGroup(vms.IsolateGroup obj) {
assertNotNull(obj);
assertString(obj.type);
assertString(obj.id);
assertString(obj.number);
assertString(obj.name);
assertListOfIsolateRef(obj.isolates);
return obj;
}

vms.InboundReferences assertInboundReferences(vms.InboundReferences obj) {
assertNotNull(obj);
assertString(obj.type);
Expand Down Expand Up @@ -1108,5 +1135,6 @@ vms.VM assertVM(vms.VM obj) {
assertInt(obj.pid);
assertInt(obj.startTime);
assertListOfIsolateRef(obj.isolates);
assertListOfIsolateGroupRef(obj.isolateGroups);
return obj;
}
4 changes: 4 additions & 0 deletions pkg/vm_service/java/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ src/org/dartlang/vm/service/consumer/EvaluateInFrameConsumer.java
src/org/dartlang/vm/service/consumer/FlagListConsumer.java
src/org/dartlang/vm/service/consumer/GetInboundReferencesConsumer.java
src/org/dartlang/vm/service/consumer/GetIsolateConsumer.java
src/org/dartlang/vm/service/consumer/GetIsolateGroupConsumer.java
src/org/dartlang/vm/service/consumer/GetIsolateGroupMemoryUsageConsumer.java
src/org/dartlang/vm/service/consumer/GetMemoryUsageConsumer.java
src/org/dartlang/vm/service/consumer/GetObjectConsumer.java
src/org/dartlang/vm/service/consumer/InstanceSetConsumer.java
Expand Down Expand Up @@ -63,6 +65,8 @@ src/org/dartlang/vm/service/element/InstanceKind.java
src/org/dartlang/vm/service/element/InstanceRef.java
src/org/dartlang/vm/service/element/InstanceSet.java
src/org/dartlang/vm/service/element/Isolate.java
src/org/dartlang/vm/service/element/IsolateGroup.java
src/org/dartlang/vm/service/element/IsolateGroupRef.java
src/org/dartlang/vm/service/element/IsolateRef.java
src/org/dartlang/vm/service/element/Library.java
src/org/dartlang/vm/service/element/LibraryDependency.java
Expand Down
158 changes: 158 additions & 0 deletions pkg/vm_service/lib/vm_service.dart
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,8 @@ Map<String, Function> _typeFactories = {
'Instance': Instance.parse,
'@Isolate': IsolateRef.parse,
'Isolate': Isolate.parse,
'@IsolateGroup': IsolateGroupRef.parse,
'IsolateGroup': IsolateGroup.parse,
'InboundReferences': InboundReferences.parse,
'InboundReference': InboundReference.parse,
'InstanceSet': InstanceSet.parse,
Expand Down Expand Up @@ -188,7 +190,9 @@ Map<String, List<String>> _methodReturnTypes = {
'getInboundReferences': const ['InboundReferences', 'Sentinel'],
'getInstances': const ['InstanceSet'],
'getIsolate': const ['Isolate', 'Sentinel'],
'getIsolateGroup': const ['IsolateGroup', 'Sentinel'],
'getMemoryUsage': const ['MemoryUsage', 'Sentinel'],
'getIsolateGroupMemoryUsage': const ['MemoryUsage', 'Sentinel'],
'getScripts': const ['ScriptList'],
'getObject': const ['Obj', 'Sentinel'],
'getRetainingPath': const ['RetainingPath'],
Expand Down Expand Up @@ -506,6 +510,21 @@ abstract class VmServiceInterface {
/// The return value can be one of [Isolate] or [Sentinel].
Future<dynamic> getIsolate(String isolateId);

/// The `getIsolateGroup` RPC is used to lookup an `IsolateGroup` object by
/// its `id`.
///
/// If `isolateGroupId` refers to an isolate group which has exited, then the
/// `Expired` [Sentinel] is returned.
///
/// `IsolateGroup` `id` is an opaque identifier that can be fetched from an
/// `IsolateGroup`. List of active `IsolateGroup`'s, for example, is available
/// on `VM` object.
///
/// See [IsolateGroup], [VM].
///
/// The return value can be one of [IsolateGroup] or [Sentinel].
Future<dynamic> getIsolateGroup(String isolateGroupId);

/// The `getMemoryUsage` RPC is used to lookup an isolate's memory usage
/// statistics by its `id`.
///
Expand All @@ -517,6 +536,17 @@ abstract class VmServiceInterface {
/// The return value can be one of [MemoryUsage] or [Sentinel].
Future<dynamic> getMemoryUsage(String isolateId);

/// The `getIsolateGroupMemoryUsage` RPC is used to lookup an isolate group's
/// memory usage statistics by its `id`.
///
/// If `isolateGroupId` refers to an isolate group which has exited, then the
/// `Expired` [Sentinel] is returned.
///
/// See [IsolateGroup].
///
/// The return value can be one of [MemoryUsage] or [Sentinel].
Future<dynamic> getIsolateGroupMemoryUsage(String isolateGroupId);

/// The `getScripts` RPC is used to retrieve a `ScriptList` containing all
/// scripts for an isolate based on the isolate's `isolateId`.
///
Expand Down Expand Up @@ -1027,11 +1057,21 @@ class VmServerConnection {
params['isolateId'],
);
break;
case 'getIsolateGroup':
response = await _serviceImplementation.getIsolateGroup(
params['isolateGroupId'],
);
break;
case 'getMemoryUsage':
response = await _serviceImplementation.getMemoryUsage(
params['isolateId'],
);
break;
case 'getIsolateGroupMemoryUsage':
response = await _serviceImplementation.getIsolateGroupMemoryUsage(
params['isolateGroupId'],
);
break;
case 'getScripts':
response = await _serviceImplementation.getScripts(
params['isolateId'],
Expand Down Expand Up @@ -1468,11 +1508,22 @@ class VmService implements VmServiceInterface {
return _call('getIsolate', {'isolateId': isolateId});
}

@override
Future<dynamic> getIsolateGroup(String isolateGroupId) {
return _call('getIsolateGroup', {'isolateGroupId': isolateGroupId});
}

@override
Future<dynamic> getMemoryUsage(String isolateId) {
return _call('getMemoryUsage', {'isolateId': isolateId});
}

@override
Future<dynamic> getIsolateGroupMemoryUsage(String isolateGroupId) {
return _call(
'getIsolateGroupMemoryUsage', {'isolateGroupId': isolateGroupId});
}

@override
Future<ScriptList> getScripts(String isolateId) {
return _call('getScripts', {'isolateId': isolateId});
Expand Down Expand Up @@ -1699,6 +1750,7 @@ class VmService implements VmServiceInterface {
void dispose() {
_streamSub.cancel();
_completers.values.forEach((c) => c.completeError('disposed'));
_completers.clear();
if (_disposeHandler != null) {
_disposeHandler();
}
Expand Down Expand Up @@ -4444,6 +4496,105 @@ class Isolate extends Response {
String toString() => '[Isolate]';
}

/// `IsolateGroupRef` is a reference to an `IsolateGroup` object.
class IsolateGroupRef extends Response {
static IsolateGroupRef parse(Map<String, dynamic> json) =>
json == null ? null : IsolateGroupRef._fromJson(json);

/// The id which is passed to the getIsolateGroup RPC to load this isolate
/// group.
String id;

/// A numeric id for this isolate group, represented as a string. Unique.
String number;

/// A name identifying this isolate group. Not guaranteed to be unique.
String name;

IsolateGroupRef({
@required this.id,
@required this.number,
@required this.name,
});
IsolateGroupRef._fromJson(Map<String, dynamic> json) : super._fromJson(json) {
id = json['id'];
number = json['number'];
name = json['name'];
}

@override
Map<String, dynamic> toJson() {
var json = <String, dynamic>{};
json['type'] = '@IsolateGroup';
json.addAll({
'id': id,
'number': number,
'name': name,
});
return json;
}

int get hashCode => id.hashCode;

operator ==(other) => other is IsolateGroupRef && id == other.id;

String toString() =>
'[IsolateGroupRef type: ${type}, id: ${id}, number: ${number}, name: ${name}]';
}

/// An `Isolate` object provides information about one isolate in the VM.
class IsolateGroup extends Response {
static IsolateGroup parse(Map<String, dynamic> json) =>
json == null ? null : IsolateGroup._fromJson(json);

/// The id which is passed to the getIsolate RPC to reload this isolate.
String id;

/// A numeric id for this isolate, represented as a string. Unique.
String number;

/// A name identifying this isolate. Not guaranteed to be unique.
String name;

/// A list of all isolates in this isolate group.
List<IsolateRef> isolates;

IsolateGroup({
@required this.id,
@required this.number,
@required this.name,
@required this.isolates,
});
IsolateGroup._fromJson(Map<String, dynamic> json) : super._fromJson(json) {
id = json['id'];
number = json['number'];
name = json['name'];
isolates = List<IsolateRef>.from(
createServiceObject(json['isolates'], const ['IsolateRef']));
}

@override
Map<String, dynamic> toJson() {
var json = <String, dynamic>{};
json['type'] = 'IsolateGroup';
json.addAll({
'id': id,
'number': number,
'name': name,
'isolates': isolates.map((f) => f.toJson()).toList(),
});
return json;
}

int get hashCode => id.hashCode;

operator ==(other) => other is IsolateGroup && id == other.id;

String toString() => '[IsolateGroup ' //
'type: ${type}, id: ${id}, number: ${number}, name: ${name}, ' //
'isolates: ${isolates}]';
}

/// See [getInboundReferences].
class InboundReferences extends Response {
static InboundReferences parse(Map<String, dynamic> json) =>
Expand Down Expand Up @@ -6236,6 +6387,9 @@ class VM extends Response {
/// A list of isolates running in the VM.
List<IsolateRef> isolates;

/// A list of isolate groups running in the VM.
List<IsolateGroupRef> isolateGroups;

VM({
@required this.name,
@required this.architectureBits,
Expand All @@ -6246,6 +6400,7 @@ class VM extends Response {
@required this.pid,
@required this.startTime,
@required this.isolates,
@required this.isolateGroups,
});
VM._fromJson(Map<String, dynamic> json) : super._fromJson(json) {
name = json['name'];
Expand All @@ -6258,6 +6413,8 @@ class VM extends Response {
startTime = json['startTime'];
isolates = List<IsolateRef>.from(
createServiceObject(json['isolates'], const ['IsolateRef']));
isolateGroups = List<IsolateGroupRef>.from(
createServiceObject(json['isolateGroups'], const ['IsolateGroupRef']));
}

@override
Expand All @@ -6274,6 +6431,7 @@ class VM extends Response {
'pid': pid,
'startTime': startTime,
'isolates': isolates.map((f) => f.toJson()).toList(),
'isolateGroups': isolateGroups.map((f) => f.toJson()).toList(),
});
return json;
}
Expand Down
35 changes: 35 additions & 0 deletions pkg/vm_service/test/get_isolate_group_memory_usage.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
// 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:test/test.dart';
import 'package:vm_service/vm_service.dart';

import 'common/test_helper.dart';

var tests = <VMTest>[
(VmService service) async {
final vm = await service.getVM();
final result =
await service.getIsolateGroupMemoryUsage(vm.isolateGroups.first.id);
expect(result.heapUsage, isPositive);
expect(result.heapCapacity, isPositive);
expect(result.externalUsage, isNonNegative);
},
(VmService service) async {
bool caughtException;
try {
await service.getMemoryUsage('badid');
fail('Unreachable');
} on RPCError catch (e) {
caughtException = true;
expect(
e.details,
contains(
"getMemoryUsage: invalid 'isolateGroupId' parameter: badid"));
}
expect(caughtException, isTrue);
},
];

main(args) async => runVMTests(args, tests);
5 changes: 5 additions & 0 deletions runtime/observatory/analysis_options.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,8 @@ analyzer:
- tests/service/get_isolate_after_language_error_test.dart
- tests/service/get_user_level_retaining_path_rpc_test.dart
- tests/service/pause_on_unhandled_async_exceptions_test.dart

linter:
rules:
- prefer_final_fields
- prefer_final_locals
2 changes: 2 additions & 0 deletions runtime/observatory/lib/models.dart
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ part 'src/models/objects/icdata.dart';
part 'src/models/objects/inbound_references.dart';
part 'src/models/objects/instance.dart';
part 'src/models/objects/isolate.dart';
part 'src/models/objects/isolate_group.dart';
part 'src/models/objects/library.dart';
part 'src/models/objects/local_var_descriptors.dart';
part 'src/models/objects/map_association.dart';
Expand Down Expand Up @@ -74,6 +75,7 @@ part 'src/models/repositories/icdata.dart';
part 'src/models/repositories/inbound_references.dart';
part 'src/models/repositories/instance.dart';
part 'src/models/repositories/isolate.dart';
part 'src/models/repositories/isolate_group.dart';
part 'src/models/repositories/library.dart';
part 'src/models/repositories/megamorphiccache.dart';
part 'src/models/repositories/metric.dart';
Expand Down
1 change: 1 addition & 0 deletions runtime/observatory/lib/repositories.dart
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ part 'src/repositories/icdata.dart';
part 'src/repositories/inbound_references.dart';
part 'src/repositories/instance.dart';
part 'src/repositories/isolate.dart';
part 'src/repositories/isolate_group.dart';
part 'src/repositories/library.dart';
part 'src/repositories/megamorphiccache.dart';
part 'src/repositories/metric.dart';
Expand Down
Loading

0 comments on commit f219e51

Please sign in to comment.