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

Unified Diff: runtime/observatory/lib/src/cpu_profile/cpu_profile.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
Index: runtime/observatory/lib/src/cpu_profile/cpu_profile.dart
diff --git a/runtime/observatory/lib/src/cpu_profile/cpu_profile.dart b/runtime/observatory/lib/src/cpu_profile/cpu_profile.dart
new file mode 100644
index 0000000000000000000000000000000000000000..99744f6029952257f37e8723dac377569ce17cba
--- /dev/null
+++ b/runtime/observatory/lib/src/cpu_profile/cpu_profile.dart
@@ -0,0 +1,312 @@
+// Copyright (c) 2015, 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 cpu_profiler;
+
+class CodeTrieNode {
+ final ProfileCode profileCode;
+ final int count;
+ final children = new List<CodeTrieNode>();
+ CodeTrieNode(this.profileCode, this.count);
+}
+
+class FunctionTrieNodeCode {
+ final ProfileCode code;
+ final int ticks;
+ FunctionTrieNodeCode(this.code, this.ticks);
+}
+
+class FunctionTrieNode {
+ final ProfileFunction profileFunction;
+ final int count;
+ final children = new List<FunctionTrieNode>();
+ final codes = new List<FunctionTrieNodeCode>();
+ int _totalCodeTicks = 0;
+ int get totalCodesTicks => _totalCodeTicks;
+ FunctionTrieNode(this.profileFunction, this.count);
+}
+
+class CodeTick {
+ final int exclusiveTicks;
+ final int inclusiveTicks;
+ CodeTick(this.exclusiveTicks, this.inclusiveTicks);
+}
+
+class InlineIntervalTick {
+ final int startAddress;
+ int _inclusiveTicks = 0;
+ int get inclusiveTicks => _inclusiveTicks;
+ int _exclusiveTicks = 0;
+ int get exclusiveTicks => _exclusiveTicks;
+ InlineIntervalTick(this.startAddress);
+}
+
+class ProfileCode {
+ final CpuProfile profile;
+ final Code code;
+ int exclusiveTicks;
+ int inclusiveTicks;
+ final addressTicks = new Map<int, CodeTick>();
+ final intervalTicks = new Map<int, InlineIntervalTick>();
+ String formattedInclusiveTicks = '';
+ String formattedExclusiveTicks = '';
+
+ 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(exclusive, inclusive);
+ addressTicks[address] = tick;
+
+ var interval = code.findInterval(address);
+ if (interval != null) {
+ var intervalTick = intervalTicks[interval.start];
+ if (intervalTick == null) {
+ // Insert into map.
+ intervalTick = new InlineIntervalTick(interval.start);
+ intervalTicks[interval.start] = intervalTick;
+ }
+ intervalTick._inclusiveTicks += inclusive;
+ intervalTick._exclusiveTicks += exclusive;
+ }
+ }
+ }
+
+ ProfileCode.fromMap(this.profile, this.code, Map data) {
+ assert(profile != null);
+ assert(code != null);
+
+ code.profile = this;
+
+ inclusiveTicks = int.parse(data['inclusiveTicks']);
+ exclusiveTicks = int.parse(data['exclusiveTicks']);
+ var ticks = data['ticks'];
+ if (ticks != null) {
+ _processTicks(ticks);
+ }
+
+ formattedInclusiveTicks =
+ '${Utils.formatPercent(inclusiveTicks, profile.sampleCount)} '
+ '($inclusiveTicks)';
+
+ formattedExclusiveTicks =
+ '${Utils.formatPercent(exclusiveTicks, profile.sampleCount)} '
+ '($exclusiveTicks)';
+ }
+}
+
+class ProfileFunction {
+ final CpuProfile profile;
+ final ServiceFunction function;
+ // List of compiled code objects containing this function.
+ final List<ProfileCode> profileCodes = new List<ProfileCode>();
+
+ // Absolute ticks:
+ int exclusiveTicks = 0;
+ int inclusiveTicks = 0;
+
+ // Global percentages:
+ double globalExclusiveTicks = 0.0;
+ double globalInclusiveTicks = 0.0;
+
+ int _sortCodes(ProfileCode a, ProfileCode b) {
+ if (a.code.isOptimized == b.code.isOptimized) {
+ return b.code.profile.exclusiveTicks - a.code.profile.exclusiveTicks;
+ }
+ if (a.code.isOptimized) {
+ return -1;
+ }
+ return 1;
+ }
+
+ ProfileFunction.fromMap(this.profile, this.function, Map data) {
+ for (var codeIndex in data['codes']) {
+ var profileCode = profile.codes[codeIndex];
+ profileCodes.add(profileCode);
+ }
+ profileCodes.sort(_sortCodes);
+
+ exclusiveTicks = int.parse(data['exclusiveTicks']);
+ inclusiveTicks = int.parse(data['inclusiveTicks']);
+
+ globalExclusiveTicks = exclusiveTicks / profile.sampleCount;
+ globalInclusiveTicks = inclusiveTicks / profile.sampleCount;
+ }
+}
+
+
+class CpuProfile {
+ final double MICROSECONDS_PER_SECOND = 1000000.0;
+ final double displayThreshold = 0.0002; // 0.02%.
+
+ Isolate isolate;
+
+ int sampleCount = 0;
+ int samplePeriod = 0;
+ double sampleRate = 0.0;
+
+ int stackDepth = 0;
+
+ double timeSpan = 0.0;
+
+ CodeTrieNode codeTrieRoot;
+ FunctionTrieNode functionTrieRoot;
+
+ final List<ProfileCode> codes = new List<ProfileCode>();
+ final List<ProfileFunction> functions = new List<ProfileFunction>();
+
+ void clear() {
+ sampleCount = 0;
+ samplePeriod = 0;
+ sampleRate = 0.0;
+ stackDepth = 0;
+ timeSpan = 0.0;
+ codeTrieRoot = null;
+ functionTrieRoot = null;
+ codes.clear();
+ functions.clear();
+ }
+
+ void load(Isolate isolate, ServiceMap profile) {
+ if ((isolate == null) || (profile == null)) {
+ return;
+ }
+
+ this.isolate = isolate;
+ isolate.resetCachedProfileData();
+
+ clear();
+
+ sampleCount = profile['sampleCount'];
+ samplePeriod = profile['samplePeriod'];
+ sampleRate = (MICROSECONDS_PER_SECOND / samplePeriod);
+ stackDepth = profile['stackDepth'];
+ timeSpan = profile['timeSpan'];
+
+ // Process code table.
+ for (var codeRegion in profile['codes']) {
+ Code code = codeRegion['code'];
+ assert(code != null);
+ codes.add(new ProfileCode.fromMap(this, code, codeRegion));
+ }
+
+ // Process function table.
+ for (var profileFunction in profile['functions']) {
+ ServiceFunction function = profileFunction['function'];
+ assert(function != null);
+ functions.add(
+ new ProfileFunction.fromMap(this, function, profileFunction));
+ }
+
+ // Process code trie.
+ var exclusiveCodeTrie = profile['exclusiveCodeTrie'];
+ assert(exclusiveCodeTrie != null);
+ codeTrieRoot = _processCodeTrie(exclusiveCodeTrie);
+
+ // Process function trie.
+ var exclusiveFunctionTrie = profile['exclusiveFunctionTrie'];
+ assert(exclusiveFunctionTrie != null);
+ functionTrieRoot = _processFunctionTrie(exclusiveFunctionTrie);
+ }
+
+ // Data shared across calls to _read*TrieNode.
+ int _trieDataCursor;
+ List<int> _trieData;
+
+ // The code 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 _processCodeTrie(List<int> data) {
+ // 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 _readCodeTrieNode();
+ }
+
+ CodeTrieNode _readCodeTrieNode() {
+ // Read index into code table.
+ var index = _trieData[_trieDataCursor++];
+ // Lookup code object.
+ var code = codes[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 = _readCodeTrieNode();
+ node.children.add(child);
+ }
+ return node;
+ }
+
+ FunctionTrieNode _processFunctionTrie(List<int> data) {
+ // 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 _readFunctionTrieNode();
+ }
+
+ FunctionTrieNode _readFunctionTrieNode() {
+ // Read index into function table.
+ var index = _trieData[_trieDataCursor++];
+ // Lookup function object.
+ var function = functions[index];
+ // Frame counter.
+ var count = _trieData[_trieDataCursor++];
+ // Create node.
+ var node = new FunctionTrieNode(function, count);
+ // Number of code index / count pairs.
+ var codeCount = _trieData[_trieDataCursor++];
+ var totalCodeTicks = 0;
+ for (var i = 0; i < codeCount; i++) {
+ var codeIndex = _trieData[_trieDataCursor++];
+ var code = codes[codeIndex];
+ var codeTicks = _trieData[_trieDataCursor++];
+ totalCodeTicks += codeTicks;
+ var nodeCode = new FunctionTrieNodeCode(code, codeTicks);
+ node.codes.add(nodeCode);
+ }
+ node._totalCodeTicks = totalCodeTicks;
+ // Number of children.
+ var children = _trieData[_trieDataCursor++];
+ // Recursively read child nodes.
+ for (var i = 0; i < children; i++) {
+ var child = _readFunctionTrieNode();
+ node.children.add(child);
+ }
+ return node;
+ }
+
+ double approximateSecondsForCount(count) {
+ var MICROSECONDS_PER_SECOND = 1000000.0;
+ return (count * samplePeriod) / MICROSECONDS_PER_SECOND;
+ }
+}
« no previous file with comments | « runtime/observatory/lib/src/app/view_model.dart ('k') | runtime/observatory/lib/src/elements/class_ref.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698