 Chromium Code Reviews
 Chromium Code Reviews Issue 61923003:
  Timeline: show impl-side frames on the Timeline overview  (Closed) 
  Base URL: svn://svn.chromium.org/blink/trunk
    
  
    Issue 61923003:
  Timeline: show impl-side frames on the Timeline overview  (Closed) 
  Base URL: svn://svn.chromium.org/blink/trunk| OLD | NEW | 
|---|---|
| 1 /* | 1 /* | 
| 2 * Copyright (C) 2013 Google Inc. All rights reserved. | 2 * Copyright (C) 2013 Google Inc. All rights reserved. | 
| 3 * | 3 * | 
| 4 * Redistribution and use in source and binary forms, with or without | 4 * Redistribution and use in source and binary forms, with or without | 
| 5 * modification, are permitted provided that the following conditions are | 5 * modification, are permitted provided that the following conditions are | 
| 6 * met: | 6 * met: | 
| 7 * | 7 * | 
| 8 * * Redistributions of source code must retain the above copyright | 8 * * Redistributions of source code must retain the above copyright | 
| 9 * notice, this list of conditions and the following disclaimer. | 9 * notice, this list of conditions and the following disclaimer. | 
| 10 * * Redistributions in binary form must reproduce the above | 10 * * Redistributions in binary form must reproduce the above | 
| (...skipping 624 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 635 * @param {WebInspector.TimelineModel} model | 635 * @param {WebInspector.TimelineModel} model | 
| 636 */ | 636 */ | 
| 637 WebInspector.TimelineFrameOverview = function(model) | 637 WebInspector.TimelineFrameOverview = function(model) | 
| 638 { | 638 { | 
| 639 WebInspector.TimelineOverviewBase.call(this, model); | 639 WebInspector.TimelineOverviewBase.call(this, model); | 
| 640 this.element.id = "timeline-overview-frames"; | 640 this.element.id = "timeline-overview-frames"; | 
| 641 this.reset(); | 641 this.reset(); | 
| 642 | 642 | 
| 643 this._outerPadding = 4 * window.devicePixelRatio; | 643 this._outerPadding = 4 * window.devicePixelRatio; | 
| 644 this._maxInnerBarWidth = 10 * window.devicePixelRatio; | 644 this._maxInnerBarWidth = 10 * window.devicePixelRatio; | 
| 645 this._topPadding = 6 * window.devicePixelRatio; | |
| 645 | 646 | 
| 646 // The below two are really computed by update() -- but let's have something so that windowTimes() is happy. | 647 // The below two are really computed by update() -- but let's have something so that windowTimes() is happy. | 
| 647 this._actualPadding = 5 * window.devicePixelRatio; | 648 this._actualPadding = 5 * window.devicePixelRatio; | 
| 648 this._actualOuterBarWidth = this._maxInnerBarWidth + this._actualPadding; | 649 this._actualOuterBarWidth = this._maxInnerBarWidth + this._actualPadding; | 
| 649 | 650 | 
| 650 this._fillStyles = {}; | 651 this._fillStyles = {}; | 
| 651 var categories = WebInspector.TimelinePresentationModel.categories(); | 652 var categories = WebInspector.TimelinePresentationModel.categories(); | 
| 652 for (var category in categories) | 653 for (var category in categories) | 
| 653 this._fillStyles[category] = WebInspector.TimelinePresentationModel.crea teFillStyleForCategory(this._context, this._maxInnerBarWidth, 0, categories[cate gory]); | 654 this._fillStyles[category] = WebInspector.TimelinePresentationModel.crea teFillStyleForCategory(this._context, this._maxInnerBarWidth, 0, categories[cate gory]); | 
| 655 this._frameTopShadeGradient = this._context.createLinearGradient(0, 0, 0, th is._topPadding); | |
| 656 this._frameTopShadeGradient.addColorStop(0, "rgba(255, 255, 255, 0.9)"); | |
| 657 this._frameTopShadeGradient.addColorStop(1, "rgba(255, 255, 255, 0.2)"); | |
| 654 } | 658 } | 
| 655 | 659 | 
| 656 WebInspector.TimelineFrameOverview.prototype = { | 660 WebInspector.TimelineFrameOverview.prototype = { | 
| 657 reset: function() | 661 reset: function() | 
| 658 { | 662 { | 
| 659 this._recordsPerBar = 1; | 663 this._recordsPerBar = 1; | 
| 660 /** @type {!Array.<{startTime:number, endTime:number}>} */ | 664 /** @type {!Array.<{startTime:number, endTime:number}>} */ | 
| 661 this._barTimes = []; | 665 this._barTimes = []; | 
| 662 this._frames = []; | 666 this._mainThreadFrames = []; | 
| 667 this._backgroundFrames = []; | |
| 668 this._framesById = {}; | |
| 663 }, | 669 }, | 
| 664 | 670 | 
| 665 update: function() | 671 update: function() | 
| 666 { | 672 { | 
| 667 this._resetCanvas(); | 673 this._resetCanvas(); | 
| 668 this._barTimes = []; | 674 this._barTimes = []; | 
| 669 | 675 | 
| 676 var backgroundFramesHeight = 15; | |
| 677 var mainThreadFramesHeight = this._canvas.height - backgroundFramesHeigh t; | |
| 670 const minBarWidth = 4 * window.devicePixelRatio; | 678 const minBarWidth = 4 * window.devicePixelRatio; | 
| 671 var frameCount = this._frames.length; | 679 var frameCount = Math.max(this._mainThreadFrames.length, this._backgroun dFrames.length); | 
| 
pfeldman
2013/11/06 17:21:05
this._backgroundFrames.length || this._mainThreadF
 | |
| 672 var framesPerBar = Math.max(1, frameCount * minBarWidth / this._canvas.w idth); | 680 var framesPerBar = Math.max(1, frameCount * minBarWidth / this._canvas.w idth); | 
| 673 var visibleFrames = this._aggregateFrames(this._frames, framesPerBar); | 681 | 
| 674 var windowHeight = this._canvas.height; | 682 var mainThreadVisibleFrames; | 
| 675 const paddingTop = 4 * window.devicePixelRatio; | 683 var backgroundVisibleFrames; | 
| 676 var scale = (windowHeight - paddingTop) / this._computeTargetFrameLength (visibleFrames); | 684 if (this._backgroundFrames.length) { | 
| 677 this._renderBars(visibleFrames, scale, windowHeight); | 685 backgroundVisibleFrames = this._aggregateFrames(this._backgroundFram es, framesPerBar); | 
| 678 this._drawFPSMarks(scale, windowHeight); | 686 mainThreadVisibleFrames = Array(backgroundVisibleFrames.length); | 
| 
pfeldman
2013/11/06 17:21:05
This can not compile - new Array.
 | |
| 687 for (var i = 0; i < backgroundVisibleFrames.length; ++i) { | |
| 688 var frameId = backgroundVisibleFrames[i].mainThreadFrameId; | |
| 689 mainThreadVisibleFrames[i] = frameId && this._framesById[frameId ]; | |
| 690 } | |
| 691 } else { | |
| 692 mainThreadVisibleFrames = this._aggregateFrames(this._mainThreadFram es, framesPerBar); | |
| 693 } | |
| 694 | |
| 695 this._context.save(); | |
| 696 this._setCanvasWindow(0, backgroundFramesHeight, this._canvas.width, mai nThreadFramesHeight); | |
| 697 var scale = (mainThreadFramesHeight - this._topPadding) / this._computeT argetFrameLength(mainThreadVisibleFrames); | |
| 698 this._renderBars(mainThreadVisibleFrames, scale, mainThreadFramesHeight) ; | |
| 699 this._context.fillStyle = this._frameTopShadeGradient; | |
| 700 this._context.fillRect(0, 0, this._canvas.width, this._topPadding); | |
| 701 this._drawFPSMarks(scale, mainThreadFramesHeight); | |
| 702 this._context.restore(); | |
| 703 | |
| 704 var bottom = backgroundFramesHeight + 0.5; | |
| 705 this._context.strokeStyle = "rgba(120, 120, 120, 0.8)"; | |
| 706 this._context.beginPath(); | |
| 707 this._context.moveTo(0, bottom); | |
| 708 this._context.lineTo(this._canvas.width, bottom); | |
| 709 this._context.stroke(); | |
| 710 | |
| 711 if (backgroundVisibleFrames) { | |
| 712 const targetFPS = 30.0; | |
| 713 scale = (backgroundFramesHeight - this._topPadding) / (1.0 / targetF PS); | |
| 714 this._renderBars(backgroundVisibleFrames, scale, backgroundFramesHei ght); | |
| 715 } | |
| 679 }, | 716 }, | 
| 680 | 717 | 
| 681 /** | 718 /** | 
| 682 * @param {WebInspector.TimelineFrame} frame | 719 * @param {WebInspector.TimelineFrame} frame | 
| 683 */ | 720 */ | 
| 684 addFrame: function(frame) | 721 addFrame: function(frame) | 
| 685 { | 722 { | 
| 686 this._frames.push(frame); | 723 var frames; | 
| 724 if (frame.isBackground) { | |
| 725 frames = this._backgroundFrames; | |
| 726 } else { | |
| 727 frames = this._mainThreadFrames; | |
| 728 this._framesById[frame.id] = frame; | |
| 729 } | |
| 730 frames.push(frame); | |
| 687 }, | 731 }, | 
| 688 | 732 | 
| 733 /** | |
| 734 * @param {number} x0 | |
| 735 * @param {number} y0 | |
| 736 * @param {number} width | |
| 737 * @param {number} height | |
| 738 */ | |
| 739 _setCanvasWindow: function(x0, y0, width, height) | |
| 740 { | |
| 741 this._context.translate(x0, y0); | |
| 742 this._context.beginPath(); | |
| 743 this._context.moveTo(0, 0); | |
| 744 this._context.lineTo(width, 0); | |
| 745 this._context.lineTo(width, height); | |
| 746 this._context.lineTo(0, height); | |
| 747 this._context.lineTo(0, 0); | |
| 748 this._context.clip(); | |
| 749 }, | |
| 689 | 750 | 
| 690 /** | 751 /** | 
| 691 * @param {Array.<WebInspector.TimelineFrame>} frames | 752 * @param {Array.<WebInspector.TimelineFrame>} frames | 
| 692 * @param {number} framesPerBar | 753 * @param {number} framesPerBar | 
| 693 * @return {Array.<WebInspector.TimelineFrame>} | 754 * @return {Array.<WebInspector.TimelineFrame>} | 
| 694 */ | 755 */ | 
| 695 _aggregateFrames: function(frames, framesPerBar) | 756 _aggregateFrames: function(frames, framesPerBar) | 
| 696 { | 757 { | 
| 697 var visibleFrames = []; | 758 var visibleFrames = []; | 
| 698 for (var barNumber = 0, currentFrame = 0; currentFrame < frames.length; ++barNumber) { | 759 for (var barNumber = 0, currentFrame = 0; currentFrame < frames.length; ++barNumber) { | 
| 699 var barStartTime = frames[currentFrame].startTime; | 760 var barStartTime = frames[currentFrame].startTime; | 
| 700 var longestFrame = null; | 761 var longestFrame = null; | 
| 701 var longestDuration = 0; | 762 var longestDuration = 0; | 
| 702 | 763 | 
| 703 for (var lastFrame = Math.min(Math.floor((barNumber + 1) * framesPer Bar), frames.length); | 764 for (var lastFrame = Math.min(Math.floor((barNumber + 1) * framesPer Bar), frames.length); | 
| 704 currentFrame < lastFrame; ++currentFrame) { | 765 currentFrame < lastFrame; ++currentFrame) { | 
| 705 var duration = frames[currentFrame].duration; | 766 var duration = this._frameDuration(frames[currentFrame]); | 
| 706 if (!longestFrame || longestDuration < duration) { | 767 if (!longestFrame || longestDuration < duration) { | 
| 707 longestFrame = frames[currentFrame]; | 768 longestFrame = frames[currentFrame]; | 
| 708 longestDuration = duration; | 769 longestDuration = duration; | 
| 709 } | 770 } | 
| 710 } | 771 } | 
| 711 var barEndTime = frames[currentFrame - 1].endTime; | 772 var barEndTime = frames[currentFrame - 1].endTime; | 
| 712 if (longestFrame) { | 773 if (longestFrame) { | 
| 713 visibleFrames.push(longestFrame); | 774 visibleFrames.push(longestFrame); | 
| 714 this._barTimes.push({ startTime: barStartTime, endTime: barEndTi me }); | 775 this._barTimes.push({ startTime: barStartTime, endTime: barEndTi me }); | 
| 715 } | 776 } | 
| 716 } | 777 } | 
| 717 return visibleFrames; | 778 return visibleFrames; | 
| 718 }, | 779 }, | 
| 719 | 780 | 
| 720 /** | 781 /** | 
| 782 * @param {WebInspector.TimelineFrame} frame | |
| 783 */ | |
| 784 _frameDuration: function(frame) | |
| 785 { | |
| 786 var relatedFrame = frame.mainThreadFrameId && this._framesById[frame.mai nThreadFrameId]; | |
| 787 return frame.duration + (relatedFrame ? relatedFrame.duration : 0); | |
| 788 }, | |
| 789 | |
| 790 /** | |
| 721 * @param {Array.<WebInspector.TimelineFrame>} frames | 791 * @param {Array.<WebInspector.TimelineFrame>} frames | 
| 722 * @return {number} | 792 * @return {number} | 
| 723 */ | 793 */ | 
| 724 _computeTargetFrameLength: function(frames) | 794 _computeTargetFrameLength: function(frames) | 
| 725 { | 795 { | 
| 726 var durations = frames.select("duration"); | 796 var durations = []; | 
| 797 for (var i = 0; i < frames.length; ++i) { | |
| 798 if (frames[i]) | |
| 799 durations.push(frames[i].duration); | |
| 800 } | |
| 727 var medianFrameLength = durations.qselect(Math.floor(durations.length / 2)); | 801 var medianFrameLength = durations.qselect(Math.floor(durations.length / 2)); | 
| 728 | 802 | 
| 729 // Optimize appearance for 30fps. However, if at least half frames won't fit at this scale, | 803 // Optimize appearance for 30fps. However, if at least half frames won't fit at this scale, | 
| 730 // fall back to using autoscale. | 804 // fall back to using autoscale. | 
| 731 const targetFPS = 30; | 805 const targetFPS = 30; | 
| 732 var result = 1.0 / targetFPS; | 806 var result = 1.0 / targetFPS; | 
| 733 if (result >= medianFrameLength) | 807 if (result >= medianFrameLength) | 
| 734 return result; | 808 return result; | 
| 735 | 809 | 
| 736 var maxFrameLength = Math.max.apply(Math, durations); | 810 var maxFrameLength = Math.max.apply(Math, durations); | 
| 737 return Math.min(medianFrameLength * 2, maxFrameLength); | 811 return Math.min(medianFrameLength * 2, maxFrameLength); | 
| 738 }, | 812 }, | 
| 739 | 813 | 
| 740 /** | 814 /** | 
| 741 * @param {Array.<WebInspector.TimelineFrame>} frames | 815 * @param {Array.<WebInspector.TimelineFrame>} frames | 
| 742 * @param {number} scale | 816 * @param {number} scale | 
| 743 * @param {number} windowHeight | 817 * @param {number} windowHeight | 
| 744 */ | 818 */ | 
| 745 _renderBars: function(frames, scale, windowHeight) | 819 _renderBars: function(frames, scale, windowHeight) | 
| 746 { | 820 { | 
| 747 const maxPadding = 5 * window.devicePixelRatio; | 821 const maxPadding = 5 * window.devicePixelRatio; | 
| 748 this._actualOuterBarWidth = Math.min((this._canvas.width - 2 * this._out erPadding) / frames.length, this._maxInnerBarWidth + maxPadding); | 822 this._actualOuterBarWidth = Math.min((this._canvas.width - 2 * this._out erPadding) / frames.length, this._maxInnerBarWidth + maxPadding); | 
| 749 this._actualPadding = Math.min(Math.floor(this._actualOuterBarWidth / 3) , maxPadding); | 823 this._actualPadding = Math.min(Math.floor(this._actualOuterBarWidth / 3) , maxPadding); | 
| 750 | 824 | 
| 751 var barWidth = this._actualOuterBarWidth - this._actualPadding; | 825 var barWidth = this._actualOuterBarWidth - this._actualPadding; | 
| 752 for (var i = 0; i < frames.length; ++i) | 826 for (var i = 0; i < frames.length; ++i) { | 
| 753 this._renderBar(this._barNumberToScreenPosition(i), barWidth, window Height, frames[i], scale); | 827 if (frames[i]) | 
| 828 this._renderBar(this._barNumberToScreenPosition(i), barWidth, wi ndowHeight, frames[i], scale); | |
| 829 } | |
| 754 }, | 830 }, | 
| 755 | 831 | 
| 756 /** | 832 /** | 
| 757 * @param {number} n | 833 * @param {number} n | 
| 758 */ | 834 */ | 
| 759 _barNumberToScreenPosition: function(n) | 835 _barNumberToScreenPosition: function(n) | 
| 760 { | 836 { | 
| 761 return this._outerPadding + this._actualOuterBarWidth * n; | 837 return this._outerPadding + this._actualOuterBarWidth * n; | 
| 762 }, | 838 }, | 
| 763 | 839 | 
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 797 | 873 | 
| 798 this._context.moveTo(0, y); | 874 this._context.moveTo(0, y); | 
| 799 this._context.lineTo(this._canvas.width, y); | 875 this._context.lineTo(this._canvas.width, y); | 
| 800 | 876 | 
| 801 this._context.fillStyle = "rgba(255, 255, 255, 0.5)"; | 877 this._context.fillStyle = "rgba(255, 255, 255, 0.5)"; | 
| 802 this._context.fillRect(labelX - labelWidth, labelY, labelWidth, line Height); | 878 this._context.fillRect(labelX - labelWidth, labelY, labelWidth, line Height); | 
| 803 this._context.fillStyle = "black"; | 879 this._context.fillStyle = "black"; | 
| 804 this._context.fillText(label, labelX - labelPadding, labelY + lineHe ight - baselineHeight); | 880 this._context.fillText(label, labelX - labelPadding, labelY + lineHe ight - baselineHeight); | 
| 805 labelTopMargin = labelY + lineHeight; | 881 labelTopMargin = labelY + lineHeight; | 
| 806 } | 882 } | 
| 807 this._context.strokeStyle = "rgba(128, 128, 128, 0.5)"; | 883 this._context.strokeStyle = "rgba(60, 60, 60, 0.4)"; | 
| 808 this._context.stroke(); | 884 this._context.stroke(); | 
| 809 this._context.restore(); | 885 this._context.restore(); | 
| 810 }, | 886 }, | 
| 811 | 887 | 
| 812 /** | 888 /** | 
| 813 * @param {number} left | 889 * @param {number} left | 
| 814 * @param {number} width | 890 * @param {number} width | 
| 815 * @param {number} windowHeight | 891 * @param {number} windowHeight | 
| 816 * @param {WebInspector.TimelineFrame} frame | 892 * @param {WebInspector.TimelineFrame} frame | 
| 817 * @param {number} scale | 893 * @param {number} scale | 
| 818 */ | 894 */ | 
| 819 _renderBar: function(left, width, windowHeight, frame, scale) | 895 _renderBar: function(left, width, windowHeight, frame, scale) | 
| 820 { | 896 { | 
| 821 var categories = Object.keys(WebInspector.TimelinePresentationModel.cate gories()); | 897 var categories = Object.keys(WebInspector.TimelinePresentationModel.cate gories()); | 
| 822 if (!categories.length) | 898 if (!categories.length) | 
| 823 return; | 899 return; | 
| 824 var x = Math.floor(left) + 0.5; | 900 var x = Math.floor(left) + 0.5; | 
| 825 width = Math.floor(width); | 901 width = Math.floor(width); | 
| 826 | 902 | 
| 827 for (var i = 0, bottomOffset = windowHeight; i < categories.length; ++i) { | 903 for (var i = 0, bottomOffset = windowHeight; i < categories.length; ++i) { | 
| 828 var category = categories[i]; | 904 var category = categories[i]; | 
| 829 var duration = frame.timeByCategory[category]; | 905 var duration = frame.timeByCategory[category]; | 
| 830 | 906 | 
| 831 if (!duration) | 907 if (!duration) | 
| 832 continue; | 908 continue; | 
| 833 var height = duration * scale; | 909 var height = Math.round(duration * scale); | 
| 834 var y = Math.floor(bottomOffset - height) + 0.5; | 910 var y = Math.floor(bottomOffset - height) + 0.5; | 
| 835 | 911 | 
| 836 this._context.save(); | 912 this._context.save(); | 
| 837 this._context.translate(x, 0); | 913 this._context.translate(x, 0); | 
| 838 this._context.scale(width / this._maxInnerBarWidth, 1); | 914 this._context.scale(width / this._maxInnerBarWidth, 1); | 
| 839 this._context.fillStyle = this._fillStyles[category]; | 915 this._context.fillStyle = this._fillStyles[category]; | 
| 840 this._context.fillRect(0, y, this._maxInnerBarWidth, Math.floor(heig ht)); | 916 this._context.fillRect(0, y, this._maxInnerBarWidth, Math.floor(heig ht)); | 
| 841 this._context.strokeStyle = WebInspector.TimelinePresentationModel.c ategories()[category].borderColor; | 917 this._context.strokeStyle = WebInspector.TimelinePresentationModel.c ategories()[category].borderColor; | 
| 842 this._context.beginPath(); | 918 this._context.beginPath(); | 
| 843 this._context.moveTo(0, y); | 919 this._context.moveTo(0, y); | 
| (...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 955 WebInspector.TimelineWindowFilter.prototype = { | 1031 WebInspector.TimelineWindowFilter.prototype = { | 
| 956 /** | 1032 /** | 
| 957 * @param {!WebInspector.TimelinePresentationModel.Record} record | 1033 * @param {!WebInspector.TimelinePresentationModel.Record} record | 
| 958 * @return {boolean} | 1034 * @return {boolean} | 
| 959 */ | 1035 */ | 
| 960 accept: function(record) | 1036 accept: function(record) | 
| 961 { | 1037 { | 
| 962 return record.lastChildEndTime >= this._pane._windowStartTime && record. startTime <= this._pane._windowEndTime; | 1038 return record.lastChildEndTime >= this._pane._windowStartTime && record. startTime <= this._pane._windowEndTime; | 
| 963 } | 1039 } | 
| 964 } | 1040 } | 
| OLD | NEW |