Skip to content

Commit 792a074

Browse files
committed
Use Int32Array for the stackTable.prefix column.
The `prefix` column of both `RawStackTable` and `StackTable` is now an `Int32Array`, with `-1` (instead of `null`) indicating that a stack node is a root. The wire format changes accordingly, so the processed profile version is bumped to 63 with an upgrader that converts the column on load.
1 parent d116be9 commit 792a074

28 files changed

Lines changed: 562 additions & 450 deletions

docs-developer/CHANGELOG-formats.md

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

77
## Processed profile format
88

9+
### Version 66
10+
11+
The `prefix` column of `profile.shared.stackTable` now uses `-1` instead of `null`
12+
to indicate "this stack node is a root". In-memory it is now an `Int32Array`;
13+
on the JSON wire, the column is just an array of numbers (where `-1` marks a
14+
root).
15+
916
### Version 65
1017

1118
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.

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 = 65;
15+
export const PROCESSED_PROFILE_VERSION = 66;
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/app-logic/url-handling.ts

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1649,8 +1649,9 @@ function getStackIndexFromVersion3JSCallNodePath(
16491649
oldCallNodePath: CallNodePath
16501650
): IndexIntoStackTable | null {
16511651
const { stackTable, funcTable, frameTable } = shared;
1652-
const stackIndexDepth: Map<IndexIntoStackTable | null, number> = new Map();
1653-
stackIndexDepth.set(null, -1);
1652+
const stackIndexDepth: Map<IndexIntoStackTable, number> = new Map();
1653+
// Map key -1 represents the virtual root above all stack indexes.
1654+
stackIndexDepth.set(-1, -1);
16541655

16551656
for (let stackIndex = 0; stackIndex < stackTable.length; stackIndex++) {
16561657
const prefix = stackTable.prefix[stackIndex];
@@ -1659,9 +1660,8 @@ function getStackIndexFromVersion3JSCallNodePath(
16591660
const isJS = funcTable.isJS[funcIndex];
16601661
// We know that at this point stack table is sorted and the following
16611662
// condition holds:
1662-
// assert(prefixStack === null || prefixStack < stackIndex);
1663-
const doesPrefixMatchCallNodePath =
1664-
prefix === null || stackIndexDepth.has(prefix);
1663+
// assert(prefixStack === -1 || prefixStack < stackIndex);
1664+
const doesPrefixMatchCallNodePath = stackIndexDepth.has(prefix);
16651665

16661666
if (!doesPrefixMatchCallNodePath) {
16671667
continue;
@@ -1696,8 +1696,8 @@ function getVersion4JSCallNodePathFromStackIndex(
16961696
): CallNodePath {
16971697
const { funcTable, stackTable, frameTable } = shared;
16981698
const callNodePath = [];
1699-
let nextStackIndex: IndexIntoStackTable | null = stackIndex;
1700-
while (nextStackIndex !== null) {
1699+
let nextStackIndex: IndexIntoStackTable = stackIndex;
1700+
while (nextStackIndex !== -1) {
17011701
const frameIndex: IndexIntoFrameTable = stackTable.frame[nextStackIndex];
17021702
const funcIndex = frameTable.func[frameIndex];
17031703
if (funcTable.isJS[funcIndex] || funcTable.relevantForJS[funcIndex]) {

src/profile-logic/address-timings.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,7 @@ export function getStackAddressInfo(
127127
for (let stackIndex = 0; stackIndex < stackTable.length; stackIndex++) {
128128
const prefixStack = stackTable.prefix[stackIndex];
129129
const prefixAddressSet: IndexIntoAddressSetTable | -1 =
130-
prefixStack !== null ? stackIndexToAddressSetIndex[prefixStack] : -1;
130+
prefixStack !== -1 ? stackIndexToAddressSetIndex[prefixStack] : -1;
131131

132132
const frame = stackTable.frame[stackIndex];
133133
const nativeSymbolOfThisStack = frameTable.nativeSymbol[frame];

src/profile-logic/data-structures.ts

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -70,9 +70,14 @@ export function getRawStackTableBuilder(): RawStackTableBuilder {
7070
export function getRawStackTableBuilderWithExistingContents(
7171
existing: RawStackTable
7272
): RawStackTableBuilder {
73+
const prefix = new Array<IndexIntoStackTable | null>(existing.length);
74+
for (let i = 0; i < existing.length; i++) {
75+
const p = existing.prefix[i];
76+
prefix[i] = p === -1 ? null : p;
77+
}
7378
return {
7479
frame: [...existing.frame],
75-
prefix: [...existing.prefix],
80+
prefix,
7681
length: existing.length,
7782
};
7883
}
@@ -81,9 +86,14 @@ export function finishRawStackTableBuilder(
8186
builder: RawStackTableBuilder
8287
): RawStackTable {
8388
const { frame, prefix, length } = builder;
89+
const prefixCol = new Int32Array(length);
90+
for (let i = 0; i < length; i++) {
91+
const p = prefix[i];
92+
prefixCol[i] = p === null ? -1 : p;
93+
}
8494
return {
8595
frame: new Int32Array(frame),
86-
prefix,
96+
prefix: prefixCol,
8797
length,
8898
};
8999
}

src/profile-logic/import/chrome.ts

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,15 @@
55
import type {
66
Profile,
77
RawThread,
8-
RawStackTable,
98
IndexIntoStackTable,
109
MixedObject,
1110
} from 'firefox-profiler/types';
1211

13-
import { getEmptyProfile, getEmptyThread } from '../data-structures';
12+
import {
13+
getEmptyProfile,
14+
getEmptyThread,
15+
type RawStackTableBuilder,
16+
} from '../data-structures';
1417
import type { StringTable } from '../../utils/string-table';
1518
import { ensureExists, coerce } from '../../utils/types';
1619
import {
@@ -868,7 +871,7 @@ function getImageSize(
868871
* For sanity, check that stacks are ordered where the prefix stack
869872
* always preceeds the current stack index in the StackTable.
870873
*/
871-
function assertStackOrdering(stackTable: RawStackTable) {
874+
function assertStackOrdering(stackTable: RawStackTableBuilder) {
872875
const visitedStacks = new Set<number | null>([null]);
873876
for (let i = 0; i < stackTable.length; i++) {
874877
if (!visitedStacks.has(stackTable.prefix[i])) {

src/profile-logic/insert-stack-labels.ts

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44

55
import type {
66
IndexIntoFrameTable,
7-
IndexIntoStackTable,
87
RawStackTable,
98
IndexIntoFuncTable,
109
Profile,
@@ -199,7 +198,7 @@ export function insertStackLabels(
199198
for (let stackIndex = 0; stackIndex < oldStackTable.length; stackIndex++) {
200199
const parentStackIndex = oldStackTable.prefix[stackIndex];
201200
const inheritedLabelFrameIndex =
202-
parentStackIndex !== null
201+
parentStackIndex !== -1
203202
? inheritedLabelFrameIndexAtStack[parentStackIndex]
204203
: null;
205204
const frameIndex = oldStackTable.frame[stackIndex];
@@ -218,7 +217,7 @@ export function insertStackLabels(
218217
) {
219218
labelFrameIndexToInsertAtStack[stackIndex] = null;
220219
inheritedLabelFrameIndexAtStack[stackIndex] = null;
221-
} else if (parentStackIndex === null) {
220+
} else if (parentStackIndex === -1) {
222221
labelFrameIndexToInsertAtStack[stackIndex] = rootLabelFrameIndex;
223222
inheritedLabelFrameIndexAtStack[stackIndex] = rootLabelFrameIndex;
224223
stacksToInsertCount++;
@@ -230,7 +229,7 @@ export function insertStackLabels(
230229

231230
// Now compute the new stack table.
232231
const newStackCount = oldStackTable.length + stacksToInsertCount;
233-
const newPrefixCol = new Array<IndexIntoStackTable | null>(newStackCount);
232+
const newPrefixCol = new Int32Array(newStackCount);
234233
const newFrameCol = new Array<IndexIntoFrameTable>(newStackCount);
235234
const oldStackToNewStackPlusOne = new Int32Array(oldStackTable.length);
236235
let nextNewStackIndex = 0;
@@ -243,7 +242,7 @@ export function insertStackLabels(
243242
labelFrameIndexToInsertAtStack[oldStackIndex];
244243
const oldPrefix = oldStackTable.prefix[oldStackIndex];
245244
let newPrefix =
246-
oldPrefix !== null ? oldStackToNewStackPlusOne[oldPrefix] - 1 : null;
245+
oldPrefix !== -1 ? oldStackToNewStackPlusOne[oldPrefix] - 1 : -1;
247246
const frameIndex = oldStackTable.frame[oldStackIndex];
248247
if (labelFrameIndexToInsert !== null) {
249248
const insertedStackIndex = nextNewStackIndex++;

src/profile-logic/line-timings.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ export function getStackLineInfo(
5757
for (let stackIndex = 0; stackIndex < stackTable.length; stackIndex++) {
5858
const prefixStack = stackTable.prefix[stackIndex];
5959
const prefixLineSet: IndexIntoLineSetTable | -1 =
60-
prefixStack !== null ? stackIndexToLineSetIndex[prefixStack] : -1;
60+
prefixStack !== -1 ? stackIndexToLineSetIndex[prefixStack] : -1;
6161

6262
const frame = stackTable.frame[stackIndex];
6363
const func = frameTable.func[frame];

src/profile-logic/merge-compare.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1132,7 +1132,7 @@ function mergeStackTables(
11321132
);
11331133
const prefix = stackTable.prefix[i];
11341134
const newPrefix =
1135-
prefix === null ? null : oldStackToNewStackPlusOne[prefix] - 1;
1135+
prefix === -1 ? null : oldStackToNewStackPlusOne[prefix] - 1;
11361136

11371137
newStackTable.frame.push(frameIndex);
11381138
newStackTable.prefix.push(newPrefix);

src/profile-logic/process-profile.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2085,7 +2085,6 @@ export function serializeProfileToJsonSlabsFile(
20852085
// JSON" for these tables will become much smaller and we won't need to split
20862086
// out those tables anymore.
20872087
profile.threads,
2088-
profile.shared.stackTable,
20892088
profile.shared.frameTable,
20902089
profile.shared.funcTable,
20912090
profile.shared.stringArray,

0 commit comments

Comments
 (0)