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

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;
siva 2015/02/25 22:58:38 Does the key (address) also have to be in the Code
Cutch 2015/02/26 18:44:39 Done.
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 sampleCount = 0;
165 samplePeriod = 0;
166 sampleRate = 0.0;
167 stackDepth = 0;
168 timeSpan = 0.0;
169 codeTrieRoot = null;
170 functionTrieRoot = null;
171 codes.clear();
172 functions.clear();
173 }
174
175 void load(Isolate isolate, ServiceMap profile) {
176 if ((isolate == null) || (profile == null)) {
177 return;
178 }
179
180 this.isolate = isolate;
181 isolate.resetCachedProfileData();
182
183 clear();
184
185 sampleCount = profile['sampleCount'];
186 samplePeriod = profile['samplePeriod'];
187 sampleRate = (MICROSECONDS_PER_SECOND / samplePeriod);
188 stackDepth = profile['stackDepth'];
189 timeSpan = profile['timeSpan'];
190
191 // Process code table.
192 for (var codeRegion in profile['codes']) {
193 Code code = codeRegion['code'];
194 assert(code != null);
195 codes.add(new ProfileCode.fromMap(this, code, codeRegion));
196 }
197
198 // Process function table.
199 for (var profileFunction in profile['functions']) {
200 ServiceFunction function = profileFunction['function'];
201 assert(function != null);
202 functions.add(
203 new ProfileFunction.fromMap(this, function, profileFunction));
204 }
205
206 // Process code trie.
207 var exclusiveCodeTrie = profile['exclusiveCodeTrie'];
208 assert(exclusiveCodeTrie != null);
209 codeTrieRoot = _processCodeTrie(exclusiveCodeTrie);
210
211 // Process function trie.
212 var exclusiveFunctionTrie = profile['exclusiveFunctionTrie'];
213 assert(exclusiveFunctionTrie != null);
214 functionTrieRoot = _processFunctionTrie(exclusiveFunctionTrie);
215 }
216
217 // Data shared across calls to _read*TrieNode.
218 int _trieDataCursor;
219 List<int> _trieData;
220
221 // The code trie is serialized as a list of integers. Each node
222 // is recreated by consuming some portion of the list. The format is as
223 // follows:
224 // [0] index into codeTable of code object.
225 // [1] tick count (number of times this stack frame occured).
226 // [2] child node count
227 // Reading the trie is done by recursively reading the tree depth-first
228 // pre-order.
229 CodeTrieNode _processCodeTrie(List<int> data) {
230 // Setup state shared across calls to _readTrieNode.
231 _trieDataCursor = 0;
232 _trieData = data;
233 if (_trieData == null) {
234 return null;
235 }
236 if (_trieData.length < 3) {
237 // Not enough integers for 1 node.
238 return null;
239 }
240 // Read the tree, returns the root node.
241 return _readCodeTrieNode();
242 }
243
244 CodeTrieNode _readCodeTrieNode() {
245 // Read index into code table.
246 var index = _trieData[_trieDataCursor++];
247 // Lookup code object.
248 var code = codes[index];
249 // Frame counter.
250 var count = _trieData[_trieDataCursor++];
251 // Create node.
252 var node = new CodeTrieNode(code, count);
253 // Number of children.
254 var children = _trieData[_trieDataCursor++];
255 // Recursively read child nodes.
256 for (var i = 0; i < children; i++) {
257 var child = _readCodeTrieNode();
258 node.children.add(child);
259 }
260 return node;
261 }
262
263 FunctionTrieNode _processFunctionTrie(List<int> data) {
264 // Setup state shared across calls to _readTrieNode.
265 _trieDataCursor = 0;
266 _trieData = data;
267 if (_trieData == null) {
268 return null;
269 }
270 if (_trieData.length < 3) {
271 // Not enough integers for 1 node.
272 return null;
273 }
274 // Read the tree, returns the root node.
275 return _readFunctionTrieNode();
276 }
277
278 FunctionTrieNode _readFunctionTrieNode() {
279 // Read index into function table.
280 var index = _trieData[_trieDataCursor++];
281 // Lookup function object.
282 var function = functions[index];
283 // Frame counter.
284 var count = _trieData[_trieDataCursor++];
285 // Create node.
286 var node = new FunctionTrieNode(function, count);
287 // Number of code index / count pairs.
288 var codeCount = _trieData[_trieDataCursor++];
289 var totalCodeTicks = 0;
290 for (var i = 0; i < codeCount; i++) {
291 var codeIndex = _trieData[_trieDataCursor++];
292 var code = codes[codeIndex];
293 var codeTicks = _trieData[_trieDataCursor++];
294 totalCodeTicks += codeTicks;
295 var nodeCode = new FunctionTrieNodeCode(code, codeTicks);
296 node.codes.add(nodeCode);
297 }
298 node._totalCodeTicks = totalCodeTicks;
299 // Number of children.
300 var children = _trieData[_trieDataCursor++];
301 // Recursively read child nodes.
302 for (var i = 0; i < children; i++) {
303 var child = _readFunctionTrieNode();
304 node.children.add(child);
305 }
306 return node;
307 }
308
309 double approximateSecondsForCount(count) {
310 var MICROSECONDS_PER_SECOND = 1000000.0;
311 return (count * samplePeriod) / MICROSECONDS_PER_SECOND;
312 }
313 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698