@yuebai008/cli
Version:
Command line interface for rapid qg-minigame development
1 lines • 10.5 kB
JavaScript
import*as Common from"../../core/common/common.js";import*as Helpers from"./helpers/helpers.js";import*as Types from"./types/types.js";export class TracingModel{#e;#t;#s;#n;#a;#r;#o;#i;#d;#l;#c;#h=[];constructor(e){this.#e=e,this.#t=new Map,this.#s=new Map,this.#n=Number(1/0),this.#a=Number(-1/0),this.#r=[],this.#o=[],this.#i=new Map,this.#d=new Map,this.#l=new Map,this.#c=new Map}static isTopLevelEvent(e){return eventHasCategory(e,DevToolsTimelineEventCategory)&&"RunTask"===e.name||eventHasCategory(e,LegacyTopLevelEventCategory)||eventHasCategory(e,DevToolsMetadataEventCategory)&&"Program"===e.name}static extractId(e){const t=e.scope||"";if(void 0===e.id2)return t&&e.id?`${t}@${e.id}`:e.id;const s=e.id2;if("object"==typeof s&&"global"in s!="local"in s)return void 0!==s.global?`:${t}:${s.global}`:`:${t}:${e.pid}:${s.local}`;console.error(`Unexpected id2 field at ${e.ts/1e3}, one and only one of 'local' and 'global' should be present.`)}static browserMainThread(e){const t=e.sortedProcesses();if(!t.length)return null;const s="CrBrowserMain",n=[],a=[];for(const e of t)e.name().toLowerCase().endsWith("browser")&&n.push(e),a.push(...e.sortedThreads().filter((e=>e.name()===s)));if(1===a.length)return a[0];if(1===n.length)return n[0].threadByName(s);const r=e.devToolsMetadataEvents().filter((e=>"TracingStartedInBrowser"===e.name));return 1===r.length?r[0].thread:(Common.Console.Console.instance().error("Failed to find browser main thread in trace, some timeline features may be unavailable"),null)}allRawEvents(){return this.#h}devToolsMetadataEvents(){return this.#r}addEvents(e){for(let t=0;t<e.length;++t)this.addEvent(e[t])}tracingComplete(){this.processPendingAsyncEvents();for(const e of this.#t.values())for(const t of e.threads.values())t.tracingComplete()}addEvent(e){this.#h.push(e);let t=this.#t.get(e.pid);t||(t=new Process(this,e.pid),this.#t.set(e.pid,t));const s=e.ts/1e3;if(s&&s<this.#n&&eventPhasesOfInterestForTraceBounds.has(e.ph)&&!e.name.endsWith("::UMA")&&(this.#n=s),"TracingStartedInBrowser"===e.name&&(this.#n=s),eventPhasesOfInterestForTraceBounds.has(e.ph)){const t=(e.ts+(e.dur||0))/1e3;this.#a=Math.max(this.#a,t)}const n=t.addEvent(e);if(n)if("P"!==e.ph){if(Types.TraceEvents.isAsyncPhase(e.ph)&&this.#o.push(n),n.hasCategory(DevToolsMetadataEventCategory)&&this.#r.push(n),"M"===e.ph)switch(e.name){case MetadataEvent.ProcessSortIndex:t.setSortIndex(e.args.sort_index);break;case MetadataEvent.ProcessName:{const s=e.args.name;t.setName(s),this.#s.set(s,t);break}case MetadataEvent.ThreadSortIndex:t.threadById(e.tid).setSortIndex(e.args.sort_index);break;case MetadataEvent.ThreadName:t.threadById(e.tid).setName(e.args.name)}}else this.addSampleEvent(n)}addSampleEvent(e){const t=`${e.thread.process().id()}:${e.id}`,s=this.#l.get(t);s?s.addChild(e):this.#l.set(t,new ProfileEventsGroup(e))}profileGroup(e){return this.#l.get(`${e.thread.process().id()}:${e.id}`)||null}minimumRecordTime(){return this.#n}maximumRecordTime(){return this.#a}sortedProcesses(){return NamedObject.sort([...this.#t.values()])}getProcessByName(e){return this.#s.get(e)??null}getProcessById(e){return this.#t.get(e)||null}getThreadByName(e,t){const s=this.getProcessByName(e);return s&&s.threadByName(t)}processPendingAsyncEvents(){this.#o.sort(Event.compareStartTime);for(let e=0;e<this.#o.length;++e){const t=this.#o[e];Types.TraceEvents.isNestableAsyncPhase(t.phase)?this.addNestableAsyncEvent(t):this.addAsyncEvent(t)}this.#o=[],this.closeOpenAsyncEvents()}closeOpenAsyncEvents(){for(const e of this.#i.values())e.setEndTime(this.#a),e.steps[0].setEndTime(this.#a);this.#i.clear();for(const e of this.#d.values())for(;e.length;){const t=e.pop();t&&t.setEndTime(this.#a)}this.#d.clear()}addNestableAsyncEvent(e){const t=e.categoriesString+"."+e.id;let s=this.#d.get(t);switch(e.phase){case"b":{s||(s=[],this.#d.set(t,s));const n=new AsyncEvent(e);s.push(n),e.thread.addAsyncEvent(n);break}case"n":if(s&&s.length){const e=s[s.length-1];e&&e.addStep(e)}break;case"e":{if(!s||!s.length)break;const n=s.pop();if(!n)break;if(n.name!==e.name){console.error(`Begin/end event mismatch for nestable async event, ${n.name} vs. ${e.name}, key: ${t}`);break}n.addStep(e)}}}addAsyncEvent(e){const t=e.categoriesString+"."+e.name+"."+e.id;let s=this.#i.get(t);if("S"===e.phase)return s?void console.error(`Event ${e.name} has already been started`):(s=new AsyncEvent(e),this.#i.set(t,s),void e.thread.addAsyncEvent(s));if(s){if("F"===e.phase)return s.addStep(e),void this.#i.delete(t);if("T"===e.phase||"p"===e.phase){const t=s.steps[s.steps.length-1];return t&&"S"!==t.phase&&t.phase!==e.phase?void console.assert(!1,"Async event step phase mismatch: "+t.phase+" at "+t.startTime+" vs. "+e.phase+" at "+e.startTime):void s.addStep(e)}console.assert(!1,"Invalid async event phase")}}title(){return this.#e}parsedCategoriesForString(e){let t=this.#c.get(e);return t||(t=new Set(e?e.split(","):[]),this.#c.set(e,t)),t}}export const eventPhasesOfInterestForTraceBounds=new Set(["B","E","X","I"]);export const MetadataEvent={ProcessSortIndex:"process_sort_index",ProcessName:"process_name",ThreadSortIndex:"thread_sort_index",ThreadName:"thread_name"};export const LegacyTopLevelEventCategory="toplevel";export const DevToolsMetadataEventCategory="disabled-by-default-devtools.timeline";export const DevToolsTimelineEventCategory="disabled-by-default-devtools.timeline";export function eventHasPayload(e){return"rawPayload"in e}export class Event{categoriesString;#c;name;phase;startTime;thread;args;id;ordinal;selfTime;endTime;duration;constructor(e,t,s,n,a){this.categoriesString=e||"",this.#c=a.getModel().parsedCategoriesForString(this.categoriesString),this.name=t,this.phase=s,this.startTime=n,this.thread=a,this.args={},this.ordinal=0,this.selfTime=0}static compareStartTime(e,t){return e&&t?e.startTime-t.startTime:0}static orderedCompareStartTime(e,t){return e.startTime-t.startTime||e.ordinal-t.ordinal||-1}hasCategory(e){return this.#c.has(e)}setEndTime(e){e<this.startTime?console.assert(!1,"Event out of order: "+this.name):(this.endTime=e,this.duration=e-this.startTime)}addArgs(e){for(const t in e)t in this.args&&console.error("Same argument name ("+t+") is used for begin and end phases of "+this.name),this.args[t]=e[t]}complete(e){e.args?this.addArgs(e.args):console.error("Missing mandatory event argument 'args' at "+e.startTime),this.setEndTime(e.startTime)}}export class ConstructedEvent extends Event{constructor(e,t,s,n,a){super(e,t,s,n,a)}}export class PayloadEvent extends Event{#m;rawLegacyPayload(){return this.#m}rawPayload(){return this.#m}constructor(e,t,s,n,a,r){super(e,t,s,n,a),this.#m=r}static fromPayload(e,t){const s=new PayloadEvent(e.cat,e.name,e.ph,e.ts/1e3,t,e);s.#m=e,e.args&&s.addArgs(e.args),"number"==typeof e.dur&&s.setEndTime((e.ts+e.dur)/1e3);const n=TracingModel.extractId(e);return void 0!==n&&(s.id=n),s}}export class ObjectSnapshot extends PayloadEvent{constructor(e,t,s,n,a){super(e,t,"O",s,n,a)}static fromPayload(e,t){const s=new ObjectSnapshot(e.cat,e.name,e.ts/1e3,t,e),n=TracingModel.extractId(e);return void 0!==n&&(s.id=n),e.args&&e.args.snapshot?(e.args&&s.addArgs(e.args),s):(console.error("Missing mandatory 'snapshot' argument at "+e.ts/1e3),s)}getSnapshot(){const e=this.args.snapshot;if(!e)throw new Error("ObjectSnapshot has no snapshot argument.");return e}}export class AsyncEvent extends ConstructedEvent{steps;causedFrame;constructor(e){super(e.categoriesString,e.name,e.phase,e.startTime,e.thread),this.addArgs(e.args),this.steps=[e],this.causedFrame=!1}addStep(e){this.steps.push(e),"F"!==e.phase&&"e"!==e.phase||(this.setEndTime(e.startTime),this.steps[0].setEndTime(e.startTime))}}class ProfileEventsGroup{children;constructor(e){this.children=[e]}addChild(e){this.children.push(e)}}class NamedObject{model;idInternal;#p;#v;constructor(e,t){this.model=e,this.idInternal=t,this.#p="",this.#v=0}static sort(e){return e.sort(((e,t)=>e.#v!==t.#v?e.#v-t.#v:e.name().localeCompare(t.name())))}setName(e){this.#p=e}name(){return this.#p}id(){return this.idInternal}setSortIndex(e){this.#v=e}getModel(){return this.model}}export class Process extends NamedObject{threads;#u;constructor(e,t){super(e,t),this.threads=new Map,this.#u=new Map}threadById(e){let t=this.threads.get(e);return t||(t=new Thread(this,e),this.threads.set(e,t)),t}threadByName(e){return this.#u.get(e)||null}setThreadByName(e,t){this.#u.set(e,t)}addEvent(e){return this.threadById(e.tid).addEvent(e)}sortedThreads(){return NamedObject.sort([...this.threads.values()])}}export class Thread extends NamedObject{#g;#y;#T;#E;constructor(e,t){super(e.getModel(),t),this.#g=e,this.#y=[],this.#T=[],this.#E=null}#I(e,t){return e.phase===t}tracingComplete(){this.#T.sort(Event.compareStartTime),this.#y.sort(Event.compareStartTime);const e=[],t=new Set;for(let s=0;s<this.#y.length;++s){const n=this.#y[s];if(n.ordinal=s,this.#I(n,"E")){if(t.add(s),!e.length)continue;const a=e.pop();if(!a)continue;a.name!==n.name||a.categoriesString!==n.categoriesString?console.error("B/E events mismatch at "+a.startTime+" ("+a.name+") vs. "+n.startTime+" ("+n.name+")"):a.complete(n)}else this.#I(n,"B")&&e.push(n)}for(;e.length;){const t=e.pop();t&&(t.phase="I")}this.#y=this.#y.filter(((e,s)=>!t.has(s)))}addEvent(e){const t="O"===e.ph?ObjectSnapshot.fromPayload(e,this):PayloadEvent.fromPayload(e,this);if(TracingModel.isTopLevelEvent(t)){const e=this.#E;if(e&&(e.endTime||0)>t.startTime)return null;this.#E=t}return this.#y.push(t),t}addAsyncEvent(e){this.#T.push(e)}setName(e){super.setName(e),this.#g.setThreadByName(e,this)}process(){return this.#g}events(){return this.#y}asyncEvents(){return this.#T}removeEventsByName(e){const t=[];return this.#y=this.#y.filter((s=>!!s&&(s.name!==e||(t.push(s),!1)))),t}}export function timesForEventInMilliseconds(e){return e instanceof Event?{startTime:Types.Timing.MilliSeconds(e.startTime),endTime:e.endTime?Types.Timing.MilliSeconds(e.endTime):void 0,duration:Types.Timing.MilliSeconds(e.duration||0),selfTime:Types.Timing.MilliSeconds(e.selfTime)}:Helpers.Timing.eventTimingsMilliSeconds(e)}const parsedCategories=new Map;export function eventHasCategory(e,t){if(e instanceof Event)return e.hasCategory(t);let s=parsedCategories.get(e.cat);return s||(s=new Set(e.cat.split(",")||[])),s.has(t)}export function phaseForEvent(e){return e instanceof Event?e.phase:e.ph}export function threadIDForEvent(e){return e instanceof Event?e.thread.idInternal:e.tid}export function eventIsFromNewEngine(e){return null!==e&&!(e instanceof Event)}