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

Side by Side Diff: tools/profview/profview.js

Issue 2737083003: [tools/profview] Add individual function timeline view (Closed)
Patch Set: Created 3 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
« tools/profview/profile-utils.js ('K') | « tools/profview/profview.css ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2017 the V8 project authors. All rights reserved. 1 // Copyright 2017 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 "use strict" 5 "use strict"
6 6
7 function $(id) { 7 function $(id) {
8 return document.getElementById(id); 8 return document.getElementById(id);
9 } 9 }
10 10
(...skipping 133 matching lines...) Expand 10 before | Expand all | Expand 10 after
144 }, 144 },
145 145
146 setFile(file) { 146 setFile(file) {
147 if (file != main.currentState.file) { 147 if (file != main.currentState.file) {
148 main.currentState = Object.assign({}, main.currentState); 148 main.currentState = Object.assign({}, main.currentState);
149 main.currentState.file = file; 149 main.currentState.file = file;
150 main.delayRender(); 150 main.delayRender();
151 } 151 }
152 }, 152 },
153 153
154 setCurrentCode(codeId) {
155 if (codeId != main.currentState.currentCodeId) {
156 main.currentState = Object.assign({}, main.currentState);
157 main.currentState.currentCodeId = codeId;
158 main.delayRender();
159 }
160 },
161
154 onResize() { 162 onResize() {
155 main.setTimeLineDimensions( 163 main.setTimeLineDimensions(
156 window.innerWidth - 20, window.innerHeight / 8); 164 window.innerWidth - 20, window.innerHeight / 8);
157 }, 165 },
158 166
159 onLoad() { 167 onLoad() {
160 function loadHandler(evt) { 168 function loadHandler(evt) {
161 let f = evt.target.files[0]; 169 let f = evt.target.files[0];
162 if (f) { 170 if (f) {
163 let reader = new FileReader(); 171 let reader = new FileReader();
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after
234 let bucket = bucketDescriptors[i]; 242 let bucket = bucketDescriptors[i];
235 for (let j = 0; j < bucket.kinds.length; j++) { 243 for (let j = 0; j < bucket.kinds.length; j++) {
236 if (bucket.kinds[j] === kind) { 244 if (bucket.kinds[j] === kind) {
237 return bucket; 245 return bucket;
238 } 246 }
239 } 247 }
240 } 248 }
241 return null; 249 return null;
242 } 250 }
243 251
252 function codeTypeToText(type) {
253 switch (type) {
254 case "UNKNOWN":
255 return "Unknown";
256 case "CPPCOMP":
257 return "C++ (compiler)";
258 case "CPPGC":
259 return "C++";
260 case "CPPEXT":
261 return "C++ External";
262 case "CPP":
263 return "C++";
264 case "LIB":
265 return "Library";
266 case "IC":
267 return "IC";
268 case "BC":
269 return "Bytecode";
270 case "STUB":
271 return "Stub";
272 case "BUILTIN":
273 return "Builtin";
274 case "REGEXP":
275 return "RegExp";
276 case "JSOPT":
277 return "JS opt";
278 case "JSUNOPT":
279 return "JS unopt";
280 }
281 console.error("Unknown type: " + type);
282 }
283
284 function createTypeDiv(type) {
285 if (type === "CAT") {
286 return document.createTextNode("");
287 }
288 let div = document.createElement("div");
289 div.classList.add("code-type-chip");
290
291 let span = document.createElement("span");
292 span.classList.add("code-type-chip");
293 span.textContent = codeTypeToText(type);
294 div.appendChild(span);
295
296 span = document.createElement("span");
297 span.classList.add("code-type-chip-space");
298 div.appendChild(span);
299
300 return div;
301 }
302
303 function isBytecodeHandler(kind) {
304 return kind === "BytecodeHandler";
305 }
306
307 function filterFromFilterId(id) {
308 switch (id) {
309 case "full-tree":
310 return (type, kind) => true;
311 case "js-funs":
312 return (type, kind) => type !== 'CODE';
313 case "js-exclude-bc":
314 return (type, kind) =>
315 type !== 'CODE' || !isBytecodeHandler(kind);
316 }
317 }
318
244 class CallTreeView { 319 class CallTreeView {
245 constructor() { 320 constructor() {
246 this.element = $("calltree"); 321 this.element = $("calltree");
247 this.treeElement = $("calltree-table"); 322 this.treeElement = $("calltree-table");
248 this.selectAttribution = $("calltree-attribution"); 323 this.selectAttribution = $("calltree-attribution");
249 this.selectCategories = $("calltree-categories"); 324 this.selectCategories = $("calltree-categories");
250 this.selectSort = $("calltree-sort"); 325 this.selectSort = $("calltree-sort");
251 326
252 this.selectAttribution.onchange = () => { 327 this.selectAttribution.onchange = () => {
253 main.setCallTreeAttribution(this.selectAttribution.value); 328 main.setCallTreeAttribution(this.selectAttribution.value);
254 }; 329 };
255 330
256 this.selectCategories.onchange = () => { 331 this.selectCategories.onchange = () => {
257 main.setCallTreeCategories(this.selectCategories.value); 332 main.setCallTreeCategories(this.selectCategories.value);
258 }; 333 };
259 334
260 this.selectSort.onchange = () => { 335 this.selectSort.onchange = () => {
261 main.setCallTreeSort(this.selectSort.value); 336 main.setCallTreeSort(this.selectSort.value);
262 }; 337 };
263 338
264 this.currentState = null; 339 this.currentState = null;
265 } 340 }
266 341
267 filterFromFilterId(id) {
268 switch (id) {
269 case "full-tree":
270 return (type, kind) => true;
271 case "js-funs":
272 return (type, kind) => type !== 'CODE';
273 case "js-exclude-bc":
274 return (type, kind) =>
275 type !== 'CODE' || !CallTreeView.IsBytecodeHandler(kind);
276 }
277 }
278
279 sortFromId(id) { 342 sortFromId(id) {
280 switch (id) { 343 switch (id) {
281 case "time": 344 case "time":
282 return (c1, c2) => { 345 return (c1, c2) => {
283 if (c1.ticks < c2.ticks) return 1; 346 if (c1.ticks < c2.ticks) return 1;
284 else if (c1.ticks > c2.ticks) return -1; 347 else if (c1.ticks > c2.ticks) return -1;
285 return c2.ownTicks - c1.ownTicks; 348 return c2.ownTicks - c1.ownTicks;
286 } 349 }
287 case "own-time": 350 case "own-time":
288 return (c1, c2) => { 351 return (c1, c2) => {
289 if (c1.ownTicks < c2.ownTicks) return 1; 352 if (c1.ownTicks < c2.ownTicks) return 1;
290 else if (c1.ownTicks > c2.ownTicks) return -1; 353 else if (c1.ownTicks > c2.ownTicks) return -1;
291 return c2.ticks - c1.ticks; 354 return c2.ticks - c1.ticks;
292 } 355 }
293 case "category-time": 356 case "category-time":
294 return (c1, c2) => { 357 return (c1, c2) => {
295 if (c1.type === c2.type) return c2.ticks - c1.ticks; 358 if (c1.type === c2.type) return c2.ticks - c1.ticks;
296 if (c1.type < c2.type) return 1; 359 if (c1.type < c2.type) return 1;
297 return -1; 360 return -1;
298 }; 361 };
299 case "category-own-time": 362 case "category-own-time":
300 return (c1, c2) => { 363 return (c1, c2) => {
301 if (c1.type === c2.type) return c2.ownTicks - c1.ownTicks; 364 if (c1.type === c2.type) return c2.ownTicks - c1.ownTicks;
302 if (c1.type < c2.type) return 1; 365 if (c1.type < c2.type) return 1;
303 return -1; 366 return -1;
304 }; 367 };
305 } 368 }
306 } 369 }
307 370
308 static IsBytecodeHandler(kind) {
309 return kind === "BytecodeHandler";
310 }
311
312 createExpander(indent) { 371 createExpander(indent) {
313 let div = document.createElement("div"); 372 let div = document.createElement("div");
314 div.style.width = (1 + indent) + "em"; 373 div.style.width = (1 + indent) + "em";
315 div.style.display = "inline-block"; 374 div.style.display = "inline-block";
316 div.style.textAlign = "right"; 375 div.style.textAlign = "right";
317 return div; 376 return div;
318 } 377 }
319 378
320 codeTypeToText(type) { 379 createFunctionNode(name, codeId) {
321 switch (type) { 380 if (codeId == -1) {
322 case "UNKNOWN": 381 return document.createTextNode(name);
323 return "Unknown";
324 case "CPPCOMP":
325 return "C++ (compiler)";
326 case "CPPGC":
327 return "C++";
328 case "CPPEXT":
329 return "C++ External";
330 case "CPP":
331 return "C++";
332 case "LIB":
333 return "Library";
334 case "IC":
335 return "IC";
336 case "BC":
337 return "Bytecode";
338 case "STUB":
339 return "Stub";
340 case "BUILTIN":
341 return "Builtin";
342 case "REGEXP":
343 return "RegExp";
344 case "JSOPT":
345 return "JS opt";
346 case "JSUNOPT":
347 return "JS unopt";
348 } 382 }
349 console.error("Unknown type: " + type); 383 let nameElement = document.createElement("span");
350 } 384 nameElement.classList.add("codeid-link")
351 385 nameElement.onclick = function() {
352 createTypeDiv(type) { 386 main.setCurrentCode(codeId);
353 if (type === "CAT") { 387 };
354 return document.createTextNode(""); 388 nameElement.appendChild(document.createTextNode(name));
355 } 389 return nameElement;
356 let div = document.createElement("div");
357 div.classList.add("code-type-chip");
358
359 let span = document.createElement("span");
360 span.classList.add("code-type-chip");
361 span.textContent = this.codeTypeToText(type);
362 div.appendChild(span);
363
364 span = document.createElement("span");
365 span.classList.add("code-type-chip-space");
366 div.appendChild(span);
367
368 return div;
369 } 390 }
370 391
371 expandTree(tree, indent) { 392 expandTree(tree, indent) {
372 let that = this; 393 let that = this;
373 let index = 0; 394 let index = 0;
374 let id = "R/"; 395 let id = "R/";
375 let row = tree.row; 396 let row = tree.row;
376 let expander = tree.expander; 397 let expander = tree.expander;
377 398
378 if (row) { 399 if (row) {
379 console.assert("expander"); 400 console.assert("expander");
380 index = row.rowIndex; 401 index = row.rowIndex;
381 id = row.id; 402 id = row.id;
382 403
383 // Make sure we collapse the children when the row is clicked 404 // Make sure we collapse the children when the row is clicked
384 // again. 405 // again.
385 expander.textContent = "\u25BE"; 406 expander.textContent = "\u25BE";
386 let expandHandler = expander.onclick; 407 let expandHandler = expander.onclick;
387 expander.onclick = () => { 408 expander.onclick = () => {
388 that.collapseRow(tree, expander, expandHandler); 409 that.collapseRow(tree, expander, expandHandler);
389 } 410 }
390 } 411 }
391 412
392 // Collect the children, and sort them by ticks. 413 // Collect the children, and sort them by ticks.
393 let children = []; 414 let children = [];
394 let filter = 415 let filter =
395 this.filterFromFilterId(this.currentState.callTree.attribution); 416 filterFromFilterId(this.currentState.callTree.attribution);
396 for (let childId in tree.children) { 417 for (let childId in tree.children) {
397 let child = tree.children[childId]; 418 let child = tree.children[childId];
398 if (child.ticks > 0) { 419 if (child.ticks > 0) {
399 children.push(child); 420 children.push(child);
400 if (child.delayedExpansion) { 421 if (child.delayedExpansion) {
401 expandTreeNode(this.currentState.file, child, filter); 422 expandTreeNode(this.currentState.file, child, filter);
402 } 423 }
403 } 424 }
404 } 425 }
405 children.sort(this.sortFromId(this.currentState.callTree.sort)); 426 children.sort(this.sortFromId(this.currentState.callTree.sort));
(...skipping 19 matching lines...) Expand all
425 if (this.currentState.callTree.mode !== "bottom-up") { 446 if (this.currentState.callTree.mode !== "bottom-up") {
426 c = row.insertCell(-1); 447 c = row.insertCell(-1);
427 c.textContent = (node.ownTicks * 100 / this.tickCount).toFixed(2) + "%"; 448 c.textContent = (node.ownTicks * 100 / this.tickCount).toFixed(2) + "%";
428 c.style.textAlign = "right"; 449 c.style.textAlign = "right";
429 } 450 }
430 451
431 // Create the name cell. 452 // Create the name cell.
432 let nameCell = row.insertCell(); 453 let nameCell = row.insertCell();
433 let expander = this.createExpander(indent); 454 let expander = this.createExpander(indent);
434 nameCell.appendChild(expander); 455 nameCell.appendChild(expander);
435 nameCell.appendChild(this.createTypeDiv(node.type)); 456 nameCell.appendChild(createTypeDiv(node.type));
436 nameCell.appendChild(document.createTextNode(node.name)); 457 nameCell.appendChild(this.createFunctionNode(node.name, node.codeId));
437 458
438 // Inclusive ticks cell. 459 // Inclusive ticks cell.
439 c = row.insertCell(); 460 c = row.insertCell();
440 c.textContent = node.ticks; 461 c.textContent = node.ticks;
441 c.style.textAlign = "right"; 462 c.style.textAlign = "right";
442 if (this.currentState.callTree.mode !== "bottom-up") { 463 if (this.currentState.callTree.mode !== "bottom-up") {
443 // Exclusive ticks cell. 464 // Exclusive ticks cell.
444 c = row.insertCell(-1); 465 c = row.insertCell(-1);
445 c.textContent = node.ownTicks; 466 c.textContent = node.ownTicks;
446 c.style.textAlign = "right"; 467 c.style.textAlign = "right";
(...skipping 119 matching lines...) Expand 10 before | Expand all | Expand 10 after
566 } 587 }
567 588
568 let ownTimeClass = (mode === "bottom-up") ? "numeric-hidden" : "numeric"; 589 let ownTimeClass = (mode === "bottom-up") ? "numeric-hidden" : "numeric";
569 let ownTimeTh = $(this.treeElement.id + "-own-time-header"); 590 let ownTimeTh = $(this.treeElement.id + "-own-time-header");
570 ownTimeTh.classList = ownTimeClass; 591 ownTimeTh.classList = ownTimeClass;
571 let ownTicksTh = $(this.treeElement.id + "-own-ticks-header"); 592 let ownTicksTh = $(this.treeElement.id + "-own-ticks-header");
572 ownTicksTh.classList = ownTimeClass; 593 ownTicksTh.classList = ownTimeClass;
573 594
574 // Build the tree. 595 // Build the tree.
575 let stackProcessor; 596 let stackProcessor;
576 let filter = this.filterFromFilterId(this.currentState.callTree.attribution) ; 597 let filter = filterFromFilterId(this.currentState.callTree.attribution);
577 if (mode === "top-down") { 598 if (mode === "top-down") {
578 stackProcessor = 599 stackProcessor =
579 new PlainCallTreeProcessor(filter, false); 600 new PlainCallTreeProcessor(filter, false);
580 } else if (mode === "function-list") { 601 } else if (mode === "function-list") {
581 stackProcessor = new FunctionListTree( 602 stackProcessor = new FunctionListTree(
582 filter, this.currentState.callTree.categories === "code-type"); 603 filter, this.currentState.callTree.categories === "code-type");
583 604
584 } else { 605 } else {
585 console.assert(mode === "bottom-up"); 606 console.assert(mode === "bottom-up");
586 if (this.currentState.callTree.categories == "none") { 607 if (this.currentState.callTree.categories == "none") {
(...skipping 25 matching lines...) Expand all
612 // Swap in the new rows. 633 // Swap in the new rows.
613 this.treeElement.replaceChild(newRows, oldRows[0]); 634 this.treeElement.replaceChild(newRows, oldRows[0]);
614 } 635 }
615 } 636 }
616 637
617 class TimelineView { 638 class TimelineView {
618 constructor() { 639 constructor() {
619 this.element = $("timeline"); 640 this.element = $("timeline");
620 this.canvas = $("timeline-canvas"); 641 this.canvas = $("timeline-canvas");
621 this.legend = $("timeline-legend"); 642 this.legend = $("timeline-legend");
643 this.currentCode = $("timeline-currentCode");
622 644
623 this.canvas.onmousedown = this.onMouseDown.bind(this); 645 this.canvas.onmousedown = this.onMouseDown.bind(this);
624 this.canvas.onmouseup = this.onMouseUp.bind(this); 646 this.canvas.onmouseup = this.onMouseUp.bind(this);
625 this.canvas.onmousemove = this.onMouseMove.bind(this); 647 this.canvas.onmousemove = this.onMouseMove.bind(this);
626 648
627 this.selectionStart = null; 649 this.selectionStart = null;
628 this.selectionEnd = null; 650 this.selectionEnd = null;
629 this.selecting = false; 651 this.selecting = false;
630 652
631 this.currentState = null; 653 this.currentState = null;
654
655 this.functionTimelineHeight = 12;
632 } 656 }
633 657
634 onMouseDown(e) { 658 onMouseDown(e) {
635 this.selectionStart = 659 this.selectionStart =
636 e.clientX - this.canvas.getBoundingClientRect().left; 660 e.clientX - this.canvas.getBoundingClientRect().left;
637 this.selectionEnd = this.selectionStart + 1; 661 this.selectionEnd = this.selectionStart + 1;
638 this.selecting = true; 662 this.selecting = true;
639 } 663 }
640 664
641 onMouseMove(e) { 665 onMouseMove(e) {
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after
683 } 707 }
684 708
685 drawSelection() { 709 drawSelection() {
686 let ctx = this.canvas.getContext("2d"); 710 let ctx = this.canvas.getContext("2d");
687 ctx.drawImage(this.buffer, 0, 0); 711 ctx.drawImage(this.buffer, 0, 0);
688 712
689 if (this.selectionStart !== null && this.selectionEnd !== null) { 713 if (this.selectionStart !== null && this.selectionEnd !== null) {
690 ctx.fillStyle = "rgba(0, 0, 0, 0.3)"; 714 ctx.fillStyle = "rgba(0, 0, 0, 0.3)";
691 let left = Math.min(this.selectionStart, this.selectionEnd); 715 let left = Math.min(this.selectionStart, this.selectionEnd);
692 let right = Math.max(this.selectionStart, this.selectionEnd); 716 let right = Math.max(this.selectionStart, this.selectionEnd);
693 ctx.fillRect(0, 0, left, this.buffer.height); 717 let height = this.buffer.height - this.functionTimelineHeight;
694 ctx.fillRect(right, 0, this.buffer.width - right, this.buffer.height); 718 ctx.fillRect(0, 0, left, height);
719 ctx.fillRect(right, 0, this.buffer.width - right, height);
695 } 720 }
696 } 721 }
697 722
698 723
699 render(newState) { 724 render(newState) {
700 let oldState = this.currentState; 725 let oldState = this.currentState;
701 726
702 if (!newState.file) { 727 if (!newState.file) {
703 this.element.style.display = "none"; 728 this.element.style.display = "none";
704 return; 729 return;
705 } 730 }
706 731
707 this.currentState = newState; 732 this.currentState = newState;
708 if (oldState) { 733 if (oldState) {
709 if (newState.timeLine.width === oldState.timeLine.width && 734 if (newState.timeLine.width === oldState.timeLine.width &&
710 newState.timeLine.height === oldState.timeLine.height && 735 newState.timeLine.height === oldState.timeLine.height &&
711 newState.file === oldState.file && 736 newState.file === oldState.file &&
737 newState.currentCodeId === oldState.currentCodeId &&
712 newState.start === oldState.start && 738 newState.start === oldState.start &&
713 newState.end === oldState.end) { 739 newState.end === oldState.end) {
714 // No change, nothing to do. 740 // No change, nothing to do.
715 return; 741 return;
716 } 742 }
717 } 743 }
718 744
719 this.element.style.display = "inherit"; 745 this.element.style.display = "inherit";
720 746
721 // Make sure the canvas has the right dimensions. 747 // Make sure the canvas has the right dimensions.
722 let width = this.currentState.timeLine.width; 748 let width = this.currentState.timeLine.width;
723 this.canvas.width = width; 749 this.canvas.width = width;
724 this.canvas.height = this.currentState.timeLine.height; 750 this.canvas.height = this.currentState.timeLine.height;
725 751
726 let file = this.currentState.file; 752 let file = this.currentState.file;
727 if (!file) return; 753 if (!file) return;
728 754
755 let currentCodeId = this.currentState.currentCodeId;
756
729 let firstTime = file.ticks[0].tm; 757 let firstTime = file.ticks[0].tm;
730 let lastTime = file.ticks[file.ticks.length - 1].tm; 758 let lastTime = file.ticks[file.ticks.length - 1].tm;
731 let start = Math.max(this.currentState.start, firstTime); 759 let start = Math.max(this.currentState.start, firstTime);
732 let end = Math.min(this.currentState.end, lastTime); 760 let end = Math.min(this.currentState.end, lastTime);
733 761
734 this.selectionStart = (start - firstTime) / (lastTime - firstTime) * width; 762 this.selectionStart = (start - firstTime) / (lastTime - firstTime) * width;
735 this.selectionEnd = (end - firstTime) / (lastTime - firstTime) * width; 763 this.selectionEnd = (end - firstTime) / (lastTime - firstTime) * width;
736 764
737 let tickCount = file.ticks.length; 765 let tickCount = file.ticks.length;
738 766
739 let minBucketPixels = 10; 767 let minBucketPixels = 10;
740 let minBucketSamples = 30; 768 let minBucketSamples = 30;
741 let bucketCount = Math.min(width / minBucketPixels, 769 let bucketCount = Math.min(width / minBucketPixels,
742 tickCount / minBucketSamples); 770 tickCount / minBucketSamples);
743 771
744 let stackProcessor = new CategorySampler(file, bucketCount); 772 let stackProcessor = new CategorySampler(file, bucketCount);
745 generateTree(file, 0, Infinity, stackProcessor); 773 generateTree(file, 0, Infinity, stackProcessor);
774 let codeIdProcessor = new FunctionTimelineProcessor(
775 currentCodeId,
776 filterFromFilterId(this.currentState.callTree.attribution));
777 generateTree(file, 0, Infinity, codeIdProcessor);
746 778
747 let buffer = document.createElement("canvas"); 779 let buffer = document.createElement("canvas");
748 780
749 buffer.width = this.canvas.width; 781 buffer.width = this.canvas.width;
750 buffer.height = this.canvas.height; 782 buffer.height = this.canvas.height;
751 783
752 // Calculate the bar heights for each bucket. 784 // Calculate the bar heights for each bucket.
753 let graphHeight = buffer.height; 785 let graphHeight = buffer.height - this.functionTimelineHeight;
754 let buckets = stackProcessor.buckets; 786 let buckets = stackProcessor.buckets;
755 let bucketsGraph = []; 787 let bucketsGraph = [];
756 for (let i = 0; i < buckets.length; i++) { 788 for (let i = 0; i < buckets.length; i++) {
757 let sum = 0; 789 let sum = 0;
758 let bucketData = []; 790 let bucketData = [];
759 let total = buckets[i].total; 791 let total = buckets[i].total;
760 for (let j = 0; j < bucketDescriptors.length; j++) { 792 for (let j = 0; j < bucketDescriptors.length; j++) {
761 let desc = bucketDescriptors[j]; 793 let desc = bucketDescriptors[j];
762 for (let k = 0; k < desc.kinds.length; k++) { 794 for (let k = 0; k < desc.kinds.length; k++) {
763 sum += buckets[i][desc.kinds[k]]; 795 sum += buckets[i][desc.kinds[k]];
(...skipping 13 matching lines...) Expand all
777 ctx.beginPath(); 809 ctx.beginPath();
778 ctx.moveTo(i * bucketWidth, j && bucketData[j - 1]); 810 ctx.moveTo(i * bucketWidth, j && bucketData[j - 1]);
779 ctx.lineTo((i + 1) * bucketWidth, j && nextBucketData[j - 1]); 811 ctx.lineTo((i + 1) * bucketWidth, j && nextBucketData[j - 1]);
780 ctx.lineTo((i + 1) * bucketWidth, nextBucketData[j]); 812 ctx.lineTo((i + 1) * bucketWidth, nextBucketData[j]);
781 ctx.lineTo(i * bucketWidth, bucketData[j]); 813 ctx.lineTo(i * bucketWidth, bucketData[j]);
782 ctx.closePath(); 814 ctx.closePath();
783 ctx.fillStyle = bucketDescriptors[j].color; 815 ctx.fillStyle = bucketDescriptors[j].color;
784 ctx.fill(); 816 ctx.fill();
785 } 817 }
786 } 818 }
819 let functionTimelineYOffset = graphHeight;
820 let functionTimelineHeight = this.functionTimelineHeight;
821 let timestampScaler = width / (lastTime - firstTime);
822 ctx.fillStyle = "white";
823 ctx.fillRect(
824 0,
825 functionTimelineYOffset,
826 buffer.width,
827 functionTimelineHeight);
828 for (let i = 0; i < codeIdProcessor.blocks.length; i++) {
829 let block = codeIdProcessor.blocks[i];
830 ctx.fillStyle = "#000000";
831 ctx.fillRect(
832 Math.round((block.start - firstTime) * timestampScaler),
833 functionTimelineYOffset,
834 Math.max(1, Math.round((block.end - block.start) * timestampScaler)),
835 block.topOfStack ? functionTimelineHeight : functionTimelineHeight / 2);
836 }
787 837
788 // Remember stuff for later. 838 // Remember stuff for later.
789 this.buffer = buffer; 839 this.buffer = buffer;
790 840
791 // Draw the buffer. 841 // Draw the buffer.
792 this.drawSelection(); 842 this.drawSelection();
793 843
794 // (Re-)Populate the graph legend. 844 // (Re-)Populate the graph legend.
795 while (this.legend.cells.length > 0) { 845 while (this.legend.cells.length > 0) {
796 this.legend.deleteCell(0); 846 this.legend.deleteCell(0);
797 } 847 }
798 let cell = this.legend.insertCell(-1); 848 let cell = this.legend.insertCell(-1);
799 cell.textContent = "Legend: "; 849 cell.textContent = "Legend: ";
800 cell.style.padding = "1ex"; 850 cell.style.padding = "1ex";
801 for (let i = 0; i < bucketDescriptors.length; i++) { 851 for (let i = 0; i < bucketDescriptors.length; i++) {
802 let cell = this.legend.insertCell(-1); 852 let cell = this.legend.insertCell(-1);
803 cell.style.padding = "1ex"; 853 cell.style.padding = "1ex";
804 let desc = bucketDescriptors[i]; 854 let desc = bucketDescriptors[i];
805 let div = document.createElement("div"); 855 let div = document.createElement("div");
806 div.style.display = "inline-block"; 856 div.style.display = "inline-block";
807 div.style.width = "0.6em"; 857 div.style.width = "0.6em";
808 div.style.height = "1.2ex"; 858 div.style.height = "1.2ex";
809 div.style.backgroundColor = desc.color; 859 div.style.backgroundColor = desc.color;
810 div.style.borderStyle = "solid"; 860 div.style.borderStyle = "solid";
811 div.style.borderWidth = "1px"; 861 div.style.borderWidth = "1px";
812 div.style.borderColor = "Black"; 862 div.style.borderColor = "Black";
813 cell.appendChild(div); 863 cell.appendChild(div);
814 cell.appendChild(document.createTextNode(" " + desc.text)); 864 cell.appendChild(document.createTextNode(" " + desc.text));
815 } 865 }
866
867 while (this.currentCode.firstChild) {
868 this.currentCode.removeChild(this.currentCode.firstChild);
869 }
870 if (currentCodeId) {
871 let currentCode = file.code[currentCodeId];
872 this.currentCode.appendChild(createTypeDiv(resolveCodeKind(currentCode)));
873 this.currentCode.appendChild(document.createTextNode(currentCode.name));
874
875 } else {
876 this.currentCode.appendChild(document.createTextNode("<none>"));
877 }
816 } 878 }
817 } 879 }
818 880
819 class HelpView { 881 class HelpView {
820 constructor() { 882 constructor() {
821 this.element = $("help"); 883 this.element = $("help");
822 } 884 }
823 885
824 render(newState) { 886 render(newState) {
825 this.element.style.display = newState.file ? "none" : "inherit"; 887 this.element.style.display = newState.file ? "none" : "inherit";
826 } 888 }
827 } 889 }
OLDNEW
« tools/profview/profile-utils.js ('K') | « tools/profview/profview.css ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698