| Index: runtime/bin/vmservice/client/lib/src/service/object.dart
|
| diff --git a/runtime/bin/vmservice/client/lib/src/service/object.dart b/runtime/bin/vmservice/client/lib/src/service/object.dart
|
| index 6d14e12e37db615417a6e8b3eaf8d2e0994c742a..bbfe10a4c619b052a9e9e41a7a6c286dee7f29d0 100644
|
| --- a/runtime/bin/vmservice/client/lib/src/service/object.dart
|
| +++ b/runtime/bin/vmservice/client/lib/src/service/object.dart
|
| @@ -19,6 +19,9 @@ class Isolate extends ServiceObject {
|
| /// Class cache.
|
| ClassCache _classes;
|
| ClassCache get classes => _classes;
|
| + /// Function cache.
|
| + FunctionCache _functions;
|
| + FunctionCache get functions => _functions;
|
|
|
| void _initOnce() {
|
| // Only called once.
|
| @@ -27,6 +30,7 @@ class Isolate extends ServiceObject {
|
| _scripts = new ScriptCache(this);
|
| _codes = new CodeCache(this);
|
| _classes = new ClassCache(this);
|
| + _functions = new FunctionCache(this);
|
| }
|
|
|
| Isolate.fromId(this.vm, String id) : super(null, id, '@Isolate') {
|
| @@ -49,9 +53,10 @@ class Isolate extends ServiceObject {
|
| void processProfile(ServiceMap profile) {
|
| assert(profile.serviceType == 'Profile');
|
| var codeTable = new List<Code>();
|
| - var profileCodes = profile['codes'];
|
| - for (var profileCode in profileCodes) {
|
| - Code code = profileCode['code'];
|
| + var codeRegions = profile['codes'];
|
| + for (var codeRegion in codeRegions) {
|
| + Code code = codeRegion['code'];
|
| + assert(code != null);
|
| codeTable.add(code);
|
| }
|
| _codes._resetProfileData();
|
| @@ -70,6 +75,9 @@ class Isolate extends ServiceObject {
|
| if (_classes.cachesId(serviceId)) {
|
| return _classes.get(serviceId);
|
| }
|
| + if (_functions.cachesId(serviceId)) {
|
| + return _functions.get(serviceId);
|
| + }
|
| return vm.getAsMap(relativeLink(serviceId)).then((ObservableMap m) {
|
| return _upgradeToServiceObject(vm, this, m);
|
| });
|
| @@ -403,6 +411,10 @@ class CodeInstruction extends Observable {
|
| if (tick == null) {
|
| return '';
|
| }
|
| + // Don't show inclusive ticks if they are the same as exclusive ticks.
|
| + if (tick.inclusiveTicks == tick.exclusiveTicks) {
|
| + return '';
|
| + }
|
| var pcent = formatPercent(tick.inclusiveTicks, code.totalSamplesInProfile);
|
| return '$pcent (${tick.inclusiveTicks})';
|
| }
|
| @@ -423,7 +435,7 @@ class CodeInstruction extends Observable {
|
| class CodeKind {
|
| final _value;
|
| const CodeKind._internal(this._value);
|
| - String toString() => 'CodeKind.$_value';
|
| + String toString() => '$_value';
|
|
|
| static CodeKind fromString(String s) {
|
| if (s == 'Native') {
|
| @@ -432,12 +444,16 @@ class CodeKind {
|
| return Dart;
|
| } else if (s == 'Collected') {
|
| return Collected;
|
| + } else if (s == 'Reused') {
|
| + return Reused;
|
| }
|
| + Logger.root.warning('Unknown code kind $s');
|
| throw new FallThroughError();
|
| }
|
| static const Native = const CodeKind._internal('Native');
|
| static const Dart = const CodeKind._internal('Dart');
|
| static const Collected = const CodeKind._internal('Collected');
|
| + static const Reused = const CodeKind._internal('Reused');
|
| }
|
|
|
| class CodeCallCount {
|
| @@ -457,6 +473,8 @@ class Code extends ServiceObject {
|
| @reflectable final callees = new List<CodeCallCount>();
|
| @reflectable final instructions = new ObservableList<CodeInstruction>();
|
| @reflectable final addressTicks = new ObservableMap<int, CodeTick>();
|
| + @observable String formattedInclusiveTicks = '';
|
| + @observable String formattedExclusiveTicks = '';
|
|
|
| @observable ServiceMap function;
|
| String name;
|
| @@ -469,11 +487,24 @@ class Code extends ServiceObject {
|
| totalSamplesInProfile = 0;
|
| exclusiveTicks = 0;
|
| inclusiveTicks = 0;
|
| + formattedInclusiveTicks = '';
|
| + formattedExclusiveTicks = '';
|
| callers.clear();
|
| callees.clear();
|
| addressTicks.clear();
|
| }
|
|
|
| + /// Reload [this]. Returns a future which completes to [this] or
|
| + /// a [ServiceError].
|
| + Future<ServiceObject> reload() {
|
| + assert(kind != null);
|
| + if (kind == CodeKind.Dart) {
|
| + // We only reload Dart code.
|
| + return super.reload();
|
| + }
|
| + return new Future.value(this);
|
| + }
|
| +
|
| void _resolveCalls(List<CodeCallCount> calls, List data, List<Code> codes) {
|
| // Assert that this has been cleared.
|
| assert(calls.length == 0);
|
| @@ -490,11 +521,16 @@ class Code extends ServiceObject {
|
| }
|
|
|
|
|
| + static String formatPercent(num a, num total) {
|
| + var percent = 100.0 * (a / total);
|
| + return '${percent.toStringAsFixed(2)}%';
|
| + }
|
| +
|
| void updateProfileData(Map profileData,
|
| List<Code> codeTable,
|
| int sampleCount) {
|
| - // Assert we have a ProfileCode entry.
|
| - assert(profileData['type'] == 'ProfileCode');
|
| + // Assert we have a CodeRegion entry.
|
| + assert(profileData['type'] == 'CodeRegion');
|
| // Assert we are handed profile data for this code object.
|
| assert(profileData['code'] == this);
|
| totalSamplesInProfile = sampleCount;
|
| @@ -506,6 +542,12 @@ class Code extends ServiceObject {
|
| if (ticks != null) {
|
| _processTicks(ticks);
|
| }
|
| + formattedInclusiveTicks =
|
| + '${formatPercent(inclusiveTicks, totalSamplesInProfile)} '
|
| + '($inclusiveTicks)';
|
| + formattedExclusiveTicks =
|
| + '${formatPercent(exclusiveTicks, totalSamplesInProfile)} '
|
| + '($inclusiveTicks)';
|
| }
|
|
|
| void _update(ObservableMap m) {
|
| @@ -514,6 +556,7 @@ class Code extends ServiceObject {
|
| assert(ServiceObject.stripRef(m['type']) == _serviceType);
|
| name = m['user_name'];
|
| vmName = m['name'];
|
| + kind = CodeKind.fromString(m['kind']);
|
| startAddress = int.parse(m['start'], radix:16);
|
| endAddress = int.parse(m['end'], radix:16);
|
| // Upgrade the function.
|
| @@ -522,10 +565,13 @@ class Code extends ServiceObject {
|
| if (disassembly != null) {
|
| _processDisassembly(disassembly);
|
| }
|
| - // We are a reference if we don't have instructions.
|
| - _ref = (instructions.length == 0);
|
| + // We are a reference if we don't have instructions and are Dart code.
|
| + _ref = (instructions.length == 0) && (kind == CodeKind.Dart);
|
| + hasDisassembly = (instructions.length != 0) && (kind == CodeKind.Dart);
|
| }
|
|
|
| + @observable bool hasDisassembly = false;
|
| +
|
| void _processDisassembly(List<String> disassembly){
|
| assert(disassembly != null);
|
| instructions.clear();
|
|
|