-
Notifications
You must be signed in to change notification settings - Fork 462
Expand file tree
/
Copy pathprofile-derived.ts
More file actions
837 lines (777 loc) · 32.4 KB
/
profile-derived.ts
File metadata and controls
837 lines (777 loc) · 32.4 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
import type { Milliseconds, StartEndRange, Address, Bytes } from './units';
import type { MarkerPayload, MarkerSchema } from './markers';
import type {
ThreadIndex,
Pid,
IndexIntoFuncTable,
IndexIntoJsTracerEvents,
IndexIntoCategoryList,
IndexIntoResourceTable,
IndexIntoLibs,
CounterIndex,
GraphColor,
IndexIntoRawMarkerTable,
IndexIntoStringTable,
TabID,
Tid,
ProcessType,
PausedRange,
JsAllocationsTable,
NativeAllocationsTable,
RawMarkerTable,
FrameTable,
FuncTable,
ResourceTable,
NativeSymbolTable,
JsTracerTable,
IndexIntoStackTable,
WeightType,
IndexIntoFrameTable,
SourceTable,
IndexIntoSourceTable,
} from './profile';
import type { IndexedArray } from './utils';
import type { BitSet } from '../utils/bitset';
import type { StackTiming } from '../profile-logic/stack-timing';
import type { StringTable } from '../utils/string-table';
import type {
IndexIntoSetCollectionTable,
SetCollectionTable,
} from 'firefox-profiler/utils/set-collection';
export type IndexIntoCallNodeTable = number;
/**
* The derived Thread type.
*
* This type is more ergonomic than the RawThread type:
*
* - `RawThread` represents the data as it is stored in the profile file format,
* so it needs to be JSON-compatible, and it is encouraged to use more compact
* data representations, e.g. no duplication of shared data on each thread.
* - `Thread` is computed at runtime by selectors, and can store data in a way
* that's most convenient for users of the derived state.
*
* The fields that differ from RawThread are collected at the end of this type
* definition.
*/
export type Thread = {
processType: ProcessType;
processStartupTime: Milliseconds;
processShutdownTime: Milliseconds | null;
registerTime: Milliseconds;
unregisterTime: Milliseconds | null;
pausedRanges: PausedRange[];
showMarkersInTimeline?: boolean;
name: string;
isMainThread: boolean;
// The eTLD+1 of the isolated content process if provided by the back-end.
// It will be undefined if:
// - Fission is not enabled.
// - It's not an isolated content process.
// - It's a sanitized profile.
// - It's a profile from an older Firefox which doesn't include this field (introduced in Firefox 80).
'eTLD+1'?: string;
processName?: string;
isJsTracer?: boolean;
pid: Pid;
tid: Tid;
jsAllocations?: JsAllocationsTable;
nativeAllocations?: NativeAllocationsTable;
markers: RawMarkerTable;
stackTable: StackTable;
frameTable: FrameTable;
funcTable: FuncTable;
resourceTable: ResourceTable;
nativeSymbols: NativeSymbolTable;
jsTracer?: JsTracerTable;
// If present and true, this thread was launched for a private browsing session only.
// When false, it can still contain private browsing data if the profile was
// captured in a non-fission browser.
// It's absent in Firefox 97 and before, or in Firefox 98+ when this thread
// had no extra attribute at all.
isPrivateBrowsing?: boolean;
// If present and non-0, the number represents the container this thread was loaded in.
// It's absent in Firefox 97 and before, or in Firefox 98+ when this thread
// had no extra attribute at all.
userContextId?: number;
tracedObjectShapes?: Array<string[] | null>;
// The fields below this comment are derived data, and not present on the RawThread
// in the same form.
// Strings for profiles are collected into a single table, and are referred to by
// their index by other tables.
stringTable: StringTable;
// Sources for profiles are collected into a single table, containing file sources
// with their UUIDs and filenames.
sources: SourceTable;
// The stack samples collected for this thread. This field is different from
// RawThread in that the `time` column is always present.
samples: SamplesTable;
tracedValuesBuffer?: ArrayBuffer;
};
/**
* The derived samples table.
*/
export type SamplesTable = {
// Responsiveness is the older version of eventDelay. It injects events every 16ms.
// This is optional because newer profiles don't have that field anymore.
responsiveness?: Array<Milliseconds | null>;
// Event delay is the newer version of responsiveness. It allow us to get a finer-grained
// view of jank by inferring what would be the delay of a hypothetical input event at
// any point in time. It requires a pre-processing to be able to visualize properly.
// This is optional because older profiles didn't have that field.
eventDelay?: Array<Milliseconds | null>;
stack: Array<IndexIntoStackTable | null>;
time: Milliseconds[];
// An optional weight array. If not present, then the weight is assumed to be 1.
// See the WeightType type for more information.
weight: null | number[];
weightType: WeightType;
// The CPU percentage, between 0 and 100, over the time between the previous sample
// and this sample.
// This array has length + 1. The extra element at the end is the CPU percentage
// after the last sample. For a range-filtered thread, this is the corresponding
// element from the full thread.
// If the original thread has no CPU delta information, this array will contain
// synthetic values (all 100) and hasCPUDeltas will be false.
threadCPUPercent: Uint8Array;
// Whether the original thread information contained CPU delta information.
hasCPUDeltas: boolean;
// The category of each sample's stack in the unfiltered thread.
category: Uint8Array;
// The subcategory of each sample's stack in the unfiltered thread.
subcategory: Uint16Array | Uint8Array;
// This property isn't present in normal threads. However it's present for
// merged threads, so that we know the origin thread for these samples.
threadId?: Tid[];
argumentValues?: Array<number | null>;
length: number;
};
export type SampleCategoriesAndSubcategories = {
// represents a Map<IndexIntoSamplesTable, IndexIntoCategoryList>
sampleCategories: Uint8Array;
// represents a Map<IndexIntoSamplesTable, IndexIntoSubcategoryListForCategory>
sampleSubcategories: Uint16Array | Uint8Array;
};
export type SamplesLikeTable = {
stack: Array<IndexIntoStackTable | null>;
time: Milliseconds[];
// An optional weight array. If not present, then the weight is assumed to be 1.
// See the WeightType type for more information.
weight: null | number[];
weightType: WeightType;
argumentValues?: Array<number | null>;
length: number;
};
export type CounterSamplesTable = {
time: Milliseconds[];
// The number of times the Counter's "number" was changed since the previous sample.
// This property was mandatory until the format version 42, it was made optional in 43.
number?: number[];
// The count of the data, for instance for memory this would be bytes.
count: number[];
argumentValues?: Array<number | null>;
length: number;
};
export type Counter = {
name: string;
category: string;
description: string;
color?: GraphColor;
pid: Pid;
mainThreadIndex: ThreadIndex;
samples: CounterSamplesTable;
};
/**
* The `StackTable` type of the derived thread.
*
* The only difference from the `RawStackTable` is that the `StackTable` has a
* `category` and a `subcategory` column.
*
* The category of a stack node is always non-null and is derived from a stack's
* frame and its prefix. Frames can have null categories, stacks cannot. If a
* stack's frame has a null category, the stack inherits the category of its
* prefix stack. Root stacks whose frame has a null stack have their category
* set to the "default category". (The default category is currently defined as
* the category in the profile's category list whose color is "grey", and such
* a category is required to be present.)
*
* We compute the category information at the start of the thread transform
* pipeline, not at the end. This allows us to preserve categories more accurately
* when transforms are applied. Example:
*
* In the call path
* someJSFunction [JS] -> Node.insertBefore [DOM] -> nsAttrAndChildArray::InsertChildAt,
* the stack node for nsAttrAndChildArray::InsertChildAt should inherit the
* category DOM from its "Node.insertBefore" prefix stack. And it should keep
* the DOM category even if you apply the "Merge node into calling function"
* transform to Node.insertBefore. This transform removes the stack node
* "Node.insertBefore" from the stackTable, so the information about the DOM
* category would be lost if it wasn't inherited into the
* nsAttrAndChildArray::InsertChildAt stack before transforms are applied.
*/
export type StackTable = {
// Same as in RawStackTable
frame: IndexIntoFrameTable[];
prefix: Array<IndexIntoStackTable | null>;
length: number;
// Derived from RawStackTable + FrameTable
category: Uint8Array<ArrayBuffer>; // represents a Map<IndexIntoStackTable, IndexIntoCategoryList>
subcategory: Uint8Array<ArrayBuffer> | Uint16Array<ArrayBuffer>; // represents a Map<IndexIntoStackTable, IndexIntoSubcategoryListForCategory>
};
/**
* Similar to the StackTable, but based on functions rather than on frames.
*
* The CallNodeTable, like the StackTable, always describes the *non-inverted* tree.
* Indexes into its columns are the non-inverted call node indexes.
*
* # Detailed description
*
* The CallNodeTable is a table of function call information and represents the stacks of what
* functions were called, as opposed to stacks based on frames. There can be multiple
* frames for a single function call. Using stacks as opposed to a computed tree of
* CallNodes can cause duplicated functions in the call tree.
*
* For example:
*
* stack1 (funcA) callNode1 (funcA)
* | |
* v v
* stack2 (funcB) StackTable to callNode2 (funcB)
* | CallNodeTable |
* v -> v
* stack3 (funcC) callNode3 (funcC)
* / \ |
* V V v
* stack4 (funcD) stack5 (funcD) callNode4 (funcD)
* | | / \
* v V V V
* stack6 (funcE) stack7 (funcF) callNode5 (funcE) callNode6 (funcF)
*
* For a detailed explanation of callNodes see `docs-developer/call-tree.md` and
* `docs-developer/call-nodes-in-cpp.md`.
*
* # Call node ordering
*
* Call nodes are ordered in depth-first traversal order. This makes it super fast
* to check whether node A is a descendant of node B, because all subtrees are
* a contiguous range of call node indexes.
*
* More details about the ordering:
*
* - The node at index 0 is the first root node.
* - If a node A has children, then A + 1 is its first child.
* - If a node A has no children, then A + 1 is its next sibling, or the closest
* next sibling of an ancestor node if A doesn't have a next sibling.
* - For every node A, there's a single "index range" which contains this node
* and all its descendants: [A, callNodeTable.subtreeRangeEnd[A]).
* - This "tree of ranges" is well-nested.
* - The ordering of siblings doesn't have any meaning, i.e. it doesn't matter
* if a node is the first or the third child of its parent (they're not
* ordered by func or anything).
*
* Example:
*
* ```
* - 0 funcG
* - 1 funcH
* - 2 funcI
* - 3 funcG
* - 4 funcJ
* - 5 funcI
* - 6 funcK
* - 7 funcG
* - 8 funcL
* - 9 funcH
* ```
*
* In this example, the index range of the subtree of node 0 is [0, 6).
* The index range of the subtree of node 3 is [3, 4), i.e. the half-open range
* which only contains node 3.
*/
export type CallNodeTable = {
// The index of the parent call node, or -1 for root nodes.
prefix: Int32Array; // IndexIntoCallNodeTable -> IndexIntoCallNodeTable | -1
// The index of this node's next sibling, or -1 if this node is the last child / last root.
nextSibling: Int32Array; // IndexIntoCallNodeTable -> IndexIntoCallNodeTable | -1
// The index after this node's last descendant. If this node has a next sibling,
// subtreeRangeEnd is equal to nextSibling. Otherwise, this is the index
// of the next sibling of the closest ancestor node which has a next sibling.
// The last node has subtreeRangeEnd set to callNodeTable.length.
//
// The nodes in the range range [A, subtreeRangeEnd[A]) form A's subtree.
subtreeRangeEnd: Uint32Array; // IndexIntoCallNodeTable -> IndexIntoCallNodeTable
func: Int32Array; // IndexIntoCallNodeTable -> IndexIntoFuncTable
category: Int32Array; // IndexIntoCallNodeTable -> IndexIntoCategoryList
subcategory: Int32Array; // IndexIntoCallNodeTable -> IndexIntoSubcategoryListForCategory
innerWindowID: Float64Array; // IndexIntoCallNodeTable -> InnerWindowID
// IndexIntoNativeSymbolTable: all frames that collapsed into this call node inlined into the same native symbol
// -1: divergent: not all frames that collapsed into this call node were inlined, or they are from different symbols
// -2: no inlining
sourceFramesInlinedIntoSymbol: Int32Array;
// The depth of the call node. Roots have depth 0.
depth: Int32Array;
// The maximum value in the depth column, or -1 if this table is empty.
maxDepth: number;
// The number of call nodes. All columns in this table have this length.
length: number;
};
// A bitset which indicates something per call node. Use `checkBit` from
// utils/bitset to check whether a call node is part of the set.
export type CallNodeTableBitSet = BitSet;
export type LineNumber = number;
// Stores the line numbers which are hit by each stack, for one specific source
// file.
// Used to compute LineTimings in combination with a SamplesLikeTable.
//
// StackLineInfo can be computed once for a filtered thread. Then it is reused
// for the computation of different LineTimings as the preview selection changes.
//
// The order of these arrays is the same as the order of thread.stackTable;
// the array index is a stackIndex. Not all stacks are guaranteed to have a useful
// value; only stacks which are used as "self" stacks, i.e. stacks which are used
// in thread.samples.stack or in marker stacks / allocation stacks, are required
// to have their values computed - only these values will be accessed during the
// LineTimings computation.
//
// For stacks which are only used as prefix stack nodes, selfLine and
// stackLine may be null. This is fine because their values are not accessed
// during the LineTimings computation.
export type StackLineInfo = {
// Represents a Map<IndexIntoStackTable, IndexIntoLineSetTable | -1>
stackIndexToLineSetIndex: Int32Array;
// Stores entries representing a pair of (set of lines, self line), usually
// much much smaller than the stackTable because it only stores entries for
// the current source.
lineSetTable: SetCollectionTable<LineNumber>;
};
export type IndexIntoLineSetTable = IndexIntoSetCollectionTable;
// Stores, for all lines of one specific file, how many times each line is hit
// by samples in a thread. The maps only contain non-zero values.
// So map.get(line) === undefined should be treated as zero.
export type LineTimings = {
totalLineHits: Map<LineNumber, number>;
selfLineHits: Map<LineNumber, number>;
};
// Stores the addresses which are hit by each stack, for addresses belonging to
// one specific native symbol.
// Used to compute AddressTimings in combination with a SamplesLikeTable.
//
// StackAddressInfo can be computed once for a filtered thread. Then it is reused
// for the computation of different AddressTimings as the preview selection changes.
//
// The order of these arrays is the same as the order of thread.stackTable;
// the array index is a stackIndex. Not all stacks are guaranteed to have a useful
// value; only stacks which are used as "self" stacks, i.e. stacks which are used
// in thread.samples.stack or in marker stacks / allocation stacks, are required
// to have their values computed - only these values will be accessed during the
// AddressTimings computation.
//
// For stacks which are only used as prefix stack nodes, selfAddress and
// stackAddress may be null. This is fine because their values are not accessed
// during the AddressTimings computation.
export type StackAddressInfo = {
// Represents a Map<IndexIntoStackTable, IndexIntoAddressSetTable | -1>
stackIndexToAddressSetIndex: Int32Array;
// Stores entries representing the pair (set of addresses, self address), usually
// much much smaller than the stackTable because it only stores entries for the
// current native symbol.
addressSetTable: SetCollectionTable<Address>;
};
export type IndexIntoAddressSetTable = IndexIntoSetCollectionTable;
// Stores, for all addresses of one specific library, how many times each
// address is hit by samples in a thread. The maps only contain non-zero values.
// So map.get(address) === undefined should be treated as zero.
export type AddressTimings = {
totalAddressHits: Map<Address, number>;
selfAddressHits: Map<Address, number>;
};
// Stores the information that's needed to prove to the symbolication API that
// we are authorized to request the source code for a specific file.
// This "address proof" makes it easy for the browser (or local symbol server)
// to limit file access to only the set of files which are referenced by trusted
// symbol information, without forcing the browser (or local symbol server) to
// build a full list of such files upfront. Building a full list would take a
// long time - up to a minute. Checking individual addresses is much faster.
//
// By allowing access to only the files referenced by symbol information, we
// avoid giving malicious actors the ability to read arbitrary files.
// Specifically, this restriction protects against the following threats:
// - If source code is requested from the browser via the WebChannel, the check
// avoids exposing arbitrary files to a compromised profiler.firefox.com web
// page or to a compromised profiler.firefox.com content process. So the
// check only makes a difference in cases where the browser can no longer
// trust the profiler WebChannel.
// - If source code is requested from a local symbol server via an HTTP
// request, the check avoids exposing arbitrary files to a compromised
// profiler.firefox.com page, or to other web pages or outside actors who
// have guessed the correct URL to request source code from. Symbol servers
// will usually put a randomized token into the URL in order to make it even
// harder to guess the right URL. The address proof check is an extra layer
// of protection on top of that, in case the secret URL somehow leaks.
export type AddressProof = {
// The debugName of a library whose symbol information refers to the requested
// file.
debugName: string;
// The breakpadId of that library.
breakpadId: string;
// The address in that library for which the symbolicated frames refer to the
// requested file.
address: Address;
};
/**
* When working with call trees, individual nodes in the tree are not stable across
* different types of transformations and filtering operations. In order to refer
* to some place in the call tree we use a list of functions that either go from
* root to tip for normal call trees, or from tip to root for inverted call trees.
* These paths are then stored along with the implementation filter, and the whether
* or not the tree is inverted for a stable reference into a call tree.
*
* In some parts of the code the term prefix path is used to refer to a CallNodePath that
* goes from root to tip, and the term postfix path is used to refer to a CallNodePath
* that goes from tip to root.
*/
export type CallNodePath = IndexIntoFuncTable[];
/**
* This type contains the first derived `Marker[]` information, plus an IndexedArray
* to get back to the RawMarkerTable.
*/
export type DerivedMarkerInfo = {
markers: Marker[];
markerIndexToRawMarkerIndexes: IndexedArray<
MarkerIndex,
IndexIntoRawMarkerTable[]
>;
};
export type Marker = {
start: Milliseconds;
end: Milliseconds | null;
name: string;
category: IndexIntoCategoryList;
threadId: Tid | null;
data: MarkerPayload | null;
incomplete?: boolean;
};
/**
* A value with this type uniquely identifies a marker. This is the index of a
* marker in the full marker list (as returned by the selector `getFullMarkerList`),
* and the marker object is returned using the function `getMarker` as returned
* by the selector `getMarkerGetter`:
*
* const getMarker = selectedThreadSelectors.getMarkerGetter(state);
* const marker = getMarker(markerIndex);
*/
export type MarkerIndex = number;
export type CallNodeData = {
funcName: string;
total: number;
totalRelative: number;
self: number;
selfRelative: number;
};
export type ExtraBadgeInfo = {
name: string;
localizationId: string;
vars: unknown;
titleFallback: string;
contentFallback: string;
};
export type CallNodeDisplayData = Readonly<{
total: string;
totalWithUnit: string;
totalPercent: string;
self: string;
selfWithUnit: string;
name: string;
lib: string;
isFrameLabel: boolean;
categoryName: string;
categoryColor: string;
iconSrc: string | null;
badge?: ExtraBadgeInfo;
icon: string | null;
ariaLabel: string;
}>;
export type FuncTableWithReservedFunctions = {
funcTable: FuncTable;
reservedFunctionsForResources: Map<
IndexIntoResourceTable,
IndexIntoFuncTable
>;
};
/**
* The marker timing contains the necessary information to draw markers very quickly
* in the marker chart. It represents a single row of markers in the chart.
*/
export type MarkerTiming = {
// Start time in milliseconds.
start: number[];
// End time in milliseconds. It will equals start for instant markers.
end: number[];
index: MarkerIndex[];
name: string;
bucket: string;
// True if this marker timing contains only instant markers.
instantOnly: boolean;
length: number;
};
export type MarkerTimingRows = Array<MarkerTiming>;
/**
* Combined timing can be used in the Stack Chart. When this happens, the chart will
* either take both marker timing and stack timing, or just the stack timing information.
* This way, UserTiming markers can be shown together with the stack information.
*/
export type CombinedTimingRows =
| Array<MarkerTiming | StackTiming>
| Array<StackTiming>;
/**
* This type contains the necessary information to fully draw the marker chart. Each
* entry in the array represents a single fixed height row in the chart. The MarkerTiming
* represents the markers, and a bare string represents a marker "bucket". It is drawn
* as a single row in the marker chart, and serves as a separator between different
* areas. This flat array structure was chosen because it makes it really easy to
* loop through each row, and only draw the current subset on the screen.
*/
export type MarkerTimingAndBuckets = Array<MarkerTiming | string>;
export type JsTracerTiming = {
// Start time in milliseconds.
start: number[];
// End time in milliseconds.
end: number[];
index: IndexIntoJsTracerEvents[];
label: string[];
name: string;
func: Array<IndexIntoFuncTable | null>;
length: number;
};
/**
* The memory counter contains relative offsets of memory. This type provides a data
* structure that can be used to see the total range of change over all the samples.
*/
export type AccumulatedCounterSamples = {
readonly minCount: number;
readonly maxCount: number;
readonly countRange: number;
// This value holds the accumulation of all the previous counts in the Counter samples.
// For a memory counter, this gives the relative offset of bytes in that range
// selection. The array will share the indexes of the range filtered counter samples.
readonly accumulatedCounts: number[];
};
/**
* A collection of the data for all configured lines for a given marker
*/
export type CollectedCustomMarkerSamples = {
// This value holds the number per configured line
// selection. The array will share the indexes of the range filtered marker samples.
readonly numbersPerLine: number[][];
readonly markerIndexes: MarkerIndex[];
};
export type ValueBounds = {
readonly minNumber: number;
readonly maxNumber: number;
};
export type StackType = 'js' | 'native' | 'unsymbolicated';
export type GlobalTrack =
// mainThreadIndex is null when this is a fake global process added to contain
// real threads.
| {
readonly type: 'process';
readonly pid: Pid;
readonly mainThreadIndex: ThreadIndex | null;
}
| {
readonly type: 'screenshots';
readonly id: string;
readonly threadIndex: ThreadIndex;
}
| { readonly type: 'visual-progress' }
| { readonly type: 'perceptual-visual-progress' }
| { readonly type: 'contentful-visual-progress' };
export type LocalTrack =
| { readonly type: 'thread'; readonly threadIndex: ThreadIndex }
| { readonly type: 'network'; readonly threadIndex: ThreadIndex }
| { readonly type: 'memory'; readonly counterIndex: CounterIndex }
| { readonly type: 'bandwidth'; readonly counterIndex: CounterIndex }
| { readonly type: 'ipc'; readonly threadIndex: ThreadIndex }
| { readonly type: 'event-delay'; readonly threadIndex: ThreadIndex }
| { readonly type: 'process-cpu'; readonly counterIndex: CounterIndex }
| { readonly type: 'power'; readonly counterIndex: CounterIndex }
| {
readonly type: 'marker';
readonly threadIndex: ThreadIndex;
readonly markerSchema: MarkerSchema;
readonly markerName: IndexIntoStringTable;
};
export type Track = GlobalTrack | LocalTrack;
// A track index doesn't always represent uniquely a track: it's merely an index inside
// a specific structure:
// - for global tracks, this is the index in the global tracks array
// - for local tracks, this is the index in the local tracks array for a specific pid.
export type TrackIndex = number;
/**
* Type that holds the values of personally identifiable information that user
* wants to remove.
*/
export type RemoveProfileInformation = {
// Remove the given hidden threads if they are provided.
readonly shouldRemoveThreads: Set<ThreadIndex>;
// Remove the given counters if they are provided.
readonly shouldRemoveCounters: Set<CounterIndex>;
// Remove the screenshots if they are provided.
readonly shouldRemoveThreadsWithScreenshots: Set<ThreadIndex>;
// Remove the full time range if StartEndRange is provided.
readonly shouldFilterToCommittedRange: StartEndRange | null;
// Remove all the URLs if it's true.
readonly shouldRemoveUrls: boolean;
// Remove the extension list if it's true.
readonly shouldRemoveExtensions: boolean;
// Remove the preference values if it's true.
readonly shouldRemovePreferenceValues: boolean;
// Remove the private browsing data if it's true.
readonly shouldRemovePrivateBrowsingData: boolean;
// Remove the argument values captured by the JS execution tracer if it's true.
readonly shouldRemoveArgumentValues: boolean;
};
/**
* This const enum is used to decide how to highlight and stripe areas in the
* timeline.
*/
export const enum SelectedState {
// Samples can be filtered through various operations, like searching, or
// call tree transforms.
FilteredOutByTransform,
// This sample is selected because either the tip or an ancestor call node matches
// the currently selected call node.
Selected,
// This call node is not selected, and the stacks are ordered before the selected
// call node as sorted by the getTreeOrderComparator.
UnselectedOrderedBeforeSelected,
// This call node is not selected, and the stacks are ordered after the selected
// call node as sorted by the getTreeOrderComparator.
UnselectedOrderedAfterSelected,
}
/**
* It holds the initially selected track's HTMLElement. This allows the timeline
* to scroll the initially selected track into view once the page is loaded.
*/
export type InitialSelectedTrackReference = HTMLElement;
/**
* Page data for ProfileFilterNavigator component.
*/
export type ProfileFilterPageData = {
origin: string;
hostname: string;
favicon: string | null;
};
/**
* Information about the Tab selector state that is sorted by their tab activity
* scores.
*/
export type SortedTabPageData = Array<{
tabID: TabID;
tabScore: number;
pageData: ProfileFilterPageData;
}>;
export type CallNodeSelfAndSummary = {
// This property stores the amount of unit (time, bytes, count, etc.) spent in
// this call node and not in any of its descendant nodes.
callNodeSelf: Float64Array;
// The sum of absolute values in callNodeSelf.
// This is used for computing the percentages displayed in the call tree.
rootTotalSummary: number;
};
/**
* The self and total time, usually for a single call node.
* As with most places where the terms "self" and "total" are used, the meaning
* of the numbers depends on the context:
* - When used for "traced" timing, the values are Milliseconds.
* - Otherwise, the values are in the same unit as the sample weight type. For
* example, they could be sample counts, weights, or bytes.
*/
export type SelfAndTotal = { self: number; total: number };
/*
* Event delay table that holds the pre-processed event delay values and other
* statistics about it.
* Gecko sends the non processed event delay values to the front-end and we have
* to make a calculation to find out their real values. Also see:
* https://searchfox.org/mozilla-central/rev/3811b11b5773c1dccfe8228bfc7143b10a9a2a99/tools/profiler/core/platform.cpp#3000-3186
*/
export type EventDelayInfo = {
readonly eventDelays: Float32Array;
readonly minDelay: Milliseconds;
readonly maxDelay: Milliseconds;
readonly delayRange: Milliseconds;
};
/**
* This is a unique key that can be used in an object cache that represents either
* a single thread, or a selection of multiple threads. When it's a number, it's
* the ThreadIndex. When there are multiple threads, the key is a string of sorted,
* comma separated thread indexes, e.g. "5,7,10"
*/
export type ThreadsKey = string | number;
/**
* A representation of a native symbol which is independent from a thread.
* This is used for storing the global state of the assembly view, which needs
* to be independent from the selected thread. An IndexIntoNativeSymbolTable
* would only be meaningful within a thread.
* This can be removed if the native symbol table ever becomes global.
*/
export type NativeSymbolInfo = {
name: string;
address: Address;
// The number of bytes belonging to this function, starting at the symbol address.
// If functionSizeIsKnown is false, then this is a minimum size.
functionSize: Bytes;
functionSizeIsKnown: boolean;
libIndex: IndexIntoLibs;
};
/**
* Information about the initiating call node when the bottom box (source view +
* assembly view) is updated.
*/
export type BottomBoxInfo = {
libIndex: IndexIntoLibs | null;
sourceIndex: IndexIntoSourceTable | null;
nativeSymbols: NativeSymbolInfo[];
initialNativeSymbol: number | null; // index into `nativeSymbols`
// Optional line number + instruction address to scroll into view.
scrollToLineNumber?: number;
scrollToInstructionAddress?: number;
// Which lines / instructions to highlight (or none). This is used when clicking
// a stack frame in a marker stack.
highlightedLineNumber: number | null;
highlightedInstructionAddress: number | null;
};
/**
* Favicon data that is retrieved from the browser connection.
*/
export type FaviconData = {
readonly data: ArrayBuffer;
readonly mimeType: string;
};
/**
* Information about how the indexes in a profile have changed, for example
* after profile compaction.
*/
export type ProfileIndexTranslationMaps = {
oldThreadIndexToNew: Map<ThreadIndex, ThreadIndex> | null;
oldFuncCount: number;
newFuncCount: number;
oldStackToNewStackPlusOne: Int32Array;
oldFrameToNewFramePlusOne: Int32Array;
oldFuncToNewFuncPlusOne: Int32Array;
oldResourceToNewResourcePlusOne: Int32Array;
oldNativeSymbolToNewNativeSymbolPlusOne: Int32Array;
oldSourceToNewSourcePlusOne: Int32Array;
oldStringToNewStringPlusOne: Int32Array;
oldLibToNewLibPlusOne: Int32Array;
};
export type TransformEffectOnThreadData = {
dropIfOldStackIsNot?: BitSet;
oldStackToNewStack?: Int32Array; // drop if oldStackToNewStack[oldStack] === -1
};
export type TransformOutput = {
newStackTable: StackTable;
effectOnThreadData: TransformEffectOnThreadData;
};