Skip to content

Commit 079db2c

Browse files
committed
Make stackTable (sub)category derived data.
Stop storing them in the file, compute them at runtime. This reduces profile sizes.
1 parent cf6429d commit 079db2c

25 files changed

+46192
-84924
lines changed

src/app-logic/constants.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ export const GECKO_PROFILE_VERSION = 31;
1414
// The current version of the "processed" profile format.
1515
// Please don't forget to update the processed profile format changelog in
1616
// `docs-developer/CHANGELOG-formats.md`.
17-
export const PROCESSED_PROFILE_VERSION = 51;
17+
export const PROCESSED_PROFILE_VERSION = 52;
1818

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

src/profile-logic/data-structures.js

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import type {
1313
RawSamplesTable,
1414
SamplesTable,
1515
FrameTable,
16+
RawStackTable,
1617
StackTable,
1718
FuncTable,
1819
RawMarkerTable,
@@ -46,6 +47,18 @@ export function getEmptyStackTable(): StackTable {
4647
};
4748
}
4849

50+
export function getEmptyRawStackTable(): RawStackTable {
51+
return {
52+
// Important!
53+
// If modifying this structure, please update all callers of this function to ensure
54+
// that they are pushing on correctly to the data structure. These pushes may not
55+
// be caught by the type system.
56+
frame: [],
57+
prefix: [],
58+
length: 0,
59+
};
60+
}
61+
4962
/**
5063
* Returns an empty samples table with eventDelay field instead of responsiveness.
5164
* eventDelay is a new field and it replaced responsiveness. We should still
@@ -370,7 +383,7 @@ export function getEmptyThread(overrides?: $Shape<RawThread>): RawThread {
370383
// Creating samples with event delay since it's the new samples table.
371384
samples: getEmptySamplesTableWithEventDelay(),
372385
markers: getEmptyRawMarkerTable(),
373-
stackTable: getEmptyStackTable(),
386+
stackTable: getEmptyRawStackTable(),
374387
frameTable: getEmptyFrameTable(),
375388
stringArray: [],
376389
funcTable: getEmptyFuncTable(),

src/profile-logic/import/chrome.js

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@
44
// @flow
55
import type {
66
Profile,
7-
StackTable,
87
RawThread,
8+
RawStackTable,
99
IndexIntoFuncTable,
1010
IndexIntoStackTable,
1111
IndexIntoResourceTable,
@@ -688,8 +688,6 @@ async function processTracingEvents(
688688
frameTable.length = Math.max(frameTable.length, frameIndex + 1);
689689

690690
stackTable.frame.push(frameIndex);
691-
stackTable.category.push(category);
692-
stackTable.subcategory.push(0);
693691
stackTable.prefix.push(prefixStackIndex);
694692
nodeIdToStackId.set(nodeIndex, stackTable.length++);
695693
}
@@ -909,7 +907,7 @@ function getImageSize(
909907
* For sanity, check that stacks are ordered where the prefix stack
910908
* always preceeds the current stack index in the StackTable.
911909
*/
912-
function assertStackOrdering(stackTable: StackTable) {
910+
function assertStackOrdering(stackTable: RawStackTable) {
913911
const visitedStacks = new Set([null]);
914912
for (let i = 0; i < stackTable.length; i++) {
915913
if (!visitedStacks.has(stackTable.prefix[i])) {

src/profile-logic/import/dhat.js

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -215,8 +215,6 @@ export function attemptToConvertDhat(json: mixed): Profile | null {
215215
const rootFrameIndex = frameTable.length++;
216216

217217
stackTable.frame.push(rootFrameIndex);
218-
stackTable.category.push(otherCategory);
219-
stackTable.subcategory.push(otherSubCategory);
220218
stackTable.prefix.push(null);
221219
const rootStackIndex = stackTable.length++;
222220

@@ -333,8 +331,6 @@ export function attemptToConvertDhat(json: mixed): Profile | null {
333331
if (stackIndex === stackTable.length) {
334332
// No stack index was found, add on a new one.
335333
stackTable.frame.push(frameIndex);
336-
stackTable.category.push(otherCategory);
337-
stackTable.subcategory.push(otherSubCategory);
338334
stackTable.prefix.push(prefix);
339335

340336
if (candidateStackTables) {
@@ -399,8 +395,6 @@ export function attemptToConvertDhat(json: mixed): Profile | null {
399395
thread.frameTable.length = frameTable.length;
400396

401397
thread.stackTable.frame = stackTable.frame.slice();
402-
thread.stackTable.category = stackTable.category.slice();
403-
thread.stackTable.category = stackTable.category.slice();
404398
thread.stackTable.prefix = stackTable.prefix.slice();
405399
thread.stackTable.length = stackTable.length;
406400

src/profile-logic/js-tracer.js

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
import {
77
getEmptyFrameTable,
8-
getEmptyStackTable,
8+
getEmptyRawStackTable,
99
getEmptySamplesTableWithEventDelay,
1010
getEmptyRawMarkerTable,
1111
} from './data-structures';
@@ -508,7 +508,7 @@ export function convertJsTracerToThreadWithoutSamples(
508508
// Create a new thread, with empty information, but preserve some of the existing
509509
// thread information.
510510
const frameTable = getEmptyFrameTable();
511-
const stackTable = getEmptyStackTable();
511+
const stackTable = getEmptyRawStackTable();
512512
const samples: RawSamplesTable = {
513513
...getEmptySamplesTableWithEventDelay(),
514514
weight: [],
@@ -652,7 +652,6 @@ export function convertJsTracerToThreadWithoutSamples(
652652
// Each event gets a stack table entry.
653653
const stackIndex = stackTable.length++;
654654
stackTable.frame.push(frameIndex);
655-
stackTable.category.push(otherCategory);
656655
stackTable.prefix.push(prefixIndex);
657656
stackMap.set(tracerEventIndex, stackIndex);
658657

src/profile-logic/merge-compare.js

Lines changed: 4 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ import {
2020
getEmptyNativeSymbolTable,
2121
getEmptyFrameTable,
2222
getEmptyFuncTable,
23-
getEmptyStackTable,
23+
getEmptyRawStackTable,
2424
getEmptyRawMarkerTable,
2525
getEmptySamplesTableWithEventDelay,
2626
} from './data-structures';
@@ -55,8 +55,8 @@ import type {
5555
Lib,
5656
NativeSymbolTable,
5757
ResourceTable,
58-
StackTable,
5958
RawSamplesTable,
59+
RawStackTable,
6060
UrlState,
6161
ImplementationFilter,
6262
TransformStacksPerThread,
@@ -162,13 +162,6 @@ export function mergeProfilesForDiffing(
162162

163163
// We adjust the categories using the maps computed above.
164164
// TODO issue #2151: Also adjust subcategories.
165-
thread.stackTable = {
166-
...thread.stackTable,
167-
category: adjustCategories(
168-
thread.stackTable.category,
169-
translationMapsForCategories[i]
170-
),
171-
};
172165
thread.frameTable = {
173166
...thread.frameTable,
174167
category: adjustNullableCategories(
@@ -396,27 +389,6 @@ function mergeCategories(categoriesPerThread: Array<CategoryList | void>): {|
396389
return { categories: newCategories, translationMaps };
397390
}
398391

399-
/**
400-
* Adjusts the category indices in a category list using a translation map.
401-
*/
402-
function adjustCategories(
403-
categories: $ReadOnlyArray<IndexIntoCategoryList>,
404-
translationMap: TranslationMapForCategories
405-
): Array<IndexIntoCategoryList> {
406-
return categories.map((category) => {
407-
const result = translationMap.get(category);
408-
if (result === undefined) {
409-
throw new Error(
410-
stripIndent`
411-
Category with index ${category} hasn't been found in the translation map.
412-
This shouldn't happen and indicates a bug in the profiler's code.
413-
`
414-
);
415-
}
416-
return result;
417-
});
418-
}
419-
420392
/**
421393
* Adjusts the category indices in a category list using a translation map.
422394
*/
@@ -790,9 +762,9 @@ function combineFrameTables(
790762
function combineStackTables(
791763
translationMapsForFrames: TranslationMapForFrames[],
792764
threads: $ReadOnlyArray<RawThread>
793-
): { stackTable: StackTable, translationMaps: TranslationMapForStacks[] } {
765+
): { stackTable: RawStackTable, translationMaps: TranslationMapForStacks[] } {
794766
const translationMaps = [];
795-
const newStackTable = getEmptyStackTable();
767+
const newStackTable = getEmptyRawStackTable();
796768

797769
threads.forEach((thread, threadIndex) => {
798770
const { stackTable } = thread;
@@ -818,8 +790,6 @@ function combineStackTables(
818790
}
819791

820792
newStackTable.frame.push(newFrameIndex);
821-
newStackTable.category.push(stackTable.category[i]);
822-
newStackTable.subcategory.push(stackTable.subcategory[i]);
823793
newStackTable.prefix.push(newPrefix);
824794

825795
translationMap.set(i, newStackTable.length);

src/profile-logic/process-profile.js

Lines changed: 4 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -43,10 +43,9 @@ import type {
4343
RawThread,
4444
RawCounter,
4545
ExtensionTable,
46-
CategoryList,
4746
FrameTable,
4847
RawSamplesTable,
49-
StackTable,
48+
RawStackTable,
5049
RawMarkerTable,
5150
Lib,
5251
LibMapping,
@@ -616,44 +615,9 @@ function _processFrameTable(
616615
* Explicitly recreate the stack table here to help enforce our assumptions about types.
617616
* Also add a category column.
618617
*/
619-
function _processStackTable(
620-
geckoStackTable: GeckoStackStruct,
621-
frameTable: FrameTable,
622-
categories: CategoryList
623-
): StackTable {
624-
// Compute a non-null category for every stack
625-
const defaultCategory = categories.findIndex((c) => c.color === 'grey') || 0;
626-
const categoryColumn = new Array(geckoStackTable.length);
627-
const subcategoryColumn = new Array(geckoStackTable.length);
628-
for (let stackIndex = 0; stackIndex < geckoStackTable.length; stackIndex++) {
629-
const frameIndex = geckoStackTable.frame[stackIndex];
630-
const frameCategory = frameTable.category[frameIndex];
631-
const frameSubcategory = frameTable.subcategory[frameIndex];
632-
let stackCategory;
633-
let stackSubcategory;
634-
if (frameCategory !== null) {
635-
stackCategory = frameCategory;
636-
stackSubcategory = frameSubcategory || 0;
637-
} else {
638-
const prefix = geckoStackTable.prefix[stackIndex];
639-
if (prefix !== null) {
640-
// Because of the structure of the stack table, prefix < stackIndex.
641-
// So we've already computed the category for the prefix.
642-
stackCategory = categoryColumn[prefix];
643-
stackSubcategory = subcategoryColumn[prefix];
644-
} else {
645-
stackCategory = defaultCategory;
646-
stackSubcategory = 0;
647-
}
648-
}
649-
categoryColumn[stackIndex] = stackCategory;
650-
subcategoryColumn[stackIndex] = stackSubcategory;
651-
}
652-
618+
function _processStackTable(geckoStackTable: GeckoStackStruct): RawStackTable {
653619
return {
654620
frame: geckoStackTable.frame,
655-
category: categoryColumn,
656-
subcategory: subcategoryColumn,
657621
prefix: geckoStackTable.prefix,
658622
length: geckoStackTable.length,
659623
};
@@ -1132,7 +1096,7 @@ function _processThread(
11321096
);
11331097
11341098
const { libs, pausedRanges, meta } = processProfile;
1135-
const { categories, shutdownTime } = meta;
1099+
const { shutdownTime } = meta;
11361100
11371101
const mutatedStringArray = thread.stringTable.slice();
11381102
const stringTable = StringTable.withBackingArray(mutatedStringArray);
@@ -1151,11 +1115,7 @@ function _processThread(
11511115
frameFuncs,
11521116
frameAddresses
11531117
);
1154-
const stackTable = _processStackTable(
1155-
geckoStackTable,
1156-
frameTable,
1157-
categories
1158-
);
1118+
const stackTable = _processStackTable(geckoStackTable);
11591119
const { markers, jsAllocations, nativeAllocations } =
11601120
_processMarkers(geckoMarkers);
11611121
const samples = _processSamples(geckoSamples);

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

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2299,6 +2299,31 @@ const _upgraders = {
22992299
// marker data with the new field types data, and no modification is needed in the
23002300
// frontend to display older formats.
23012301
},
2302+
[52]: (profile) => {
2303+
for (const thread of profile.threads) {
2304+
const { frameTable, stackTable } = thread;
2305+
2306+
// Workaround for Lean profiles missing frameTable.category
2307+
if (!('category' in frameTable)) {
2308+
frameTable.category = [];
2309+
frameTable.subcategory = [];
2310+
for (let frameIndex = 0; frameIndex < frameTable.length; frameIndex++) {
2311+
frameTable.category[frameIndex] = null;
2312+
frameTable.subcategory[frameIndex] = null;
2313+
}
2314+
for (let stackIndex = 0; stackIndex < stackTable.length; stackIndex++) {
2315+
const frameIndex = stackTable.frame[stackIndex];
2316+
frameTable.category[frameIndex] = stackTable.category[stackIndex];
2317+
frameTable.subcategory[frameIndex] =
2318+
stackTable.subcategory[stackIndex];
2319+
}
2320+
}
2321+
2322+
// Remove stackTable.category and stackTable.subcategory.
2323+
delete stackTable.category;
2324+
delete stackTable.subcategory;
2325+
}
2326+
},
23022327
// If you add a new upgrader here, please document the change in
23032328
// `docs-developer/CHANGELOG-formats.md`.
23042329
};

0 commit comments

Comments
 (0)