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

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

Issue 168833005: Add callers and callees to profiler output (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 6 years, 9 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
1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 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. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 part of observatory; 5 part of observatory;
6 6
7 class CodeInstruction extends Observable { 7 class CodeInstruction extends Observable {
8 @observable final int address; 8 @observable final int address;
9 @observable final String machine; 9 @observable final String machine;
10 @observable final String human; 10 @observable final String human;
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
48 } 48 }
49 throw new FallThroughError(); 49 throw new FallThroughError();
50 } 50 }
51 static const Native = const CodeKind._internal('Native'); 51 static const Native = const CodeKind._internal('Native');
52 static const Dart = const CodeKind._internal('Dart'); 52 static const Dart = const CodeKind._internal('Dart');
53 static const Collected = const CodeKind._internal('Collected'); 53 static const Collected = const CodeKind._internal('Collected');
54 } 54 }
55 55
56 class CodeTick { 56 class CodeTick {
57 final int address; 57 final int address;
58 final int ticks; 58 final int exclusive_ticks;
59 CodeTick(this.address, this.ticks); 59 final int inclusive_ticks;
60 CodeTick(this.address, this.exclusive_ticks, this.inclusive_ticks);
61 }
62
63 class CodeCallCount {
64 final Code code;
65 final int count;
66 CodeCallCount(this.code, this.count);
60 } 67 }
61 68
62 class Code extends Observable { 69 class Code extends Observable {
63 final CodeKind kind; 70 final CodeKind kind;
64 final int startAddress; 71 final int startAddress;
65 final int endAddress; 72 final int endAddress;
66 final List<CodeTick> ticks = []; 73 final List<CodeTick> ticks = [];
74 final List<CodeCallCount> callers = [];
75 final List<CodeCallCount> callees = [];
67 int inclusiveTicks = 0; 76 int inclusiveTicks = 0;
68 int exclusiveTicks = 0; 77 int exclusiveTicks = 0;
69 @observable final List<CodeInstruction> instructions = toObservable([]); 78 @observable final List<CodeInstruction> instructions = toObservable([]);
70 @observable Map functionRef = toObservable({}); 79 @observable Map functionRef = toObservable({});
71 @observable Map codeRef = toObservable({}); 80 @observable Map codeRef = toObservable({});
72 @observable String name; 81 @observable String name;
73 @observable String user_name; 82 @observable String userName;
74 83
75 Code(this.kind, this.name, this.startAddress, this.endAddress); 84 Code(this.kind, this.name, this.startAddress, this.endAddress);
76 85
77 Code.fromMap(Map m) : 86 Code.fromMap(Map map) :
78 kind = CodeKind.Dart, 87 kind = CodeKind.Dart,
79 startAddress = int.parse(m['start'], radix:16), 88 startAddress = int.parse(map['start'], radix: 16),
80 endAddress = int.parse(m['end'], radix:16) { 89 endAddress = int.parse(map['end'], radix: 16) {
81 functionRef = toObservable(m['function']); 90 functionRef = toObservable(map['function']);
82 codeRef = { 91 codeRef = toObservable({
83 'type': '@Code', 92 'type': '@Code',
84 'id': m['id'], 93 'id': map['id'],
85 'name': m['name'], 94 'name': map['name'],
86 'user_name': m['user_name'] 95 'user_name': map['user_name']
87 }; 96 });
88 name = m['name']; 97 name = map['name'];
89 user_name = m['user_name']; 98 userName = map['user_name'];
90 _loadInstructions(m['disassembly']); 99 if (map['disassembly'] != null) {
100 _loadInstructions(map['disassembly']);
101 }
102 }
103
104 factory Code.fromProfileMap(Map map) {
105 var kind = CodeKind.fromString(map['kind']);
106 var startAddress;
107 var endAddress;
108 var name;
109 var userName;
110 var codeRef;
111 var functionRef;
112 // Initial extraction of startAddress, endAddress, and name depends on what
113 // kind of code this is and whether or not the code has been collected.
114 if (kind == CodeKind.Dart) {
115 var code = map['code'];
116 if (code != null) {
117 // Extract from Dart code.
118 startAddress = int.parse(code['start'], radix:16);
119 endAddress = int.parse(code['end'], radix:16);
120 name = code['name'];
121 userName = code['user_name'];
122 codeRef = toObservable({
123 'type': '@Code',
124 'id': code['id'],
125 'name': name,
126 'user_name': userName
127 });
128 functionRef = toObservable(code['function']);
129 }
130 }
131 if (startAddress == null) {
132 // Extract from Profile code.
133 // This is either a native or collected piece of code.
134 startAddress = int.parse(map['start'], radix:16);
135 endAddress = int.parse(map['end'], radix: 16);
136 name = map['name'];
137 userName = name;
138 }
139 var code = new Code(kind, name, startAddress, endAddress);
140 code.codeRef = codeRef;
141 code.functionRef = functionRef;
142 code.userName = userName;
143 if (map['disassembly'] != null) {
144 code._loadInstructions(map['disassembly']);
145 }
146 return code;
147 }
148
149 // Refresh tick counts, etc for a code object.
150 void _refresh(Map map) {
151 inclusiveTicks = int.parse(map['inclusive_ticks']);
152 exclusiveTicks = int.parse(map['exclusive_ticks']);
153 // Load address ticks.
154 var ticksList = map['ticks'];
155 if ((ticksList != null) && (ticksList.length > 0)) {
156 assert((ticks.length % 3) == 0);
157 for (var i = 0; i < ticksList.length; i += 3) {
158 var address = int.parse(ticksList[i], radix:16);
159 var inclusive_ticks = int.parse(ticksList[i + 1]);
160 var exclusive_ticks = int.parse(ticksList[i + 2]);
161 var codeTick = new CodeTick(address, exclusive_ticks, inclusive_ticks);
162 ticks.add(codeTick);
163 }
164 }
165 }
166
167 /// Sum all caller counts.
168 int sumCallersCount() => _sumCallCount(callers);
169 /// Specific caller count.
170 int callersCount(Code code) => _callCount(callers, code);
171 /// Sum of callees count.
172 int sumCalleesCount() => _sumCallCount(callees);
173 /// Specific callee count.
174 int calleesCount(Code code) => _callCount(callees, code);
175
176 int _sumCallCount(List<CodeCallCount> calls) {
177 var sum = 0;
178 for (CodeCallCount caller in calls) {
179 sum += caller.count;
180 }
181 return sum;
182 }
183
184 int _callCount(List<CodeCallCount> calls, Code code) {
185 for (CodeCallCount caller in calls) {
186 if (caller.code == code) {
187 return caller.count;
188 }
189 }
190 return 0;
191 }
192
193 void resolveCalls(Map code, List<Code> codes) {
194 _resolveCalls(callers, code['callers'], codes);
195 _resolveCalls(callees, code['callees'], codes);
196 }
197
198 void _resolveCalls(List<CodeCallCount> calls, List data, List<Code> codes) {
199 // Clear.
200 calls.clear();
201 // Resolve.
202 for (var i = 0; i < data.length; i += 2) {
203 var index = int.parse(data[i]);
204 var count = int.parse(data[i + 1]);
205 assert(index >= 0);
206 assert(index < codes.length);
207 calls.add(new CodeCallCount(codes[index], count));
208 }
209 // Sort to descending count order.
210 calls.sort((a, b) => b.count - a.count);
91 } 211 }
92 212
93 /// Resets all tick counts to 0. 213 /// Resets all tick counts to 0.
94 void resetTicks() { 214 void resetTicks() {
95 inclusiveTicks = 0; 215 inclusiveTicks = 0;
96 exclusiveTicks = 0; 216 exclusiveTicks = 0;
97 ticks.clear(); 217 ticks.clear();
98 for (var instruction in instructions) { 218 for (var instruction in instructions) {
99 instruction.ticks = 0; 219 instruction.ticks = 0;
100 } 220 }
(...skipping 28 matching lines...) Expand all
129 } 249 }
130 250
131 /// returns true if [address] is inside the address range. 251 /// returns true if [address] is inside the address range.
132 bool contains(int address) { 252 bool contains(int address) {
133 return (address >= startAddress) && (address < endAddress); 253 return (address >= startAddress) && (address < endAddress);
134 } 254 }
135 } 255 }
136 256
137 class Profile { 257 class Profile {
138 final Isolate isolate; 258 final Isolate isolate;
259 final List<Code> _codeObjectsInImportOrder = new List<Code>();
260 int totalSamples = 0;
261
139 Profile.fromMap(this.isolate, Map m) { 262 Profile.fromMap(this.isolate, Map m) {
140 var codes = m['codes']; 263 var codes = m['codes'];
141 totalSamples = m['samples']; 264 totalSamples = m['samples'];
142 Logger.root.info('Creating profile from ${totalSamples} samples ' 265 Logger.root.info('Creating profile from ${totalSamples} samples '
143 'and ${codes.length} code objects.'); 266 'and ${codes.length} code objects.');
144 isolate.resetCodeTicks(); 267 isolate.resetCodeTicks();
268 _codeObjectsInImportOrder.clear();
145 codes.forEach((code) { 269 codes.forEach((code) {
146 try { 270 try {
147 _processCode(code); 271 _processCode(code);
148 } catch (e, st) { 272 } catch (e, st) {
149 Logger.root.warning('Error processing code object. $e $st', e, st); 273 Logger.root.warning('Error processing code object. $e $st', e, st);
150 } 274 }
151 }); 275 });
152 } 276 // Now that code objects have been loaded, post-process them
153 int totalSamples = 0; 277 // and resolve callers and callees.
154 278 assert(_codeObjectsInImportOrder.length == codes.length);
155 Code _processDartCode(Map dartCode) { 279 for (var i = 0; i < codes.length; i++) {
156 var codeObject = dartCode['code']; 280 Code code = _codeObjectsInImportOrder[i];
157 if ((codeObject == null)) { 281 code.resolveCalls(codes[i], _codeObjectsInImportOrder);
158 // Detached code objects are handled like 'other' code.
159 return _processOtherCode(CodeKind.Dart, dartCode);
160 } 282 }
161 var code = new Code.fromMap(codeObject); 283 _codeObjectsInImportOrder.clear();
162 return code;
163 } 284 }
164 285
165 Code _processOtherCode(CodeKind kind, Map otherCode) { 286 int _extractCodeStartAddress(Map code) {
166 var startAddress = int.parse(otherCode['start'], radix:16); 287 var kind = CodeKind.fromString(code['kind']);
167 var endAddress = int.parse(otherCode['end'], radix: 16); 288 if ((kind == CodeKind.Dart) && (code['code'] != null)) {
168 var name = otherCode['name']; 289 // Start address is inside the dart code map.
169 assert(name != null); 290 return int.parse(code['code']['start'], radix:16);
170 return new Code(kind, name, startAddress, endAddress); 291 }
292 // Start address is inside the profile code map.
293 return int.parse(code['start'], radix:16);
171 } 294 }
172 295
173 void _processCode(Map profileCode) { 296 void _processCode(Map profileCode) {
174 if (profileCode['type'] != 'ProfileCode') { 297 if (profileCode['type'] != 'ProfileCode') {
175 return; 298 return;
176 } 299 }
177 var kind = CodeKind.fromString(profileCode['kind']); 300 int address = _extractCodeStartAddress(profileCode);
178 var address;
179 if (kind == CodeKind.Dart) {
180 if (profileCode['code'] != null) {
181 address = int.parse(profileCode['code']['start'], radix:16);
182 } else {
183 address = int.parse(profileCode['start'], radix:16);
184 }
185 } else {
186 address = int.parse(profileCode['start'], radix:16);
187 }
188 assert(address != null);
189 var code = isolate.findCodeByAddress(address); 301 var code = isolate.findCodeByAddress(address);
190 if (code == null) { 302 if (code == null) {
191 if (kind == CodeKind.Dart) { 303 // Never seen a code object at this address before, create a new one.
192 code = _processDartCode(profileCode); 304 code = new Code.fromProfileMap(profileCode);
193 } else {
194 code = _processOtherCode(kind, profileCode);
195 }
196 assert(code != null);
197 isolate.codes.add(code); 305 isolate.codes.add(code);
198 } 306 }
199 // Load code object tick counts and set them. 307 code._refresh(profileCode);
200 var inclusive = int.parse(profileCode['inclusive_ticks']); 308 _codeObjectsInImportOrder.add(code);
201 var exclusive = int.parse(profileCode['exclusive_ticks']);
202 code.inclusiveTicks = inclusive;
203 code.exclusiveTicks = exclusive;
204 // Load address specific ticks.
205 List ticksList = profileCode['ticks'];
206 if (ticksList != null && (ticksList.length > 0)) {
207 for (var i = 0; i < ticksList.length; i += 2) {
208 var address = int.parse(ticksList[i], radix:16);
209 var ticks = int.parse(ticksList[i + 1]);
210 var codeTick = new CodeTick(address, ticks);
211 code.ticks.add(codeTick);
212 }
213 }
214 if ((code.ticks.length > 0) && (code.instructions.length > 0)) {
215 // Apply address ticks to instruction stream.
216 code.ticks.forEach((CodeTick tick) {
217 code.tick(tick.address, tick.ticks);
218 });
219 code.instructions.forEach((i) {
220 i.updateTickString(code);
221 });
222 }
223 } 309 }
224 310
225 List<Code> topExclusive(int count) { 311 List<Code> topExclusive(int count) {
226 List<Code> exclusive = isolate.codes; 312 List<Code> exclusive = isolate.codes;
227 exclusive.sort((Code a, Code b) { 313 exclusive.sort((Code a, Code b) {
228 return b.exclusiveTicks - a.exclusiveTicks; 314 return b.exclusiveTicks - a.exclusiveTicks;
229 }); 315 });
230 if ((exclusive.length < count) || (count == 0)) { 316 if ((exclusive.length < count) || (count == 0)) {
231 return exclusive; 317 return exclusive;
232 } 318 }
233 return exclusive.sublist(0, count); 319 return exclusive.sublist(0, count);
234 } 320 }
235
236 List<Code> topInclusive(int count) {
237 List<Code> inclusive = isolate.codes;
238 inclusive.sort((Code a, Code b) {
239 return b.inclusiveTicks - a.inclusiveTicks;
240 });
241 if ((inclusive.length < count) || (count == 0)) {
242 return inclusive;
243 }
244 return inclusive.sublist(0, count);
245 }
246 } 321 }
247 322
248 class ScriptLine extends Observable { 323 class ScriptLine extends Observable {
249 @observable final int line; 324 @observable final int line;
250 @observable int hits = -1; 325 @observable int hits = -1;
251 @observable String text = ''; 326 @observable String text = '';
252 /// Is this a line of executable code? 327 /// Is this a line of executable code?
253 bool get executable => hits >= 0; 328 bool get executable => hits >= 0;
254 /// Has this line executed before? 329 /// Has this line executed before?
255 bool get covered => hits > 0; 330 bool get covered => hits > 0;
(...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after
338 if (executableLines == 0) { 413 if (executableLines == 0) {
339 return 0.0; 414 return 0.0;
340 } 415 }
341 return (coveredLines / executableLines) * 100.0; 416 return (coveredLines / executableLines) * 100.0;
342 } 417 }
343 418
344 @observable String coveredPercentageFormatted() { 419 @observable String coveredPercentageFormatted() {
345 return '(' + coveredPercentage().toStringAsFixed(1) + '% covered)'; 420 return '(' + coveredPercentage().toStringAsFixed(1) + '% covered)';
346 } 421 }
347 } 422 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698