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

Side by Side 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 unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file.
4
5 part of cpu_profiler;
6
7 class CodeTrieNode {
8 final ProfileCode profileCode;
9 final int count;
10 final children = new List<CodeTrieNode>();
11 CodeTrieNode(this.profileCode, this.count);
12 }
13
14 class FunctionTrieNodeCode {
15 final ProfileCode code;
16 final int ticks;
17 FunctionTrieNodeCode(this.code, this.ticks);
18 }
19
20 class FunctionTrieNode {
21 final ProfileFunction profileFunction;
22 final int count;
23 final children = new List<FunctionTrieNode>();
24 final codes = new List<FunctionTrieNodeCode>();
25 int _totalCodeTicks = 0;
26 int get totalCodesTicks => _totalCodeTicks;
27 FunctionTrieNode(this.profileFunction, this.count);
28 }
29
30 class CodeTick {
31 final int address;
32 final int exclusiveTicks;
33 final int inclusiveTicks;
34 CodeTick(this.address, this.exclusiveTicks, this.inclusiveTicks);
35 }
36
37 class InlineIntervalTick {
38 final int startAddress;
39 int _inclusiveTicks = 0;
40 int get inclusiveTicks => _inclusiveTicks;
41 int _exclusiveTicks = 0;
42 int get exclusiveTicks => _exclusiveTicks;
43 InlineIntervalTick(this.startAddress);
44 }
45
46 class ProfileCode {
47 final CpuProfile profile;
48 final Code code;
49 int exclusiveTicks;
50 int inclusiveTicks;
51 final addressTicks = new Map<int, CodeTick>();
52 final intervalTicks = new Map<int, InlineIntervalTick>();
53 String formattedInclusiveTicks = '';
54 String formattedExclusiveTicks = '';
55
56 void _processTicks(List<String> profileTicks) {
57 assert(profileTicks != null);
58 assert((profileTicks.length % 3) == 0);
59 for (var i = 0; i < profileTicks.length; i += 3) {
60 var address = int.parse(profileTicks[i], radix:16);
61 var exclusive = int.parse(profileTicks[i + 1]);
62 var inclusive = int.parse(profileTicks[i + 2]);
63 var tick = new CodeTick(address, exclusive, inclusive);
64 addressTicks[address] = tick;
65
66 var interval = code.findInterval(address);
67 if (interval != null) {
68 var intervalTick = intervalTicks[interval.start];
69 if (intervalTick == null) {
70 // Insert into map.
71 intervalTick = new InlineIntervalTick(interval.start);
72 intervalTicks[interval.start] = intervalTick;
73 }
74 intervalTick._inclusiveTicks += inclusive;
75 intervalTick._exclusiveTicks += exclusive;
76 }
77 }
78 }
79
80 ProfileCode.fromMap(this.profile, this.code, Map data) {
81 assert(profile != null);
82 assert(code != null);
83
84 code.profile = this;
85
86 inclusiveTicks = int.parse(data['inclusiveTicks']);
87 exclusiveTicks = int.parse(data['exclusiveTicks']);
88 var ticks = data['ticks'];
89 if (ticks != null) {
90 _processTicks(ticks);
91 }
92
93 formattedInclusiveTicks =
94 '${Utils.formatPercent(inclusiveTicks, profile.sampleCount)} '
95 '($inclusiveTicks)';
96
97 formattedExclusiveTicks =
98 '${Utils.formatPercent(exclusiveTicks, profile.sampleCount)} '
99 '($exclusiveTicks)';
100 }
101 }
102
103 class ProfileFunction {
104 final CpuProfile profile;
105 final ServiceFunction function;
106 // List of compiled code objects containing this function.
107 final List<ProfileCode> profileCodes = new List<ProfileCode>();
108
109 // Absolute ticks:
110 int exclusiveTicks = 0;
111 int inclusiveTicks = 0;
112
113 // Global percentages:
114 double globalExclusiveTicks = 0.0;
115 double globalInclusiveTicks = 0.0;
116
117 int _sortCodes(ProfileCode a, ProfileCode b) {
118 if (a.code.isOptimized == b.code.isOptimized) {
119 return b.code.profile.exclusiveTicks - a.code.profile.exclusiveTicks;
120 }
121 if (a.code.isOptimized) {
122 return -1;
123 }
124 return 1;
125 }
126
127 ProfileFunction.fromMap(this.profile, this.function, Map data) {
128 for (var codeIndex in data['codes']) {
129 var profileCode = profile.codes[codeIndex];
130 profileCodes.add(profileCode);
131 }
132 profileCodes.sort(_sortCodes);
133
134 exclusiveTicks = int.parse(data['exclusiveTicks']);
135 inclusiveTicks = int.parse(data['inclusiveTicks']);
136
137 globalExclusiveTicks = exclusiveTicks / profile.sampleCount;
138 globalInclusiveTicks = inclusiveTicks / profile.sampleCount;
139 }
140 }
141
142
143 class CpuProfile {
144 final double MICROSECONDS_PER_SECOND = 1000000.0;
145 final double displayThreshold = 0.0002; // 0.02%.
146
147 Isolate isolate;
148
149 int sampleCount = 0;
150 int samplePeriod = 0;
151 double sampleRate = 0.0;
152
153 int stackDepth = 0;
154
155 double timeSpan = 0.0;
156
157 CodeTrieNode codeTrieRoot;
158 FunctionTrieNode functionTrieRoot;
159
160 final List<ProfileCode> codes = new List<ProfileCode>();
161 final List<ProfileFunction> functions = new List<ProfileFunction>();
162
163 void clear() {
164 codeTrieRoot = null;
165 functionTrieRoot = null;
166 codes.clear();
167 functions.clear();
168 }
169
170 void load(Isolate isolate, ServiceMap profile) {
171 if ((isolate == null) || (profile == null)) {
172 return;
173 }
174
175 this.isolate = isolate;
176 isolate.resetCachedProfileData();
177
178 clear();
179
180 sampleCount = profile['sampleCount'];
181 samplePeriod = profile['samplePeriod'];
182 sampleRate = (MICROSECONDS_PER_SECOND / samplePeriod);
183 stackDepth = profile['stackDepth'];
184 timeSpan = profile['timeSpan'];
185
186 // Process code table.
187 for (var codeRegion in profile['codes']) {
188 Code code = codeRegion['code'];
189 assert(code != null);
190 codes.add(new ProfileCode.fromMap(this, code, codeRegion));
191 }
192
193 // Process function table.
194 for (var profileFunction in profile['functions']) {
195 ServiceFunction function = profileFunction['function'];
196 assert(function != null);
197 functions.add(
198 new ProfileFunction.fromMap(this, function, profileFunction));
199 }
200
201 // Process code trie.
202 var exclusiveCodeTrie = profile['exclusiveCodeTrie'];
203 assert(exclusiveCodeTrie != null);
204 codeTrieRoot = _processCodeTrie(exclusiveCodeTrie);
205
206 // Process function trie.
207 var exclusiveFunctionTrie = profile['exclusiveFunctionTrie'];
208 assert(exclusiveFunctionTrie != null);
209 functionTrieRoot = _processFunctionTrie(exclusiveFunctionTrie);
210 }
211
212 // Data shared across calls to _read*TrieNode.
213 int _trieDataCursor;
214 List<int> _trieData;
215
216 // The code trie is serialized as a list of integers. Each node
217 // is recreated by consuming some portion of the list. The format is as
218 // follows:
219 // [0] index into codeTable of code object.
220 // [1] tick count (number of times this stack frame occured).
221 // [2] child node count
222 // Reading the trie is done by recursively reading the tree depth-first
223 // pre-order.
224 CodeTrieNode _processCodeTrie(List<int> data) {
225 // Setup state shared across calls to _readTrieNode.
226 _trieDataCursor = 0;
227 _trieData = data;
228 if (_trieData == null) {
229 return null;
230 }
231 if (_trieData.length < 3) {
232 // Not enough integers for 1 node.
233 return null;
234 }
235 // Read the tree, returns the root node.
236 return _readCodeTrieNode();
237 }
238
239 CodeTrieNode _readCodeTrieNode() {
240 // Read index into code table.
241 var index = _trieData[_trieDataCursor++];
242 // Lookup code object.
243 var code = codes[index];
244 // Frame counter.
245 var count = _trieData[_trieDataCursor++];
246 // Create node.
247 var node = new CodeTrieNode(code, count);
248 // Number of children.
249 var children = _trieData[_trieDataCursor++];
250 // Recursively read child nodes.
251 for (var i = 0; i < children; i++) {
252 var child = _readCodeTrieNode();
253 node.children.add(child);
254 }
255 return node;
256 }
257
258 FunctionTrieNode _processFunctionTrie(List<int> data) {
259 // Setup state shared across calls to _readTrieNode.
260 _trieDataCursor = 0;
261 _trieData = data;
262 if (_trieData == null) {
263 return null;
264 }
265 if (_trieData.length < 3) {
266 // Not enough integers for 1 node.
267 return null;
268 }
269 // Read the tree, returns the root node.
270 return _readFunctionTrieNode();
271 }
272
273 FunctionTrieNode _readFunctionTrieNode() {
274 // Read index into function table.
275 var index = _trieData[_trieDataCursor++];
276 // Lookup function object.
277 var function = functions[index];
278 // Frame counter.
279 var count = _trieData[_trieDataCursor++];
280 // Create node.
281 var node = new FunctionTrieNode(function, count);
282 // Number of code index / count pairs.
283 var codeCount = _trieData[_trieDataCursor++];
284 var totalCodeTicks = 0;
285 for (var i = 0; i < codeCount; i++) {
286 var codeIndex = _trieData[_trieDataCursor++];
287 var code = codes[codeIndex];
288 var codeTicks = _trieData[_trieDataCursor++];
289 totalCodeTicks += codeTicks;
290 var nodeCode = new FunctionTrieNodeCode(code, codeTicks);
291 node.codes.add(nodeCode);
292 }
293 node._totalCodeTicks = totalCodeTicks;
294 // Number of children.
295 var children = _trieData[_trieDataCursor++];
296 // Recursively read child nodes.
297 for (var i = 0; i < children; i++) {
298 var child = _readFunctionTrieNode();
299 node.children.add(child);
300 }
301 return node;
302 }
303
304 double approximateSecondsForCount(count) {
305 var MICROSECONDS_PER_SECOND = 1000000.0;
306 return (count * samplePeriod) / MICROSECONDS_PER_SECOND;
307 }
308 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698