@yuebai008/cli
Version:
Command line interface for rapid qg-minigame development
1 lines • 20.9 kB
JavaScript
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 SDK from"../../core/sdk/sdk.js";import*as TimelineModel from"../../models/timeline_model/timeline_model.js";import*as TraceEngine from"../../models/trace/trace.js";import*as DataGrid from"../../ui/legacy/components/data_grid/data_grid.js";import*as Components from"../../ui/legacy/components/utils/utils.js";import*as UI from"../../ui/legacy/legacy.js";import{TimelineRegExp}from"./TimelineFilters.js";import{TimelineUIUtils}from"./TimelineUIUtils.js";const UIStrings={performance:"Performance",filter:"Filter",selfTime:"Self Time",totalTime:"Total Time",activity:"Activity",selectItemForDetails:"Select item for details.",notOptimizedS:"Not optimized: {PH1}",fms:"{PH1} ms",percentPlaceholder:"{PH1} %",chromeExtensionsOverhead:"[`Chrome` extensions overhead]",vRuntime:"[`V8` Runtime]",unattributed:"[unattributed]",javascript:"JavaScript",page:"Page",noGrouping:"No Grouping",groupByActivity:"Group by Activity",groupByCategory:"Group by Category",groupByDomain:"Group by Domain",groupByFrame:"Group by Frame",groupBySubdomain:"Group by Subdomain",groupByUrl:"Group by URL",groupBy:"Group by",filterCallTree:"Filter call tree",filterBottomup:"Filter bottom-up",heaviestStack:"Heaviest stack",showHeaviestStack:"Show Heaviest stack",hideHeaviestStack:"Hide Heaviest stack",heaviestStackShown:"Heaviest stack sidebar shown",heaviestStackHidden:"Heaviest stack sidebar hidden",timelineStack:"Timeline Stack"},str_=i18n.i18n.registerUIStrings("panels/timeline/TimelineTreeView.ts",UIStrings),i18nString=i18n.i18n.getLocalizedString.bind(void 0,str_);export class TimelineTreeView extends UI.Widget.VBox{modelInternal;#e;searchResults;linkifier;dataGrid;lastHoveredProfileNode;textFilterInternal;taskFilter;startTime;endTime;splitWidget;detailsView;searchableView;currentThreadSetting;lastSelectedNodeInternal;root;currentResult;textFilterUI;#t=null;constructor(){super(),this.modelInternal=null,this.#e=null,this.element.classList.add("timeline-tree-view"),this.searchResults=[]}static eventNameForSorting(e){if(TimelineModel.TimelineModel.TimelineModelImpl.isJsFrameEvent(e)){const t=e.args.data;return t.functionName+"@"+(t.scriptId||t.url||"")}return e.name+":@"+TimelineModel.TimelineProfileTree.eventURL(e)}setSearchableView(e){this.searchableView=e}setModelWithEvents(e,t,i=null){this.modelInternal=e,this.#t=i,this.#e=t,this.refreshTree()}setModel(e,t){this.setModelWithEvents(e,t?.eventsForTreeView()||null)}getToolbarInputAccessiblePlaceHolder(){return""}model(){return this.modelInternal}traceParseData(){return this.#t}init(){this.linkifier=new Components.Linkifier.Linkifier,this.taskFilter=new TimelineModel.TimelineModelFilter.ExclusiveNameFilter([TimelineModel.TimelineModel.RecordType.Task]),this.textFilterInternal=new TimelineRegExp,this.currentThreadSetting=Common.Settings.Settings.instance().createSetting("timelineTreeCurrentThread",0),this.currentThreadSetting.addChangeListener(this.refreshTree,this);const e=[];this.populateColumns(e),this.splitWidget=new UI.SplitWidget.SplitWidget(!0,!0,"timelineTreeViewDetailsSplitWidget");const t=new UI.Widget.VBox,i=new UI.Toolbar.Toolbar("",t.element);i.makeWrappable(!0),this.populateToolbar(i),this.dataGrid=new DataGrid.SortableDataGrid.SortableDataGrid({displayName:i18nString(UIStrings.performance),columns:e,refreshCallback:void 0,editCallback:void 0,deleteCallback:void 0}),this.dataGrid.addEventListener(DataGrid.DataGrid.Events.SortingChanged,this.sortingChanged,this),this.dataGrid.element.addEventListener("mousemove",this.onMouseMove.bind(this),!0),this.dataGrid.setResizeMethod(DataGrid.DataGrid.ResizeMethod.Last),this.dataGrid.setRowContextMenuCallback(this.onContextMenu.bind(this)),this.dataGrid.asWidget().show(t.element),this.dataGrid.addEventListener(DataGrid.DataGrid.Events.SelectedNode,this.updateDetailsForSelection,this),this.detailsView=new UI.Widget.VBox,this.detailsView.element.classList.add("timeline-details-view","timeline-details-view-body"),this.splitWidget.setMainWidget(t),this.splitWidget.setSidebarWidget(this.detailsView),this.splitWidget.hideSidebar(),this.splitWidget.show(this.element),this.splitWidget.addEventListener(UI.SplitWidget.Events.ShowModeChanged,this.onShowModeChanged,this),this.lastSelectedNodeInternal}lastSelectedNode(){return this.lastSelectedNodeInternal}updateContents(e){this.setRange(e.startTime,e.endTime)}setRange(e,t){this.startTime=e,this.endTime=t,this.refreshTree()}filters(){return[this.taskFilter,this.textFilterInternal,...this.modelInternal?this.modelInternal.filters():[]]}filtersWithoutTextFilter(){return[this.taskFilter,...this.modelInternal?this.modelInternal.filters():[]]}textFilter(){return this.textFilterInternal}exposePercentages(){return!1}populateToolbar(e){const t=new UI.Toolbar.ToolbarInput(i18nString(UIStrings.filter),this.getToolbarInputAccessiblePlaceHolder());t.addEventListener(UI.Toolbar.ToolbarInput.Event.TextChanged,(()=>{const e=t.value();this.textFilterInternal.setRegExp(e?Platform.StringUtilities.createPlainTextSearchRegex(e,"i"):null),this.refreshTree()}),this),this.textFilterUI=t,e.appendToolbarItem(t)}modelEvents(){return this.#e||[]}onHover(e){}appendContextMenuItems(e,t){}selectProfileNode(e,t){const i=[];let r=e;for(;r;r=r.parent)i.push(r);for(let e=i.length-1;e>0;--e){const t=this.dataGridNodeForTreeNode(i[e]);t&&t.dataGrid&&t.expand()}const n=this.dataGridNodeForTreeNode(e);n&&n.dataGrid&&(n.reveal(),n.select(t))}refreshTree(){if(this.linkifier.reset(),this.dataGrid.rootNode().removeChildren(),!this.modelInternal)return void this.updateDetailsForSelection();this.root=this.buildTree();const e=this.root.children();let t=0,i=0;const r=this.root.totalTime-this.root.selfTime;for(const r of e.values())t=Math.max(t,r.selfTime),i=Math.max(i,r.totalTime);for(const n of e.values()){const e=new TreeGridNode(n,r,t,i,this);this.dataGrid.insertChild(e)}this.sortingChanged(),this.updateDetailsForSelection(),this.searchableView&&this.searchableView.refreshSearch();const n=this.dataGrid.rootNode();n.children.length>0&&n.children[0].select(!0)}buildTree(){throw new Error("Not Implemented")}buildTopDownTree(e,t){return new TimelineModel.TimelineProfileTree.TopDownRootNode(this.modelEvents(),this.filters(),this.startTime,this.endTime,e,t)}populateColumns(e){e.push({id:"self",title:i18nString(UIStrings.selfTime),width:"120px",fixedWidth:!0,sortable:!0}),e.push({id:"total",title:i18nString(UIStrings.totalTime),width:"120px",fixedWidth:!0,sortable:!0}),e.push({id:"activity",title:i18nString(UIStrings.activity),disclosure:!0,sortable:!0})}sortingChanged(){const e=this.dataGrid.sortColumnId();if(!e)return;let t;switch(e){case"startTime":t=function(e,t){const i=t,r=e.profileNode.event,n=i.profileNode.event;return r.startTime-n.startTime};break;case"self":t=i.bind(null,"selfTime");break;case"total":t=i.bind(null,"totalTime");break;case"activity":t=function(e,t){const i=t,r=e.profileNode.event,n=i.profileNode.event,s=TimelineTreeView.eventNameForSorting(r),o=TimelineTreeView.eventNameForSorting(n);return s.localeCompare(o)};break;default:return void console.assert(!1,"Unknown sort field: "+e)}function i(e,t,i){const r=i;return t.profileNode[e]-r.profileNode[e]}this.dataGrid.sortNodes(t,!this.dataGrid.isSortOrderAscending())}onShowModeChanged(){this.splitWidget.showMode()!==UI.SplitWidget.ShowMode.OnlyMain&&(this.lastSelectedNodeInternal=void 0,this.updateDetailsForSelection())}updateDetailsForSelection(){const e=this.dataGrid.selectedNode?this.dataGrid.selectedNode.profileNode:null;if(e===this.lastSelectedNodeInternal)return;if(this.lastSelectedNodeInternal=e,this.splitWidget.showMode()===UI.SplitWidget.ShowMode.OnlyMain)return;if(this.detailsView.detachChildWidgets(),this.detailsView.element.removeChildren(),e&&this.showDetailsForNode(e))return;const t=this.detailsView.element.createChild("div","full-widget-dimmed-banner");UI.UIUtils.createTextChild(t,i18nString(UIStrings.selectItemForDetails))}showDetailsForNode(e){return!1}onMouseMove(e){const t=e.target&&e.target instanceof Node?this.dataGrid.dataGridNodeFromNode(e.target):null,i=t&&t._profileNode;i!==this.lastHoveredProfileNode&&(this.lastHoveredProfileNode=i,this.onHover(i))}onContextMenu(e,t){const i=t;i.linkElement&&!e.containsTarget(i.linkElement)&&e.appendApplicableItems(i.linkElement);const r=i.profileNode;r&&this.appendContextMenuItems(e,r)}dataGridNodeForTreeNode(e){return profileNodeToTreeGridNode.get(e)||null}onSearchCanceled(){this.searchResults=[],this.currentResult=0}performSearch(e,t,i){if(this.searchResults=[],this.currentResult=0,!this.root)return;const r=e.toSearchRegex();this.searchResults=this.root.searchTree((e=>TimelineUIUtils.testContentMatching(e,r.regex))),this.searchableView.updateSearchMatchesCount(this.searchResults.length)}jumpToNextSearchResult(){this.searchResults.length&&void 0!==this.currentResult&&(this.selectProfileNode(this.searchResults[this.currentResult],!1),this.currentResult=Platform.NumberUtilities.mod(this.currentResult+1,this.searchResults.length))}jumpToPreviousSearchResult(){this.searchResults.length&&void 0!==this.currentResult&&(this.selectProfileNode(this.searchResults[this.currentResult],!1),this.currentResult=Platform.NumberUtilities.mod(this.currentResult-1,this.searchResults.length))}supportsCaseSensitiveSearch(){return!0}supportsRegexSearch(){return!0}}export class GridNode extends DataGrid.SortableDataGrid.SortableDataGridNode{populated;profileNode;treeView;grandTotalTime;maxSelfTime;maxTotalTime;linkElement;constructor(e,t,i,r,n){super(null,!1),this.populated=!1,this.profileNode=e,this.treeView=n,this.grandTotalTime=t,this.maxSelfTime=i,this.maxTotalTime=r,this.linkElement=null}createCell(e){return"activity"===e?this.createNameCell(e):this.createValueCell(e)||super.createCell(e)}createNameCell(e){const t=this.createTD(e),i=t.createChild("div","name-container"),r=i.createChild("div","activity-icon-container"),n=r.createChild("div","activity-icon"),s=i.createChild("div","activity-name"),o=this.profileNode.event;if(this.profileNode.isGroupNode()){const e=this.treeView.displayInfoForGroupNode(this.profileNode);s.textContent=e.name,n.style.backgroundColor=e.color,e.icon&&r.insertBefore(e.icon,n)}else if(o){const e=o.args.data,t=e&&e.deoptReason;t&&(i.createChild("div","activity-warning").title=i18nString(UIStrings.notOptimizedS,{PH1:t})),s.textContent=TimelineUIUtils.eventTitle(o);const r=this.treeView.modelInternal?.timelineModel().targetByEvent(o)||null,a=this.treeView.linkifier,l=Boolean(this.treeView.modelInternal?.timelineModel().isFreshRecording());this.linkElement=TimelineUIUtils.linkifyTopCallFrame(o,r,a,l),this.linkElement&&i.createChild("div","activity-link").appendChild(this.linkElement);const d=TimelineUIUtils.eventStyle(o).category;UI.ARIAUtils.setLabel(n,d.title),n.style.backgroundColor=d.color}return t}createValueCell(e){if("self"!==e&&"total"!==e&&"startTime"!==e)return null;let t,i,r,n=!1;switch(e){case"startTime":{r=this.profileNode.event;const e=this.treeView.model();if(!e)throw new Error("Unable to find model for tree view");const i=r&&TraceEngine.Legacy.timesForEventInMilliseconds(r);t=(i?.startTime??0)-e.timelineModel().minimumRecordTime()}break;case"self":t=this.profileNode.selfTime,i=this.maxSelfTime,n=!0;break;case"total":t=this.profileNode.totalTime,i=this.maxTotalTime,n=!0;break;default:return null}const s=this.createTD(e);s.className="numeric-column",s.setAttribute("title",i18nString(UIStrings.fms,{PH1:t.toFixed(4)}));const o=s.createChild("div");return o.createChild("span").textContent=i18nString(UIStrings.fms,{PH1:t.toFixed(1)}),n&&this.treeView.exposePercentages()&&(o.createChild("span","percent-column").textContent=i18nString(UIStrings.percentPlaceholder,{PH1:(t/this.grandTotalTime*100).toFixed(1)})),i&&(o.classList.add("background-percent-bar"),s.createChild("div","background-bar-container").createChild("div","background-bar").style.width=(100*t/i).toFixed(1)+"%"),s}}export class TreeGridNode extends GridNode{constructor(e,t,i,r,n){super(e,t,i,r,n),this.setHasChildren(this.profileNode.hasChildren()),profileNodeToTreeGridNode.set(e,this)}populate(){if(!this.populated&&(this.populated=!0,this.profileNode.children))for(const e of this.profileNode.children().values()){const t=new TreeGridNode(e,this.grandTotalTime,this.maxSelfTime,this.maxTotalTime,this.treeView);this.insertChildOrdered(t)}}}const profileNodeToTreeGridNode=new WeakMap;export class AggregatedTimelineTreeView extends TimelineTreeView{groupBySetting;stackView;executionContextNamesByOrigin=new Map;constructor(){super(),this.groupBySetting=Common.Settings.Settings.instance().createSetting("timelineTreeGroupBy",AggregatedTimelineTreeView.GroupBy.None),this.groupBySetting.addChangeListener(this.refreshTree.bind(this)),this.init(),this.stackView=new TimelineStackView(this),this.stackView.addEventListener(TimelineStackView.Events.SelectionChanged,this.onStackViewSelectionChanged,this)}setGroupBySettingForTests(e){this.groupBySetting.set(e)}setModelWithEvents(e,t,i=null){super.setModelWithEvents(e,t,i)}setModel(e,t){super.setModel(e,t)}updateContents(e){this.updateExtensionResolver(),super.updateContents(e);const t=this.dataGrid.rootNode();t.children.length&&t.children[0].select(!0)}updateExtensionResolver(){this.executionContextNamesByOrigin=new Map;for(const e of SDK.TargetManager.TargetManager.instance().models(SDK.RuntimeModel.RuntimeModel))for(const t of e.executionContexts())this.executionContextNamesByOrigin.set(t.origin,t.name)}beautifyDomainName(e){return AggregatedTimelineTreeView.isExtensionInternalURL(e)?e=i18nString(UIStrings.chromeExtensionsOverhead):AggregatedTimelineTreeView.isV8NativeURL(e)?e=i18nString(UIStrings.vRuntime):e.startsWith("chrome-extension")&&(e=this.executionContextNamesByOrigin.get(e)||e),e}displayInfoForGroupNode(e){const t=TimelineUIUtils.categories(),i=e.id?TimelineUIUtils.eventColor(e.event):t.other.color,r=i18nString(UIStrings.unattributed),n="symbol"==typeof e.id?void 0:e.id;switch(this.groupBySetting.get()){case AggregatedTimelineTreeView.GroupBy.Category:{const e=n?t[n]||t.other:{title:r,color:r};return{name:e.title,color:e.color,icon:void 0}}case AggregatedTimelineTreeView.GroupBy.Domain:case AggregatedTimelineTreeView.GroupBy.Subdomain:return{name:(n?this.beautifyDomainName(n):void 0)||r,color:i,icon:void 0};case AggregatedTimelineTreeView.GroupBy.EventName:if(!e.event)throw new Error("Unable to find event for group by operation");return{name:TimelineModel.TimelineModel.TimelineModelImpl.isJsFrameEvent(e.event)?i18nString(UIStrings.javascript):TimelineUIUtils.eventTitle(e.event),color:TimelineModel.TimelineModel.TimelineModelImpl.isJsFrameEvent(e.event)?TimelineUIUtils.eventStyle(e.event).category.color:i,icon:void 0};case AggregatedTimelineTreeView.GroupBy.URL:break;case AggregatedTimelineTreeView.GroupBy.Frame:{if(!this.modelInternal)throw new Error("Unable to find model for group by frame operation");const e=n?this.modelInternal.timelineModel().pageFrameById(n):void 0;return{name:e?TimelineUIUtils.displayNameForFrame(e,80):i18nString(UIStrings.page),color:i,icon:void 0}}default:console.assert(!1,"Unexpected grouping type")}return{name:n||r,color:i,icon:void 0}}populateToolbar(e){super.populateToolbar(e);const t=AggregatedTimelineTreeView.GroupBy,i=[{label:i18nString(UIStrings.noGrouping),value:t.None},{label:i18nString(UIStrings.groupByActivity),value:t.EventName},{label:i18nString(UIStrings.groupByCategory),value:t.Category},{label:i18nString(UIStrings.groupByDomain),value:t.Domain},{label:i18nString(UIStrings.groupByFrame),value:t.Frame},{label:i18nString(UIStrings.groupBySubdomain),value:t.Subdomain},{label:i18nString(UIStrings.groupByUrl),value:t.URL}];e.appendToolbarItem(new UI.Toolbar.ToolbarSettingComboBox(i,this.groupBySetting,i18nString(UIStrings.groupBy))),e.appendSpacer(),e.appendToolbarItem(this.splitWidget.createShowHideSidebarButton(i18nString(UIStrings.showHeaviestStack),i18nString(UIStrings.hideHeaviestStack),i18nString(UIStrings.heaviestStackShown),i18nString(UIStrings.heaviestStackHidden)))}buildHeaviestStack(e){console.assert(Boolean(e.parent),"Attempt to build stack for tree root");let t=[];for(let i=e;i&&i.parent;i=i.parent)t.push(i);t=t.reverse();for(let i=e;i&&i.children()&&i.children().size;){const e=Array.from(i.children().values());i=e.reduce(((e,t)=>e.totalTime>t.totalTime?e:t)),t.push(i)}return t}exposePercentages(){return!0}onStackViewSelectionChanged(){const e=this.stackView.selectedTreeNode();e&&this.selectProfileNode(e,!0)}showDetailsForNode(e){const t=this.buildHeaviestStack(e);return this.stackView.setStack(t,e),this.stackView.show(this.detailsView.element),!0}groupingFunction(e){const t=AggregatedTimelineTreeView.GroupBy;switch(e){case t.None:return null;case t.EventName:return e=>TimelineUIUtils.eventStyle(e).title;case t.Category:return e=>TimelineUIUtils.eventStyle(e).category.name;case t.Subdomain:return this.domainByEvent.bind(this,!1);case t.Domain:return this.domainByEvent.bind(this,!0);case t.URL:return e=>TimelineModel.TimelineProfileTree.eventURL(e)||"";case t.Frame:return e=>TimelineModel.TimelineModel.EventOnTimelineData.forEvent(e).frameId||"";default:return console.assert(!1,`Unexpected aggregation setting: ${e}`),null}}domainByEvent(e,t){const i=TimelineModel.TimelineProfileTree.eventURL(t);if(!i)return"";if(AggregatedTimelineTreeView.isExtensionInternalURL(i))return AggregatedTimelineTreeView.extensionInternalPrefix;if(AggregatedTimelineTreeView.isV8NativeURL(i))return AggregatedTimelineTreeView.v8NativePrefix;const r=Common.ParsedURL.ParsedURL.fromString(i);if(!r)return"";if("chrome-extension"===r.scheme)return r.scheme+"://"+r.host;if(!e)return r.host;if(/^[.0-9]+$/.test(r.host))return r.host;const n=/([^.]*\.)?[^.]*$/.exec(r.host);return n&&n[0]||""}appendContextMenuItems(e,t){if(this.groupBySetting.get()!==AggregatedTimelineTreeView.GroupBy.Frame)return;if(!t.isGroupNode())return;if(!this.modelInternal)return;const i=this.modelInternal.timelineModel().pageFrameById(t.id);i&&i.ownerNode&&e.appendApplicableItems(i.ownerNode)}static isExtensionInternalURL(e){return e.startsWith(AggregatedTimelineTreeView.extensionInternalPrefix)}static isV8NativeURL(e){return e.startsWith(AggregatedTimelineTreeView.v8NativePrefix)}static extensionInternalPrefix="extensions::";static v8NativePrefix="native "}!function(e){let t;!function(e){e.None="None",e.EventName="EventName",e.Category="Category",e.Domain="Domain",e.Subdomain="Subdomain",e.URL="URL",e.Frame="Frame"}(t=e.GroupBy||(e.GroupBy={}))}(AggregatedTimelineTreeView||(AggregatedTimelineTreeView={}));export class CallTreeTimelineTreeView extends AggregatedTimelineTreeView{constructor(){super(),this.dataGrid.markColumnAsSortedBy("total",DataGrid.DataGrid.Order.Descending)}getToolbarInputAccessiblePlaceHolder(){return i18nString(UIStrings.filterCallTree)}buildTree(){const e=this.groupBySetting.get();return this.buildTopDownTree(!1,this.groupingFunction(e))}}export class BottomUpTimelineTreeView extends AggregatedTimelineTreeView{constructor(){super(),this.dataGrid.markColumnAsSortedBy("self",DataGrid.DataGrid.Order.Descending)}getToolbarInputAccessiblePlaceHolder(){return i18nString(UIStrings.filterBottomup)}buildTree(){return new TimelineModel.TimelineProfileTree.BottomUpRootNode(this.modelEvents(),this.textFilter(),this.filtersWithoutTextFilter(),this.startTime,this.endTime,this.groupingFunction(this.groupBySetting.get()))}}export class TimelineStackView extends(Common.ObjectWrapper.eventMixin(UI.Widget.VBox)){treeView;dataGrid;constructor(e){super();this.element.createChild("div","timeline-stack-view-header").textContent=i18nString(UIStrings.heaviestStack),this.treeView=e;const t=[{id:"total",title:i18nString(UIStrings.totalTime),fixedWidth:!0,width:"110px"},{id:"activity",title:i18nString(UIStrings.activity)}];this.dataGrid=new DataGrid.ViewportDataGrid.ViewportDataGrid({displayName:i18nString(UIStrings.timelineStack),columns:t,deleteCallback:void 0,editCallback:void 0,refreshCallback:void 0}),this.dataGrid.setResizeMethod(DataGrid.DataGrid.ResizeMethod.Last),this.dataGrid.addEventListener(DataGrid.DataGrid.Events.SelectedNode,this.onSelectionChanged,this),this.dataGrid.asWidget().show(this.element)}setStack(e,t){const i=this.dataGrid.rootNode();i.removeChildren();let r=null;const n=Math.max.apply(Math,e.map((e=>e.totalTime)));for(const s of e){const e=new GridNode(s,n,n,n,this.treeView);i.appendChild(e),s===t&&(r=e)}r&&r.revealAndSelect()}selectedTreeNode(){const e=this.dataGrid.selectedNode;return e&&e.profileNode}onSelectionChanged(){this.dispatchEventToListeners(TimelineStackView.Events.SelectionChanged)}}!function(e){let t;!function(e){e.SelectionChanged="SelectionChanged"}(t=e.Events||(e.Events={}))}(TimelineStackView||(TimelineStackView={}));