Skip to content

Commit 54536aa

Browse files
authored
Some performance improvements (#5878)
[Production](https://share.firefox.dev/4l9htnS) | [Deploy preview](https://deploy-preview-5878--perf-html.netlify.app/public/fkmw9djz29ntsmaznezy93hhft85jy0zjrp5my8/calltree/?globalTrackOrder=0&profileName=FullSp3Firefox-15x-symbolicated&thread=0&v=12) This PR contains some changes which make it faster to change the selected call node in the call tree. Whenever the selected call node changes, we redraw the activity graph and we compute which information to display in the sidebar.
2 parents bf252cc + 23fea36 commit 54536aa

File tree

16 files changed

+325
-146
lines changed

16 files changed

+325
-146
lines changed

src/components/flame-graph/Canvas.tsx

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ import type {
3232
SamplesLikeTable,
3333
InnerWindowID,
3434
Page,
35+
SampleCategoriesAndSubcategories,
3536
} from 'firefox-profiler/types';
3637

3738
import type {
@@ -55,8 +56,6 @@ export type OwnProps = {
5556
readonly thread: Thread;
5657
readonly weightType: WeightType;
5758
readonly innerWindowIDToPageMap: Map<InnerWindowID, Page> | null;
58-
readonly unfilteredThread: Thread;
59-
readonly ctssSampleIndexOffset: number;
6059
readonly maxStackDepthPlusOne: number;
6160
readonly flameGraphTiming: FlameGraphTiming;
6261
readonly callNodeInfo: CallNodeInfo;
@@ -74,7 +73,7 @@ export type OwnProps = {
7473
readonly isInverted: boolean;
7574
readonly callTreeSummaryStrategy: CallTreeSummaryStrategy;
7675
readonly ctssSamples: SamplesLikeTable;
77-
readonly unfilteredCtssSamples: SamplesLikeTable;
76+
readonly ctssSampleCategoriesAndSubcategories: SampleCategoriesAndSubcategories;
7877
readonly tracedTiming: CallTreeTimingsNonInverted | null;
7978
readonly displayStackType: boolean;
8079
};
@@ -355,8 +354,6 @@ class FlameGraphCanvasImpl extends React.PureComponent<Props> {
355354
}: HoveredStackTiming): React.ReactNode => {
356355
const {
357356
thread,
358-
unfilteredThread,
359-
ctssSampleIndexOffset,
360357
flameGraphTiming,
361358
callTree,
362359
callNodeInfo,
@@ -367,7 +364,7 @@ class FlameGraphCanvasImpl extends React.PureComponent<Props> {
367364
innerWindowIDToPageMap,
368365
weightType,
369366
ctssSamples,
370-
unfilteredCtssSamples,
367+
ctssSampleCategoriesAndSubcategories,
371368
tracedTiming,
372369
displayStackType,
373370
} = this.props;
@@ -426,11 +423,9 @@ class FlameGraphCanvasImpl extends React.PureComponent<Props> {
426423
? this._getTimingsForCallNodeIndex(
427424
callNodeIndex,
428425
callNodeInfo,
429-
unfilteredThread,
430-
ctssSampleIndexOffset,
431426
categories,
432427
ctssSamples,
433-
unfilteredCtssSamples
428+
ctssSampleCategoriesAndSubcategories
434429
)
435430
: undefined
436431
}

src/components/flame-graph/FlameGraph.tsx

Lines changed: 8 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ import type {
4343
ThreadsKey,
4444
InnerWindowID,
4545
Page,
46+
SampleCategoriesAndSubcategories,
4647
} from 'firefox-profiler/types';
4748

4849
import type { FlameGraphTiming } from 'firefox-profiler/profile-logic/flame-graph';
@@ -70,8 +71,6 @@ type StateProps = {
7071
readonly thread: Thread;
7172
readonly weightType: WeightType;
7273
readonly innerWindowIDToPageMap: Map<InnerWindowID, Page> | null;
73-
readonly unfilteredThread: Thread;
74-
readonly ctssSampleIndexOffset: number;
7574
readonly maxStackDepthPlusOne: number;
7675
readonly timeRange: StartEndRange;
7776
readonly previewSelection: PreviewSelection | null;
@@ -87,7 +86,7 @@ type StateProps = {
8786
readonly isInverted: boolean;
8887
readonly callTreeSummaryStrategy: CallTreeSummaryStrategy;
8988
readonly ctssSamples: SamplesLikeTable;
90-
readonly unfilteredCtssSamples: SamplesLikeTable;
89+
readonly ctssSampleCategoriesAndSubcategories: SampleCategoriesAndSubcategories;
9190
readonly tracedTiming: CallTreeTimings | null;
9291
readonly displayStackType: boolean;
9392
};
@@ -324,8 +323,6 @@ class FlameGraphImpl
324323
override render() {
325324
const {
326325
thread,
327-
unfilteredThread,
328-
ctssSampleIndexOffset,
329326
threadsKey,
330327
maxStackDepthPlusOne,
331328
flameGraphTiming,
@@ -343,7 +340,7 @@ class FlameGraphImpl
343340
innerWindowIDToPageMap,
344341
weightType,
345342
ctssSamples,
346-
unfilteredCtssSamples,
343+
ctssSampleCategoriesAndSubcategories,
347344
tracedTiming,
348345
displayStackType,
349346
} = this.props;
@@ -391,8 +388,6 @@ class FlameGraphImpl
391388
thread,
392389
innerWindowIDToPageMap,
393390
weightType,
394-
unfilteredThread,
395-
ctssSampleIndexOffset,
396391
maxStackDepthPlusOne,
397392
flameGraphTiming,
398393
callTree,
@@ -410,7 +405,7 @@ class FlameGraphImpl
410405
interval,
411406
isInverted,
412407
ctssSamples,
413-
unfilteredCtssSamples,
408+
ctssSampleCategoriesAndSubcategories,
414409
tracedTiming: tracedTimingNonInverted,
415410
displayStackType,
416411
}}
@@ -437,7 +432,6 @@ export const FlameGraph = explicitConnectWithForwardRef<
437432
>({
438433
mapStateToProps: (state) => ({
439434
thread: selectedThreadSelectors.getFilteredThread(state),
440-
unfilteredThread: selectedThreadSelectors.getThread(state),
441435
weightType: selectedThreadSelectors.getWeightTypeForCallTree(state),
442436
// Use the filtered call node max depth, rather than the preview filtered one, so
443437
// that the viewport height is stable across preview selections.
@@ -461,10 +455,10 @@ export const FlameGraph = explicitConnectWithForwardRef<
461455
selectedThreadSelectors.getCallTreeSummaryStrategy(state),
462456
innerWindowIDToPageMap: getInnerWindowIDToPageMap(state),
463457
ctssSamples: selectedThreadSelectors.getPreviewFilteredCtssSamples(state),
464-
ctssSampleIndexOffset:
465-
selectedThreadSelectors.getPreviewFilteredCtssSampleIndexOffset(state),
466-
unfilteredCtssSamples:
467-
selectedThreadSelectors.getUnfilteredCtssSamples(state),
458+
ctssSampleCategoriesAndSubcategories:
459+
selectedThreadSelectors.getPreviewFilteredCtssSampleCategoriesAndSubcategories(
460+
state
461+
),
468462
tracedTiming: selectedThreadSelectors.getTracedTiming(state),
469463
displayStackType: getProfileUsesMultipleStackTypes(state),
470464
}),

src/components/shared/thread/ActivityGraphCanvas.tsx

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,6 @@ export class ActivityGraphCanvas extends React.PureComponent<CanvasProps> {
133133
sampleIndexOffset,
134134
samplesSelectedStates,
135135
treeOrderSampleComparator,
136-
categories,
137136
enableCPUUsage,
138137
width,
139138
height,
@@ -158,7 +157,6 @@ export class ActivityGraphCanvas extends React.PureComponent<CanvasProps> {
158157
enableCPUUsage,
159158
xPixelsPerMs: canvasPixelWidth / (rangeEnd - rangeStart),
160159
treeOrderSampleComparator,
161-
greyCategoryIndex: categories.findIndex((c) => c.color === 'grey') || 0,
162160
categoryDrawStyles: this._getCategoryDrawStyles(ctx!),
163161
});
164162

src/components/shared/thread/ActivityGraphFills.tsx

Lines changed: 4 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,6 @@ type RenderedComponentSettings = {
4141
readonly treeOrderSampleComparator:
4242
| ((a: IndexIntoSamplesTable, b: IndexIntoSamplesTable) => number)
4343
| null;
44-
readonly greyCategoryIndex: IndexIntoCategoryList;
4544
readonly samplesSelectedStates: null | Array<SelectedState>;
4645
readonly categoryDrawStyles: CategoryDrawStyles;
4746
};
@@ -215,9 +214,8 @@ export class ActivityGraphFillComputer {
215214
_accumulateSampleCategories() {
216215
const {
217216
fullThread,
218-
rangeFilteredThread: { samples, stackTable },
217+
rangeFilteredThread: { samples },
219218
interval,
220-
greyCategoryIndex,
221219
enableCPUUsage,
222220
sampleIndexOffset,
223221
} = this.renderedComponentSettings;
@@ -242,11 +240,7 @@ export class ActivityGraphFillComputer {
242240
const { threadCPURatio } = samples;
243241
for (let i = 0; i < samples.length - 1; i++) {
244242
const nextSampleTime = samples.time[i + 1];
245-
const stackIndex = samples.stack[i];
246-
const category =
247-
stackIndex === null
248-
? greyCategoryIndex
249-
: stackTable.category[stackIndex];
243+
const category = samples.category[i];
250244

251245
let beforeSampleCpuRatio = 1;
252246
let afterSampleCpuRatio = 1;
@@ -272,11 +266,7 @@ export class ActivityGraphFillComputer {
272266

273267
// Handle the last sample, which was not covered by the for loop above.
274268
const lastIdx = samples.length - 1;
275-
const lastSampleStack = samples.stack[lastIdx];
276-
const lastSampleCategory =
277-
lastSampleStack !== null
278-
? stackTable.category[lastSampleStack]
279-
: greyCategoryIndex;
269+
const lastSampleCategory = samples.category[lastIdx];
280270

281271
let beforeSampleCpuRatio = 1;
282272
let afterSampleCpuRatio = 1;
@@ -322,11 +312,7 @@ export class ActivityGraphFillComputer {
322312
beforeSampleCpuRatio: number,
323313
afterSampleCpuRatio: number
324314
) {
325-
const { rangeEnd, rangeStart } = this.renderedComponentSettings;
326-
if (sampleTime < rangeStart || sampleTime >= rangeEnd) {
327-
return;
328-
}
329-
315+
const { rangeStart } = this.renderedComponentSettings;
330316
const percentageBuffers = this.mutablePercentageBuffers[category];
331317
const percentageBuffer = this._pickPercentageBuffer(
332318
percentageBuffers,

src/profile-logic/call-tree.ts

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ import type {
2626
CallNodeSelfAndSummary,
2727
SelfAndTotal,
2828
BalancedNativeAllocationsTable,
29+
SampleCategoriesAndSubcategories,
30+
IndexIntoCategoryList,
2931
} from 'firefox-profiler/types';
3032
import { ResourceType } from 'firefox-profiler/types';
3133

@@ -1225,6 +1227,25 @@ export function extractUnfilteredSamplesLikeTable(
12251227
}
12261228
}
12271229

1230+
export function computeUnfilteredCtssSampleCategoriesAndSubcategories(
1231+
thread: Thread,
1232+
ctssSamples: SamplesLikeTable,
1233+
defaultCategory: IndexIntoCategoryList
1234+
): SampleCategoriesAndSubcategories {
1235+
if (ctssSamples === thread.samples) {
1236+
const { category, subcategory } = thread.samples;
1237+
return {
1238+
sampleCategories: category,
1239+
sampleSubcategories: subcategory,
1240+
};
1241+
}
1242+
return ProfileData.computeSampleCategoriesAndSubcategories(
1243+
ctssSamples.stack,
1244+
thread.stackTable,
1245+
defaultCategory
1246+
);
1247+
}
1248+
12281249
/**
12291250
* This function is extremely similar to computeCallNodeSelfAndSummary,
12301251
* but is specialized for converting sample counts into traced timing. Samples

src/profile-logic/data-structures.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,8 @@ export function getEmptyStackTable(): StackTable {
4141
// be caught by the type system.
4242
frame: [],
4343
prefix: [],
44-
category: [],
45-
subcategory: [],
44+
category: new Uint8Array(),
45+
subcategory: new Uint8Array(),
4646
length: 0,
4747
};
4848
}

0 commit comments

Comments
 (0)