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

Side by Side Diff: runtime/observatory/lib/src/elements/script_inset.dart

Issue 1087833005: Add annotation for function declarations. Mark functions with performance problems in red. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 5 years, 8 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
« no previous file with comments | « no previous file | runtime/observatory/lib/src/elements/script_inset.html » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2013, 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 library script_inset_element; 5 library script_inset_element;
6 6
7 import 'dart:async'; 7 import 'dart:async';
8 import 'dart:html'; 8 import 'dart:html';
9 import 'observatory_element.dart'; 9 import 'observatory_element.dart';
10 import 'service_ref.dart'; 10 import 'service_ref.dart';
11 import 'package:observatory/service.dart'; 11 import 'package:observatory/service.dart';
12 import 'package:polymer/polymer.dart'; 12 import 'package:polymer/polymer.dart';
13 13
14 const nbsp = "\u00A0"; 14 const nbsp = "\u00A0";
15 15
16 void addInfoBox(content, infoBox) { 16 void addInfoBox(Element content, Function infoBoxGenerator) {
17 infoBox.style.position = 'absolute'; 17 var infoBox;
18 infoBox.style.padding = '1em';
19 infoBox.style.border = 'solid black 2px';
20 infoBox.style.zIndex = '10';
21 infoBox.style.backgroundColor = 'white';
22 infoBox.style.cursor = 'auto';
23 infoBox.style.display = 'none'; // Initially hidden.
24
25 var show = false; 18 var show = false;
19 var originalBackground = content.style.backgroundColor;
26 content.onClick.listen((event) { 20 content.onClick.listen((event) {
27 show = !show; 21 show = !show;
22 if (infoBox == null) {
Cutch 2015/04/16 14:55:27 add comment that you are lazily generating infobox
23 infoBox = infoBoxGenerator();
24 infoBox.style.position = 'absolute';
25 infoBox.style.padding = '1em';
26 infoBox.style.border = 'solid black 2px';
27 infoBox.style.zIndex = '10';
28 infoBox.style.backgroundColor = 'white';
29 infoBox.style.cursor = 'auto';
30 content.append(infoBox);
31 }
32
28 infoBox.style.display = show ? 'block' : 'none'; 33 infoBox.style.display = show ? 'block' : 'none';
29 content.style.backgroundColor = show ? 'white' : ''; 34 content.style.backgroundColor = show ? 'white' : originalBackground;
30 }); 35 });
31 36
32 // Causes infoBox to be positioned relative to the bottom-left of content. 37 // Causes infoBox to be positioned relative to the bottom-left of content.
33 content.style.display = 'inline-block'; 38 content.style.display = 'inline-block';
34 content.style.cursor = 'pointer'; 39 content.style.cursor = 'pointer';
35 content.append(infoBox);
36 } 40 }
37 41
38 abstract class Annotation { 42 abstract class Annotation implements Comparable<Annotation>{
Cutch 2015/04/16 14:55:27 whitespace between > and {
rmacnak 2015/04/16 18:43:08 Done.
39 int line; 43 int line;
40 int columnStart; 44 int columnStart;
41 int columnStop; 45 int columnStop;
42 46
43 void applyStyleTo(element); 47 void applyStyleTo(element);
44 }
45 48
46 class CurrentExecutionAnnotation extends Annotation { 49 int compareTo(Annotation other) {
47 void applyStyleTo(element) { 50 if (line == other.line) {
48 if (element == null) { 51 return columnStart.compareTo(other.columnStart);
49 return; // TODO(rmacnak): Handling overlapping annotations.
50 } 52 }
51 element.classes.add("currentCol"); 53 return line.compareTo(other.line);
52 element.title = "Current execution";
53 } 54 }
54 }
55 55
56 class CallSiteAnnotation extends Annotation { 56 Element table() {
57 CallSite callSite; 57 var e = new DivElement();
58 e.style.display = "table";
59 e.style.color = "#333";
60 e.style.font = "400 14px 'Montserrat', sans-serif";
61 return e;
62 }
58 63
59 Element row([content]) { 64 Element row([content]) {
60 var e = new DivElement(); 65 var e = new DivElement();
61 e.style.display = "table-row"; 66 e.style.display = "table-row";
62 if (content is String) e.text = content; 67 if (content is String) e.text = content;
68 if (content is Element) e.children.add(content);
63 return e; 69 return e;
64 } 70 }
65 71
66 Element cell(content) { 72 Element cell(content) {
67 var e = new DivElement(); 73 var e = new DivElement();
68 e.style.display = "table-cell"; 74 e.style.display = "table-cell";
69 e.style.padding = "3px"; 75 e.style.padding = "3px";
70 if (content is String) e.text = content; 76 if (content is String) e.text = content;
71 if (content is Element) e.children.add(content); 77 if (content is Element) e.children.add(content);
72 return e; 78 return e;
73 } 79 }
74 80
75 Element serviceRef(object) { 81 Element serviceRef(object) {
76 AnyServiceRefElement e = new Element.tag("any-service-ref"); 82 AnyServiceRefElement e = new Element.tag("any-service-ref");
77 e.ref = object; 83 e.ref = object;
78 return e; 84 return e;
79 } 85 }
86 }
80 87
81 Element entriesTable() { 88 class CurrentExecutionAnnotation extends Annotation {
82 var e = new DivElement(); 89 void applyStyleTo(element) {
83 e.style.display = "table"; 90 if (element == null) {
84 e.style.color = "#333"; 91 return; // TODO(rmacnak): Handling overlapping annotations.
85 e.style.font = "400 14px 'Montserrat', sans-serif"; 92 }
93 element.classes.add("currentCol");
94 element.title = "Current execution";
95 }
96 }
86 97
87 if (callSite.entries.isEmpty) { 98 class CallSiteAnnotation extends Annotation {
88 e.append(row('Did not execute')); 99 CallSite callSite;
89 } else {
90 var r = row();
91 r.append(cell("Container"));
92 r.append(cell("Count"));
93 r.append(cell("Target"));
94 e.append(r);
95 100
96 for (var entry in callSite.entries) { 101 CallSiteAnnotation(this.callSite) {
97 var r = row(); 102 line = callSite.line;
98 r.append(cell(serviceRef(entry.receiverContainer))); 103 columnStart = callSite.column - 1; // Call site is 1-origin.
99 r.append(cell(entry.count.toString())); 104 var tokenLength = callSite.name.length; // Approximate.
100 r.append(cell(serviceRef(entry.target))); 105 if (callSite.name.startsWith("get:") ||
101 e.append(r); 106 callSite.name.startsWith("set:")) tokenLength -= 4;
102 } 107 columnStop = columnStart + tokenLength;
103 }
104
105 return e;
106 } 108 }
107 109
108 void applyStyleTo(element) { 110 void applyStyleTo(element) {
111 if (element == null) {
112 return; // TODO(rmacnak): Handling overlapping annotations.
113 }
114 element.style.fontWeight = "bold";
115 element.title = "Call site: ${callSite.name}";
116
117 addInfoBox(element, () {
118 var details = table();
119 if (callSite.entries.isEmpty) {
120 details.append(row('Did not execute'));
121 } else {
122 var r = row();
123 r.append(cell("Container"));
124 r.append(cell("Count"));
125 r.append(cell("Target"));
126 details.append(r);
127
128 for (var entry in callSite.entries) {
129 var r = row();
130 r.append(cell(serviceRef(entry.receiverContainer)));
131 r.append(cell(entry.count.toString()));
132 r.append(cell(serviceRef(entry.target)));
133 details.append(r);
134 }
135 }
136 return details;
137 });
138 }
139 }
140
141
142 class FunctionDeclarationAnnotation extends Annotation {
143 ServiceFunction function;
144
145 FunctionDeclarationAnnotation(this.function) {
146 assert(function.loaded);
147 var script = function.script;
148 line = script.tokenToLine(function.tokenPos);
149 columnStart = script.tokenToCol(function.tokenPos);
150 if (line == null || columnStart == null) {
Cutch 2015/04/16 14:55:27 if ((line == null) || (columnStart == null)) { (h
rmacnak 2015/04/16 18:43:08 Done.
151 line = 0;
152 columnStart = 0;
153 columnStop = 0;
154 } else {
155 columnStart--; // 1-origin -> 0-origin.
156
157 // The method's token position is at the beginning of the method
158 // declaration, which may be a return type annotation, metadata, static
159 // modifier, etc. Try to scan forward to position this annotation on the
160 // function's name instead.
161 var lineSource = script.getLine(line).text;
162 var betterStart = lineSource.indexOf(function.name, columnStart);
163 if (betterStart != -1) columnStart = betterStart;
Cutch 2015/04/16 14:55:27 if (...) {\n...\n}\n
rmacnak 2015/04/16 18:43:08 Done.
164
165 columnStop = columnStart + function.name.length;
166 }
167 }
168
169 void applyStyleTo(element) {
109 if (element == null) { 170 if (element == null) {
110 return; // TODO(rmacnak): Handling overlapping annotations. 171 return; // TODO(rmacnak): Handling overlapping annotations.
111 } 172 }
112 element.style.fontWeight = "bold"; 173 element.style.fontWeight = "bold";
113 element.title = "Call site: ${callSite.name}"; 174 element.title = "Function declaration: ${function.name}";
114 175
115 addInfoBox(element, entriesTable()); 176 if (function.isOptimizable == false ||
177 function.isInlinable == false ||
178 function.deoptimizations > 0) {
179 element.style.backgroundColor = "red";
180 }
181
182 addInfoBox(element, () {
183 var details = table();
184 var r = row();
185 r.append(cell("Function"));
186 r.append(cell(serviceRef(function)));
187 details.append(r);
188
189 r = row();
190 r.append(cell("Usage Count"));
191 r.append(cell("${function.usageCounter}"));
192 details.append(r);
193
194 if (function.isOptimizable == false) {
195 details.append(row(cell("Unoptimizable!")));
196 }
197 if (function.isInlinable == false) {
198 details.append(row(cell("Not inlinable!")));
199 }
200 if (function.deoptimizations > 0) {
201 details.append(row("Deoptimized ${function.deoptimizations} times!"));
202 }
203 return details;
204 });
116 } 205 }
117 } 206 }
118 207
119 /// Box with script source code in it. 208 /// Box with script source code in it.
120 @CustomTag('script-inset') 209 @CustomTag('script-inset')
121 class ScriptInsetElement extends ObservatoryElement { 210 class ScriptInsetElement extends ObservatoryElement {
122 @published Script script; 211 @published Script script;
123 212
124 /// Set the height to make the script inset scroll. Otherwise it 213 /// Set the height to make the script inset scroll. Otherwise it
125 /// will show from startPos to endPos. 214 /// will show from startPos to endPos.
(...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after
219 var table = linesTable(); 308 var table = linesTable();
220 if (container == null) { 309 if (container == null) {
221 // Indirect to avoid deleting the style element. 310 // Indirect to avoid deleting the style element.
222 container = new DivElement(); 311 container = new DivElement();
223 shadowRoot.append(container); 312 shadowRoot.append(container);
224 } 313 }
225 container.children.clear(); 314 container.children.clear();
226 container.children.add(table); 315 container.children.add(table);
227 } 316 }
228 317
318 void loadFunctionsOf(Library lib) {
319 lib.load().then((lib) {
320 for (var func in lib.functions) func.load();
Cutch 2015/04/16 14:55:27 braces and new lines
rmacnak 2015/04/16 18:43:07 Done.
321 for (var cls in lib.classes) {
322 cls.load().then((cls) {
323 for (var func in cls.functions) func.load();
324 });
325 }
326 });
327 }
328
229 void computeAnnotations() { 329 void computeAnnotations() {
230 startLine = (startPos != null 330 startLine = (startPos != null
231 ? script.tokenToLine(startPos) 331 ? script.tokenToLine(startPos)
232 : 1); 332 : 1);
233 currentLine = (currentPos != null 333 currentLine = (currentPos != null
234 ? script.tokenToLine(currentPos) 334 ? script.tokenToLine(currentPos)
235 : null); 335 : null);
236 currentCol = (currentPos != null 336 currentCol = (currentPos != null
237 ? (script.tokenToCol(currentPos) - 1) // make this 0-based. 337 ? (script.tokenToCol(currentPos) - 1) // make this 0-based.
238 : null); 338 : null);
239 endLine = (endPos != null 339 endLine = (endPos != null
240 ? script.tokenToLine(endPos) 340 ? script.tokenToLine(endPos)
241 : script.lines.length); 341 : script.lines.length);
242 342
243 annotations.clear(); 343 annotations.clear();
244 if (currentLine != null) { 344 if (currentLine != null) {
245 var a = new CurrentExecutionAnnotation(); 345 var a = new CurrentExecutionAnnotation();
246 a.line = currentLine; 346 a.line = currentLine;
247 a.columnStart = currentCol; 347 a.columnStart = currentCol;
248 a.columnStop = currentCol + 1; 348 a.columnStop = currentCol + 1;
249 annotations.add(a); 349 annotations.add(a);
250 } 350 }
251 351
252 for (var callSite in script.callSites) { 352 loadFunctionsOf(script.library);
253 var a = new CallSiteAnnotation(); 353
254 a.line = callSite.line; 354 for (var func in script.library.functions) {
255 a.columnStart = callSite.column - 1; // Call site is 1-origin. 355 if (func.script == script) {
256 var tokenLength = callSite.name.length; // Approximate. 356 annotations.add(new FunctionDeclarationAnnotation(func));
257 a.columnStop = a.columnStart + tokenLength; 357 }
258 a.callSite = callSite; 358 }
259 annotations.add(a); 359 for (var cls in script.library.classes) {
360 for (var func in cls.functions) {
361 if (func.script == script) {
362 annotations.add(new FunctionDeclarationAnnotation(func));
363 }
364 }
260 } 365 }
261 366
262 annotations.sort((a, b) { 367 for (var callSite in script.callSites) {
263 if (a.line == b.line) { 368 annotations.add(new CallSiteAnnotation(callSite));
264 return a.columnStart.compareTo(b.columnStart); 369 }
265 } 370
266 return a.line.compareTo(b.line); 371 annotations.sort();
267 });
268 } 372 }
269 373
270 Element linesTable() { 374 Element linesTable() {
271 var table = new DivElement(); 375 var table = new DivElement();
272 table.classes.add("sourceTable"); 376 table.classes.add("sourceTable");
273 377
274 annotationsCursor = 0; 378 annotationsCursor = 0;
275 379
276 int blankLineCount = 0; 380 int blankLineCount = 0;
277 for (int i = (startLine - 1); i <= (endLine - 1); i++) { 381 for (int i = (startLine - 1); i <= (endLine - 1); i++) {
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
315 Element lineElement(ScriptLine line) { 419 Element lineElement(ScriptLine line) {
316 var e = new DivElement(); 420 var e = new DivElement();
317 e.classes.add("sourceRow"); 421 e.classes.add("sourceRow");
318 e.append(lineBreakpointElement(line)); 422 e.append(lineBreakpointElement(line));
319 e.append(lineNumberElement(line)); 423 e.append(lineNumberElement(line));
320 e.append(lineSourceElement(line)); 424 e.append(lineSourceElement(line));
321 return e; 425 return e;
322 } 426 }
323 427
324 Element lineBreakpointElement(ScriptLine line) { 428 Element lineBreakpointElement(ScriptLine line) {
325 BreakpointToggleElement e = new Element.tag("breakpoint-toggle"); 429 var e = new DivElement();
326 e.line = line; 430 var busy = false;
431 if (line == null || !line.possibleBpt) {
432 e.classes.add("emptyBreakpoint");
433 e.text = nbsp;
434 return e;
435 }
436 e.text = 'B';
437 update() {
438 if (busy) {
439 e.classes.clear();
440 e.classes.add("busyBreakpoint");
441 } else {
442 if (line.breakpoints != null) {
443 if (line.breakpointResolved) {
444 e.classes.clear();
445 e.classes.add("resolvedBreakpoint");
446 } else {
447 e.classes.clear();
448 e.classes.add("unresolvedBreakpoint");
449 }
450 } else {
451 e.classes.clear();
452 e.classes.add("possibleBreakpoint");
453 }
454 }
455 }
456 line.changes.listen((_) => update());
457 e.onClick.listen((event) {
458 if (busy) {
459 return;
460 }
461 busy = true;
462 if (line.breakpoints == null) {
463 // No breakpoint. Add it.
464 line.script.isolate.addBreakpoint(line.script, line.line).then((_) {
465 busy = false;
466 update();
467 });
468 } else {
469 // Existing breakpoint. Remove it.
470 List pending = [];
471 for (var bpt in line.breakpoints) {
472 pending.add(line.script.isolate.removeBreakpoint(bpt));
473 }
474 Future.wait(pending).then((_) {
475 busy = false;
476 update();
477 });
478 }
479 update();
480 });
481 update();
327 return e; 482 return e;
328 } 483 }
329 484
330 Element lineNumberElement(ScriptLine line) { 485 Element lineNumberElement(ScriptLine line) {
331 var lineNumber = line == null ? "..." : line.line; 486 var lineNumber = line == null ? "..." : line.line;
332 var e = span("$nbsp$lineNumber$nbsp"); 487 var e = span("$nbsp$lineNumber$nbsp");
333 488
334 if ((line == null) || (line.hits == null)) { 489 if ((line == null) || (line.hits == null)) {
335 hitsUnknown(e); 490 hitsUnknown(e);
336 } else if (line.hits == 0) { 491 } else if (line.hits == 0) {
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
377 annotation.applyStyleTo(consumeUntil(annotation.columnStop)); 532 annotation.applyStyleTo(consumeUntil(annotation.columnStop));
378 } 533 }
379 consumeUntil(line.text.length); 534 consumeUntil(line.text.length);
380 } 535 }
381 536
382 return e; 537 return e;
383 } 538 }
384 539
385 ScriptInsetElement.created() : super.created(); 540 ScriptInsetElement.created() : super.created();
386 } 541 }
387
388 @CustomTag('breakpoint-toggle')
389 class BreakpointToggleElement extends ObservatoryElement {
390 @published ScriptLine line;
391 @observable bool busy = false;
392
393 void toggleBreakpoint(var a, var b, var c) {
394 if (busy) {
395 return;
396 }
397 busy = true;
398 if (line.breakpoints == null) {
399 // No breakpoint. Add it.
400 line.script.isolate.addBreakpoint(line.script, line.line).then((_) {
401 busy = false;
402 });
403 } else {
404 // Existing breakpoint. Remove it.
405 List pending = [];
406 for (var bpt in line.breakpoints) {
407 pending.add(line.script.isolate.removeBreakpoint(bpt));
408 }
409 Future.wait(pending).then((_) {
410 busy = false;
411 });
412 }
413 }
414
415 BreakpointToggleElement.created() : super.created();
416 }
OLDNEW
« no previous file with comments | « no previous file | runtime/observatory/lib/src/elements/script_inset.html » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698