@@ -28,6 +28,7 @@ import type {
2828 ExtraBadgeInfo ,
2929 BottomBoxInfo ,
3030 CallNodeLeafAndSummary ,
31+ SelfAndTotal ,
3132} from 'firefox-profiler/types' ;
3233
3334import ExtensionIcon from '../../res/img/svg/extension.svg' ;
@@ -63,89 +64,151 @@ function extractFaviconFromLibname(libname: string): string | null {
6364 }
6465}
6566
66- export class CallTree {
67- _categories : CategoryList ;
67+ interface CallTreeInternal {
68+ hasChildren ( callNodeIndex : IndexIntoCallNodeTable ) : boolean ;
69+ createChildren ( nodeIndex : IndexIntoCallNodeTable ) : CallNodeChildren ;
70+ createRoots ( ) : CallNodeChildren ;
71+ getSelfAndTotal ( nodeIndex : IndexIntoCallNodeTable ) : SelfAndTotal ;
72+ findHeaviestPathInSubtree (
73+ callNodeIndex : IndexIntoCallNodeTable
74+ ) : CallNodePath ;
75+ }
76+
77+ export class CallTreeInternalImpl implements CallTreeInternal {
6878 _callNodeInfo : CallNodeInfo ;
6979 _callNodeTable : CallNodeTable ;
7080 _callTreeTimings : CallTreeTimings ;
7181 _callNodeHasChildren : Uint8Array ; // A table column matching the callNodeTable
82+
83+ constructor ( callNodeInfo : CallNodeInfo , callTreeTimings : CallTreeTimings ) {
84+ this . _callNodeInfo = callNodeInfo ;
85+ this . _callNodeTable = callNodeInfo . getCallNodeTable ( ) ;
86+ this . _callTreeTimings = callTreeTimings ;
87+ this . _callNodeHasChildren = callTreeTimings . callNodeHasChildren ;
88+ }
89+
90+ _getFirstChildIndex (
91+ callNodeIndex : IndexIntoCallNodeTable | - 1
92+ ) : IndexIntoCallNodeTable | - 1 {
93+ if ( callNodeIndex === - 1 ) {
94+ return this . _callNodeTable . length !== 0 ? 0 : - 1 ;
95+ }
96+ const subtreeRangeEnd = this . _callNodeTable . subtreeRangeEnd [ callNodeIndex ] ;
97+ if ( subtreeRangeEnd !== callNodeIndex + 1 ) {
98+ return callNodeIndex + 1 ;
99+ }
100+ return - 1 ;
101+ }
102+
103+ createRoots ( ) {
104+ return this . createChildren ( - 1 ) ;
105+ }
106+
107+ createChildren ( callNodeIndex : IndexIntoCallNodeTable ) : CallNodeChildren {
108+ const firstChild = this . _getFirstChildIndex ( callNodeIndex ) ;
109+ const children = [ ] ;
110+ for (
111+ let childCallNodeIndex = firstChild ;
112+ childCallNodeIndex !== - 1 ;
113+ childCallNodeIndex = this . _callNodeTable . nextSibling [ childCallNodeIndex ]
114+ ) {
115+ const childTotalSummary = this . _callTreeTimings . total [ childCallNodeIndex ] ;
116+ const childHasChildren = this . _callNodeHasChildren [ childCallNodeIndex ] ;
117+
118+ if ( childTotalSummary !== 0 || childHasChildren !== 0 ) {
119+ children . push ( childCallNodeIndex ) ;
120+ }
121+ }
122+ children . sort (
123+ ( a , b ) =>
124+ Math . abs ( this . _callTreeTimings . total [ b ] ) -
125+ Math . abs ( this . _callTreeTimings . total [ a ] )
126+ ) ;
127+ return children ;
128+ }
129+
130+ hasChildren ( callNodeIndex : IndexIntoCallNodeTable ) : boolean {
131+ return this . _callNodeHasChildren [ callNodeIndex ] !== 0 ;
132+ }
133+
134+ getSelfAndTotal ( callNodeIndex : IndexIntoCallNodeTable ) : SelfAndTotal {
135+ const self = this . _callTreeTimings . self [ callNodeIndex ] ;
136+ const total = this . _callTreeTimings . total [ callNodeIndex ] ;
137+ return { self, total } ;
138+ }
139+
140+ findHeaviestPathInSubtree (
141+ callNodeIndex : IndexIntoCallNodeTable
142+ ) : CallNodePath {
143+ const rangeEnd = this . _callNodeTable . subtreeRangeEnd [ callNodeIndex ] ;
144+
145+ // Find the call node with the highest leaf time.
146+ let maxNode = - 1 ;
147+ let maxAbs = 0 ;
148+ for ( let nodeIndex = callNodeIndex ; nodeIndex < rangeEnd ; nodeIndex ++ ) {
149+ const nodeLeaf = Math . abs ( this . _callTreeTimings . leaf [ nodeIndex ] ) ;
150+ if ( maxNode === - 1 || nodeLeaf > maxAbs ) {
151+ maxNode = nodeIndex ;
152+ maxAbs = nodeLeaf ;
153+ }
154+ }
155+
156+ return this . _callNodeInfo . getCallNodePathFromIndex ( maxNode ) ;
157+ }
158+ }
159+
160+ export class CallTree {
161+ _categories : CategoryList ;
162+ _internal: CallTreeInternal ;
163+ _callNodeInfo: CallNodeInfo ;
164+ _callNodeTable: CallNodeTable ;
72165 _thread: Thread ;
73166 _rootTotalSummary: number ;
74167 _displayDataByIndex: Map < IndexIntoCallNodeTable , CallNodeDisplayData > ;
75168 // _children is indexed by IndexIntoCallNodeTable. Since they are
76169 // integers, using an array directly is faster than going through a Map.
77170 _children: Array < CallNodeChildren > ;
171+ _roots: IndexIntoCallNodeTable [ ] ;
78172 _isHighPrecision: boolean ;
79173 _weightType: WeightType ;
80174
81175 constructor (
82176 thread : Thread ,
83177 categories : CategoryList ,
84178 callNodeInfo : CallNodeInfo ,
85- callTreeTimings : CallTreeTimings ,
179+ internal : CallTreeInternal ,
180+ rootTotalSummary : number ,
86181 isHighPrecision : boolean ,
87182 weightType : WeightType
88183 ) {
89184 this . _categories = categories ;
185+ this . _internal = internal ;
90186 this . _callNodeInfo = callNodeInfo ;
91187 this . _callNodeTable = callNodeInfo . getCallNodeTable ( ) ;
92- this . _callTreeTimings = callTreeTimings ;
93- this . _callNodeHasChildren = callTreeTimings . callNodeHasChildren ;
94188 this . _thread = thread ;
95- this . _rootTotalSummary = callTreeTimings . rootTotalSummary ;
189+ this . _rootTotalSummary = rootTotalSummary ;
96190 this . _displayDataByIndex = new Map ( ) ;
97191 this . _children = [ ] ;
192+ this . _roots = internal . createRoots ( ) ;
98193 this . _isHighPrecision = isHighPrecision ;
99194 this . _weightType = weightType ;
100195 }
101196
102- _getFirstChildIndex (
103- callNodeIndex : IndexIntoCallNodeTable | - 1
104- ) : IndexIntoCallNodeTable | - 1 {
105- if ( callNodeIndex === - 1 ) {
106- return this . _callNodeTable . length !== 0 ? 0 : - 1 ;
107- }
108- const subtreeRangeEnd = this . _callNodeTable . subtreeRangeEnd [ callNodeIndex ] ;
109- if ( subtreeRangeEnd !== callNodeIndex + 1 ) {
110- return callNodeIndex + 1 ;
111- }
112- return - 1 ;
113- }
114-
115197 getRoots ( ) {
116- return this . getChildren ( - 1 ) ;
198+ return this . _roots ;
117199 }
118200
119201 getChildren ( callNodeIndex : IndexIntoCallNodeTable ) : CallNodeChildren {
120202 let children = this . _children [ callNodeIndex ] ;
121203 if ( children === undefined ) {
122- children = [ ] ;
123- const firstChild = this . _getFirstChildIndex ( callNodeIndex ) ;
124- for (
125- let childCallNodeIndex = firstChild ;
126- childCallNodeIndex !== - 1 ;
127- childCallNodeIndex = this . _callNodeTable . nextSibling [ childCallNodeIndex ]
128- ) {
129- const childTotalSummary =
130- this . _callTreeTimings . total [ childCallNodeIndex ] ;
131- const childHasChildren = this . _callNodeHasChildren [ childCallNodeIndex ] ;
132-
133- if ( childTotalSummary !== 0 || childHasChildren !== 0 ) {
134- children . push ( childCallNodeIndex ) ;
135- }
136- }
137- children . sort (
138- ( a , b ) =>
139- Math . abs ( this . _callTreeTimings . total [ b ] ) -
140- Math . abs ( this . _callTreeTimings . total [ a ] )
141- ) ;
204+ children = this . _internal . createChildren ( callNodeIndex ) ;
142205 this . _children [ callNodeIndex ] = children ;
143206 }
144207 return children ;
145208 }
146209
147210 hasChildren ( callNodeIndex : IndexIntoCallNodeTable ) : boolean {
148- return this . _callNodeHasChildren [ callNodeIndex ] !== 0 ;
211+ return this . _internal . hasChildren ( callNodeIndex ) ;
149212 }
150213
151214 _addDescendantsToSet (
@@ -181,9 +244,9 @@ export class CallTree {
181244 const funcName = this . _thread . stringTable . getString (
182245 this . _thread . funcTable . name [ funcIndex ]
183246 ) ;
184- const total = this . _callTreeTimings . total [ callNodeIndex ] ;
247+
248+ const { self, total } = this . _internal . getSelfAndTotal ( callNodeIndex ) ;
185249 const totalRelative = total / this . _rootTotalSummary ;
186- const self = this . _callTreeTimings . self [ callNodeIndex ] ;
187250 const selfRelative = self / this . _rootTotalSummary ;
188251
189252 return {
@@ -382,30 +445,12 @@ export class CallTree {
382445 if ( callNodeIndex === null ) {
383446 return [ ] ;
384447 }
385- const heaviestPath = this . findHeaviestPathInSubtree ( callNodeIndex ) ;
448+ const heaviestPath =
449+ this . _internal . findHeaviestPathInSubtree ( callNodeIndex ) ;
386450 const startingDepth = this . _callNodeTable . depth [ callNodeIndex ] ;
387451 const partialPath = heaviestPath . slice ( startingDepth ) ;
388452 return partialPath . reverse ( ) ;
389453 }
390-
391- findHeaviestPathInSubtree (
392- callNodeIndex : IndexIntoCallNodeTable
393- ) : CallNodePath {
394- const rangeEnd = this . _callNodeTable . subtreeRangeEnd [ callNodeIndex ] ;
395-
396- // Find the call node with the highest leaf time.
397- let maxNode = - 1 ;
398- let maxAbs = 0 ;
399- for ( let nodeIndex = callNodeIndex ; nodeIndex < rangeEnd ; nodeIndex ++ ) {
400- const nodeLeaf = Math . abs ( this . _callTreeTimings . leaf [ nodeIndex ] ) ;
401- if ( maxNode === - 1 || nodeLeaf > maxAbs ) {
402- maxNode = nodeIndex ;
403- maxAbs = nodeLeaf ;
404- }
405- }
406-
407- return this . _callNodeInfo . getCallNodePathFromIndex ( maxNode ) ;
408- }
409454}
410455
411456// In an inverted profile, all the amount of self unit (time, bytes, count, etc.) is
@@ -547,7 +592,8 @@ export function getCallTree(
547592 thread ,
548593 categories ,
549594 callNodeInfo ,
550- callTreeTimings ,
595+ new CallTreeInternalImpl ( callNodeInfo , callTreeTimings ) ,
596+ callTreeTimings . rootTotalSummary ,
551597 Boolean ( thread . isJsTracer ) ,
552598 weightType
553599 ) ;
0 commit comments