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

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

Issue 192443004: Complete the switch to ServiceObject (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
(Empty)
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
3 // BSD-style license that can be found in the LICENSE file.
4
5 part of app;
6
7 class CodeInstruction extends Observable {
8 @observable final int address;
9 @observable final String machine;
10 @observable final String human;
11 @observable int ticks = 0;
12 @observable double percent;
13 @observable String formattedTicks() {
14 if (percent == null || percent <= 0.0) {
15 return '';
16 }
17 return '${percent.toStringAsFixed(2)}% (${ticks})';
18 }
19 @observable String formattedAddress() {
20 return '0x${address.toRadixString(16)}';
21 }
22 CodeInstruction(this.address, this.machine, this.human);
23 void updateTickString(Code code) {
24 if ((code == null) || (code.inclusiveTicks == 0)) {
25 percent = null;
26 return;
27 }
28 percent = (ticks / code.inclusiveTicks) * 100.0;
29 if (percent <= 0.00) {
30 percent = null;
31 return;
32 }
33 }
34 }
35
36 class CodeKind {
37 final _value;
38 const CodeKind._internal(this._value);
39 String toString() => 'CodeKind.$_value';
40
41 static CodeKind fromString(String s) {
42 if (s == 'Native') {
43 return Native;
44 } else if (s == 'Dart') {
45 return Dart;
46 } else if (s == 'Collected') {
47 return Collected;
48 }
49 throw new FallThroughError();
50 }
51 static const Native = const CodeKind._internal('Native');
52 static const Dart = const CodeKind._internal('Dart');
53 static const Collected = const CodeKind._internal('Collected');
54 }
55
56 class CodeTick {
57 final int address;
58 final int exclusive_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);
67 }
68
69 class Code extends Observable {
70 final CodeKind kind;
71 final int startAddress;
72 final int endAddress;
73 final List<CodeTick> ticks = [];
74 final List<CodeCallCount> callers = [];
75 final List<CodeCallCount> callees = [];
76 int inclusiveTicks = 0;
77 int exclusiveTicks = 0;
78 @observable final List<CodeInstruction> instructions = toObservable([]);
79 @observable Map functionRef = toObservable({});
80 @observable Map codeRef = toObservable({});
81 @observable String name;
82 @observable String userName;
83
84 Code(this.kind, this.name, this.startAddress, this.endAddress);
85
86 Code.fromMap(Map map) :
87 kind = CodeKind.Dart,
88 startAddress = int.parse(map['start'], radix: 16),
89 endAddress = int.parse(map['end'], radix: 16) {
90 functionRef = toObservable(map['function']);
91 codeRef = toObservable(map);
92 name = map['name'];
93 userName = map['user_name'];
94 if (map['disassembly'] != null) {
95 _loadInstructions(map['disassembly']);
96 }
97 }
98
99 factory Code.fromProfileMap(Map map) {
100 var kind = CodeKind.fromString(map['kind']);
101 var startAddress;
102 var endAddress;
103 var name;
104 var userName;
105 var codeRef = map['code'];
106 assert(codeRef != null);
107 startAddress = int.parse(codeRef['start'], radix:16);
108 endAddress = int.parse(codeRef['end'], radix:16);
109 name = codeRef['name'];
110 userName = codeRef['user_name'];
111 var code = new Code(kind, name, startAddress, endAddress);
112 code.codeRef = codeRef;
113 code.functionRef = toObservable(codeRef['function']);;
114 code.userName = userName;
115 if (codeRef['disassembly'] != null) {
116 code._loadInstructions(codeRef['disassembly']);
117 // Throw the JSON version away after loading the disassembly.
118 codeRef['disassembly'] = null;
119 }
120 return code;
121 }
122
123 // Refresh tick counts, etc for a code object.
124 void _refresh(Map map) {
125 inclusiveTicks = int.parse(map['inclusive_ticks']);
126 exclusiveTicks = int.parse(map['exclusive_ticks']);
127 // Load address ticks.
128 var ticksList = map['ticks'];
129 if ((ticksList != null) && (ticksList.length > 0)) {
130 assert((ticks.length % 3) == 0);
131 for (var i = 0; i < ticksList.length; i += 3) {
132 var address = int.parse(ticksList[i], radix:16);
133 var inclusive_ticks = int.parse(ticksList[i + 1]);
134 var exclusive_ticks = int.parse(ticksList[i + 2]);
135 var codeTick = new CodeTick(address, exclusive_ticks, inclusive_ticks);
136 ticks.add(codeTick);
137 }
138 }
139 }
140
141 /// Sum all caller counts.
142 int sumCallersCount() => _sumCallCount(callers);
143 /// Specific caller count.
144 int callersCount(Code code) => _callCount(callers, code);
145 /// Sum of callees count.
146 int sumCalleesCount() => _sumCallCount(callees);
147 /// Specific callee count.
148 int calleesCount(Code code) => _callCount(callees, code);
149
150 int _sumCallCount(List<CodeCallCount> calls) {
151 var sum = 0;
152 for (CodeCallCount caller in calls) {
153 sum += caller.count;
154 }
155 return sum;
156 }
157
158 int _callCount(List<CodeCallCount> calls, Code code) {
159 for (CodeCallCount caller in calls) {
160 if (caller.code == code) {
161 return caller.count;
162 }
163 }
164 return 0;
165 }
166
167 void resolveCalls(Map code, List<Code> codes) {
168 _resolveCalls(callers, code['callers'], codes);
169 _resolveCalls(callees, code['callees'], codes);
170 }
171
172 void _resolveCalls(List<CodeCallCount> calls, List data, List<Code> codes) {
173 // Clear.
174 calls.clear();
175 // Resolve.
176 for (var i = 0; i < data.length; i += 2) {
177 var index = int.parse(data[i]);
178 var count = int.parse(data[i + 1]);
179 assert(index >= 0);
180 assert(index < codes.length);
181 calls.add(new CodeCallCount(codes[index], count));
182 }
183 // Sort to descending count order.
184 calls.sort((a, b) => b.count - a.count);
185 }
186
187 /// Resets all tick counts to 0.
188 void resetTicks() {
189 inclusiveTicks = 0;
190 exclusiveTicks = 0;
191 ticks.clear();
192 for (var instruction in instructions) {
193 instruction.ticks = 0;
194 }
195 }
196
197 /// Adds [count] to the tick count for the instruction at [address].
198 void tick(int address, int count) {
199 for (var instruction in instructions) {
200 if (instruction.address == address) {
201 instruction.ticks += count;
202 return;
203 }
204 }
205 }
206
207 /// Clears [instructions] and then adds all instructions from
208 /// [instructionList].
209 void _loadInstructions(List instructionList) {
210 instructions.clear();
211 // Load disassembly into code object.
212 for (int i = 0; i < instructionList.length; i += 3) {
213 if (instructionList[i] == '') {
214 // Code comment.
215 // TODO(johnmccutchan): Insert code comments into instructions.
216 continue;
217 }
218 var address = int.parse(instructionList[i]);
219 var machine = instructionList[i + 1];
220 var human = instructionList[i + 2];
221 instructions.add(new CodeInstruction(address, machine, human));
222 }
223 }
224
225 /// returns true if [address] is inside the address range.
226 bool contains(int address) {
227 return (address >= startAddress) && (address < endAddress);
228 }
229 }
230
231 class Profile {
232 final Isolate isolate;
233 final List<Code> _codeObjectsInImportOrder = new List<Code>();
234 int totalSamples = 0;
235
236 Profile.fromMap(this.isolate, Map m) {
237 var codes = m['codes'];
238 totalSamples = m['samples'];
239 Logger.root.info('Creating profile from ${totalSamples} samples '
240 'and ${codes.length} code objects.');
241 isolate.resetCodeTicks();
242 _codeObjectsInImportOrder.clear();
243 codes.forEach((code) {
244 try {
245 _processCode(code);
246 } catch (e, st) {
247 Logger.root.warning('Error processing code object. $e $st', e, st);
248 }
249 });
250 // Now that code objects have been loaded, post-process them
251 // and resolve callers and callees.
252 assert(_codeObjectsInImportOrder.length == codes.length);
253 for (var i = 0; i < codes.length; i++) {
254 Code code = _codeObjectsInImportOrder[i];
255 code.resolveCalls(codes[i], _codeObjectsInImportOrder);
256 }
257 _codeObjectsInImportOrder.clear();
258 }
259
260 int _extractCodeStartAddress(Map code) {
261 return int.parse(code['code']['start'], radix:16);
262 }
263
264 void _processCode(Map profileCode) {
265 if (profileCode['type'] != 'ProfileCode') {
266 return;
267 }
268 int address = _extractCodeStartAddress(profileCode);
269 var code = isolate.findCodeByAddress(address);
270 if (code == null) {
271 // Never seen a code object at this address before, create a new one.
272 code = new Code.fromProfileMap(profileCode);
273 isolate.codes.add(code);
274 }
275 code._refresh(profileCode);
276 _codeObjectsInImportOrder.add(code);
277 }
278
279 List<Code> topExclusive(int count) {
280 List<Code> exclusive = isolate.codes;
281 exclusive.sort((Code a, Code b) {
282 return b.exclusiveTicks - a.exclusiveTicks;
283 });
284 if ((exclusive.length < count) || (count == 0)) {
285 return exclusive;
286 }
287 return exclusive.sublist(0, count);
288 }
289 }
290
291 class ScriptLine extends Observable {
292 @observable final int line;
293 @observable int hits = -1;
294 @observable String text = '';
295 /// Is this a line of executable code?
296 bool get executable => hits >= 0;
297 /// Has this line executed before?
298 bool get covered => hits > 0;
299 ScriptLine(this.line);
300 }
301
302 class Script extends Observable {
303 @observable String kind = null;
304 @observable Map scriptRef = toObservable({});
305 @published String shortName;
306 @observable Map libraryRef = toObservable({});
307 @observable final List<ScriptLine> lines =
308 toObservable(new List<ScriptLine>());
309 bool _needsSource = true;
310 bool get needsSource => _needsSource;
311 Script.fromMap(Map map) {
312 scriptRef = toObservable({
313 'id': map['id'],
314 'name': map['name'],
315 'user_name': map['user_name']
316 });
317 shortName = map['name'].substring(map['name'].lastIndexOf('/') + 1);
318 libraryRef = toObservable(map['library']);
319 kind = map['kind'];
320 _processSource(map['source']);
321 }
322
323 // Iterable of lines for display. Skips line '0'.
324 @observable Iterable get linesForDisplay {
325 return lines.skip(1);
326 }
327
328 // Fetch (possibly create) the ScriptLine for [lineNumber].
329 ScriptLine _getLine(int lineNumber) {
330 assert(lineNumber != 0);
331 if (lineNumber >= lines.length) {
332 // Grow lines list.
333 lines.length = lineNumber + 1;
334 }
335 var line = lines[lineNumber];
336 if (line == null) {
337 // Create this line.
338 line = new ScriptLine(lineNumber);
339 lines[lineNumber] = line;
340 }
341 return line;
342 }
343
344 void _processSource(String source) {
345 if (source == null) {
346 return;
347 }
348 Logger.root.info('Loading source for ${scriptRef['name']}');
349 var sourceLines = source.split('\n');
350 _needsSource = sourceLines.length == 0;
351 for (var i = 0; i < sourceLines.length; i++) {
352 var line = _getLine(i + 1);
353 line.text = sourceLines[i];
354 }
355 }
356
357 void _processCoverageHits(List hits) {
358 for (var i = 0; i < hits.length; i += 2) {
359 var line = _getLine(hits[i]);
360 line.hits = hits[i + 1];
361 }
362 notifyPropertyChange(#coveredPercentageFormatted, '',
363 coveredPercentageFormatted());
364 }
365
366 /// What percentage of lines in this script have been covered?
367 @observable double coveredPercentage() {
368 int coveredLines = 0;
369 int executableLines = 0;
370 for (var line in lines) {
371 if (line == null) {
372 continue;
373 }
374 if (!line.executable) {
375 continue;
376 }
377 executableLines++;
378 if (!line.covered) {
379 continue;
380 }
381 coveredLines++;
382 }
383 if (executableLines == 0) {
384 return 0.0;
385 }
386 return (coveredLines / executableLines) * 100.0;
387 }
388
389 @observable String coveredPercentageFormatted() {
390 return '(' + coveredPercentage().toStringAsFixed(1) + '% covered)';
391 }
392 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698