PerformanceMonitor.PerformanceMonitor=class extends UI.HBox{constructor(){super(true);this.registerRequiredCSS('performance_monitor/performanceMonitor.css');this.contentElement.classList.add('perfmon-pane');this._metricsBuffer=[];this._pixelsPerMs=10/1000;this._pollIntervalMs=500;this._scaleHeight=16;this._graphHeight=90;this._gridColor=UI.themeSupport.patchColorText('rgba(0, 0, 0, 0.08)',UI.ThemeSupport.ColorUsage.Foreground);this._controlPane=new PerformanceMonitor.PerformanceMonitor.ControlPane(this.contentElement);const chartContainer=this.contentElement.createChild('div','perfmon-chart-container');this._canvas=(chartContainer.createChild('canvas'));this.contentElement.createChild('div','perfmon-chart-suspend-overlay fill').createChild('div').textContent=Common.UIString('Paused');this._controlPane.addEventListener(PerformanceMonitor.PerformanceMonitor.ControlPane.Events.MetricChanged,this._recalcChartHeight,this);SDK.targetManager.observeModels(SDK.PerformanceMetricsModel,this);}
wasShown(){if(!this._model)
return;SDK.targetManager.addEventListener(SDK.TargetManager.Events.SuspendStateChanged,this._suspendStateChanged,this);this._model.enable();this._suspendStateChanged();}
willHide(){if(!this._model)
return;SDK.targetManager.removeEventListener(SDK.TargetManager.Events.SuspendStateChanged,this._suspendStateChanged,this);this._stopPolling();this._model.disable();}
modelAdded(model){if(this._model)
return;this._model=model;if(this.isShowing())
this.wasShown();}
modelRemoved(model){if(this._model!==model)
return;if(this.isShowing())
this.willHide();this._model=null;}
_suspendStateChanged(){const suspended=SDK.targetManager.allTargetsSuspended();if(suspended)
this._stopPolling();else
this._startPolling();this.contentElement.classList.toggle('suspended',suspended);}
_startPolling(){this._startTimestamp=0;this._pollTimer=setInterval(()=>this._poll(),this._pollIntervalMs);this.onResize();animate.call(this);function animate(){this._draw();this._animationId=this.contentElement.window().requestAnimationFrame(animate.bind(this));}}
_stopPolling(){clearInterval(this._pollTimer);this.contentElement.window().cancelAnimationFrame(this._animationId);this._metricsBuffer=[];}
async _poll(){const data=await this._model.requestMetrics();const timestamp=data.timestamp;const metrics=data.metrics;this._metricsBuffer.push({timestamp,metrics:metrics});const millisPerWidth=this._width/this._pixelsPerMs;const maxCount=Math.ceil(millisPerWidth/this._pollIntervalMs*2);if(this._metricsBuffer.length>maxCount*2)
this._metricsBuffer.splice(0,this._metricsBuffer.length-maxCount);this._controlPane.updateMetrics(metrics);}
_draw(){const ctx=(this._canvas.getContext('2d'));ctx.save();ctx.scale(window.devicePixelRatio,window.devicePixelRatio);ctx.clearRect(0,0,this._width,this._height);ctx.save();ctx.translate(0,this._scaleHeight);for(const chartInfo of this._controlPane.charts()){if(!this._controlPane.isActive(chartInfo.metrics[0].name))
continue;this._drawChart(ctx,chartInfo,this._graphHeight);ctx.translate(0,this._graphHeight);}
ctx.restore();this._drawHorizontalGrid(ctx);ctx.restore();}
_drawHorizontalGrid(ctx){const labelDistanceSeconds=10;const lightGray=UI.themeSupport.patchColorText('rgba(0, 0, 0, 0.02)',UI.ThemeSupport.ColorUsage.Foreground);ctx.font='10px '+Host.fontFamily();ctx.fillStyle=UI.themeSupport.patchColorText('rgba(0, 0, 0, 0.3)',UI.ThemeSupport.ColorUsage.Foreground);const currentTime=Date.now()/1000;for(let sec=Math.ceil(currentTime);;--sec){const x=this._width-((currentTime-sec)*1000-this._pollIntervalMs)*this._pixelsPerMs;if(x<-50)
break;ctx.beginPath();ctx.moveTo(Math.round(x)+0.5,0);ctx.lineTo(Math.round(x)+0.5,this._height);if(sec>=0&&sec%labelDistanceSeconds===0)
ctx.fillText(new Date(sec*1000).toLocaleTimeString(),Math.round(x)+4,12);ctx.strokeStyle=sec%labelDistanceSeconds?lightGray:this._gridColor;ctx.stroke();}}
_drawChart(ctx,chartInfo,height){ctx.save();ctx.rect(0,0,this._width,height);ctx.clip();const bottomPadding=8;const extraSpace=1.05;const max=this._calcMax(chartInfo)*extraSpace;const stackedChartBaseLandscape=chartInfo.stacked?new Map():null;const paths=[];for(let i=chartInfo.metrics.length-1;i>=0;--i){const metricInfo=chartInfo.metrics[i];paths.push({path:this._buildMetricPath(chartInfo,metricInfo,height-bottomPadding,max,i?stackedChartBaseLandscape:null),color:metricInfo.color});}
const backgroundColor=Common.Color.parse(UI.themeSupport.patchColorText('white',UI.ThemeSupport.ColorUsage.Background));for(const path of paths.reverse()){const color=path.color;ctx.save();ctx.fillStyle=backgroundColor.blendWith(Common.Color.parse(color).setAlpha(0.2)).asString(null);ctx.fill(path.path);ctx.strokeStyle=color;ctx.lineWidth=0.5;ctx.stroke(path.path);ctx.restore();}
this._drawVerticalGrid(ctx,height-bottomPadding,max,chartInfo);ctx.restore();}
_calcMax(chartInfo){if(chartInfo.max)
return chartInfo.max;const width=this._width;const startTime=performance.now()-this._pollIntervalMs-width/this._pixelsPerMs;let max=-Infinity;for(const metricInfo of chartInfo.metrics){for(let i=this._metricsBuffer.length-1;i>=0;--i){const metrics=this._metricsBuffer[i];const value=metrics.metrics.get(metricInfo.name);max=Math.max(max,value);if(metrics.timestamp<startTime)
break;}}
if(!this._metricsBuffer.length)
return 10;const base10=Math.pow(10,Math.floor(Math.log10(max)));max=Math.ceil(max/base10/2)*base10*2;const alpha=0.2;chartInfo.currentMax=max*alpha+(chartInfo.currentMax||max)*(1-alpha);return chartInfo.currentMax;}
_drawVerticalGrid(ctx,height,max,info){let base=Math.pow(10,Math.floor(Math.log10(max)));const firstDigit=Math.floor(max/base);if(firstDigit!==1&&firstDigit%2===1)
base*=2;let scaleValue=Math.floor(max/base)*base;const span=max;const topPadding=5;const visibleHeight=height-topPadding;ctx.fillStyle=UI.themeSupport.patchColorText('rgba(0, 0, 0, 0.3)',UI.ThemeSupport.ColorUsage.Foreground);ctx.strokeStyle=this._gridColor;ctx.beginPath();for(let i=0;i<2;++i){const y=calcY(scaleValue);const labelText=PerformanceMonitor.PerformanceMonitor.MetricIndicator._formatNumber(scaleValue,info);ctx.moveTo(0,y);ctx.lineTo(4,y);ctx.moveTo(ctx.measureText(labelText).width+12,y);ctx.lineTo(this._width,y);ctx.fillText(labelText,8,calcY(scaleValue)+3);scaleValue/=2;}
ctx.stroke();ctx.beginPath();ctx.moveTo(0,height+0.5);ctx.lineTo(this._width,height+0.5);ctx.strokeStyle=UI.themeSupport.patchColorText('rgba(0, 0, 0, 0.2)',UI.ThemeSupport.ColorUsage.Foreground);ctx.stroke();function calcY(value){return Math.round(height-visibleHeight*value/span)+0.5;}}
_buildMetricPath(chartInfo,metricInfo,height,scaleMax,stackedChartBaseLandscape){const path=new Path2D();const topPadding=5;const visibleHeight=height-topPadding;if(visibleHeight<1)
return path;const span=scaleMax;const metricName=metricInfo.name;const pixelsPerMs=this._pixelsPerMs;const startTime=performance.now()-this._pollIntervalMs-this._width/pixelsPerMs;const smooth=chartInfo.smooth;let x=0;let lastY=0;let lastX=0;if(this._metricsBuffer.length){x=(this._metricsBuffer[0].timestamp-startTime)*pixelsPerMs;path.moveTo(x,calcY(0));path.lineTo(this._width+5,calcY(0));lastY=calcY(this._metricsBuffer.peekLast().metrics.get(metricName));lastX=this._width+5;path.lineTo(lastX,lastY);}
for(let i=this._metricsBuffer.length-1;i>=0;--i){const metrics=this._metricsBuffer[i];const timestamp=metrics.timestamp;let value=metrics.metrics.get(metricName);if(stackedChartBaseLandscape){value+=stackedChartBaseLandscape.get(timestamp)||0;value=Number.constrain(value,0,1);stackedChartBaseLandscape.set(timestamp,value);}
const y=calcY(value);x=(timestamp-startTime)*pixelsPerMs;if(smooth){const midX=(lastX+x)/2;path.bezierCurveTo(midX,lastY,midX,y,x,y);}else{path.lineTo(x,lastY);path.lineTo(x,y);}
lastX=x;lastY=y;if(timestamp<startTime)
break;}
return path;function calcY(value){return Math.round(height-visibleHeight*value/span)+0.5;}}
onResize(){super.onResize();this._width=this._canvas.offsetWidth;this._canvas.width=Math.round(this._width*window.devicePixelRatio);this._recalcChartHeight();}
_recalcChartHeight(){let height=this._scaleHeight;for(const chartInfo of this._controlPane.charts()){if(this._controlPane.isActive(chartInfo.metrics[0].name))
height+=this._graphHeight;}
this._height=Math.ceil(height*window.devicePixelRatio);this._canvas.height=this._height;this._canvas.style.height=`${this._height / window.devicePixelRatio}px`;}};PerformanceMonitor.PerformanceMonitor.Format={Percent:Symbol('Percent'),Bytes:Symbol('Bytes'),};PerformanceMonitor.PerformanceMonitor.ChartInfo;PerformanceMonitor.PerformanceMonitor.MetricInfo;PerformanceMonitor.PerformanceMonitor.ControlPane=class extends Common.Object{constructor(parent){super();this.element=parent.createChild('div','perfmon-control-pane');this._enabledChartsSetting=Common.settings.createSetting('perfmonActiveIndicators2',['TaskDuration','JSHeapTotalSize','Nodes']);this._enabledCharts=new Set(this._enabledChartsSetting.get());const format=PerformanceMonitor.PerformanceMonitor.Format;this._chartsInfo=[{title:Common.UIString('CPU usage'),metrics:[{name:'TaskDuration',color:'#999'},{name:'ScriptDuration',color:'orange'},{name:'LayoutDuration',color:'blueviolet'},{name:'RecalcStyleDuration',color:'violet'}],format:format.Percent,smooth:true,stacked:true,color:'red',max:1},{title:Common.UIString('JS heap size'),metrics:[{name:'JSHeapTotalSize',color:'#99f'},{name:'JSHeapUsedSize',color:'blue'}],format:format.Bytes,color:'blue'},{title:Common.UIString('DOM Nodes'),metrics:[{name:'Nodes',color:'green'}]},{title:Common.UIString('JS event listeners'),metrics:[{name:'JSEventListeners',color:'yellowgreen'}]},{title:Common.UIString('Documents'),metrics:[{name:'Documents',color:'darkblue'}]},{title:Common.UIString('Document Frames'),metrics:[{name:'Frames',color:'darkcyan'}]},{title:Common.UIString('Layouts / sec'),metrics:[{name:'LayoutCount',color:'hotpink'}]},{title:Common.UIString('Style recalcs / sec'),metrics:[{name:'RecalcStyleCount',color:'deeppink'}]}];for(const info of this._chartsInfo){for(const metric of info.metrics)
metric.color=UI.themeSupport.patchColorText(metric.color,UI.ThemeSupport.ColorUsage.Foreground);}
this._indicators=new Map();for(const chartInfo of this._chartsInfo){const chartName=chartInfo.metrics[0].name;const active=this._enabledCharts.has(chartName);const indicator=new PerformanceMonitor.PerformanceMonitor.MetricIndicator(this.element,chartInfo,active,this._onToggle.bind(this,chartName));this._indicators.set(chartName,indicator);}}
_onToggle(chartName,active){if(active)
this._enabledCharts.add(chartName);else
this._enabledCharts.delete(chartName);this._enabledChartsSetting.set(Array.from(this._enabledCharts));this.dispatchEventToListeners(PerformanceMonitor.PerformanceMonitor.ControlPane.Events.MetricChanged);}
charts(){return this._chartsInfo;}
isActive(metricName){return this._enabledCharts.has(metricName);}
updateMetrics(metrics){for(const name of this._indicators.keys()){if(metrics.has(name))
this._indicators.get(name).setValue(metrics.get(name));}}};PerformanceMonitor.PerformanceMonitor.ControlPane.Events={MetricChanged:Symbol('MetricChanged')};PerformanceMonitor.PerformanceMonitor.MetricIndicator=class{constructor(parent,info,active,onToggle){const color=info.color||info.metrics[0].color;this._info=info;this._active=active;this._onToggle=onToggle;this.element=parent.createChild('div','perfmon-indicator');this._swatchElement=UI.Icon.create('smallicon-checkmark-square','perfmon-indicator-swatch');this._swatchElement.style.backgroundColor=color;this.element.appendChild(this._swatchElement);this.element.createChild('div','perfmon-indicator-title').textContent=info.title;this._valueElement=this.element.createChild('div','perfmon-indicator-value');this._valueElement.style.color=color;this.element.addEventListener('click',()=>this._toggleIndicator());this.element.classList.toggle('active',active);}
static _formatNumber(value,info){if(!PerformanceMonitor.PerformanceMonitor.MetricIndicator._numberFormatter){PerformanceMonitor.PerformanceMonitor.MetricIndicator._numberFormatter=new Intl.NumberFormat('en-US',{maximumFractionDigits:1});PerformanceMonitor.PerformanceMonitor.MetricIndicator._percentFormatter=new Intl.NumberFormat('en-US',{maximumFractionDigits:1,style:'percent'});}
switch(info.format){case PerformanceMonitor.PerformanceMonitor.Format.Percent:return PerformanceMonitor.PerformanceMonitor.MetricIndicator._percentFormatter.format(value);case PerformanceMonitor.PerformanceMonitor.Format.Bytes:return Number.bytesToString(value);default:return PerformanceMonitor.PerformanceMonitor.MetricIndicator._numberFormatter.format(value);}}
setValue(value){this._valueElement.textContent=PerformanceMonitor.PerformanceMonitor.MetricIndicator._formatNumber(value,this._info);}
_toggleIndicator(){this._active=!this._active;this.element.classList.toggle('active',this._active);this._onToggle(this._active);}};PerformanceMonitor.PerformanceMonitor.MetricIndicator._format=new Intl.NumberFormat('en-US',{maximumFractionDigits:1});;Runtime.cachedResources["performance_monitor/performanceMonitor.css"]="/*\n * Copyright 2017 The Chromium Authors. All rights reserved.\n * Use of this source code is governed by a BSD-style license that can be\n * found in the LICENSE file.\n */\n\n.perfmon-pane {\n  overflow: hidden;\n}\n\n.perfmon-pane.suspended {\n  opacity: 0.4;\n  pointer-events: none;\n}\n\n.perfmon-pane .perfmon-chart-suspend-overlay {\n  display: none;\n  font-size: 26px;\n  align-items: center;\n  justify-content: center;\n}\n\n.perfmon-pane.suspended .perfmon-chart-suspend-overlay {\n  display: flex;\n}\n\n.perfmon-control-pane {\n  display: flex;\n  flex-direction: column;\n  padding: 6px 0;\n  overflow-x: hidden;\n  overflow-y: auto;\n}\n\n.perfmon-chart-container {\n  display: flex;\n  flex: 1 1;\n  border-left: 1px solid #ccc;\n  overflow-y: auto;\n}\n\n.perfmon-chart-container canvas {\n  width: 100%;\n}\n\n.perfmon-indicator {\n  padding: 6px 12px;\n  margin: -1px 0;\n  display: flex;\n  flex-shrink: 0;\n  width: 210px;\n}\n\n.perfmon-indicator:hover {\n  background-color: #f8f8f8;\n}\n\n.perfmon-indicator-swatch {\n  margin-right: 6px;\n}\n\n.perfmon-indicator:not(.active) .perfmon-indicator-swatch {\n  background-color: #eee !important;\n}\n\n.perfmon-indicator-title {\n  flex: 0 0 115px;\n}\n\n.perfmon-indicator:not(.active) .perfmon-indicator-title {\n  color: #aaa;\n}\n\n.perfmon-indicator-value {\n  flex: 0 0 55px;\n  text-align: right;\n  overflow: visible;\n}\n\n.perfmon-indicator:not(.active) .perfmon-indicator-value {\n  opacity: 0;\n}\n\n.perfmon-indicator-close {\n  padding-left: 4px;\n}\n\n.perfmon-indicator:not(:hover) .perfmon-indicator-close {\n  opacity: 0;\n}\n\n.perfmon-add-button:not(:hover) {\n  color: #bbb;\n}\n\n/*# sourceURL=performance_monitor/performanceMonitor.css */";