[ package:vm_service ] Added support for service protocol version 3.27.

Change-Id: I1cb3ca42821f817eaa9aed98d1aabb93e53fb0ce
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/115079
Commit-Queue: Ben Konyi <bkonyi@google.com>
Reviewed-by: Devon Carew <devoncarew@google.com>
This commit is contained in:
Ben Konyi 2019-09-07 05:31:37 +00:00 committed by commit-bot@chromium.org
parent 13a69b5631
commit 9391e15cfd
8 changed files with 402 additions and 3 deletions

View file

@ -1,5 +1,10 @@
# Changelog
## 1.2.0
- Support service protocol version 3.27:
- Added `getCpuSamples` and `clearCpuSamples` methods
- Added `CpuSamples`, `CpuSample`, and `ProfileFunction` classes.
## 1.1.2
- Fixed issue where `closureFunction` and `closureContext` were only expected in
`Instance` objects rather than `InstanceRef`.

View file

@ -28,6 +28,11 @@ double assertDouble(double obj) {
return obj;
}
dynamic assertDynamic(dynamic obj) {
assertNotNull(obj);
return obj;
}
List<int> assertListOfInt(List<int> list) {
for (int elem in list) {
assertInt(elem);
@ -429,6 +434,36 @@ List<vms.ContextElement> assertListOfContextElement(
return list;
}
vms.CpuSamples assertCpuSamples(vms.CpuSamples obj) {
assertNotNull(obj);
assertString(obj.type);
assertInt(obj.samplePeriod);
assertInt(obj.maxStackDepth);
assertInt(obj.sampleCount);
assertInt(obj.timeSpan);
assertInt(obj.timeOriginMicros);
assertInt(obj.timeExtentMicros);
assertInt(obj.pid);
assertListOfProfileFunction(obj.functions);
assertListOfCpuSample(obj.samples);
return obj;
}
vms.CpuSample assertCpuSample(vms.CpuSample obj) {
assertNotNull(obj);
assertInt(obj.tid);
assertInt(obj.timestamp);
assertListOfInt(obj.stack);
return obj;
}
List<vms.CpuSample> assertListOfCpuSample(List<vms.CpuSample> list) {
for (vms.CpuSample elem in list) {
assertCpuSample(elem);
}
return list;
}
vms.ErrorRef assertErrorRef(vms.ErrorRef obj) {
assertNotNull(obj);
assertString(obj.type);
@ -773,6 +808,12 @@ List<vms.Message> assertListOfMessage(List<vms.Message> list) {
return list;
}
vms.NativeFunction assertNativeFunction(vms.NativeFunction obj) {
assertNotNull(obj);
assertString(obj.name);
return obj;
}
vms.NullValRef assertNullValRef(vms.NullValRef obj) {
assertNotNull(obj);
assertString(obj.type);
@ -821,6 +862,24 @@ vms.Obj assertObj(vms.Obj obj) {
return obj;
}
vms.ProfileFunction assertProfileFunction(vms.ProfileFunction obj) {
assertNotNull(obj);
assertString(obj.kind);
assertInt(obj.inclusiveTicks);
assertInt(obj.exclusiveTicks);
assertString(obj.resolvedUrl);
assertDynamic(obj.function);
return obj;
}
List<vms.ProfileFunction> assertListOfProfileFunction(
List<vms.ProfileFunction> list) {
for (vms.ProfileFunction elem in list) {
assertProfileFunction(elem);
}
return list;
}
vms.ReloadReport assertReloadReport(vms.ReloadReport obj) {
assertNotNull(obj);
assertString(obj.type);

View file

@ -3,6 +3,7 @@
src/org/dartlang/vm/service/VmService.java
src/org/dartlang/vm/service/consumer/AllocationProfileConsumer.java
src/org/dartlang/vm/service/consumer/BreakpointConsumer.java
src/org/dartlang/vm/service/consumer/CpuSamplesConsumer.java
src/org/dartlang/vm/service/consumer/EvaluateConsumer.java
src/org/dartlang/vm/service/consumer/EvaluateInFrameConsumer.java
src/org/dartlang/vm/service/consumer/FlagListConsumer.java
@ -37,6 +38,8 @@ src/org/dartlang/vm/service/element/CodeRef.java
src/org/dartlang/vm/service/element/Context.java
src/org/dartlang/vm/service/element/ContextElement.java
src/org/dartlang/vm/service/element/ContextRef.java
src/org/dartlang/vm/service/element/CpuSample.java
src/org/dartlang/vm/service/element/CpuSamples.java
src/org/dartlang/vm/service/element/ErrorKind.java
src/org/dartlang/vm/service/element/ErrorObj.java
src/org/dartlang/vm/service/element/ErrorRef.java
@ -67,10 +70,12 @@ src/org/dartlang/vm/service/element/LogRecord.java
src/org/dartlang/vm/service/element/MapAssociation.java
src/org/dartlang/vm/service/element/MemoryUsage.java
src/org/dartlang/vm/service/element/Message.java
src/org/dartlang/vm/service/element/NativeFunction.java
src/org/dartlang/vm/service/element/Null.java
src/org/dartlang/vm/service/element/NullRef.java
src/org/dartlang/vm/service/element/Obj.java
src/org/dartlang/vm/service/element/ObjRef.java
src/org/dartlang/vm/service/element/ProfileFunction.java
src/org/dartlang/vm/service/element/ReloadReport.java
src/org/dartlang/vm/service/element/Response.java
src/org/dartlang/vm/service/element/RetainingObject.java

View file

@ -1 +1 @@
version=3.26
version=3.27

View file

@ -17,7 +17,7 @@ import 'src/service_extension_registry.dart';
export 'src/service_extension_registry.dart' show ServiceExtensionRegistry;
const String vmServiceVersion = '3.26.0';
const String vmServiceVersion = '3.27.0';
/// @optional
const String optional = 'optional';
@ -102,6 +102,8 @@ Map<String, Function> _typeFactories = {
'@Context': ContextRef.parse,
'Context': Context.parse,
'ContextElement': ContextElement.parse,
'CpuSamples': CpuSamples.parse,
'CpuSample': CpuSample.parse,
'@Error': ErrorRef.parse,
'Error': Error.parse,
'Event': Event.parse,
@ -127,10 +129,12 @@ Map<String, Function> _typeFactories = {
'MapAssociation': MapAssociation.parse,
'MemoryUsage': MemoryUsage.parse,
'Message': Message.parse,
'NativeFunction': NativeFunction.parse,
'@Null': NullValRef.parse,
'Null': NullVal.parse,
'@Object': ObjRef.parse,
'Object': Obj.parse,
'ProfileFunction': ProfileFunction.parse,
'ReloadReport': ReloadReport.parse,
'RetainingObject': RetainingObject.parse,
'RetainingPath': RetainingPath.parse,
@ -161,11 +165,13 @@ Map<String, List<String>> _methodReturnTypes = {
'addBreakpoint': const ['Breakpoint'],
'addBreakpointWithScriptUri': const ['Breakpoint'],
'addBreakpointAtEntry': const ['Breakpoint'],
'clearCpuSamples': const ['Success'],
'clearVMTimeline': const ['Success'],
'invoke': const ['InstanceRef', 'ErrorRef', 'Sentinel'],
'evaluate': const ['InstanceRef', 'ErrorRef', 'Sentinel'],
'evaluateInFrame': const ['InstanceRef', 'ErrorRef', 'Sentinel'],
'getAllocationProfile': const ['AllocationProfile'],
'getCpuSamples': const ['CpuSamples'],
'getFlagList': const ['FlagList'],
'getInboundReferences': const ['InboundReferences', 'Sentinel'],
'getInstances': const ['InstanceSet'],
@ -283,6 +289,11 @@ abstract class VmServiceInterface {
/// Note that breakpoints are added and removed on a per-isolate basis.
Future<Breakpoint> addBreakpointAtEntry(String isolateId, String functionId);
/// Clears all CPU profiling samples.
///
/// See [Success].
Future<Success> clearCpuSamples(String isolateId);
/// Clears all VM timeline events.
///
/// See [Success].
@ -410,6 +421,16 @@ abstract class VmServiceInterface {
Future<AllocationProfile> getAllocationProfile(String isolateId,
{bool reset, bool gc});
/// The `getCpuSamples` RPC is used to retrieve samples collected by the CPU
/// profiler. Only samples collected in the time range `[timeOriginMicros,
/// timeOriginMicros + timeExtentMicros]` will be reported.
///
/// If the profiler is disabled, an error response will be returned.
///
/// See [CpuSamples].
Future<CpuSamples> getCpuSamples(
String isolateId, int timeOriginMicros, int timeExtentMicros);
/// The `getFlagList` RPC returns a list of all command line flags in the VM
/// along with their current values.
///
@ -921,6 +942,11 @@ class VmServerConnection {
params['functionId'],
);
break;
case 'clearCpuSamples':
response = await _serviceImplementation.clearCpuSamples(
params['isolateId'],
);
break;
case 'clearVMTimeline':
response = await _serviceImplementation.clearVMTimeline();
break;
@ -958,6 +984,13 @@ class VmServerConnection {
gc: params['gc'],
);
break;
case 'getCpuSamples':
response = await _serviceImplementation.getCpuSamples(
params['isolateId'],
params['timeOriginMicros'],
params['timeExtentMicros'],
);
break;
case 'getFlagList':
response = await _serviceImplementation.getFlagList();
break;
@ -1305,6 +1338,11 @@ class VmService implements VmServiceInterface {
{'isolateId': isolateId, 'functionId': functionId});
}
@override
Future<Success> clearCpuSamples(String isolateId) {
return _call('clearCpuSamples', {'isolateId': isolateId});
}
@override
Future<Success> clearVMTimeline() => _call('clearVMTimeline');
@ -1385,6 +1423,16 @@ class VmService implements VmServiceInterface {
return _call('getAllocationProfile', m);
}
@override
Future<CpuSamples> getCpuSamples(
String isolateId, int timeOriginMicros, int timeExtentMicros) {
return _call('getCpuSamples', {
'isolateId': isolateId,
'timeOriginMicros': timeOriginMicros,
'timeExtentMicros': timeExtentMicros
});
}
@override
Future<FlagList> getFlagList() => _call('getFlagList');
@ -2732,6 +2780,144 @@ class ContextElement {
String toString() => '[ContextElement value: ${value}]';
}
/// See [getCpuSamples] and [CpuSample].
class CpuSamples extends Response {
static CpuSamples parse(Map<String, dynamic> json) =>
json == null ? null : new CpuSamples._fromJson(json);
/// The sampling rate for the profiler in microseconds.
int samplePeriod;
/// The maximum possible stack depth for samples.
int maxStackDepth;
/// The number of samples returned.
int sampleCount;
/// The timespan the set of returned samples covers, in microseconds.
int timeSpan;
/// The start of the period of time in which the returned samples were
/// collected.
int timeOriginMicros;
/// The duration of time covered by the returned samples.
int timeExtentMicros;
/// The process ID for the VM.
int pid;
/// A list of functions seen in the relevant samples. These references can be
/// looked up using the indicies provided in a `CpuSample` `stack` to
/// determine which function was on the stack.
List<ProfileFunction> functions;
/// A list of samples collected in the range `[timeOriginMicros,
/// timeOriginMicros + timeExtentMicros]`
List<CpuSample> samples;
CpuSamples();
CpuSamples._fromJson(Map<String, dynamic> json) : super._fromJson(json) {
samplePeriod = json['samplePeriod'];
maxStackDepth = json['maxStackDepth'];
sampleCount = json['sampleCount'];
timeSpan = json['timeSpan'];
timeOriginMicros = json['timeOriginMicros'];
timeExtentMicros = json['timeExtentMicros'];
pid = json['pid'];
functions = new List<ProfileFunction>.from(
createServiceObject(json['functions'], const ['ProfileFunction']));
samples = new List<CpuSample>.from(
createServiceObject(json['samples'], const ['CpuSample']));
}
@override
Map<String, dynamic> toJson() {
var json = <String, dynamic>{};
json['type'] = 'CpuSamples';
json.addAll({
'samplePeriod': samplePeriod,
'maxStackDepth': maxStackDepth,
'sampleCount': sampleCount,
'timeSpan': timeSpan,
'timeOriginMicros': timeOriginMicros,
'timeExtentMicros': timeExtentMicros,
'pid': pid,
'functions': functions.map((f) => f.toJson()).toList(),
'samples': samples.map((f) => f.toJson()).toList(),
});
return json;
}
String toString() => '[CpuSamples]';
}
/// See [getCpuSamples] and [CpuSamples].
class CpuSample {
static CpuSample parse(Map<String, dynamic> json) =>
json == null ? null : new CpuSample._fromJson(json);
/// The thread ID representing the thread on which this sample was collected.
int tid;
/// The time this sample was collected in microseconds.
int timestamp;
/// The name of VM tag set when this sample was collected. Omitted if the VM
/// tag for the sample is not considered valid.
@optional
String vmTag;
/// The name of the User tag set when this sample was collected. Omitted if no
/// User tag was set when this sample was collected.
@optional
String userTag;
/// Provided and set to true if the sample's stack was truncated. This can
/// happen if the stack is deeper than the `stackDepth` in the `CpuSamples`
/// response.
@optional
bool truncated;
/// The call stack at the time this sample was collected. The stack is to be
/// interpreted as top to bottom. Each element in this array is a key into the
/// `functions` array in `CpuSamples`.
///
/// Example:
///
/// `functions[stack[0]] = @Function(bar())` `functions[stack[1]] =
/// @Function(foo())` `functions[stack[2]] = @Function(main())`
List<int> stack;
CpuSample();
CpuSample._fromJson(Map<String, dynamic> json) {
tid = json['tid'];
timestamp = json['timestamp'];
vmTag = json['vmTag'];
userTag = json['userTag'];
truncated = json['truncated'];
stack = new List<int>.from(json['stack']);
}
Map<String, dynamic> toJson() {
var json = <String, dynamic>{};
json.addAll({
'tid': tid,
'timestamp': timestamp,
'stack': stack.map((f) => f).toList(),
});
_setIfNotNull(json, 'vmTag', vmTag);
_setIfNotNull(json, 'userTag', userTag);
_setIfNotNull(json, 'truncated', truncated);
return json;
}
String toString() =>
'[CpuSample tid: ${tid}, timestamp: ${timestamp}, stack: ${stack}]';
}
/// `ErrorRef` is a reference to an `Error`.
class ErrorRef extends ObjRef {
static ErrorRef parse(Map<String, dynamic> json) =>
@ -4510,6 +4696,32 @@ class Message extends Response {
'size: ${size}]';
}
/// A `NativeFunction` object is used to represent native functions in profiler
/// samples. See [CpuSamples];
class NativeFunction {
static NativeFunction parse(Map<String, dynamic> json) =>
json == null ? null : new NativeFunction._fromJson(json);
/// The name of the native function this object represents.
String name;
NativeFunction();
NativeFunction._fromJson(Map<String, dynamic> json) {
name = json['name'];
}
Map<String, dynamic> toJson() {
var json = <String, dynamic>{};
json.addAll({
'name': name,
});
return json;
}
String toString() => '[NativeFunction name: ${name}]';
}
/// `NullValRef` is a reference to an a `NullVal`.
class NullValRef extends InstanceRef {
static NullValRef parse(Map<String, dynamic> json) =>
@ -4685,6 +4897,57 @@ class Obj extends Response {
String toString() => '[Obj type: ${type}, id: ${id}]';
}
/// A `ProfileFunction` contains profiling information about a Dart or native
/// function.
///
/// See [CpuSamples].
class ProfileFunction {
static ProfileFunction parse(Map<String, dynamic> json) =>
json == null ? null : new ProfileFunction._fromJson(json);
/// The kind of function this object represents.
String kind;
/// The number of times function appeared on the stack during sampling events.
int inclusiveTicks;
/// The number of times function appeared on the top of the stack during
/// sampling events.
int exclusiveTicks;
/// The resolved URL for the script containing function.
String resolvedUrl;
/// The function captured during profiling.
dynamic function;
ProfileFunction();
ProfileFunction._fromJson(Map<String, dynamic> json) {
kind = json['kind'];
inclusiveTicks = json['inclusiveTicks'];
exclusiveTicks = json['exclusiveTicks'];
resolvedUrl = json['resolvedUrl'];
function = createServiceObject(json['function'], const ['dynamic']);
}
Map<String, dynamic> toJson() {
var json = <String, dynamic>{};
json.addAll({
'kind': kind,
'inclusiveTicks': inclusiveTicks,
'exclusiveTicks': exclusiveTicks,
'resolvedUrl': resolvedUrl,
'function': function.toJson(),
});
return json;
}
String toString() => '[ProfileFunction ' //
'kind: ${kind}, inclusiveTicks: ${inclusiveTicks}, exclusiveTicks: ${exclusiveTicks}, ' //
'resolvedUrl: ${resolvedUrl}, function: ${function}]';
}
class ReloadReport extends Response {
static ReloadReport parse(Map<String, dynamic> json) =>
json == null ? null : new ReloadReport._fromJson(json);

View file

@ -2,7 +2,7 @@ name: vm_service
description: >-
A library to communicate with a service implementing the Dart VM
service protocol.
version: 1.1.2
version: 1.2.0
author: Dart Team <misc@dartlang.org>
homepage: https://github.com/dart-lang/sdk/tree/master/pkg/vm_service

View file

@ -0,0 +1,61 @@
// 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 'dart:async';
import 'package:vm_service/vm_service.dart';
import 'package:test/test.dart';
import 'common/service_test_common.dart';
import 'common/test_helper.dart';
fib(n) {
if (n < 0) return 0;
if (n == 0) return 1;
return fib(n - 1) + fib(n - 2);
}
testeeDo() {
print("Testee doing something.");
fib(30);
print("Testee did something.");
}
Future checkSamples(VmService service, IsolateRef isolate) async {
// Grab all the samples.
final result = await service.getCpuSamples(isolate.id, 0, ~0);
final isString = TypeMatcher<String>();
final isInt = TypeMatcher<int>();
final isList = TypeMatcher<List>();
expect(result.functions.length, greaterThan(10),
reason: "Should have many functions");
final samples = result.samples;
expect(samples.length, greaterThan(10), reason: "Should have many samples");
expect(samples.length, result.sampleCount);
final sample = samples.first;
expect(sample.tid, isInt);
expect(sample.timestamp, isInt);
if (sample.vmTag != null) {
expect(sample.vmTag, isString);
}
if (sample.userTag != null) {
expect(sample.userTag, isString);
}
expect(sample.stack, isList);
}
var tests = <IsolateTest>[
(VmService service, IsolateRef i) => checkSamples(service, i),
];
var vmArgs = [
'--profiler=true',
'--profile-vm=false', // So this also works with DBC and KBC.
];
main(args) async =>
runIsolateTests(args, tests, testeeBefore: testeeDo, extraArgs: vmArgs);

View file

@ -831,6 +831,11 @@ double assertDouble(double obj) {
return obj;
}
dynamic assertDynamic(dynamic obj) {
assertNotNull(obj);
return obj;
}
List<int> assertListOfInt(List<int> list) {
for (int elem in list) {
assertInt(elem);
@ -925,6 +930,7 @@ vms.Event assertIsolateEvent(vms.Event event) {
'ClassHeapStats',
'CodeRegion',
'ContextElement',
'CpuSample',
'Flag',
'Frame',
'InboundReference',