TimelineModel.js 47 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261
  1. export class TimelineModelImpl{constructor(){this._reset();}
  2. static forEachEvent(events,onStartEvent,onEndEvent,onInstantEvent,startTime,endTime,filter){startTime=startTime||0;endTime=endTime||Infinity;const stack=[];const startEvent=TimelineModelImpl._topLevelEventEndingAfter(events,startTime);for(let i=startEvent;i<events.length;++i){const e=events[i];if((e.endTime||e.startTime)<startTime){continue;}
  3. if(e.startTime>=endTime){break;}
  4. if(SDK.TracingModel.isAsyncPhase(e.phase)||SDK.TracingModel.isFlowPhase(e.phase)){continue;}
  5. while(stack.length&&stack.peekLast().endTime<=e.startTime){onEndEvent(stack.pop());}
  6. if(filter&&!filter(e)){continue;}
  7. if(e.duration){onStartEvent(e);stack.push(e);}else{onInstantEvent&&onInstantEvent(e,stack.peekLast()||null);}}
  8. while(stack.length){onEndEvent(stack.pop());}}
  9. static _topLevelEventEndingAfter(events,time){let index=events.upperBound(time,(time,event)=>time-event.startTime)-1;while(index>0&&!SDK.TracingModel.isTopLevelEvent(events[index])){index--;}
  10. return Math.max(index,0);}
  11. isMarkerEvent(event){const recordTypes=RecordType;switch(event.name){case recordTypes.TimeStamp:return true;case recordTypes.MarkFirstPaint:case recordTypes.MarkFCP:case recordTypes.MarkFMP:return this._mainFrame&&event.args.frame===this._mainFrame.frameId&&!!event.args.data;case recordTypes.MarkDOMContent:case recordTypes.MarkLoad:case recordTypes.MarkLCPCandidate:case recordTypes.MarkLCPInvalidate:return!!event.args['data']['isMainFrame'];default:return false;}}
  12. isLCPCandidateEvent(event){return event.name===RecordType.MarkLCPCandidate&&!!event.args['data']['isMainFrame'];}
  13. isLCPInvalidateEvent(event){return event.name===RecordType.MarkLCPInvalidate&&!!event.args['data']['isMainFrame'];}
  14. static globalEventId(event,field){const data=event.args['data']||event.args['beginData'];const id=data&&data[field];if(!id){return'';}
  15. return`${event.thread.process().id()}.${id}`;}
  16. static eventFrameId(event){const data=event.args['data']||event.args['beginData'];return data&&data['frame']||'';}
  17. cpuProfiles(){return this._cpuProfiles;}
  18. targetByEvent(event){const workerId=this._workerIdByThread.get(event.thread);const mainTarget=SDK.targetManager.mainTarget();return workerId?SDK.targetManager.targetById(workerId):mainTarget;}
  19. setEvents(tracingModel){this._reset();this._resetProcessingState();this._tracingModel=tracingModel;this._minimumRecordTime=tracingModel.minimumRecordTime();this._maximumRecordTime=tracingModel.maximumRecordTime();this._processSyncBrowserEvents(tracingModel);if(this._browserFrameTracking){this._processThreadsForBrowserFrames(tracingModel);}else{const metadataEvents=this._processMetadataEvents(tracingModel);this._isGenericTrace=!metadataEvents;if(metadataEvents){this._processMetadataAndThreads(tracingModel,metadataEvents);}else{this._processGenericTrace(tracingModel);}}
  20. this._inspectedTargetEvents.sort(SDK.TracingModel.Event.compareStartTime);this._processAsyncBrowserEvents(tracingModel);this._buildGPUEvents(tracingModel);this._resetProcessingState();}
  21. _processGenericTrace(tracingModel){let browserMainThread=SDK.TracingModel.browserMainThread(tracingModel);if(!browserMainThread&&tracingModel.sortedProcesses().length){browserMainThread=tracingModel.sortedProcesses()[0].sortedThreads()[0];}
  22. for(const process of tracingModel.sortedProcesses()){for(const thread of process.sortedThreads()){this._processThreadEvents(tracingModel,[{from:0,to:Infinity}],thread,thread===browserMainThread,false,true,null);}}}
  23. _processMetadataAndThreads(tracingModel,metadataEvents){let startTime=0;for(let i=0,length=metadataEvents.page.length;i<length;i++){const metaEvent=metadataEvents.page[i];const process=metaEvent.thread.process();const endTime=i+1<length?metadataEvents.page[i+1].startTime:Infinity;if(startTime===endTime){continue;}
  24. this._legacyCurrentPage=metaEvent.args['data']&&metaEvent.args['data']['page'];for(const thread of process.sortedThreads()){let workerUrl=null;if(thread.name()===TimelineModelImpl.WorkerThreadName||thread.name()===TimelineModelImpl.WorkerThreadNameLegacy){const workerMetaEvent=metadataEvents.workers.find(e=>{if(e.args['data']['workerThreadId']!==thread.id()){return false;}
  25. if(e.args['data']['sessionId']===this._sessionId){return true;}
  26. return!!this._pageFrames.get(TimelineModelImpl.eventFrameId(e));});if(!workerMetaEvent){continue;}
  27. const workerId=workerMetaEvent.args['data']['workerId'];if(workerId){this._workerIdByThread.set(thread,workerId);}
  28. workerUrl=workerMetaEvent.args['data']['url']||'';}
  29. this._processThreadEvents(tracingModel,[{from:startTime,to:endTime}],thread,thread===metaEvent.thread,!!workerUrl,true,workerUrl);}
  30. startTime=endTime;}}
  31. _processThreadsForBrowserFrames(tracingModel){const processData=new Map();for(const frame of this._pageFrames.values()){for(let i=0;i<frame.processes.length;i++){const pid=frame.processes[i].processId;let data=processData.get(pid);if(!data){data=[];processData.set(pid,data);}
  32. const to=i===frame.processes.length-1?(frame.deletedTime||Infinity):frame.processes[i+1].time;data.push({from:frame.processes[i].time,to:to,main:!frame.parent,url:frame.processes[i].url});}}
  33. const allMetadataEvents=tracingModel.devToolsMetadataEvents();for(const process of tracingModel.sortedProcesses()){const data=processData.get(process.id());if(!data){continue;}
  34. data.sort((a,b)=>a.from-b.from||a.to-b.to);const ranges=[];let lastUrl=null;let lastMainUrl=null;let hasMain=false;for(const item of data){if(!ranges.length||item.from>ranges.peekLast().to){ranges.push({from:item.from,to:item.to});}else{ranges.peekLast().to=item.to;}
  35. if(item.main){hasMain=true;}
  36. if(item.url){if(item.main){lastMainUrl=item.url;}
  37. lastUrl=item.url;}}
  38. for(const thread of process.sortedThreads()){if(thread.name()===TimelineModelImpl.RendererMainThreadName){this._processThreadEvents(tracingModel,ranges,thread,true,false,hasMain,hasMain?lastMainUrl:lastUrl);}else if(thread.name()===TimelineModelImpl.WorkerThreadName||thread.name()===TimelineModelImpl.WorkerThreadNameLegacy){const workerMetaEvent=allMetadataEvents.find(e=>{if(e.name!==TimelineModelImpl.DevToolsMetadataEvent.TracingSessionIdForWorker){return false;}
  39. if(e.thread.process()!==process){return false;}
  40. if(e.args['data']['workerThreadId']!==thread.id()){return false;}
  41. return!!this._pageFrames.get(TimelineModelImpl.eventFrameId(e));});if(!workerMetaEvent){continue;}
  42. this._workerIdByThread.set(thread,workerMetaEvent.args['data']['workerId']||'');this._processThreadEvents(tracingModel,ranges,thread,false,true,false,workerMetaEvent.args['data']['url']||'');}else{this._processThreadEvents(tracingModel,ranges,thread,false,false,false,null);}}}}
  43. _processMetadataEvents(tracingModel){const metadataEvents=tracingModel.devToolsMetadataEvents();const pageDevToolsMetadataEvents=[];const workersDevToolsMetadataEvents=[];for(const event of metadataEvents){if(event.name===TimelineModelImpl.DevToolsMetadataEvent.TracingStartedInPage){pageDevToolsMetadataEvents.push(event);if(event.args['data']&&event.args['data']['persistentIds']){this._persistentIds=true;}
  44. const frames=((event.args['data']&&event.args['data']['frames'])||[]);frames.forEach(payload=>this._addPageFrame(event,payload));this._mainFrame=this.rootFrames()[0];}else if(event.name===TimelineModelImpl.DevToolsMetadataEvent.TracingSessionIdForWorker){workersDevToolsMetadataEvents.push(event);}else if(event.name===TimelineModelImpl.DevToolsMetadataEvent.TracingStartedInBrowser){console.assert(!this._mainFrameNodeId,'Multiple sessions in trace');this._mainFrameNodeId=event.args['frameTreeNodeId'];}}
  45. if(!pageDevToolsMetadataEvents.length){return null;}
  46. const sessionId=pageDevToolsMetadataEvents[0].args['sessionId']||pageDevToolsMetadataEvents[0].args['data']['sessionId'];this._sessionId=sessionId;const mismatchingIds=new Set();function checkSessionId(event){let args=event.args;if(args['data']){args=args['data'];}
  47. const id=args['sessionId'];if(id===sessionId){return true;}
  48. mismatchingIds.add(id);return false;}
  49. const result={page:pageDevToolsMetadataEvents.filter(checkSessionId).sort(SDK.TracingModel.Event.compareStartTime),workers:workersDevToolsMetadataEvents.sort(SDK.TracingModel.Event.compareStartTime)};if(mismatchingIds.size){Common.console.error('Timeline recording was started in more than one page simultaneously. Session id mismatch: '+
  50. this._sessionId+' and '+mismatchingIds.valuesArray()+'.');}
  51. return result;}
  52. _processSyncBrowserEvents(tracingModel){const browserMain=SDK.TracingModel.browserMainThread(tracingModel);if(browserMain){browserMain.events().forEach(this._processBrowserEvent,this);}}
  53. _processAsyncBrowserEvents(tracingModel){const browserMain=SDK.TracingModel.browserMainThread(tracingModel);if(browserMain){this._processAsyncEvents(browserMain,[{from:0,to:Infinity}]);}}
  54. _buildGPUEvents(tracingModel){const thread=tracingModel.threadByName('GPU Process','CrGpuMain');if(!thread){return;}
  55. const gpuEventName=RecordType.GPUTask;const track=this._ensureNamedTrack(TrackType.GPU);track.thread=thread;track.events=thread.events().filter(event=>event.name===gpuEventName);}
  56. _resetProcessingState(){this._asyncEventTracker=new TimelineAsyncEventTracker();this._invalidationTracker=new InvalidationTracker();this._layoutInvalidate={};this._lastScheduleStyleRecalculation={};this._paintImageEventByPixelRefId={};this._lastPaintForLayer={};this._lastRecalculateStylesEvent=null;this._currentScriptEvent=null;this._eventStack=[];this._knownInputEvents=new Set();this._browserFrameTracking=false;this._persistentIds=false;this._legacyCurrentPage=null;}
  57. _extractCpuProfile(tracingModel,thread){const events=thread.events();let cpuProfile;let target=null;let cpuProfileEvent=events.peekLast();if(cpuProfileEvent&&cpuProfileEvent.name===RecordType.CpuProfile){const eventData=cpuProfileEvent.args['data'];cpuProfile=(eventData&&eventData['cpuProfile']);target=this.targetByEvent(cpuProfileEvent);}
  58. if(!cpuProfile){cpuProfileEvent=events.find(e=>e.name===RecordType.Profile);if(!cpuProfileEvent){return null;}
  59. target=this.targetByEvent(cpuProfileEvent);const profileGroup=tracingModel.profileGroup(cpuProfileEvent);if(!profileGroup){Common.console.error('Invalid CPU profile format.');return null;}
  60. cpuProfile=({startTime:cpuProfileEvent.args['data']['startTime'],endTime:0,nodes:[],samples:[],timeDeltas:[],lines:[]});for(const profileEvent of profileGroup.children){const eventData=profileEvent.args['data'];if('startTime'in eventData){cpuProfile.startTime=eventData['startTime'];}
  61. if('endTime'in eventData){cpuProfile.endTime=eventData['endTime'];}
  62. const nodesAndSamples=eventData['cpuProfile']||{};const samples=nodesAndSamples['samples']||[];const lines=eventData['lines']||Array(samples.length).fill(0);cpuProfile.nodes.pushAll(nodesAndSamples['nodes']||[]);cpuProfile.lines.pushAll(lines);cpuProfile.samples.pushAll(samples);cpuProfile.timeDeltas.pushAll(eventData['timeDeltas']||[]);if(cpuProfile.samples.length!==cpuProfile.timeDeltas.length){Common.console.error('Failed to parse CPU profile.');return null;}}
  63. if(!cpuProfile.endTime){cpuProfile.endTime=cpuProfile.timeDeltas.reduce((x,y)=>x+y,cpuProfile.startTime);}}
  64. try{const jsProfileModel=new SDK.CPUProfileDataModel(cpuProfile,target);this._cpuProfiles.push(jsProfileModel);return jsProfileModel;}catch(e){Common.console.error('Failed to parse CPU profile.');}
  65. return null;}
  66. _injectJSFrameEvents(tracingModel,thread){const jsProfileModel=this._extractCpuProfile(tracingModel,thread);let events=thread.events();const jsSamples=jsProfileModel?TimelineModel.TimelineJSProfileProcessor.generateTracingEventsFromCpuProfile(jsProfileModel,thread):null;if(jsSamples&&jsSamples.length){events=events.mergeOrdered(jsSamples,SDK.TracingModel.Event.orderedCompareStartTime);}
  67. if(jsSamples||events.some(e=>e.name===RecordType.JSSample)){const jsFrameEvents=TimelineModel.TimelineJSProfileProcessor.generateJSFrameEvents(events);if(jsFrameEvents&&jsFrameEvents.length){events=jsFrameEvents.mergeOrdered(events,SDK.TracingModel.Event.orderedCompareStartTime);}}
  68. return events;}
  69. _processThreadEvents(tracingModel,ranges,thread,isMainThread,isWorker,forMainFrame,url){const track=new Track();track.name=thread.name()||ls`Thread ${thread.id()}`;track.type=TrackType.Other;track.thread=thread;if(isMainThread){track.type=TrackType.MainThread;track.url=url||null;track.forMainFrame=forMainFrame;}else if(isWorker){track.type=TrackType.Worker;track.url=url;}else if(thread.name().startsWith('CompositorTileWorker')){track.type=TrackType.Raster;}
  70. this._tracks.push(track);const events=this._injectJSFrameEvents(tracingModel,thread);this._eventStack=[];const eventStack=this._eventStack;for(const range of ranges){let i=events.lowerBound(range.from,(time,event)=>time-event.startTime);for(;i<events.length;i++){const event=events[i];if(event.startTime>=range.to){break;}
  71. while(eventStack.length&&eventStack.peekLast().endTime<=event.startTime){eventStack.pop();}
  72. if(!this._processEvent(event)){continue;}
  73. if(!SDK.TracingModel.isAsyncPhase(event.phase)&&event.duration){if(eventStack.length){const parent=eventStack.peekLast();parent.selfTime-=event.duration;if(parent.selfTime<0){this._fixNegativeDuration(parent,event);}}
  74. event.selfTime=event.duration;if(!eventStack.length){track.tasks.push(event);}
  75. eventStack.push(event);}
  76. if(this.isMarkerEvent(event)){this._timeMarkerEvents.push(event);}
  77. track.events.push(event);this._inspectedTargetEvents.push(event);}}
  78. this._processAsyncEvents(thread,ranges);}
  79. _fixNegativeDuration(event,child){const epsilon=1e-3;if(event.selfTime<-epsilon){console.error(`Children are longer than parent at ${event.startTime} `+`(${(child.startTime - this.minimumRecordTime()).toFixed(3)} by ${(-event.selfTime).toFixed(3)}`);}
  80. event.selfTime=0;}
  81. _processAsyncEvents(thread,ranges){const asyncEvents=thread.asyncEvents();const groups=new Map();function group(type){if(!groups.has(type)){groups.set(type,[]);}
  82. return groups.get(type);}
  83. for(const range of ranges){let i=asyncEvents.lowerBound(range.from,function(time,asyncEvent){return time-asyncEvent.startTime;});for(;i<asyncEvents.length;++i){const asyncEvent=asyncEvents[i];if(asyncEvent.startTime>=range.to){break;}
  84. if(asyncEvent.hasCategory(TimelineModelImpl.Category.Console)){group(TrackType.Console).push(asyncEvent);continue;}
  85. if(asyncEvent.hasCategory(TimelineModelImpl.Category.UserTiming)){group(TrackType.Timings).push(asyncEvent);continue;}
  86. if(asyncEvent.name===RecordType.Animation){group(TrackType.Animation).push(asyncEvent);continue;}
  87. if(asyncEvent.hasCategory(TimelineModelImpl.Category.LatencyInfo)||asyncEvent.name===RecordType.ImplSideFling){const lastStep=asyncEvent.steps.peekLast();if(lastStep.phase!==SDK.TracingModel.Phase.AsyncEnd){continue;}
  88. const data=lastStep.args['data'];asyncEvent.causedFrame=!!(data&&data['INPUT_EVENT_LATENCY_RENDERER_SWAP_COMPONENT']);if(asyncEvent.hasCategory(TimelineModelImpl.Category.LatencyInfo)){if(!this._knownInputEvents.has(lastStep.id)){continue;}
  89. if(asyncEvent.name===RecordType.InputLatencyMouseMove&&!asyncEvent.causedFrame){continue;}
  90. if(data['is_coalesced']){continue;}
  91. const rendererMain=data['INPUT_EVENT_LATENCY_RENDERER_MAIN_COMPONENT'];if(rendererMain){const time=rendererMain['time']/1000;TimelineData.forEvent(asyncEvent.steps[0]).timeWaitingForMainThread=time-asyncEvent.steps[0].startTime;}}
  92. group(TrackType.Input).push(asyncEvent);continue;}}}
  93. for(const[type,events]of groups){const track=this._ensureNamedTrack(type);track.thread=thread;track.asyncEvents=track.asyncEvents.mergeOrdered(events,SDK.TracingModel.Event.compareStartTime);}}
  94. _processEvent(event){const recordTypes=RecordType;const eventStack=this._eventStack;if(!eventStack.length){if(this._currentTaskLayoutAndRecalcEvents&&this._currentTaskLayoutAndRecalcEvents.length){const totalTime=this._currentTaskLayoutAndRecalcEvents.reduce((time,event)=>time+event.duration,0);if(totalTime>TimelineModelImpl.Thresholds.ForcedLayout){for(const e of this._currentTaskLayoutAndRecalcEvents){const timelineData=TimelineData.forEvent(e);timelineData.warning=e.name===recordTypes.Layout?TimelineModelImpl.WarningType.ForcedLayout:TimelineModelImpl.WarningType.ForcedStyle;}}}
  95. this._currentTaskLayoutAndRecalcEvents=[];}
  96. if(this._currentScriptEvent&&event.startTime>this._currentScriptEvent.endTime){this._currentScriptEvent=null;}
  97. const eventData=event.args['data']||event.args['beginData']||{};const timelineData=TimelineData.forEvent(event);if(eventData['stackTrace']){timelineData.stackTrace=eventData['stackTrace'];}
  98. if(timelineData.stackTrace&&event.name!==recordTypes.JSSample){for(let i=0;i<timelineData.stackTrace.length;++i){--timelineData.stackTrace[i].lineNumber;--timelineData.stackTrace[i].columnNumber;}}
  99. let pageFrameId=TimelineModelImpl.eventFrameId(event);if(!pageFrameId&&eventStack.length){pageFrameId=TimelineData.forEvent(eventStack.peekLast()).frameId;}
  100. timelineData.frameId=pageFrameId||(this._mainFrame&&this._mainFrame.frameId)||'';this._asyncEventTracker.processEvent(event);if(this.isMarkerEvent(event)){this._ensureNamedTrack(TrackType.Timings);}
  101. switch(event.name){case recordTypes.ResourceSendRequest:case recordTypes.WebSocketCreate:timelineData.setInitiator(eventStack.peekLast()||null);timelineData.url=eventData['url'];break;case recordTypes.ScheduleStyleRecalculation:this._lastScheduleStyleRecalculation[eventData['frame']]=event;break;case recordTypes.UpdateLayoutTree:case recordTypes.RecalculateStyles:this._invalidationTracker.didRecalcStyle(event);if(event.args['beginData']){timelineData.setInitiator(this._lastScheduleStyleRecalculation[event.args['beginData']['frame']]);}
  102. this._lastRecalculateStylesEvent=event;if(this._currentScriptEvent){this._currentTaskLayoutAndRecalcEvents.push(event);}
  103. break;case recordTypes.ScheduleStyleInvalidationTracking:case recordTypes.StyleRecalcInvalidationTracking:case recordTypes.StyleInvalidatorInvalidationTracking:case recordTypes.LayoutInvalidationTracking:this._invalidationTracker.addInvalidation(new InvalidationTrackingEvent(event));break;case recordTypes.InvalidateLayout:{let layoutInitator=event;const frameId=eventData['frame'];if(!this._layoutInvalidate[frameId]&&this._lastRecalculateStylesEvent&&this._lastRecalculateStylesEvent.endTime>event.startTime){layoutInitator=TimelineData.forEvent(this._lastRecalculateStylesEvent).initiator();}
  104. this._layoutInvalidate[frameId]=layoutInitator;break;}
  105. case recordTypes.Layout:{this._invalidationTracker.didLayout(event);const frameId=event.args['beginData']['frame'];timelineData.setInitiator(this._layoutInvalidate[frameId]);if(event.args['endData']){timelineData.backendNodeId=event.args['endData']['rootNode'];}
  106. this._layoutInvalidate[frameId]=null;if(this._currentScriptEvent){this._currentTaskLayoutAndRecalcEvents.push(event);}
  107. break;}
  108. case recordTypes.Task:if(event.duration>TimelineModelImpl.Thresholds.LongTask){timelineData.warning=TimelineModelImpl.WarningType.LongTask;}
  109. break;case recordTypes.EventDispatch:if(event.duration>TimelineModelImpl.Thresholds.RecurringHandler){timelineData.warning=TimelineModelImpl.WarningType.LongHandler;}
  110. break;case recordTypes.TimerFire:case recordTypes.FireAnimationFrame:if(event.duration>TimelineModelImpl.Thresholds.RecurringHandler){timelineData.warning=TimelineModelImpl.WarningType.LongRecurringHandler;}
  111. break;case recordTypes.FunctionCall:if(typeof eventData['scriptName']==='string'){eventData['url']=eventData['scriptName'];}
  112. if(typeof eventData['scriptLine']==='number'){eventData['lineNumber']=eventData['scriptLine'];}
  113. case recordTypes.EvaluateScript:case recordTypes.CompileScript:if(typeof eventData['lineNumber']==='number'){--eventData['lineNumber'];}
  114. if(typeof eventData['columnNumber']==='number'){--eventData['columnNumber'];}
  115. case recordTypes.RunMicrotasks:if(!this._currentScriptEvent){this._currentScriptEvent=event;}
  116. break;case recordTypes.SetLayerTreeId:if(this._sessionId&&eventData['sessionId']&&this._sessionId===eventData['sessionId']){this._mainFrameLayerTreeId=eventData['layerTreeId'];break;}
  117. const frameId=TimelineModelImpl.eventFrameId(event);const pageFrame=this._pageFrames.get(frameId);if(!pageFrame||pageFrame.parent){return false;}
  118. this._mainFrameLayerTreeId=eventData['layerTreeId'];break;case recordTypes.Paint:{this._invalidationTracker.didPaint(event);timelineData.backendNodeId=eventData['nodeId'];if(!eventData['layerId']){break;}
  119. const layerId=eventData['layerId'];this._lastPaintForLayer[layerId]=event;break;}
  120. case recordTypes.DisplayItemListSnapshot:case recordTypes.PictureSnapshot:{const layerUpdateEvent=this._findAncestorEvent(recordTypes.UpdateLayer);if(!layerUpdateEvent||layerUpdateEvent.args['layerTreeId']!==this._mainFrameLayerTreeId){break;}
  121. const paintEvent=this._lastPaintForLayer[layerUpdateEvent.args['layerId']];if(paintEvent){TimelineData.forEvent(paintEvent).picture=(event);}
  122. break;}
  123. case recordTypes.ScrollLayer:timelineData.backendNodeId=eventData['nodeId'];break;case recordTypes.PaintImage:timelineData.backendNodeId=eventData['nodeId'];timelineData.url=eventData['url'];break;case recordTypes.DecodeImage:case recordTypes.ResizeImage:{let paintImageEvent=this._findAncestorEvent(recordTypes.PaintImage);if(!paintImageEvent){const decodeLazyPixelRefEvent=this._findAncestorEvent(recordTypes.DecodeLazyPixelRef);paintImageEvent=decodeLazyPixelRefEvent&&this._paintImageEventByPixelRefId[decodeLazyPixelRefEvent.args['LazyPixelRef']];}
  124. if(!paintImageEvent){break;}
  125. const paintImageData=TimelineData.forEvent(paintImageEvent);timelineData.backendNodeId=paintImageData.backendNodeId;timelineData.url=paintImageData.url;break;}
  126. case recordTypes.DrawLazyPixelRef:{const paintImageEvent=this._findAncestorEvent(recordTypes.PaintImage);if(!paintImageEvent){break;}
  127. this._paintImageEventByPixelRefId[event.args['LazyPixelRef']]=paintImageEvent;const paintImageData=TimelineData.forEvent(paintImageEvent);timelineData.backendNodeId=paintImageData.backendNodeId;timelineData.url=paintImageData.url;break;}
  128. case recordTypes.FrameStartedLoading:if(timelineData.frameId!==event.args['frame']){return false;}
  129. break;case recordTypes.MarkLCPCandidate:timelineData.backendNodeId=eventData['nodeId'];break;case recordTypes.MarkDOMContent:case recordTypes.MarkLoad:{const frameId=TimelineModelImpl.eventFrameId(event);if(!this._pageFrames.has(frameId)){return false;}
  130. break;}
  131. case recordTypes.CommitLoad:{if(this._browserFrameTracking){break;}
  132. const frameId=TimelineModelImpl.eventFrameId(event);const isMainFrame=!!eventData['isMainFrame'];const pageFrame=this._pageFrames.get(frameId);if(pageFrame){pageFrame.update(event.startTime,eventData);}else{if(!this._persistentIds){if(eventData['page']&&eventData['page']!==this._legacyCurrentPage){return false;}}else if(isMainFrame){return false;}else if(!this._addPageFrame(event,eventData)){return false;}}
  133. if(isMainFrame){this._mainFrame=this._pageFrames.get(frameId);}
  134. break;}
  135. case recordTypes.FireIdleCallback:if(event.duration>eventData['allottedMilliseconds']+TimelineModelImpl.Thresholds.IdleCallbackAddon){timelineData.warning=TimelineModelImpl.WarningType.IdleDeadlineExceeded;}
  136. break;}
  137. return true;}
  138. _processBrowserEvent(event){if(event.name===RecordType.LatencyInfoFlow){const frameId=event.args['frameTreeNodeId'];if(typeof frameId==='number'&&frameId===this._mainFrameNodeId){this._knownInputEvents.add(event.bind_id);}
  139. return;}
  140. if(event.name===RecordType.ResourceWillSendRequest){const requestId=event.args['data']['requestId'];if(typeof requestId==='string'){this._requestsFromBrowser.set(requestId,event);}
  141. return;}
  142. if(event.hasCategory(SDK.TracingModel.DevToolsMetadataEventCategory)&&event.args['data']){const data=event.args['data'];if(event.name===TimelineModelImpl.DevToolsMetadataEvent.TracingStartedInBrowser){if(!data['persistentIds']){return;}
  143. this._browserFrameTracking=true;this._mainFrameNodeId=data['frameTreeNodeId'];const frames=data['frames']||[];frames.forEach(payload=>{const parent=payload['parent']&&this._pageFrames.get(payload['parent']);if(payload['parent']&&!parent){return;}
  144. let frame=this._pageFrames.get(payload['frame']);if(!frame){frame=new PageFrame(payload);this._pageFrames.set(frame.frameId,frame);if(parent){parent.addChild(frame);}else{this._mainFrame=frame;}}
  145. frame.update(this._minimumRecordTime,payload);});return;}
  146. if(event.name===TimelineModelImpl.DevToolsMetadataEvent.FrameCommittedInBrowser&&this._browserFrameTracking){let frame=this._pageFrames.get(data['frame']);if(!frame){const parent=data['parent']&&this._pageFrames.get(data['parent']);if(!parent){return;}
  147. frame=new PageFrame(data);this._pageFrames.set(frame.frameId,frame);parent.addChild(frame);}
  148. frame.update(event.startTime,data);return;}
  149. if(event.name===TimelineModelImpl.DevToolsMetadataEvent.ProcessReadyInBrowser&&this._browserFrameTracking){const frame=this._pageFrames.get(data['frame']);if(frame){frame.processReady(data['processPseudoId'],data['processId']);}
  150. return;}
  151. if(event.name===TimelineModelImpl.DevToolsMetadataEvent.FrameDeletedInBrowser&&this._browserFrameTracking){const frame=this._pageFrames.get(data['frame']);if(frame){frame.deletedTime=event.startTime;}
  152. return;}}}
  153. _ensureNamedTrack(type){if(!this._namedTracks.has(type)){const track=new Track();track.type=type;this._tracks.push(track);this._namedTracks.set(type,track);}
  154. return this._namedTracks.get(type);}
  155. _findAncestorEvent(name){for(let i=this._eventStack.length-1;i>=0;--i){const event=this._eventStack[i];if(event.name===name){return event;}}
  156. return null;}
  157. _addPageFrame(event,payload){const parent=payload['parent']&&this._pageFrames.get(payload['parent']);if(payload['parent']&&!parent){return false;}
  158. const pageFrame=new PageFrame(payload);this._pageFrames.set(pageFrame.frameId,pageFrame);pageFrame.update(event.startTime,payload);if(parent){parent.addChild(pageFrame);}
  159. return true;}
  160. _reset(){this._isGenericTrace=false;this._tracks=[];this._namedTracks=new Map();this._inspectedTargetEvents=[];this._timeMarkerEvents=[];this._sessionId=null;this._mainFrameNodeId=null;this._cpuProfiles=[];this._workerIdByThread=new WeakMap();this._pageFrames=new Map();this._mainFrame=null;this._requestsFromBrowser=new Map();this._minimumRecordTime=0;this._maximumRecordTime=0;}
  161. isGenericTrace(){return this._isGenericTrace;}
  162. tracingModel(){return this._tracingModel;}
  163. minimumRecordTime(){return this._minimumRecordTime;}
  164. maximumRecordTime(){return this._maximumRecordTime;}
  165. inspectedTargetEvents(){return this._inspectedTargetEvents;}
  166. tracks(){return this._tracks;}
  167. isEmpty(){return this.minimumRecordTime()===0&&this.maximumRecordTime()===0;}
  168. timeMarkerEvents(){return this._timeMarkerEvents;}
  169. rootFrames(){return Array.from(this._pageFrames.values()).filter(frame=>!frame.parent);}
  170. pageURL(){return this._mainFrame&&this._mainFrame.url||'';}
  171. pageFrameById(frameId){return frameId?this._pageFrames.get(frameId)||null:null;}
  172. networkRequests(){if(this.isGenericTrace()){return[];}
  173. const requests=new Map();const requestsList=[];const zeroStartRequestsList=[];const types=RecordType;const resourceTypes=new Set([types.ResourceWillSendRequest,types.ResourceSendRequest,types.ResourceReceiveResponse,types.ResourceReceivedData,types.ResourceFinish,types.ResourceMarkAsCached]);const events=this.inspectedTargetEvents();for(let i=0;i<events.length;++i){const e=events[i];if(!resourceTypes.has(e.name)){continue;}
  174. const id=TimelineModelImpl.globalEventId(e,'requestId');if(e.name===types.ResourceSendRequest&&this._requestsFromBrowser.has(e.args.data.requestId)){addRequest(this._requestsFromBrowser.get(e.args.data.requestId),id);}
  175. addRequest(e,id);}
  176. function addRequest(e,id){let request=requests.get(id);if(request){request.addEvent(e);}else{request=new NetworkRequest(e);requests.set(id,request);if(request.startTime){requestsList.push(request);}else{zeroStartRequestsList.push(request);}}}
  177. return zeroStartRequestsList.concat(requestsList);}}
  178. export const RecordType={Task:'RunTask',Program:'Program',EventDispatch:'EventDispatch',GPUTask:'GPUTask',Animation:'Animation',RequestMainThreadFrame:'RequestMainThreadFrame',BeginFrame:'BeginFrame',NeedsBeginFrameChanged:'NeedsBeginFrameChanged',BeginMainThreadFrame:'BeginMainThreadFrame',ActivateLayerTree:'ActivateLayerTree',DrawFrame:'DrawFrame',HitTest:'HitTest',ScheduleStyleRecalculation:'ScheduleStyleRecalculation',RecalculateStyles:'RecalculateStyles',UpdateLayoutTree:'UpdateLayoutTree',InvalidateLayout:'InvalidateLayout',Layout:'Layout',UpdateLayer:'UpdateLayer',UpdateLayerTree:'UpdateLayerTree',PaintSetup:'PaintSetup',Paint:'Paint',PaintImage:'PaintImage',Rasterize:'Rasterize',RasterTask:'RasterTask',ScrollLayer:'ScrollLayer',CompositeLayers:'CompositeLayers',ScheduleStyleInvalidationTracking:'ScheduleStyleInvalidationTracking',StyleRecalcInvalidationTracking:'StyleRecalcInvalidationTracking',StyleInvalidatorInvalidationTracking:'StyleInvalidatorInvalidationTracking',LayoutInvalidationTracking:'LayoutInvalidationTracking',ParseHTML:'ParseHTML',ParseAuthorStyleSheet:'ParseAuthorStyleSheet',TimerInstall:'TimerInstall',TimerRemove:'TimerRemove',TimerFire:'TimerFire',XHRReadyStateChange:'XHRReadyStateChange',XHRLoad:'XHRLoad',CompileScript:'v8.compile',EvaluateScript:'EvaluateScript',CompileModule:'v8.compileModule',EvaluateModule:'v8.evaluateModule',WasmStreamFromResponseCallback:'v8.wasm.streamFromResponseCallback',WasmCompiledModule:'v8.wasm.compiledModule',WasmCachedModule:'v8.wasm.cachedModule',WasmModuleCacheHit:'v8.wasm.moduleCacheHit',WasmModuleCacheInvalid:'v8.wasm.moduleCacheInvalid',FrameStartedLoading:'FrameStartedLoading',CommitLoad:'CommitLoad',MarkLoad:'MarkLoad',MarkDOMContent:'MarkDOMContent',MarkFirstPaint:'firstPaint',MarkFCP:'firstContentfulPaint',MarkFMP:'firstMeaningfulPaint',MarkLCPCandidate:'largestContentfulPaint::Candidate',MarkLCPInvalidate:'largestContentfulPaint::Invalidate',TimeStamp:'TimeStamp',ConsoleTime:'ConsoleTime',UserTiming:'UserTiming',ResourceWillSendRequest:'ResourceWillSendRequest',ResourceSendRequest:'ResourceSendRequest',ResourceReceiveResponse:'ResourceReceiveResponse',ResourceReceivedData:'ResourceReceivedData',ResourceFinish:'ResourceFinish',ResourceMarkAsCached:'ResourceMarkAsCached',RunMicrotasks:'RunMicrotasks',FunctionCall:'FunctionCall',GCEvent:'GCEvent',MajorGC:'MajorGC',MinorGC:'MinorGC',JSFrame:'JSFrame',JSSample:'JSSample',V8Sample:'V8Sample',JitCodeAdded:'JitCodeAdded',JitCodeMoved:'JitCodeMoved',StreamingCompileScript:'v8.parseOnBackground',StreamingCompileScriptWaiting:'v8.parseOnBackgroundWaiting',StreamingCompileScriptParsing:'v8.parseOnBackgroundParsing',V8Execute:'V8.Execute',UpdateCounters:'UpdateCounters',RequestAnimationFrame:'RequestAnimationFrame',CancelAnimationFrame:'CancelAnimationFrame',FireAnimationFrame:'FireAnimationFrame',RequestIdleCallback:'RequestIdleCallback',CancelIdleCallback:'CancelIdleCallback',FireIdleCallback:'FireIdleCallback',WebSocketCreate:'WebSocketCreate',WebSocketSendHandshakeRequest:'WebSocketSendHandshakeRequest',WebSocketReceiveHandshakeResponse:'WebSocketReceiveHandshakeResponse',WebSocketDestroy:'WebSocketDestroy',EmbedderCallback:'EmbedderCallback',SetLayerTreeId:'SetLayerTreeId',TracingStartedInPage:'TracingStartedInPage',TracingSessionIdForWorker:'TracingSessionIdForWorker',DecodeImage:'Decode Image',ResizeImage:'Resize Image',DrawLazyPixelRef:'Draw LazyPixelRef',DecodeLazyPixelRef:'Decode LazyPixelRef',LazyPixelRef:'LazyPixelRef',LayerTreeHostImplSnapshot:'cc::LayerTreeHostImpl',PictureSnapshot:'cc::Picture',DisplayItemListSnapshot:'cc::DisplayItemList',LatencyInfo:'LatencyInfo',LatencyInfoFlow:'LatencyInfo.Flow',InputLatencyMouseMove:'InputLatency::MouseMove',InputLatencyMouseWheel:'InputLatency::MouseWheel',ImplSideFling:'InputHandlerProxy::HandleGestureFling::started',GCCollectGarbage:'BlinkGC.AtomicPhase',CryptoDoEncrypt:'DoEncrypt',CryptoDoEncryptReply:'DoEncryptReply',CryptoDoDecrypt:'DoDecrypt',CryptoDoDecryptReply:'DoDecryptReply',CryptoDoDigest:'DoDigest',CryptoDoDigestReply:'DoDigestReply',CryptoDoSign:'DoSign',CryptoDoSignReply:'DoSignReply',CryptoDoVerify:'DoVerify',CryptoDoVerifyReply:'DoVerifyReply',CpuProfile:'CpuProfile',Profile:'Profile',AsyncTask:'AsyncTask',};TimelineModelImpl.Category={Console:'blink.console',UserTiming:'blink.user_timing',LatencyInfo:'latencyInfo'};TimelineModelImpl.WarningType={LongTask:'LongTask',ForcedStyle:'ForcedStyle',ForcedLayout:'ForcedLayout',IdleDeadlineExceeded:'IdleDeadlineExceeded',LongHandler:'LongHandler',LongRecurringHandler:'LongRecurringHandler',V8Deopt:'V8Deopt'};TimelineModelImpl.WorkerThreadName='DedicatedWorker thread';TimelineModelImpl.WorkerThreadNameLegacy='DedicatedWorker Thread';TimelineModelImpl.RendererMainThreadName='CrRendererMain';TimelineModelImpl.BrowserMainThreadName='CrBrowserMain';TimelineModelImpl.DevToolsMetadataEvent={TracingStartedInBrowser:'TracingStartedInBrowser',TracingStartedInPage:'TracingStartedInPage',TracingSessionIdForWorker:'TracingSessionIdForWorker',FrameCommittedInBrowser:'FrameCommittedInBrowser',ProcessReadyInBrowser:'ProcessReadyInBrowser',FrameDeletedInBrowser:'FrameDeletedInBrowser',};TimelineModelImpl.Thresholds={LongTask:200,Handler:150,RecurringHandler:50,ForcedLayout:30,IdleCallbackAddon:5};export class Track{constructor(){this.name='';this.type=TrackType.Other;this.forMainFrame=false;this.url='';this.events=[];this.asyncEvents=[];this.tasks=[];this._syncEvents=null;this.thread=null;}
  179. syncEvents(){if(this.events.length){return this.events;}
  180. if(this._syncEvents){return this._syncEvents;}
  181. const stack=[];this._syncEvents=[];for(const event of this.asyncEvents){const startTime=event.startTime;const endTime=event.endTime;while(stack.length&&startTime>=stack.peekLast().endTime){stack.pop();}
  182. if(stack.length&&endTime>stack.peekLast().endTime){this._syncEvents=[];break;}
  183. const syncEvent=new SDK.TracingModel.Event(event.categoriesString,event.name,SDK.TracingModel.Phase.Complete,startTime,event.thread);syncEvent.setEndTime(endTime);syncEvent.addArgs(event.args);this._syncEvents.push(syncEvent);stack.push(syncEvent);}
  184. return this._syncEvents;}}
  185. export const TrackType={MainThread:Symbol('MainThread'),Worker:Symbol('Worker'),Input:Symbol('Input'),Animation:Symbol('Animation'),Timings:Symbol('Timings'),Console:Symbol('Console'),Raster:Symbol('Raster'),GPU:Symbol('GPU'),Other:Symbol('Other'),};export class PageFrame{constructor(payload){this.frameId=payload['frame'];this.url=payload['url']||'';this.name=payload['name'];this.children=[];this.parent=null;this.processes=[];this.deletedTime=null;this.ownerNode=null;}
  186. update(time,payload){this.url=payload['url']||'';this.name=payload['name'];if(payload['processId']){this.processes.push({time:time,processId:payload['processId'],processPseudoId:'',url:payload['url']||''});}else{this.processes.push({time:time,processId:-1,processPseudoId:payload['processPseudoId'],url:payload['url']||''});}}
  187. processReady(processPseudoId,processId){for(const process of this.processes){if(process.processPseudoId===processPseudoId){process.processPseudoId='';process.processId=processId;}}}
  188. addChild(child){this.children.push(child);child.parent=this;}}
  189. export class NetworkRequest{constructor(event){const recordType=RecordType;const isInitial=event.name===recordType.ResourceSendRequest||event.name===recordType.ResourceWillSendRequest;this.startTime=isInitial?event.startTime:0;this.endTime=Infinity;this.encodedDataLength=0;this.decodedBodyLength=0;this.children=[];this.timing;this.mimeType;this.url;this.requestMethod;this._transferSize=0;this._maybeDiskCached=false;this._memoryCached=false;this.addEvent(event);}
  190. addEvent(event){this.children.push(event);const recordType=RecordType;this.startTime=Math.min(this.startTime,event.startTime);const eventData=event.args['data'];if(eventData['mimeType']){this.mimeType=eventData['mimeType'];}
  191. if('priority'in eventData){this.priority=eventData['priority'];}
  192. if(event.name===recordType.ResourceFinish){this.endTime=event.startTime;}
  193. if(eventData['finishTime']){this.finishTime=eventData['finishTime']*1000;}
  194. if(!this.responseTime&&(event.name===recordType.ResourceReceiveResponse||event.name===recordType.ResourceReceivedData)){this.responseTime=event.startTime;}
  195. const encodedDataLength=eventData['encodedDataLength']||0;if(event.name===recordType.ResourceMarkAsCached){this._memoryCached=true;}
  196. if(event.name===recordType.ResourceReceiveResponse){if(eventData['fromCache']){this._maybeDiskCached=true;}
  197. if(eventData['fromServiceWorker']){this.fromServiceWorker=true;}
  198. if(eventData['hasCachedResource']){this.hasCachedResource=true;}
  199. this.encodedDataLength=encodedDataLength;}
  200. if(event.name===recordType.ResourceReceivedData){this.encodedDataLength+=encodedDataLength;}
  201. if(event.name===recordType.ResourceFinish&&encodedDataLength){this.encodedDataLength=encodedDataLength;this._transferSize=encodedDataLength;}
  202. const decodedBodyLength=eventData['decodedBodyLength'];if(event.name===recordType.ResourceFinish&&decodedBodyLength){this.decodedBodyLength=decodedBodyLength;}
  203. if(!this.url){this.url=eventData['url'];}
  204. if(!this.requestMethod){this.requestMethod=eventData['requestMethod'];}
  205. if(!this.timing){this.timing=eventData['timing'];}
  206. if(eventData['fromServiceWorker']){this.fromServiceWorker=true;}}
  207. cached(){return!!this._memoryCached||(!!this._maybeDiskCached&&!this._transferSize&&!this.fromServiceWorker);}
  208. memoryCached(){return this._memoryCached;}
  209. getSendReceiveTiming(){if(this.cached()||!this.timing){return{sendStartTime:this.startTime,headersEndTime:this.startTime};}
  210. const requestTime=this.timing.requestTime*1000;const sendStartTime=requestTime+this.timing.sendStart;const headersEndTime=requestTime+this.timing.receiveHeadersEnd;return{sendStartTime,headersEndTime};}
  211. getStartTime(){return Math.min(this.startTime,!this.cached()&&this.timing&&this.timing.requestTime*1000||Infinity);}
  212. beginTime(){return Math.min(this.getStartTime(),!this.cached()&&this.timing&&this.timing.pushStart*1000||Infinity);}}
  213. export class InvalidationTrackingEvent{constructor(event){this.type=event.name;this.startTime=event.startTime;this._tracingEvent=event;const eventData=event.args['data'];this.frame=eventData['frame'];this.nodeId=eventData['nodeId'];this.nodeName=eventData['nodeName'];this.invalidationSet=eventData['invalidationSet'];this.invalidatedSelectorId=eventData['invalidatedSelectorId'];this.changedId=eventData['changedId'];this.changedClass=eventData['changedClass'];this.changedAttribute=eventData['changedAttribute'];this.changedPseudo=eventData['changedPseudo'];this.selectorPart=eventData['selectorPart'];this.extraData=eventData['extraData'];this.invalidationList=eventData['invalidationList'];this.cause={reason:eventData['reason'],stackTrace:eventData['stackTrace']};if(!this.cause.reason&&this.cause.stackTrace&&this.type===RecordType.LayoutInvalidationTracking){this.cause.reason='Layout forced';}}}
  214. export class InvalidationTracker{constructor(){this._lastRecalcStyle=null;this._lastPaintWithLayer=null;this._didPaint=false;this._initializePerFrameState();}
  215. static invalidationEventsFor(event){return event[InvalidationTracker._invalidationTrackingEventsSymbol]||null;}
  216. addInvalidation(invalidation){this._startNewFrameIfNeeded();if(!invalidation.nodeId){console.error('Invalidation lacks node information.');console.error(invalidation);return;}
  217. const recordTypes=RecordType;if(invalidation.type===recordTypes.StyleRecalcInvalidationTracking&&invalidation.cause.reason==='StyleInvalidator'){return;}
  218. const styleRecalcInvalidation=(invalidation.type===recordTypes.ScheduleStyleInvalidationTracking||invalidation.type===recordTypes.StyleInvalidatorInvalidationTracking||invalidation.type===recordTypes.StyleRecalcInvalidationTracking);if(styleRecalcInvalidation){const duringRecalcStyle=invalidation.startTime&&this._lastRecalcStyle&&invalidation.startTime>=this._lastRecalcStyle.startTime&&invalidation.startTime<=this._lastRecalcStyle.endTime;if(duringRecalcStyle){this._associateWithLastRecalcStyleEvent(invalidation);}}
  219. if(this._invalidations[invalidation.type]){this._invalidations[invalidation.type].push(invalidation);}else{this._invalidations[invalidation.type]=[invalidation];}
  220. if(invalidation.nodeId){if(this._invalidationsByNodeId[invalidation.nodeId]){this._invalidationsByNodeId[invalidation.nodeId].push(invalidation);}else{this._invalidationsByNodeId[invalidation.nodeId]=[invalidation];}}}
  221. didRecalcStyle(recalcStyleEvent){this._lastRecalcStyle=recalcStyleEvent;const types=[RecordType.ScheduleStyleInvalidationTracking,RecordType.StyleInvalidatorInvalidationTracking,RecordType.StyleRecalcInvalidationTracking];for(const invalidation of this._invalidationsOfTypes(types)){this._associateWithLastRecalcStyleEvent(invalidation);}}
  222. _associateWithLastRecalcStyleEvent(invalidation){if(invalidation.linkedRecalcStyleEvent){return;}
  223. const recordTypes=RecordType;const recalcStyleFrameId=this._lastRecalcStyle.args['beginData']['frame'];if(invalidation.type===recordTypes.StyleInvalidatorInvalidationTracking){this._addSyntheticStyleRecalcInvalidations(this._lastRecalcStyle,recalcStyleFrameId,invalidation);}else if(invalidation.type===recordTypes.ScheduleStyleInvalidationTracking){}else{this._addInvalidationToEvent(this._lastRecalcStyle,recalcStyleFrameId,invalidation);}
  224. invalidation.linkedRecalcStyleEvent=true;}
  225. _addSyntheticStyleRecalcInvalidations(event,frameId,styleInvalidatorInvalidation){if(!styleInvalidatorInvalidation.invalidationList){this._addSyntheticStyleRecalcInvalidation(styleInvalidatorInvalidation._tracingEvent,styleInvalidatorInvalidation);return;}
  226. if(!styleInvalidatorInvalidation.nodeId){console.error('Invalidation lacks node information.');console.error(styleInvalidatorInvalidation);return;}
  227. for(let i=0;i<styleInvalidatorInvalidation.invalidationList.length;i++){const setId=styleInvalidatorInvalidation.invalidationList[i]['id'];let lastScheduleStyleRecalculation;const nodeInvalidations=this._invalidationsByNodeId[styleInvalidatorInvalidation.nodeId]||[];for(let j=0;j<nodeInvalidations.length;j++){const invalidation=nodeInvalidations[j];if(invalidation.frame!==frameId||invalidation.invalidationSet!==setId||invalidation.type!==RecordType.ScheduleStyleInvalidationTracking){continue;}
  228. lastScheduleStyleRecalculation=invalidation;}
  229. if(!lastScheduleStyleRecalculation){console.error('Failed to lookup the event that scheduled a style invalidator invalidation.');continue;}
  230. this._addSyntheticStyleRecalcInvalidation(lastScheduleStyleRecalculation._tracingEvent,styleInvalidatorInvalidation);}}
  231. _addSyntheticStyleRecalcInvalidation(baseEvent,styleInvalidatorInvalidation){const invalidation=new InvalidationTrackingEvent(baseEvent);invalidation.type=RecordType.StyleRecalcInvalidationTracking;if(styleInvalidatorInvalidation.cause.reason){invalidation.cause.reason=styleInvalidatorInvalidation.cause.reason;}
  232. if(styleInvalidatorInvalidation.selectorPart){invalidation.selectorPart=styleInvalidatorInvalidation.selectorPart;}
  233. this.addInvalidation(invalidation);if(!invalidation.linkedRecalcStyleEvent){this._associateWithLastRecalcStyleEvent(invalidation);}}
  234. didLayout(layoutEvent){const layoutFrameId=layoutEvent.args['beginData']['frame'];for(const invalidation of this._invalidationsOfTypes([RecordType.LayoutInvalidationTracking])){if(invalidation.linkedLayoutEvent){continue;}
  235. this._addInvalidationToEvent(layoutEvent,layoutFrameId,invalidation);invalidation.linkedLayoutEvent=true;}}
  236. didPaint(paintEvent){this._didPaint=true;}
  237. _addInvalidationToEvent(event,eventFrameId,invalidation){if(eventFrameId!==invalidation.frame){return;}
  238. if(!event[InvalidationTracker._invalidationTrackingEventsSymbol]){event[InvalidationTracker._invalidationTrackingEventsSymbol]=[invalidation];}else{event[InvalidationTracker._invalidationTrackingEventsSymbol].push(invalidation);}}
  239. _invalidationsOfTypes(types){const invalidations=this._invalidations;if(!types){types=Object.keys(invalidations);}
  240. function*generator(){for(let i=0;i<types.length;++i){const invalidationList=invalidations[types[i]]||[];for(let j=0;j<invalidationList.length;++j){yield invalidationList[j];}}}
  241. return generator();}
  242. _startNewFrameIfNeeded(){if(!this._didPaint){return;}
  243. this._initializePerFrameState();}
  244. _initializePerFrameState(){this._invalidations={};this._invalidationsByNodeId={};this._lastRecalcStyle=null;this._lastPaintWithLayer=null;this._didPaint=false;}}
  245. InvalidationTracker._invalidationTrackingEventsSymbol=Symbol('invalidationTrackingEvents');export class TimelineAsyncEventTracker{constructor(){TimelineAsyncEventTracker._initialize();this._initiatorByType=new Map();for(const initiator of TimelineAsyncEventTracker._asyncEvents.keys()){this._initiatorByType.set(initiator,new Map());}}
  246. static _initialize(){if(TimelineAsyncEventTracker._asyncEvents){return;}
  247. const events=new Map();let type=RecordType;events.set(type.TimerInstall,{causes:[type.TimerFire],joinBy:'timerId'});events.set(type.ResourceSendRequest,{causes:[type.ResourceMarkAsCached,type.ResourceReceiveResponse,type.ResourceReceivedData,type.ResourceFinish],joinBy:'requestId'});events.set(type.RequestAnimationFrame,{causes:[type.FireAnimationFrame],joinBy:'id'});events.set(type.RequestIdleCallback,{causes:[type.FireIdleCallback],joinBy:'id'});events.set(type.WebSocketCreate,{causes:[type.WebSocketSendHandshakeRequest,type.WebSocketReceiveHandshakeResponse,type.WebSocketDestroy],joinBy:'identifier'});TimelineAsyncEventTracker._asyncEvents=events;TimelineAsyncEventTracker._typeToInitiator=new Map();for(const entry of events){const types=entry[1].causes;for(type of types){TimelineAsyncEventTracker._typeToInitiator.set(type,entry[0]);}}}
  248. processEvent(event){let initiatorType=TimelineAsyncEventTracker._typeToInitiator.get((event.name));const isInitiator=!initiatorType;if(!initiatorType){initiatorType=(event.name);}
  249. const initiatorInfo=TimelineAsyncEventTracker._asyncEvents.get(initiatorType);if(!initiatorInfo){return;}
  250. const id=TimelineModelImpl.globalEventId(event,initiatorInfo.joinBy);if(!id){return;}
  251. const initiatorMap=this._initiatorByType.get(initiatorType);if(isInitiator){initiatorMap.set(id,event);return;}
  252. const initiator=initiatorMap.get(id)||null;const timelineData=TimelineData.forEvent(event);timelineData.setInitiator(initiator);if(!timelineData.frameId&&initiator){timelineData.frameId=TimelineModelImpl.eventFrameId(initiator);}}}
  253. export class TimelineData{constructor(){this.warning=null;this.previewElement=null;this.url=null;this.backendNodeId=0;this.stackTrace=null;this.picture=null;this._initiator=null;this.frameId='';this.timeWaitingForMainThread;}
  254. setInitiator(initiator){this._initiator=initiator;if(!initiator||this.url){return;}
  255. const initiatorURL=TimelineData.forEvent(initiator).url;if(initiatorURL){this.url=initiatorURL;}}
  256. initiator(){return this._initiator;}
  257. topFrame(){const stackTrace=this.stackTraceForSelfOrInitiator();return stackTrace&&stackTrace[0]||null;}
  258. stackTraceForSelfOrInitiator(){return this.stackTrace||(this._initiator&&TimelineData.forEvent(this._initiator).stackTrace);}
  259. static forEvent(event){let data=event[TimelineData._symbol];if(!data){data=new TimelineData();event[TimelineData._symbol]=data;}
  260. return data;}}
  261. TimelineData._symbol=Symbol('timelineData');self.TimelineModel=self.TimelineModel||{};TimelineModel=TimelineModel||{};TimelineModel.TimelineModel=TimelineModelImpl;TimelineModel.TimelineModel.Track=Track;TimelineModel.TimelineModel.TrackType=TrackType;TimelineModel.TimelineModel.RecordType=RecordType;TimelineModel.TimelineModel.PageFrame=PageFrame;TimelineModel.TimelineModel.NetworkRequest=NetworkRequest;TimelineModel.InvalidationTrackingEvent=InvalidationTrackingEvent;TimelineModel.InvalidationTracker=InvalidationTracker;TimelineModel.TimelineAsyncEventTracker=TimelineAsyncEventTracker;TimelineModel.TimelineData=TimelineData;TimelineModel.InvalidationCause;TimelineModel.TimelineModel.MetadataEvents;