UNPKG

@yuebai008/cli

Version:

Command line interface for rapid qg-minigame development

1 lines 11.9 kB
import*as Common from"../../core/common/common.js";import*as i18n from"../../core/i18n/i18n.js";import*as Platform from"../../core/platform/platform.js";import*as Root from"../../core/root/root.js";import*as SDK from"../../core/sdk/sdk.js";import*as IconButton from"../../ui/components/icon_button/icon_button.js";import*as PerfUI from"../../ui/legacy/components/perf_ui/perf_ui.js";import*as Components from"../../ui/legacy/components/utils/utils.js";import*as UI from"../../ui/legacy/legacy.js";import*as CPUProfile from"../../models/cpu_profile/cpu_profile.js";import{ProfileFlameChartDataProvider}from"./CPUProfileFlameChart.js";import{HeapTimelineOverview}from"./HeapTimelineOverview.js";import{ProfileEvents,ProfileType}from"./ProfileHeader.js";import{ProfileView,WritableProfileHeader}from"./ProfileView.js";const UIStrings={selectedSizeS:"Selected size: {PH1}",selfSizeBytes:"Self Size (bytes)",totalSizeBytes:"Total Size (bytes)",stopHeapProfiling:"Stop heap profiling",startHeapProfiling:"Start heap profiling",recording:"Recording…",heapProfilerIsRecording:"Heap profiler is recording",stopping:"Stopping…",allocationSampling:"Allocation sampling",samplingProfiles:"SAMPLING PROFILES",recordMemoryAllocations:"Record memory allocations using sampling method.",thisProfileTypeHasMinimal:"This profile type has minimal performance overhead and can be used for long running operations.",itProvidesGoodApproximation:"It provides good approximation of allocations broken down by `JavaScript` execution stack.",profileD:"Profile {PH1}",sBytes:"{PH1} bytes",formatPercent:"{PH1} %",skb:"{PH1} kB",name:"Name",selfSize:"Self size",totalSize:"Total size",url:"URL"},str_=i18n.i18n.registerUIStrings("panels/profiler/HeapProfileView.ts",UIStrings),i18nString=i18n.i18n.getLocalizedString.bind(void 0,str_);function convertToSamplingHeapProfile(e){return e.profile||e.protocolProfile()}export class HeapProfileView extends ProfileView{profileHeader;profileType;adjustedTotal;selectedSizeText;timestamps;sizes;max;ordinals;totalTime;lastOrdinal;timelineOverview;constructor(e){super(),this.profileHeader=e,this.profileType=e.profileType(),this.initialize(new NodeFormatter(this));const i=new SamplingHeapProfileModel(convertToSamplingHeapProfile(e));this.adjustedTotal=i.total,this.setProfile(i),this.selectedSizeText=new UI.Toolbar.ToolbarText,this.timestamps=[],this.sizes=[],this.max=[],this.ordinals=[],this.totalTime=0,this.lastOrdinal=0,this.timelineOverview=new HeapTimelineOverview,Root.Runtime.experiments.isEnabled("samplingHeapProfilerTimeline")&&(this.timelineOverview.addEventListener("IdsRangeChanged",this.onIdsRangeChanged.bind(this)),this.timelineOverview.show(this.element,this.element.firstChild),this.timelineOverview.start(),this.profileType.addEventListener("StatsUpdate",this.onStatsUpdate,this),this.profileType.once(ProfileEvents.ProfileComplete).then((()=>{this.profileType.removeEventListener("StatsUpdate",this.onStatsUpdate,this),this.timelineOverview.stop(),this.timelineOverview.updateGrid()})))}async toolbarItems(){return[...await super.toolbarItems(),this.selectedSizeText]}onIdsRangeChanged(e){const{minId:i,maxId:t}=e.data;this.selectedSizeText.setText(i18nString(UIStrings.selectedSizeS,{PH1:Platform.NumberUtilities.bytesToString(e.data.size)})),this.setSelectionRange(i,t)}setSelectionRange(e,i){const t=convertToSamplingHeapProfile(this.profileHeader),r=new SamplingHeapProfileModel(t,e,i);this.adjustedTotal=r.total,this.setProfile(r)}onStatsUpdate(e){const i=e.data;this.totalTime||(this.timestamps=[],this.sizes=[],this.max=[],this.ordinals=[],this.totalTime=3e4,this.lastOrdinal=0),this.sizes.fill(0),this.sizes.push(0),this.timestamps.push(Date.now()),this.ordinals.push(this.lastOrdinal+1);for(const e of i?.samples??[]){this.lastOrdinal=Math.max(this.lastOrdinal,e.ordinal);const i=Platform.ArrayUtilities.upperBound(this.ordinals,e.ordinal,Platform.ArrayUtilities.DEFAULT_COMPARATOR)-1;this.sizes[i]+=e.size}this.max.push(this.sizes[this.sizes.length-1]);this.timestamps[this.timestamps.length-1]-this.timestamps[0]>this.totalTime&&(this.totalTime*=2);const t={sizes:this.sizes,max:this.max,ids:this.ordinals,timestamps:this.timestamps,totalTime:this.totalTime};this.timelineOverview.setSamples(t)}columnHeader(e){switch(e){case"self":return i18nString(UIStrings.selfSizeBytes);case"total":return i18nString(UIStrings.totalSizeBytes)}return Common.UIString.LocalizedEmptyString}createFlameChartDataProvider(){return new HeapFlameChartDataProvider(this.profile(),this.profileHeader.heapProfilerModel())}}export class SamplingHeapProfileTypeBase extends(Common.ObjectWrapper.eventMixin(ProfileType)){recording;clearedDuringRecording;constructor(e,i){super(e,i),this.recording=!1,this.clearedDuringRecording=!1}profileBeingRecorded(){return super.profileBeingRecorded()}typeName(){return"Heap"}fileExtension(){return".heapprofile"}get buttonTooltip(){return this.recording?i18nString(UIStrings.stopHeapProfiling):i18nString(UIStrings.startHeapProfiling)}buttonClicked(){return this.recording?this.stopRecordingProfile():this.startRecordingProfile(),this.recording}startRecordingProfile(){const e=UI.Context.Context.instance().flavor(SDK.HeapProfilerModel.HeapProfilerModel);if(this.profileBeingRecorded()||!e)return;const i=new SamplingHeapProfileHeader(e,this);this.setProfileBeingRecorded(i),this.addProfile(i),i.updateStatus(i18nString(UIStrings.recording));const t=new IconButton.Icon.Icon;t.data={iconName:"warning-filled",color:"var(--icon-warning)",width:"14px",height:"14px"},UI.Tooltip.Tooltip.install(t,i18nString(UIStrings.heapProfilerIsRecording)),UI.InspectorView.InspectorView.instance().setPanelIcon("heap_profiler",t),this.recording=!0,this.startSampling()}async stopRecordingProfile(){this.recording=!1;const e=this.profileBeingRecorded();if(!e||!e.heapProfilerModel())return;e.updateStatus(i18nString(UIStrings.stopping));const i=await this.stopSampling();e&&(console.assert(void 0!==i),e.setProtocolProfile(i),e.updateStatus(""),this.setProfileBeingRecorded(null)),UI.InspectorView.InspectorView.instance().setPanelIcon("heap_profiler",null);const t=this.clearedDuringRecording;this.clearedDuringRecording=!1,t||this.dispatchEventToListeners(ProfileEvents.ProfileComplete,e)}createProfileLoadedFromFile(e){return new SamplingHeapProfileHeader(null,this,e)}profileBeingRecordedRemoved(){this.clearedDuringRecording=!0,this.stopRecordingProfile()}startSampling(){throw"Not implemented"}stopSampling(){throw"Not implemented"}}let samplingHeapProfileTypeInstance;export class SamplingHeapProfileType extends SamplingHeapProfileTypeBase{updateTimer;updateIntervalMs;constructor(){super(SamplingHeapProfileType.TypeId,i18nString(UIStrings.allocationSampling)),samplingHeapProfileTypeInstance||(samplingHeapProfileTypeInstance=this),this.updateTimer=0,this.updateIntervalMs=200}static get instance(){return samplingHeapProfileTypeInstance}get treeItemTitle(){return i18nString(UIStrings.samplingProfiles)}get description(){return[i18nString(UIStrings.recordMemoryAllocations),i18nString(UIStrings.thisProfileTypeHasMinimal),i18nString(UIStrings.itProvidesGoodApproximation)].join("\n")}hasTemporaryView(){return Root.Runtime.experiments.isEnabled("samplingHeapProfilerTimeline")}startSampling(){const e=this.obtainRecordingProfile();e&&(e.startSampling(),Root.Runtime.experiments.isEnabled("samplingHeapProfilerTimeline")&&(this.updateTimer=window.setTimeout((()=>{this.updateStats()}),this.updateIntervalMs)))}obtainRecordingProfile(){const e=this.profileBeingRecorded();if(e){return e.heapProfilerModel()}return null}async stopSampling(){window.clearTimeout(this.updateTimer),this.updateTimer=0,this.dispatchEventToListeners("RecordingStopped");const e=this.obtainRecordingProfile();if(!e)throw new Error("No heap profiler model");const i=await e.stopSampling();if(!i)throw new Error("No sampling profile found");return i}async updateStats(){const e=this.obtainRecordingProfile();if(!e)return;const i=await e.getSamplingProfile();this.updateTimer&&(this.dispatchEventToListeners("StatsUpdate",i),this.updateTimer=window.setTimeout((()=>{this.updateStats()}),this.updateIntervalMs))}static TypeId="SamplingHeap"}export class SamplingHeapProfileHeader extends WritableProfileHeader{heapProfilerModelInternal;protocolProfileInternal;constructor(e,i,t){super(e&&e.debuggerModel(),i,t||i18nString(UIStrings.profileD,{PH1:i.nextProfileUid()})),this.heapProfilerModelInternal=e,this.protocolProfileInternal={head:{callFrame:{functionName:"",scriptId:"",url:"",lineNumber:0,columnNumber:0},children:[],selfSize:0,id:0},samples:[],startTime:0,endTime:0,nodes:[]}}createView(){return new HeapProfileView(this)}protocolProfile(){return this.protocolProfileInternal}heapProfilerModel(){return this.heapProfilerModelInternal}profileType(){return super.profileType()}}export class SamplingHeapProfileNode extends CPUProfile.ProfileTreeModel.ProfileNode{self;constructor(e){super(e.callFrame||{functionName:e.functionName,scriptId:e.scriptId,url:e.url,lineNumber:e.lineNumber-1,columnNumber:e.columnNumber-1}),this.self=e.selfSize}}export class SamplingHeapProfileModel extends CPUProfile.ProfileTreeModel.ProfileTreeModel{modules;constructor(e,i,t){super(),this.modules=e.modules||[];let r=null;if(i||t){r=new Map,i=i||0,t=t||1/0;for(const o of e.samples){if(o.ordinal<i||o.ordinal>t)continue;const e=r.get(o.nodeId)||0;r.set(o.nodeId,e+o.size)}}function o(e){return e.children=e.children.filter(o),Boolean(e.children.length||e.self)}this.initialize(function(e){const i=new SamplingHeapProfileNode(e),t=[e],n=[i];for(;t.length;){const e=t.pop(),i=n.pop();i.children=e.children.map((e=>{const i=new SamplingHeapProfileNode(e);return r&&(i.self=r.get(e.id)||0),i})),t.push(...e.children),n.push(...i.children)}return o(i),i}(e.head))}}export class NodeFormatter{profileView;constructor(e){this.profileView=e}formatValue(e){return Platform.NumberUtilities.withThousandsSeparator(e)}formatValueAccessibleText(e){return i18nString(UIStrings.sBytes,{PH1:e})}formatPercent(e,i){return i18nString(UIStrings.formatPercent,{PH1:e.toFixed(2)})}linkifyNode(e){const i=this.profileView.profileHeader.heapProfilerModel(),t=i?i.target():null;return this.profileView.linkifier().maybeLinkifyConsoleCallFrame(t,e.profileNode.callFrame,{className:"profile-node-file",inlineFrameIndex:0})}}export class HeapFlameChartDataProvider extends ProfileFlameChartDataProvider{profile;heapProfilerModel;timelineDataInternal;constructor(e,i){super(),this.profile=e,this.heapProfilerModel=i}minimumBoundary(){return 0}totalTime(){return this.profile.root.total}entryHasDeoptReason(e){return!1}formatValue(e,i){return i18nString(UIStrings.skb,{PH1:Platform.NumberUtilities.withThousandsSeparator(e/1e3)})}calculateTimelineData(){const e=function e(i){return i.children.reduce(((i,t)=>i+e(t)),1)}(this.profile.root),i=new Array(e),t=new Uint16Array(e),r=new Float32Array(e),o=new Float64Array(e);let n=0,s=0,l=0,a=0;return function e(p){const d=l;i[a]=p,t[a]=n,r[a]=p.total,o[a]=l,++a,++n,p.children.forEach(e),--n,s=Math.max(s,n),l=d+p.total}(this.profile.root),this.maxStackDepthInternal=s+1,this.entryNodes=i,this.timelineDataInternal=PerfUI.FlameChart.FlameChartTimelineData.create({entryLevels:t,entryTotalTimes:r,entryStartTimes:o,groups:null}),this.timelineDataInternal}prepareHighlightedEntryInfo(e){const i=this.entryNodes[e];if(!i)return null;const t=[];function r(e,i){t.push({title:e,value:i})}r(i18nString(UIStrings.name),UI.UIUtils.beautifyFunctionName(i.functionName)),r(i18nString(UIStrings.selfSize),Platform.NumberUtilities.bytesToString(i.self)),r(i18nString(UIStrings.totalSize),Platform.NumberUtilities.bytesToString(i.total));const o=new Components.Linkifier.Linkifier,n=o.maybeLinkifyConsoleCallFrame(this.heapProfilerModel?this.heapProfilerModel.target():null,i.callFrame);return n&&r(i18nString(UIStrings.url),n.textContent),o.dispose(),ProfileView.buildPopoverTable(t)}}