Skip to content

Commit 46dde73

Browse files
committed
Allow the stackTable.frame column to contain an Int32Array.
This is the first typed array that we're supporting inside the profile format. When a profile is saved in the JsonSlabs format, it will now have this column as a separate slab that doesn't require JSON parsing. Profile compacting now always turns `stackTable.frame` into a typed array, even if that column was a regular JS array in the input profile. We still allow a regular JSON array here, because profiles stored as JSON cannot contain typed arrays, and we want to use the same type definition for JSON and JSLB profiles. Here's how this change impacts profile sizes and loading times on this profile: https://storage.googleapis.com/profiler-get-symbols-fixtures/large-speedometer3-profile.json.gz | Version | .jslb.gz size | .jslb size | Load time | Profile of it loading | |---------|---------------|------------|-------------|-----------------------------------| | 64 | 122 MB | 605 MB | 7.6 seconds | https://share.firefox.dev/4ogUKba | | 65 | 125 MB | 544 MB | 6.0 seconds | https://share.firefox.dev/3Qopiem | The compressed size has grown a small bit, but the other savings are significant: - We no longer have 131 MB of text for the frame column in the JSON - the frame column is now stored in a 70 MB i32 slab. - Less time in GZ decompression, because the uncompressed size is now smaller. - There is a lot less time spent in TextDecoder.decode and JSON.parse, because we're no longer decoding and parsing 131 MB of text for the frame column.
1 parent 080ba39 commit 46dde73

10 files changed

Lines changed: 87 additions & 33 deletions

File tree

docs-developer/CHANGELOG-formats.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,10 @@ Note that this is not an exhaustive list. Processed profile format upgraders can
66

77
## Processed profile format
88

9+
### Version 65
10+
11+
The stack table's `frame` column (stored at `profile.shared.stackTable.frame`) can now optionally be stored as an `Int32Array`, for profiles loaded from [JsonSlabs](https://github.com/mstange/json-slabs/) files (.jslb, .jslb.gz). Regular JS / JSON arrays are still accepted.
12+
913
### Version 64
1014

1115
A new `SourceLocationTable` has been added to `profile.shared.sourceLocationTable`. It holds the original (pre-compilation) source positions produced by source map symbolication, paired with the generated `line`/`column` already on `FrameTable`.

src/app-logic/constants.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ export const GECKO_PROFILE_VERSION = 34;
1212
// The current version of the "processed" profile format.
1313
// Please don't forget to update the processed profile format changelog in
1414
// `docs-developer/CHANGELOG-formats.md`.
15-
export const PROCESSED_PROFILE_VERSION = 64;
15+
export const PROCESSED_PROFILE_VERSION = 65;
1616

1717
// The following are the margin sizes for the left and right of the timeline. Independent
1818
// components need to share these values.

src/profile-logic/data-structures.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ export function finishRawStackTableBuilder(
8282
): RawStackTable {
8383
const { frame, prefix, length } = builder;
8484
return {
85-
frame,
85+
frame: new Int32Array(frame),
8686
prefix,
8787
length,
8888
};

src/profile-logic/processed-profile-versioning.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3255,6 +3255,11 @@ const _upgraders: {
32553255
};
32563256
sources.content = new Array(sources.length).fill(null);
32573257
},
3258+
[65]: (_profile: any) => {
3259+
// The type of `profile.shared.stackTable.frame` was changed from
3260+
// `IndexIntoFrameTable[]` to `IndexIntoFrameTable[] | Int32Array<ArrayBuffer>`.
3261+
// All valid v64 profiles are valid v65 profiles, so no upgrader is needed.
3262+
}
32583263
// If you add a new upgrader here, please document the change in
32593264
// `docs-developer/CHANGELOG-formats.md`.
32603265
};

src/profile-logic/profile-compacting.ts

Lines changed: 51 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -48,22 +48,33 @@ type ColumnDescription<TCol> = null extends (
4848
| { type: 'INDEX_REF_OR_NULL'; referencedTable: TableCompactionState }
4949
| { type: 'SELF_INDEX_REF_OR_NULL' }
5050
| { type: 'NO_REF' }
51-
:
52-
| { type: 'INDEX_REF'; referencedTable: TableCompactionState }
53-
| { type: 'INDEX_REF_OR_NEG_ONE'; referencedTable: TableCompactionState }
54-
| { type: 'NO_REF' };
51+
: Int32Array<ArrayBuffer> extends TCol
52+
?
53+
| { type: 'INDEX_REF_INT32'; referencedTable: TableCompactionState }
54+
| { type: 'NO_REF' }
55+
:
56+
| { type: 'INDEX_REF'; referencedTable: TableCompactionState }
57+
| {
58+
type: 'INDEX_REF_OR_NEG_ONE';
59+
referencedTable: TableCompactionState;
60+
}
61+
| { type: 'NO_REF' };
5562

5663
type TableDescription<T> = {
57-
[K in keyof T as T[K] extends Array<any> ? K : never]: ColumnDescription<
58-
T[K]
59-
>;
64+
[K in keyof T as T[K] extends Array<any> | Int32Array<ArrayBuffer>
65+
? K
66+
: never]: ColumnDescription<T[K]>;
6067
};
6168

6269
const ColDesc = {
6370
indexRef: (referencedTable: TableCompactionState) => ({
6471
type: 'INDEX_REF' as const,
6572
referencedTable,
6673
}),
74+
indexRefInt32: (referencedTable: TableCompactionState) => ({
75+
type: 'INDEX_REF_INT32' as const,
76+
referencedTable,
77+
}),
6778
indexRefOrNull: (referencedTable: TableCompactionState) => ({
6879
type: 'INDEX_REF_OR_NULL' as const,
6980
referencedTable,
@@ -145,7 +156,7 @@ export function computeCompactedProfile(
145156
};
146157

147158
const stackTableDesc: TableDescription<RawStackTable> = {
148-
frame: ColDesc.indexRef(tcs.frameTable),
159+
frame: ColDesc.indexRefInt32(tcs.frameTable),
149160
prefix: ColDesc.selfIndexRefOrNull(),
150161
};
151162
const frameTableDesc: TableDescription<FrameTable> = {
@@ -326,6 +337,7 @@ function _markTableAndComputeTranslation<T>(
326337
const col = (table as any)[key];
327338
switch (desc.type) {
328339
case 'INDEX_REF':
340+
case 'INDEX_REF_INT32':
329341
markColumn(col, markBuffer, desc.referencedTable.markBuffer);
330342
break;
331343
case 'INDEX_REF_OR_NULL':
@@ -354,7 +366,13 @@ function _markTableAndComputeTranslation<T>(
354366
thisTableCompactionState.computeIndexTranslation();
355367
}
356368

357-
function markColumn(col: Array<number>, shouldMark: BitSet, markBuf: BitSet) {
369+
function markColumn(
370+
col: Array<number> | Int32Array<ArrayBuffer>,
371+
shouldMark: BitSet,
372+
markBuf: BitSet
373+
) {
374+
// Polymorphic: indexing works the same on Int32Array as on number[], so the
375+
// INDEX_REF and INDEX_REF_INT32 cases share this function.
358376
for (let i = 0; i < col.length; i++) {
359377
if (checkBit(shouldMark, i)) {
360378
const val = col[i];
@@ -499,6 +517,14 @@ function _compactTable<T extends { length: number }>(
499517
newLength
500518
);
501519
break;
520+
case 'INDEX_REF_INT32':
521+
result[key] = _compactColIndexInt32(
522+
oldCol,
523+
markBuffer,
524+
desc.referencedTable.oldIndexToNewIndexPlusOne,
525+
newLength
526+
);
527+
break;
502528
case 'INDEX_REF_OR_NULL':
503529
result[key] = _compactColIndexOrNull(
504530
oldCol,
@@ -564,6 +590,22 @@ function _compactColIndex(
564590
return newCol;
565591
}
566592

593+
function _compactColIndexInt32(
594+
oldCol: Int32Array<ArrayBuffer>,
595+
markBuffer: BitSet,
596+
oldIndexToNewIndexPlusOne: Int32Array,
597+
newLength: number
598+
): Int32Array<ArrayBuffer> {
599+
const newCol = new Int32Array(newLength);
600+
let newIndex = 0;
601+
for (let i = 0; i < oldCol.length; i++) {
602+
if (checkBit(markBuffer, i)) {
603+
newCol[newIndex++] = oldIndexToNewIndexPlusOne[oldCol[i]] - 1;
604+
}
605+
}
606+
return newCol;
607+
}
608+
567609
function _compactColIndexOrNull(
568610
oldCol: (number | null)[],
569611
markBuffer: BitSet,

src/profile-logic/profile-data.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4766,7 +4766,10 @@ export function computeStackTableFromRawStackTable(
47664766
}
47674767

47684768
// The frame column is a typed array in the derived stack table.
4769-
const frame = new Int32Array(rawStackTable.frame);
4769+
const frame =
4770+
rawStackTable.frame instanceof Int32Array
4771+
? rawStackTable.frame
4772+
: new Int32Array(rawStackTable.frame);
47704773

47714774
return {
47724775
frame,

src/test/store/__snapshots__/profile-view.test.ts.snap

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -676,7 +676,7 @@ Object {
676676
"startLine": Array [],
677677
},
678678
"stackTable": Object {
679-
"frame": Array [
679+
"frame": Int32Array [
680680
0,
681681
1,
682682
2,

src/test/unit/__snapshots__/profile-conversion.test.ts.snap

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -43096,7 +43096,7 @@ Object {
4309643096
"startLine": Array [],
4309743097
},
4309843098
"stackTable": Object {
43099-
"frame": Array [
43099+
"frame": Int32Array [
4310043100
0,
4310143101
1,
4310243102
2,
@@ -167262,7 +167262,7 @@ Object {
167262167262
"startLine": Array [],
167263167263
},
167264167264
"stackTable": Object {
167265-
"frame": Array [
167265+
"frame": Int32Array [
167266167266
0,
167267167267
1,
167268167268
2,
@@ -329817,7 +329817,7 @@ Object {
329817329817
],
329818329818
},
329819329819
"stackTable": Object {
329820-
"frame": Array [
329820+
"frame": Int32Array [
329821329821
0,
329822329822
1,
329823329823
2,
@@ -364798,7 +364798,7 @@ Object {
364798364798
],
364799364799
},
364800364800
"stackTable": Object {
364801-
"frame": Array [
364801+
"frame": Int32Array [
364802364802
0,
364803364803
1,
364804364804
2,
@@ -400087,7 +400087,7 @@ Object {
400087400087
],
400088400088
},
400089400089
"stackTable": Object {
400090-
"frame": Array [
400090+
"frame": Int32Array [
400091400091
0,
400092400092
1,
400093400093
2,
@@ -401993,7 +401993,7 @@ Object {
401993401993
"startLine": Array [],
401994401994
},
401995401995
"stackTable": Object {
401996-
"frame": Array [],
401996+
"frame": Int32Array [],
401997401997
"length": 0,
401998401998
"prefix": Array [],
401999401999
},
@@ -406722,7 +406722,7 @@ Object {
406722406722
],
406723406723
},
406724406724
"stackTable": Object {
406725-
"frame": Array [
406725+
"frame": Int32Array [
406726406726
0,
406727406727
1,
406728406728
2,
@@ -411314,7 +411314,7 @@ Object {
411314411314
],
411315411315
},
411316411316
"stackTable": Object {
411317-
"frame": Array [
411317+
"frame": Int32Array [
411318411318
0,
411319411319
1,
411320411320
2,
@@ -414267,7 +414267,7 @@ Object {
414267414267
],
414268414268
},
414269414269
"stackTable": Object {
414270-
"frame": Array [
414270+
"frame": Int32Array [
414271414271
0,
414272414272
1,
414273414273
2,
@@ -417285,7 +417285,7 @@ Object {
417285417285
"startLine": Array [],
417286417286
},
417287417287
"stackTable": Object {
417288-
"frame": Array [
417288+
"frame": Int32Array [
417289417289
0,
417290417290
1,
417291417291
2,
@@ -429901,7 +429901,7 @@ Object {
429901429901
"startLine": Array [],
429902429902
},
429903429903
"stackTable": Object {
429904-
"frame": Array [
429904+
"frame": Int32Array [
429905429905
0,
429906429906
1,
429907429907
2,
@@ -439076,7 +439076,7 @@ Object {
439076439076
"startLine": Array [],
439077439077
},
439078439078
"stackTable": Object {
439079-
"frame": Array [
439079+
"frame": Int32Array [
439080439080
0,
439081439081
1,
439082439082
2,
@@ -454858,7 +454858,7 @@ Object {
454858454858
"startLine": Array [],
454859454859
},
454860454860
"stackTable": Object {
454861-
"frame": Array [
454861+
"frame": Int32Array [
454862454862
0,
454863454863
1,
454864454864
2,
@@ -499592,7 +499592,7 @@ Object {
499592499592
"startLine": Array [],
499593499593
},
499594499594
"stackTable": Object {
499595-
"frame": Array [
499595+
"frame": Int32Array [
499596499596
0,
499597499597
1,
499598499598
2,
@@ -559132,7 +559132,7 @@ Object {
559132559132
"startLine": Array [],
559133559133
},
559134559134
"stackTable": Object {
559135-
"frame": Array [
559135+
"frame": Int32Array [
559136559136
0,
559137559137
1,
559138559138
2,
@@ -594273,7 +594273,7 @@ Object {
594273594273
],
594274594274
},
594275594275
"stackTable": Object {
594276-
"frame": Array [
594276+
"frame": Int32Array [
594277594277
0,
594278594278
56,
594279594279
55,
@@ -600033,7 +600033,7 @@ Object {
600033600033
"startLine": Array [],
600034600034
},
600035600035
"stackTable": Object {
600036-
"frame": Array [
600036+
"frame": Int32Array [
600037600037
0,
600038600038
1,
600039600039
2,
@@ -905556,7 +905556,7 @@ Object {
905556905556
"startLine": Array [],
905557905557
},
905558905558
"stackTable": Object {
905559-
"frame": Array [
905559+
"frame": Int32Array [
905560905560
0,
905561905561
1,
905562905562
2,

src/test/unit/__snapshots__/profile-upgrading.test.ts.snap

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2781,7 +2781,7 @@ Object {
27812781
"startLine": Array [],
27822782
},
27832783
"stackTable": Object {
2784-
"frame": Array [
2784+
"frame": Int32Array [
27852785
0,
27862786
1,
27872787
2,

src/types/profile.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ export type Pid = string;
6060
* to storing them as actual lists of frames.
6161
*/
6262
export type RawStackTable = {
63-
frame: IndexIntoFrameTable[];
63+
frame: IndexIntoFrameTable[] | Int32Array<ArrayBuffer>;
6464
prefix: Array<IndexIntoStackTable | null>;
6565
length: number;
6666
};

0 commit comments

Comments
 (0)