Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(629)

Unified Diff: runtime/bin/vmservice/client/lib/src/observatory/model.dart

Issue 135843006: Improve Code object support in service and observatory (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 6 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: runtime/bin/vmservice/client/lib/src/observatory/model.dart
diff --git a/runtime/bin/vmservice/client/lib/src/observatory/model.dart b/runtime/bin/vmservice/client/lib/src/observatory/model.dart
new file mode 100644
index 0000000000000000000000000000000000000000..1604a49a235dffc7d8f7af4f476a6747355d980c
--- /dev/null
+++ b/runtime/bin/vmservice/client/lib/src/observatory/model.dart
@@ -0,0 +1,244 @@
+// Copyright (c) 2014, 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.
+
+part of observatory;
+
+class CodeInstruction extends Observable {
+ @observable final int address;
+ @observable final String machine;
+ @observable final String human;
+ @observable int ticks = 0;
+ @observable String formattedTicks = '';
+ @observable String formattedAddress() {
+ return '0x${address.toRadixString(16)}';
+ }
+ CodeInstruction(this.address, this.machine, this.human);
+ void updateTickString(Code code) {
+ formattedTicks = '';
+ if ((code == null) || (code.inclusiveTicks == 0)) {
+ return;
+ }
+ double percent = (ticks / code.inclusiveTicks) * 100.0;
+ if (percent <= 0.00) {
+ return;
+ }
+ formattedTicks = percent.toStringAsFixed(2);
turnidge 2014/01/17 19:30:21 Is it important to cache the formattedTicks? Woul
Cutch 2014/01/17 21:15:42 I only cache the percentage now (and only if it's
+ }
+}
+
+class CodeKind {
+ final _value;
+ const CodeKind._internal(this._value);
+ String toString() => 'CodeKind.$_value';
+
+ static CodeKind fromString(String s) {
+ if (s == 'Native') {
+ return Native;
+ } else if (s == 'Dart') {
+ return Dart;
+ } else if (s == 'Collected') {
+ return Collected;
+ }
+ throw new FallThroughError();
+ }
+ static const Native = const CodeKind._internal('Native');
+ static const Dart = const CodeKind._internal('Dart');
+ static const Collected = const CodeKind._internal('Collected');
+}
+
+class CodeTick {
+ final int address;
+ final int ticks;
+ CodeTick(this.address, this.ticks);
+}
+
+class Code extends Observable {
+ final CodeKind kind;
+ final int startAddress;
+ final int endAddress;
+ final List<CodeTick> ticks = [];
+ int inclusiveTicks = 0;
+ int exclusiveTicks = 0;
+ @observable final List<CodeInstruction> instructions = toObservable([]);
+ @observable Map functionRef = toObservable({});
+ @observable Map codeRef = toObservable({});
+ @observable String name;
+ @observable String user_name;
+
+ Code(this.kind, this.name, this.startAddress, this.endAddress);
+
+ Code.fromMap(Map m) :
+ kind = CodeKind.Dart,
+ startAddress = int.parse(m['start'], radix:16),
+ endAddress = int.parse(m['end'], radix:16) {
+ functionRef = toObservable(m['function']);
+ codeRef = {
+ 'type': '@Code',
+ 'id': m['id'],
+ 'name': m['name'],
+ 'user_name': m['user_name']
+ };
+ name = m['name'];
+ user_name = m['user_name'];
+ _loadInstructions(m['disassembly']);
+ }
+
+ /// Resets all tick counts to 0.
+ void resetTicks() {
+ inclusiveTicks = 0;
+ exclusiveTicks = 0;
+ ticks.clear();
+ for (var i = 0; i < instructions.length; i++) {
turnidge 2014/01/17 19:30:21 does this work instead of using an index to iterat
Cutch 2014/01/17 21:15:42 Done.
+ var instruction = instructions[i];
+ instruction.ticks = 0;
+ }
+ }
+
+ /// Adds [count] to the tick count for the instruction at [address].
+ void tick(int address, int count) {
+ for (var i = 0; i < instructions.length; i++) {
+ var instruction = instructions[i];
+ if (instruction.address == address) {
+ instruction.ticks += count;
+ return;
+ }
+ }
+ }
+
+ /// Clears [instructions] and then adds all instructions from
+ /// [instructionList].
+ void _loadInstructions(List instructionList) {
+ if (instructionList == null) {
turnidge 2014/01/17 19:30:21 Does this happen?
Cutch 2014/01/17 21:15:42 Done.
+ return;
+ }
+ instructions.clear();
+ // Load disassembly into code object.
+ for (int i = 0; i < instructionList.length; i += 3) {
+ if (instructionList[i] == '') {
+ // Code comment.
+ // TODO(johnmccutchan): Insert code comments into instructions.
+ continue;
+ }
+ var address = int.parse(instructionList[i]);
+ var machine = instructionList[i + 1];
+ var human = instructionList[i + 2];
+ instructions.add(new CodeInstruction(address, machine, human));
+ }
+ }
+
+ /// returns true if [address] is inside the address range.
+ bool contains(int address) {
+ return (address >= startAddress) && (address < endAddress);
+ }
+}
+
+class Profile {
+ final Isolate isolate;
+ Profile.fromMap(this.isolate, Map m) {
+ var codes = m['codes'];
+ totalSamples = m['samples'];
+ Logger.root.info('Creating profile from ${totalSamples} samples '
+ 'and ${codes.length} code objects.');
+ isolate.resetCodeTicks();
+ codes.forEach((code) {
+ try {
+ _processCode(code);
+ } catch (e, st) {
+ Logger.root.warning('Error processing code object.', e, st);
+ }
+ });
+ }
+ int totalSamples = 0;
+
+ Code _processDartCode(Map dartCode) {
+ var codeObject = dartCode['code'];
+ if ((codeObject == null)) {
+ // Detached code objects are handled like 'other' code.
+ return _processOtherCode(CodeKind.Dart, dartCode);
+ }
+ var code = new Code.fromMap(codeObject);
+ return code;
+ }
+
+ Code _processOtherCode(CodeKind kind, Map otherCode) {
+ var startAddress = int.parse(otherCode['start'], radix:16);
+ var endAddress = int.parse(otherCode['end'], radix: 16);
+ var name = otherCode['name'];
+ assert(name != null);
+ return new Code(kind, name, startAddress, endAddress);
+ }
+
+ void _processCode(Map profileCode) {
+ if (profileCode['type'] != 'ProfileCode') {
+ return;
+ }
+ var kind = CodeKind.fromString(profileCode['kind']);
+ var address;
+ if (kind == CodeKind.Dart) {
+ address = int.parse(profileCode['code']['start'], radix:16);
+ } else {
+ address = int.parse(profileCode['start'], radix:16);
+ }
+ var code = isolate.findCodeByAddress(address);
+ if (code == null) {
+ if (kind == CodeKind.Dart) {
+ code = _processDartCode(profileCode);
+ } else {
+ code = _processOtherCode(kind, profileCode);
+ }
+ assert(code != null);
+ Logger.root.info(
+ 'Added code with 0x${address.toRadixString(16)} to isolate.');
+ isolate.codes.add(code);
+ }
+ // Load code object tick counts and set them.
+ var inclusive = int.parse(profileCode['inclusive_ticks']);
+ var exclusive = int.parse(profileCode['exclusive_ticks']);
+ code.inclusiveTicks = inclusive;
+ code.exclusiveTicks = exclusive;
+ // Load address specific ticks.
+ List ticksList = profileCode['ticks'];
+ if (ticksList != null && (ticksList.length > 0)) {
+ for (var i = 0; i < ticksList.length; i += 2) {
+ var address = int.parse(ticksList[i], radix:16);
+ var ticks = int.parse(ticksList[i + 1]);
+ var codeTick = new CodeTick(address, ticks);
+ code.ticks.add(codeTick);
+ }
+ }
+ if ((code.ticks.length > 0) && (code.instructions.length > 0)) {
+ // Apply address ticks to instruction stream.
+ code.ticks.forEach((CodeTick tick) {
+ code.tick(tick.address, tick.ticks);
+ });
+ code.instructions.forEach((i) {
+ i.updateTickString(code);
+ });
+ }
+ }
+
+
+
turnidge 2014/01/17 19:30:21 Too many blank lines?
Cutch 2014/01/17 21:15:42 Done.
+ List<Code> topExclusive(int N) {
turnidge 2014/01/17 19:30:21 N uses a non-standard variable casing. Consider "
Cutch 2014/01/17 21:15:42 Done.
+ List<Code> exclusive = isolate.codes;
+ exclusive.sort((Code a, Code b) {
+ return b.exclusiveTicks - a.exclusiveTicks;
+ });
+ if ((exclusive.length < N) || (N == 0)) {
+ return exclusive;
+ }
+ return exclusive.sublist(0, N);
+ }
+
+ List<Code> topInclusive(int N) {
+ List<Code> inclusive = isolate.codes;
+ inclusive.sort((Code a, Code b) {
+ return b.inclusiveTicks - a.inclusiveTicks;
+ });
+ if ((inclusive.length < N) || (N == 0)) {
+ return inclusive;
+ }
+ return inclusive.sublist(0, N);
+ }
+}

Powered by Google App Engine
This is Rietveld 408576698