@@ -132,14 +132,20 @@ export class TimelineFlameChartDataProvider extends Common.ObjectWrapper.ObjectW
132132
133133 private entryTypeByLevel : EntryType [ ] = [ ] ;
134134 private entryIndexToTitle : string [ ] = [ ] ;
135- private lastInitiatorEntry = - 1 ;
136- private lastInitiatorsData : PerfUI . FlameChart . FlameChartInitiatorData [ ] = [ ] ;
135+ #lastInitiatorEntryIndex = - 1 ;
137136
138137 private lastSelection : Selection | null = null ;
139138 readonly #font = `${ PerfUI . Font . DEFAULT_FONT_SIZE } ${ PerfUI . Font . getFontFamilyForCanvas ( ) } ` ;
140139 #eventIndexByEvent = new WeakMap < Trace . Types . Events . Event , number | null > ( ) ;
141140 #entityMapper: Utils . EntityMapper . EntityMapper | null = null ;
142141
142+ /**
143+ * When we create initiator chains for a selected event, we store those
144+ * chains in this map so that if the user reselects the same event we do not
145+ * have to recalculate. This is reset when the trace changes.
146+ */
147+ #initiatorsCache = new Map < number , PerfUI . FlameChart . FlameChartInitiatorData [ ] > ( ) ;
148+
143149 constructor ( ) {
144150 super ( ) ;
145151 this . reset ( ) ;
@@ -543,6 +549,8 @@ export class TimelineFlameChartDataProvider extends Common.ObjectWrapper.ObjectW
543549 this . timelineDataInternal = null ;
544550 this . parsedTrace = null ;
545551 this . #entityMapper = null ;
552+ this . #lastInitiatorEntryIndex = - 1 ;
553+ this . #initiatorsCache. clear ( ) ;
546554 }
547555
548556 maxStackDepth ( ) : number {
@@ -1243,45 +1251,52 @@ export class TimelineFlameChartDataProvider extends Common.ObjectWrapper.ObjectW
12431251 * @returns if we should re-render the flame chart (canvas)
12441252 */
12451253 buildFlowForInitiator ( entryIndex : number ) : boolean {
1246- if ( ! this . parsedTrace ) {
1254+ if ( ! this . parsedTrace || ! this . compatibilityTracksAppender || ! this . timelineDataInternal ) {
12471255 return false ;
12481256 }
1249- if ( ! this . timelineDataInternal ) {
1257+
1258+ if ( this . #lastInitiatorEntryIndex === entryIndex ) {
1259+ // If the user clicks on an entry twice by mistake, this can fire. But if
1260+ // the entry matches the selected entry, then there is nothing more for
1261+ // us to do.
12501262 return false ;
12511263 }
1252- // Remove all previously assigned decorations indicating that the flow event entries are hidden
1264+
1265+ this . #lastInitiatorEntryIndex = entryIndex ;
1266+
12531267 const previousInitiatorsDataLength = this . timelineDataInternal . initiatorsData . length ;
1254- // |entryIndex| equals -1 means there is no entry selected, just clear the
1255- // initiator cache if there is any previous arrow and return true to
1256- // re-render.
1268+
12571269 if ( entryIndex === - 1 ) {
1258- this . lastInitiatorEntry = entryIndex ;
1259- if ( previousInitiatorsDataLength === 0 ) {
1260- // This means there is no arrow before , so we don't need to re-render .
1270+ // User has deselected an event, so if it had any initiators we need to clear them.
1271+ if ( this . timelineDataInternal . initiatorsData . length === 0 ) {
1272+ // The previous selected entry had no initiators , so we can early exit and not redraw anything .
12611273 return false ;
12621274 }
1263- // Reset to clear any previous arrows from the last event .
1264- this . timelineDataInternal . resetFlowData ( ) ;
1275+ // Clear initiator data and trigger a re-render .
1276+ this . timelineDataInternal . emptyInitiators ( ) ;
12651277 return true ;
12661278 }
1267- if ( this . lastInitiatorEntry === entryIndex ) {
1268- if ( this . lastInitiatorsData ) {
1269- this . timelineDataInternal . initiatorsData = this . lastInitiatorsData ;
1270- }
1271- return false ;
1272- }
1273- if ( ! this . compatibilityTracksAppender ) {
1274- return false ;
1275- }
12761279
1280+ // If the user hasn't clicked on an event, bail, as there are no initiators
1281+ // for screenshots or frames.
12771282 const entryType = this . #entryTypeForIndex( entryIndex ) ;
12781283 if ( entryType !== EntryType . TRACK_APPENDER ) {
12791284 return false ;
12801285 }
1286+
1287+ // Avoid re-building the initiators if we already did it previously.
1288+ const cached = this . #initiatorsCache. get ( entryIndex ) ;
1289+ if ( cached ) {
1290+ this . timelineDataInternal . initiatorsData = cached ;
1291+ return true ;
1292+ }
1293+
1294+ // At this point, we know we:
1295+ // 1. Have an event to build initiators for.
1296+ // 2. Know that it's not an event with initiators that are cached.
12811297 const event = this . entryData [ entryIndex ] ;
12821298 // Reset to clear any previous arrows from the last event.
1283- this . timelineDataInternal . resetFlowData ( ) ;
1284- this . lastInitiatorEntry = entryIndex ;
1299+ this . timelineDataInternal . emptyInitiators ( ) ;
12851300
12861301 const hiddenEvents : Trace . Types . Events . Event [ ] =
12871302 ModificationsManager . activeManager ( ) ?. getEntriesFilter ( ) . invisibleEntries ( ) ?? [ ] ;
@@ -1294,10 +1309,19 @@ export class TimelineFlameChartDataProvider extends Common.ObjectWrapper.ObjectW
12941309 hiddenEvents ,
12951310 expandableEntries ,
12961311 ) ;
1297- // This means there is no change for arrows.
1312+
1313+ if ( initiatorsData . length === 0 ) {
1314+ // Small optimization: cache if this entry has 0 initiators, meaning if
1315+ // it gets reselected we don't redo the work to find out it has 0
1316+ // initiators.
1317+ this . #initiatorsCache. set ( entryIndex , [ ] ) ;
1318+ }
1319+
1320+ // Previous event had 0 initiators, new event has 0, therefore exit early and don't render.
12981321 if ( previousInitiatorsDataLength === 0 && initiatorsData . length === 0 ) {
12991322 return false ;
13001323 }
1324+
13011325 for ( const initiatorData of initiatorsData ) {
13021326 const eventIndex = this . indexForEvent ( initiatorData . event ) ;
13031327 const initiatorIndex = this . indexForEvent ( initiatorData . initiator ) ;
@@ -1311,7 +1335,7 @@ export class TimelineFlameChartDataProvider extends Common.ObjectWrapper.ObjectW
13111335 isEntryHidden : initiatorData . isEntryHidden ,
13121336 } ) ;
13131337 }
1314- this . lastInitiatorsData = this . timelineDataInternal . initiatorsData ;
1338+ this . #initiatorsCache . set ( entryIndex , this . timelineDataInternal . initiatorsData ) ;
13151339 return true ;
13161340 }
13171341
0 commit comments