Skip to content

Commit 2cf85e6

Browse files
authored
In the profile format, store a shared stringArray for all threads (#5481)
This implements the next incremental step for #3918. The shared `stringArray` is stored at `profile.shared.stringArray`. Sharing the string table is an easy first step - at least easier than sharing other tables - because there are no string indexes in the URL, so we don't need a URL upgrader for this modification. I've also folded some basic "compacting" into this PR: Before upload, we will remove any unused strings from the shared stringArray.
2 parents eda47ae + ddb4eeb commit 2cf85e6

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

61 files changed

+35803
-41056
lines changed

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 56
10+
11+
The `stringArray` is now shared across threads. The shared array is stored at `profile.shared.stringArray`.
12+
913
### Version 55
1014

1115
Changes to the `MarkerSchema` type which is used for the elements of the array at `profile.meta.markerSchema`:

src/actions/receive-profile.js

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -398,7 +398,7 @@ export function finalizeFullProfileView(
398398
const thread = profile.threads[threadIndex];
399399
const { samples, jsAllocations, nativeAllocations } = thread;
400400
hasSamples = [samples, jsAllocations, nativeAllocations].some((table) =>
401-
hasUsefulSamples(table?.stack, thread)
401+
hasUsefulSamples(table?.stack, thread, profile.shared)
402402
);
403403
if (hasSamples) {
404404
break;
@@ -799,7 +799,7 @@ export function bulkProcessSymbolicationSteps(
799799
symbolicationStepsPerThread: Map<ThreadIndex, SymbolicationStepInfo[]>
800800
): ThunkAction<void> {
801801
return (dispatch, getState) => {
802-
const { threads } = getProfile(getState());
802+
const { threads, shared } = getProfile(getState());
803803
const oldFuncToNewFuncsMaps: Map<ThreadIndex, FuncToFuncsMap> = new Map();
804804
const symbolicatedThreads = threads.map((oldThread, threadIndex) => {
805805
const symbolicationSteps = symbolicationStepsPerThread.get(threadIndex);
@@ -808,6 +808,7 @@ export function bulkProcessSymbolicationSteps(
808808
}
809809
const { thread, oldFuncToNewFuncsMap } = applySymbolicationSteps(
810810
oldThread,
811+
shared,
811812
symbolicationSteps
812813
);
813814
oldFuncToNewFuncsMaps.set(threadIndex, oldFuncToNewFuncsMap);
@@ -1903,7 +1904,7 @@ export function changeTabFilter(tabID: TabID | null): ThunkAction<void> {
19031904
const thread = profile.threads[threadIndex];
19041905
const { samples, jsAllocations, nativeAllocations } = thread;
19051906
hasSamples = [samples, jsAllocations, nativeAllocations].some((table) =>
1906-
hasUsefulSamples(table?.stack, thread)
1907+
hasUsefulSamples(table?.stack, thread, profile.shared)
19071908
);
19081909
if (hasSamples) {
19091910
break;

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 = 55;
17+
export const PROCESSED_PROFILE_VERSION = 56;
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/components/js-tracer/Chart.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import { JsTracerCanvas } from './Canvas';
1515
import {
1616
getCommittedRange,
1717
getPreviewSelection,
18+
getStringTable,
1819
} from 'firefox-profiler/selectors/profile';
1920
import { selectedThreadSelectors } from 'firefox-profiler/selectors/per-thread';
2021
import { getSelectedThreadsKey } from 'firefox-profiler/selectors/url-state';
@@ -136,7 +137,7 @@ const JsTracerExpensiveChart = explicitConnect<
136137
>({
137138
mapStateToProps: (state, ownProps) => ({
138139
timeRange: getCommittedRange(state),
139-
stringTable: selectedThreadSelectors.getStringTable(state),
140+
stringTable: getStringTable(state),
140141
threadsKey: getSelectedThreadsKey(state),
141142
previewSelection: getPreviewSelection(state),
142143
jsTracerTimingRows: ensureExists(

src/profile-logic/active-tab.js

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -67,15 +67,20 @@ export function computeActiveTabTracks(
6767
const screenshots = [];
6868
const topmostInnerWindowIDs = getTopmostInnerWindowIDs(relevantPages);
6969
const innerWindowIDToPageMap = _getInnerWindowIDToPageMap(relevantPages);
70+
const { stringArray } = profile.shared;
71+
const stringTable = StringTable.withBackingArray(stringArray);
72+
73+
const screenshotNameIndex = stringTable.indexForString(
74+
'CompositorScreenshot'
75+
);
7076

7177
for (
7278
let threadIndex = 0;
7379
threadIndex < profile.threads.length;
7480
threadIndex++
7581
) {
7682
const thread = profile.threads[threadIndex];
77-
const { markers, stringArray } = thread;
78-
const stringTable = StringTable.withBackingArray(stringArray);
83+
const { markers } = thread;
7984

8085
if (thread.isMainThread) {
8186
// This is a main thread, there is a possibility that it can be a global
@@ -120,9 +125,6 @@ export function computeActiveTabTracks(
120125

121126
// Check for screenshots.
122127
const windowIDs: Set<string> = new Set();
123-
const screenshotNameIndex = stringTable.indexForString(
124-
'CompositorScreenshot'
125-
);
126128
if (screenshotNameIndex !== -1) {
127129
for (let markerIndex = 0; markerIndex < markers.length; markerIndex++) {
128130
if (markers.name[markerIndex] === screenshotNameIndex) {

src/profile-logic/data-structures.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -397,7 +397,6 @@ export function getEmptyThread(overrides?: $Shape<RawThread>): RawThread {
397397
markers: getEmptyRawMarkerTable(),
398398
stackTable: getEmptyRawStackTable(),
399399
frameTable: getEmptyFrameTable(),
400-
stringArray: [],
401400
funcTable: getEmptyFuncTable(),
402401
resourceTable: getEmptyResourceTable(),
403402
nativeSymbols: getEmptyNativeSymbolTable(),
@@ -436,6 +435,9 @@ export function getEmptyProfile(): Profile {
436435
},
437436
libs: [],
438437
pages: [],
438+
shared: {
439+
stringArray: [],
440+
},
439441
threads: [],
440442
};
441443
}

src/profile-logic/import/chrome.js

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -512,6 +512,8 @@ async function processTracingEvents(
512512
// new samples on our target interval of 500us.
513513
profile.meta.interval = 0.5;
514514

515+
const stringTable = StringTable.withBackingArray(profile.shared.stringArray);
516+
515517
let profileEvents: (ProfileEvent | CpuProfileEvent)[] =
516518
(eventsByName.get('Profile'): any) || [];
517519

@@ -577,13 +579,10 @@ async function processTracingEvents(
577579
funcTable,
578580
frameTable,
579581
stackTable,
580-
stringArray,
581582
samples: samplesTable,
582583
resourceTable,
583584
} = thread;
584585

585-
const stringTable = StringTable.withBackingArray(stringArray);
586-
587586
if (nodes) {
588587
const parentMap = new Map();
589588
for (const node of nodes) {
@@ -839,7 +838,7 @@ async function extractScreenshots(
839838
screenshots[0]
840839
);
841840

842-
const stringTable = StringTable.withBackingArray(thread.stringArray);
841+
const stringTable = StringTable.withBackingArray(profile.shared.stringArray);
843842

844843
const graphicsIndex = ensureExists(profile.meta.categories).findIndex(
845844
(category) => category.name === 'Graphics'
@@ -930,6 +929,8 @@ function extractMarkers(
930929
throw new Error('No "Other" category in empty profile category list');
931930
}
932931

932+
const stringTable = StringTable.withBackingArray(profile.shared.stringArray);
933+
933934
profile.meta.markerSchema = [
934935
{
935936
name: 'EventDispatch',
@@ -996,8 +997,7 @@ function extractMarkers(
996997
event
997998
);
998999
const { thread } = threadInfo;
999-
const { markers, stringArray } = thread;
1000-
const stringTable = StringTable.withBackingArray(stringArray);
1000+
const { markers } = thread;
10011001
let argData: MixedObject | null = null;
10021002
if (event.args && typeof event.args === 'object') {
10031003
argData = (event.args: any).data || null;

src/profile-logic/import/dhat.js

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -180,10 +180,10 @@ export function attemptToConvertDhat(json: mixed): Profile | null {
180180
const profile = getEmptyProfile();
181181
profile.meta.product = dhat.cmd + ' (dhat)';
182182
profile.meta.importedFrom = `dhat`;
183+
const stringTable = StringTable.withBackingArray(profile.shared.stringArray);
183184

184185
const allocationsTable = getEmptyUnbalancedNativeAllocationsTable();
185-
const { funcTable, stringArray, stackTable, frameTable } = getEmptyThread();
186-
const stringTable = StringTable.withBackingArray(stringArray);
186+
const { funcTable, stackTable, frameTable } = getEmptyThread();
187187

188188
const funcKeyToFuncIndex = new Map<string, IndexIntoFuncTable>();
189189

@@ -371,7 +371,6 @@ export function attemptToConvertDhat(json: mixed): Profile | null {
371371
thread.pid = dhat.pid;
372372
thread.tid = i;
373373
thread.name = name;
374-
thread.stringArray = stringTable.getBackingArray();
375374

376375
thread.funcTable.name = funcTable.name.slice();
377376
thread.funcTable.isJS = funcTable.isJS.slice();

src/profile-logic/import/simpleperf.js

Lines changed: 20 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -223,24 +223,30 @@ class FirefoxThread {
223223
tid: number;
224224
pid: number;
225225

226-
stringArray = [];
227-
strings = StringTable.withBackingArray(this.stringArray);
226+
strings: StringTable;
228227

229228
sampleTable: RawSamplesTable = getEmptySamplesTable();
230229

231-
stackTable: FirefoxSampleTable = new FirefoxSampleTable(this.strings);
232-
frameTable: FirefoxFrameTable = new FirefoxFrameTable(this.strings);
233-
funcTable: FirefoxFuncTable = new FirefoxFuncTable(this.strings);
234-
resourceTable: FirefoxResourceTable = new FirefoxResourceTable(this.strings);
230+
stackTable: FirefoxSampleTable;
231+
frameTable: FirefoxFrameTable;
232+
funcTable: FirefoxFuncTable;
233+
resourceTable: FirefoxResourceTable;
235234

236235
cpuClockEventId: number = -1;
237236

238-
constructor(thread: report.IThread) {
237+
constructor(thread: report.IThread, stringTable: StringTable) {
239238
this.tid = thread.threadId;
240239
this.pid = thread.processId;
241240

242241
this.isMainThread = thread.threadId === thread.processId;
243242
this.name = thread.threadName ?? '';
243+
244+
this.strings = stringTable;
245+
246+
this.stackTable = new FirefoxSampleTable(this.strings);
247+
this.frameTable = new FirefoxFrameTable(this.strings);
248+
this.funcTable = new FirefoxFuncTable(this.strings);
249+
this.resourceTable = new FirefoxResourceTable(this.strings);
244250
}
245251

246252
toJson(): RawThread {
@@ -259,7 +265,6 @@ class FirefoxThread {
259265
markers: getEmptyRawMarkerTable(),
260266
stackTable: this.stackTable.toJson(),
261267
frameTable: this.frameTable.toJson(),
262-
stringArray: this.stringArray,
263268
funcTable: this.funcTable.toJson(),
264269
resourceTable: this.resourceTable.toJson(),
265270
nativeSymbols: getEmptyNativeSymbolTable(),
@@ -358,10 +363,16 @@ class FirefoxProfile {
358363
sampleCount: number = 0;
359364
lostCount: number = 0;
360365

366+
stringArray = [];
367+
stringTable = StringTable.withBackingArray(this.stringArray);
368+
361369
toJson(): Profile {
362370
return {
363371
meta: this.getProfileMeta(),
364372
libs: [],
373+
shared: {
374+
stringArray: this.stringArray,
375+
},
365376
threads: this.threads.map((thread) => thread.toJson()),
366377
};
367378
}
@@ -439,7 +450,7 @@ class FirefoxProfile {
439450
}
440451

441452
addThread(thread: report.IThread) {
442-
const firefoxThread = new FirefoxThread(thread);
453+
const firefoxThread = new FirefoxThread(thread, this.stringTable);
443454
this.threads.push(firefoxThread);
444455
this.threadMap.set(thread.threadId, firefoxThread);
445456
}

src/profile-logic/js-tracer.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -738,10 +738,10 @@ export function getJsTracerFixed(jsTracer: JsTracerTable): JsTracerFixed {
738738
export function convertJsTracerToThread(
739739
fromThread: RawThread,
740740
jsTracer: JsTracerTable,
741-
categories: CategoryList
741+
categories: CategoryList,
742+
stringTable: StringTable
742743
): RawThread {
743744
const jsTracerFixed = getJsTracerFixed(jsTracer);
744-
const stringTable = StringTable.withBackingArray(fromThread.stringArray);
745745
const { thread, stackMap } = convertJsTracerToThreadWithoutSamples(
746746
fromThread,
747747
stringTable,

0 commit comments

Comments
 (0)