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

Unified Diff: runtime/observatory/lib/src/service/object.dart

Issue 928833003: Add Function based profile tree (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 5 years, 10 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
« no previous file with comments | « runtime/observatory/lib/src/elements/service_view.dart ('k') | runtime/observatory/lib/utils.dart » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: runtime/observatory/lib/src/service/object.dart
diff --git a/runtime/observatory/lib/src/service/object.dart b/runtime/observatory/lib/src/service/object.dart
index 7fde8e9b7aa07da273171808b4ebe839c3d0001d..c6b1808af895929f1bcdf395cdad248a2a63492f 100644
--- a/runtime/observatory/lib/src/service/object.dart
+++ b/runtime/observatory/lib/src/service/object.dart
@@ -577,11 +577,12 @@ abstract class VM extends ServiceObjectOwner {
Future<ServiceObject> invokeRpc(String method, Map params) {
return invokeRpcNoUpgrade(method, params).then((ObservableMap response) {
- var obj = new ServiceObject._fromMap(this, response);
- if (obj.canCache) {
- _cache.putIfAbsent(id, () => obj);
- }
- return obj;
+ var obj = new ServiceObject._fromMap(this, response);
+ if ((obj != null) && obj.canCache) {
+ String objId = obj.id;
+ _cache.putIfAbsent(objId, () => obj);
+ }
+ return obj;
});
}
@@ -777,47 +778,16 @@ class Isolate extends ServiceObjectOwner with Coverage {
assert(owner is VM);
}
- static const TAG_ROOT_ID = 'code/tag-0';
-
- /// Returns the Code object for the root tag.
- Code tagRoot() {
- // TODO(turnidge): Use get() here instead?
- return _cache[TAG_ROOT_ID];
- }
-
- void processProfile(ServiceMap profile) {
- assert(profile.type == 'CpuProfile');
- var codeTable = new List<Code>();
- var codeRegions = profile['codes'];
- for (var codeRegion in codeRegions) {
- Code code = codeRegion['code'];
- assert(code != null);
- codeTable.add(code);
- }
- _resetProfileData();
- _updateProfileData(profile, codeTable);
- var exclusiveTrie = profile['exclusive_trie'];
- if (exclusiveTrie != null) {
- profileTrieRoot = _processProfileTrie(exclusiveTrie, codeTable);
- }
- }
-
- void _resetProfileData() {
+ void resetCachedProfileData() {
_cache.values.forEach((value) {
- if (value is Code) {
- Code code = value;
- code.resetProfileData();
- }
- });
- }
-
- void _updateProfileData(ServiceMap profile, List<Code> codeTable) {
- var codeRegions = profile['codes'];
- var sampleCount = profile['samples'];
- for (var codeRegion in codeRegions) {
- Code code = codeRegion['code'];
- code.updateProfileData(codeRegion, codeTable, sampleCount);
- }
+ if (value is Code) {
+ Code code = value;
+ code.profile = null;
+ } else if (value is ServiceFunction) {
+ ServiceFunction function = value;
+ function.profile = null;
+ }
+ });
}
/// Fetches and builds the class hierarchy for this isolate. Returns the
@@ -861,16 +831,16 @@ class Isolate extends ServiceObjectOwner with Coverage {
if (map == null) {
return null;
}
- String id = map['id'];
- var obj = _cache[id];
+ String mapId = map['id'];
+ var obj = (mapId != null) ? _cache[mapId] : null;
if (obj != null) {
// Consider calling update when map is not a reference.
return obj;
}
// Build the object from the map directly.
obj = new ServiceObject._fromMap(this, map);
- if (obj != null && obj.canCache) {
- _cache[id] = obj;
+ if ((obj != null) && obj.canCache) {
+ _cache[mapId] = obj;
}
return obj;
}
@@ -882,11 +852,12 @@ class Isolate extends ServiceObjectOwner with Coverage {
Future<ServiceObject> invokeRpc(String method, Map params) {
return invokeRpcNoUpgrade(method, params).then((ObservableMap response) {
- var obj = new ServiceObject._fromMap(this, response);
- if (obj.canCache) {
- _cache.putIfAbsent(id, () => obj);
- }
- return obj;
+ var obj = new ServiceObject._fromMap(this, response);
+ if ((obj != null) && obj.canCache) {
+ String objId = obj.id;
+ _cache.putIfAbsent(objId, () => obj);
+ }
+ return obj;
});
}
@@ -1042,51 +1013,6 @@ class Isolate extends ServiceObjectOwner with Coverage {
});
}
- @reflectable CodeTrieNode profileTrieRoot;
- // The profile trie is serialized as a list of integers. Each node
- // is recreated by consuming some portion of the list. The format is as
- // follows:
- // [0] index into codeTable of code object.
- // [1] tick count (number of times this stack frame occured).
- // [2] child node count
- // Reading the trie is done by recursively reading the tree depth-first
- // pre-order.
- CodeTrieNode _processProfileTrie(List<int> data, List<Code> codeTable) {
- // Setup state shared across calls to _readTrieNode.
- _trieDataCursor = 0;
- _trieData = data;
- if (_trieData == null) {
- return null;
- }
- if (_trieData.length < 3) {
- // Not enough integers for 1 node.
- return null;
- }
- // Read the tree, returns the root node.
- return _readTrieNode(codeTable);
- }
- int _trieDataCursor;
- List<int> _trieData;
- CodeTrieNode _readTrieNode(List<Code> codeTable) {
- // Read index into code table.
- var index = _trieData[_trieDataCursor++];
- // Lookup code object.
- var code = codeTable[index];
- // Frame counter.
- var count = _trieData[_trieDataCursor++];
- // Create node.
- var node = new CodeTrieNode(code, count);
- // Number of children.
- var children = _trieData[_trieDataCursor++];
- // Recursively read child nodes.
- for (var i = 0; i < children; i++) {
- var child = _readTrieNode(codeTable);
- node.children.add(child);
- node.summedChildCount += child.count;
- }
- return node;
- }
-
ObservableList<Breakpoint> breakpoints = new ObservableList();
void _removeBreakpoint(Breakpoint bpt) {
@@ -1868,7 +1794,7 @@ class FunctionKind {
final String _strValue;
FunctionKind._internal(this._strValue);
toString() => _strValue;
- bool isFake() => [kCollected, kNative, kTag, kReused].contains(this);
+ bool isSynthetic() => [kCollected, kNative, kTag, kReused].contains(this);
static FunctionKind fromJSON(String value) {
switch(value) {
@@ -1927,6 +1853,10 @@ class ServiceFunction extends ServiceObject with Coverage {
@observable String qualifiedName;
@observable int usageCounter;
@observable bool isDart;
+ @observable ProfileFunction profile;
+
+ bool get canCache => true;
+ bool get immutable => false;
ServiceFunction._empty(ServiceObject owner) : super._empty(owner);
@@ -1939,7 +1869,7 @@ class ServiceFunction extends ServiceObject with Coverage {
owningClass = map.containsKey('owningClass') ? map['owningClass'] : null;
owningLibrary = map.containsKey('owningLibrary') ? map['owningLibrary'] : null;
kind = FunctionKind.fromJSON(map['kind']);
- isDart = !kind.isFake();
+ isDart = !kind.isSynthetic();
if (parent == null) {
qualifiedName = (owningClass != null) ?
@@ -1949,7 +1879,9 @@ class ServiceFunction extends ServiceObject with Coverage {
qualifiedName = "${parent.qualifiedName}.${name}";
}
- if (mapIsRef) { return; }
+ if (mapIsRef) {
+ return;
+ }
isStatic = map['static'];
isConst = map['const'];
@@ -1963,7 +1895,6 @@ class ServiceFunction extends ServiceObject with Coverage {
isInlinable = map['inlinable'];
deoptimizations = map['deoptimizations'];
usageCounter = map['usageCounter'];
-
}
}
@@ -2206,13 +2137,6 @@ class Script extends ServiceObject with Coverage {
}
}
-class CodeTick {
- final int address;
- final int exclusiveTicks;
- final int inclusiveTicks;
- CodeTick(this.address, this.exclusiveTicks, this.inclusiveTicks);
-}
-
class PcDescriptor extends Observable {
final int pcOffset;
@reflectable final int deoptId;
@@ -2356,51 +2280,11 @@ class CodeInstruction extends Observable {
@reflectable List<PcDescriptor> descriptors =
new ObservableList<PcDescriptor>();
- static String formatPercent(num a, num total) {
- var percent = 100.0 * (a / total);
- return '${percent.toStringAsFixed(2)}%';
- }
-
CodeInstruction(this.address, this.pcOffset, this.machine, this.human);
@reflectable bool get isComment => address == 0;
@reflectable bool get hasDescriptors => descriptors.length > 0;
- @reflectable String formattedAddress() {
- if (address == 0) {
- return '';
- }
- return '0x${address.toRadixString(16)}';
- }
-
- @reflectable String formattedInclusive(Code code) {
- if (code == null) {
- return '';
- }
- var tick = code.addressTicks[address];
- 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})';
- }
-
- @reflectable String formattedExclusive(Code code) {
- if (code == null) {
- return '';
- }
- var tick = code.addressTicks[address];
- if (tick == null) {
- return '';
- }
- var pcent = formatPercent(tick.exclusiveTicks, code.totalSamplesInProfile);
- return '$pcent (${tick.exclusiveTicks})';
- }
-
bool _isJumpInstruction() {
return human.startsWith('j');
}
@@ -2430,8 +2314,6 @@ class CodeInstruction extends Observable {
}
int address = _getJumpAddress();
if (address == 0) {
- // Could not determine jump address.
- Logger.root.severe('Could not determine jump address for $human');
return;
}
for (var i = 0; i < instructions.length; i++) {
@@ -2441,8 +2323,6 @@ class CodeInstruction extends Observable {
return;
}
}
- Logger.root.severe(
- 'Could not find instruction at ${address.toRadixString(16)}');
}
}
@@ -2473,55 +2353,33 @@ class CodeKind {
static const Tag = const CodeKind._internal('Tag');
}
-class CodeCallCount {
- final Code code;
- final int count;
- CodeCallCount(this.code, this.count);
-}
-
-class CodeTrieNode {
- final Code code;
- final int count;
- final children = new List<CodeTrieNode>();
- int summedChildCount = 0;
- CodeTrieNode(this.code, this.count);
+class CodeInlineInterval {
+ final int start;
+ final int end;
+ final List<ServiceFunction> functions = new List<ServiceFunction>();
+ bool contains(int pc) => (pc >= start) && (pc < end);
+ CodeInlineInterval(this.start, this.end);
}
class Code extends ServiceObject {
@observable CodeKind kind;
- @observable int totalSamplesInProfile = 0;
- @reflectable int exclusiveTicks = 0;
- @reflectable int inclusiveTicks = 0;
- @reflectable int startAddress = 0;
- @reflectable int endAddress = 0;
- @reflectable final callers = new List<CodeCallCount>();
- @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 Instance objectPool;
@observable ServiceFunction function;
@observable Script script;
@observable bool isOptimized = false;
-
+ @reflectable int startAddress = 0;
+ @reflectable int endAddress = 0;
+ @reflectable final instructions = new ObservableList<CodeInstruction>();
+ @observable ProfileCode profile;
+ final List<CodeInlineInterval> inlineIntervals =
+ new List<CodeInlineInterval>();
+ final ObservableList<ServiceFunction> inlinedFunctions =
+ new ObservableList<ServiceFunction>();
bool get canCache => true;
bool get immutable => true;
Code._empty(ServiceObjectOwner owner) : super._empty(owner);
- // Reset all data associated with a profile.
- void resetProfileData() {
- totalSamplesInProfile = 0;
- exclusiveTicks = 0;
- inclusiveTicks = 0;
- formattedInclusiveTicks = '';
- formattedExclusiveTicks = '';
- callers.clear();
- callees.clear();
- addressTicks.clear();
- }
-
void _updateDescriptors(Script script) {
this.script = script;
for (var instruction in instructions) {
@@ -2570,49 +2428,6 @@ class Code extends ServiceObject {
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);
- // Resolve.
- for (var i = 0; i < data.length; i += 2) {
- var index = int.parse(data[i]);
- var count = int.parse(data[i + 1]);
- assert(index >= 0);
- assert(index < codes.length);
- calls.add(new CodeCallCount(codes[index], count));
- }
- // Sort to descending count order.
- calls.sort((a, b) => b.count - a.count);
- }
-
-
- 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 are handed profile data for this code object.
- assert(profileData['code'] == this);
- totalSamplesInProfile = sampleCount;
- inclusiveTicks = int.parse(profileData['inclusive_ticks']);
- exclusiveTicks = int.parse(profileData['exclusive_ticks']);
- _resolveCalls(callers, profileData['callers'], codeTable);
- _resolveCalls(callees, profileData['callees'], codeTable);
- var ticks = profileData['ticks'];
- if (ticks != null) {
- _processTicks(ticks);
- }
- formattedInclusiveTicks =
- '${formatPercent(inclusiveTicks, totalSamplesInProfile)} '
- '($inclusiveTicks)';
- formattedExclusiveTicks =
- '${formatPercent(exclusiveTicks, totalSamplesInProfile)} '
- '($exclusiveTicks)';
- }
-
void _update(ObservableMap m, bool mapIsRef) {
name = m['name'];
vmName = (m.containsKey('vmName') ? m['vmName'] : name);
@@ -2621,6 +2436,10 @@ class Code extends ServiceObject {
startAddress = int.parse(m['start'], radix:16);
endAddress = int.parse(m['end'], radix:16);
function = isolate.getFromMap(m['function']);
+ if (mapIsRef) {
+ return;
+ }
+ _loaded = true;
objectPool = isolate.getFromMap(m['objectPool']);
var disassembly = m['disassembly'];
if (disassembly != null) {
@@ -2631,9 +2450,56 @@ class Code extends ServiceObject {
descriptors = descriptors['members'];
_processDescriptors(descriptors);
}
- // We are loaded if we have instructions or are not Dart code.
- _loaded = (instructions.length != 0) || (kind != CodeKind.Dart);
hasDisassembly = (instructions.length != 0) && (kind == CodeKind.Dart);
+ inlinedFunctions.clear();
+ var inlinedFunctionsTable = m['inlinedFunctions'];
+ var inlinedIntervals = m['inlinedIntervals'];
+ if (inlinedFunctionsTable != null) {
+ // Iterate and upgrade each ServiceFunction.
+ for (var i = 0; i < inlinedFunctionsTable.length; i++) {
+ // Upgrade each function and set it back in the list.
+ var func = isolate.getFromMap(inlinedFunctionsTable[i]);
+ inlinedFunctionsTable[i] = func;
+ if (!inlinedFunctions.contains(func)) {
+ inlinedFunctions.add(func);
+ }
+ }
+ }
+ if ((inlinedIntervals == null) || (inlinedFunctionsTable == null)) {
+ // No inline information.
+ inlineIntervals.clear();
+ return;
+ }
+ _processInline(inlinedFunctionsTable, inlinedIntervals);
+ }
+
+ CodeInlineInterval findInterval(int pc) {
+ for (var i = 0; i < inlineIntervals.length; i++) {
+ var interval = inlineIntervals[i];
+ if (interval.contains(pc)) {
+ return interval;
+ }
+ }
+ return null;
+ }
+
+ void _processInline(List<ServiceFunction> inlinedFunctionsTable,
+ List<List<int>> inlinedIntervals) {
+ for (var i = 0; i < inlinedIntervals.length; i++) {
+ var inlinedInterval = inlinedIntervals[i];
+ var start = inlinedInterval[0] + startAddress;
+ var end = inlinedInterval[1] + startAddress;
+ var codeInlineInterval = new CodeInlineInterval(start, end);
+ for (var i = 2; i < inlinedInterval.length - 1; i++) {
+ var inline_id = inlinedInterval[i];
+ if (inline_id < 0) {
+ continue;
+ }
+ var function = inlinedFunctionsTable[inline_id];
+ codeInlineInterval.functions.add(function);
+ }
+ inlineIntervals.add(codeInlineInterval);
+ }
}
@observable bool hasDisassembly = false;
@@ -2687,49 +2553,11 @@ class Code extends ServiceObject {
}
}
- void _processTicks(List<String> profileTicks) {
- assert(profileTicks != null);
- assert((profileTicks.length % 3) == 0);
- for (var i = 0; i < profileTicks.length; i += 3) {
- var address = int.parse(profileTicks[i], radix:16);
- var exclusive = int.parse(profileTicks[i + 1]);
- var inclusive = int.parse(profileTicks[i + 2]);
- var tick = new CodeTick(address, exclusive, inclusive);
- addressTicks[address] = tick;
- }
- }
-
/// Returns true if [address] is contained inside [this].
bool contains(int address) {
return (address >= startAddress) && (address < endAddress);
}
- /// Sum all caller counts.
- int sumCallersCount() => _sumCallCount(callers);
- /// Specific caller count.
- int callersCount(Code code) => _callCount(callers, code);
- /// Sum of callees count.
- int sumCalleesCount() => _sumCallCount(callees);
- /// Specific callee count.
- int calleesCount(Code code) => _callCount(callees, code);
-
- int _sumCallCount(List<CodeCallCount> calls) {
- var sum = 0;
- for (CodeCallCount caller in calls) {
- sum += caller.count;
- }
- return sum;
- }
-
- int _callCount(List<CodeCallCount> calls, Code code) {
- for (CodeCallCount caller in calls) {
- if (caller.code == code) {
- return caller.count;
- }
- }
- return 0;
- }
-
@reflectable bool get isDartCode => kind == CodeKind.Dart;
}
« no previous file with comments | « runtime/observatory/lib/src/elements/service_view.dart ('k') | runtime/observatory/lib/utils.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698