diff --git a/profiler-cli/src/test/unit/call-tree-formatting.test.ts b/profiler-cli/src/test/unit/call-tree-formatting.test.ts index 9d616bf953..ddb361a0d3 100644 --- a/profiler-cli/src/test/unit/call-tree-formatting.test.ts +++ b/profiler-cli/src/test/unit/call-tree-formatting.test.ts @@ -93,9 +93,7 @@ function buildBottomUpResult( const weightType = threadSelectors.getWeightTypeForCallTree(state); const samples = threadSelectors.getPreviewFilteredCtssSamples(state); const sampleIndexToCallNodeIndex = - threadSelectors.getSampleIndexToNonInvertedCallNodeIndexForFilteredThread( - state - ); + threadSelectors.getPreviewFilteredCtssSampleCallNodes(state); const callNodeSelfAndSummary = computeCallNodeSelfAndSummary( samples, diff --git a/src/actions/profile-view.ts b/src/actions/profile-view.ts index a02aeb2c48..6f5e3e99ae 100644 --- a/src/actions/profile-view.ts +++ b/src/actions/profile-view.ts @@ -158,9 +158,7 @@ export function selectSelfCallNode( return (dispatch, getState) => { const threadSelectors = getThreadSelectorsFromThreadsKey(threadsKey); const sampleCallNodes = - threadSelectors.getSampleIndexToNonInvertedCallNodeIndexForFilteredThread( - getState() - ); + threadSelectors.getSampleCallNodesForFilteredThread(getState()); if ( sampleIndex === null || diff --git a/src/components/flame-graph/Canvas.tsx b/src/components/flame-graph/Canvas.tsx index 655f51ede9..c7b042fa0f 100644 --- a/src/components/flame-graph/Canvas.tsx +++ b/src/components/flame-graph/Canvas.tsx @@ -2,7 +2,7 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ import * as React from 'react'; -import memoize from 'memoize-immutable'; +import memoize from 'memoize-one'; import { withChartViewport, type Viewport } from '../shared/chart/Viewport'; import { ChartCanvas } from '../shared/chart/Canvas'; import { FastFillStyle } from '../../utils'; @@ -17,9 +17,11 @@ import { formatPercent, } from 'firefox-profiler/utils/format-numbers'; import { TooltipCallNode } from 'firefox-profiler/components/tooltip/CallNode'; -import { getTimingsForCallNodeIndex } from 'firefox-profiler/profile-logic/profile-data'; import { getSelfAndTotalForCallNode } from 'firefox-profiler/profile-logic/call-tree'; -import MixedTupleMap from 'mixedtuplemap'; +import { + getCallNodeTimings, + getSampleRelationsToNode, +} from 'firefox-profiler/profile-logic/profile-data'; import type { Thread, @@ -75,6 +77,7 @@ export type OwnProps = { readonly callTreeSummaryStrategy: CallTreeSummaryStrategy; readonly ctssSamples: SamplesLikeTable; readonly ctssSampleCategoriesAndSubcategories: SampleCategoriesAndSubcategories; + readonly ctssSampleCallNodes: Array; readonly tracedTiming: CallTreeTimings | null; readonly displayStackType: boolean; }; @@ -352,10 +355,33 @@ class FlameGraphCanvasImpl extends React.PureComponent { } }; - // Properly memoize this derived information for the Tooltip component. - _getTimingsForCallNodeIndex = memoize(getTimingsForCallNodeIndex, { - cache: new MixedTupleMap(), - }); + _getCallNodeTimings = memoize( + ( + categories: CategoryList, + ctssSamples: SamplesLikeTable, + ctssSampleCategoriesAndSubcategories: SampleCategoriesAndSubcategories, + callNodeInfo: CallNodeInfo, + ctssSampleCallNodes: Array, + callNodeIndex: IndexIntoCallNodeTable + ) => { + const callNodeInfoInverted = callNodeInfo.asInverted(); + const isInvertedRoot = + callNodeInfoInverted !== null && + callNodeInfoInverted.isRoot(callNodeIndex); + const sampleRelations = getSampleRelationsToNode( + callNodeInfo, + ctssSampleCallNodes, + callNodeIndex + ); + return getCallNodeTimings( + categories, + ctssSamples, + ctssSampleCategoriesAndSubcategories, + sampleRelations, + isInvertedRoot + ); + } + ); _getHoveredStackInfo = ({ depth, @@ -374,6 +400,7 @@ class FlameGraphCanvasImpl extends React.PureComponent { weightType, ctssSamples, ctssSampleCategoriesAndSubcategories, + ctssSampleCallNodes, tracedTiming, displayStackType, } = this.props; @@ -431,12 +458,13 @@ class FlameGraphCanvasImpl extends React.PureComponent { callTreeSummaryStrategy={callTreeSummaryStrategy} timings={ shouldComputeTimings - ? this._getTimingsForCallNodeIndex( - callNodeIndex, - callNodeInfo, + ? this._getCallNodeTimings( categories, ctssSamples, - ctssSampleCategoriesAndSubcategories + ctssSampleCategoriesAndSubcategories, + callNodeInfo, + ctssSampleCallNodes, + callNodeIndex ) : undefined } diff --git a/src/components/flame-graph/ConnectedFlameGraph.tsx b/src/components/flame-graph/ConnectedFlameGraph.tsx index 21d060d600..17d8e1a46f 100644 --- a/src/components/flame-graph/ConnectedFlameGraph.tsx +++ b/src/components/flame-graph/ConnectedFlameGraph.tsx @@ -74,6 +74,7 @@ type StateProps = { readonly callTreeSummaryStrategy: CallTreeSummaryStrategy; readonly ctssSamples: SamplesLikeTable; readonly ctssSampleCategoriesAndSubcategories: SampleCategoriesAndSubcategories; + readonly ctssSampleCallNodes: Array; readonly tracedTiming: CallTreeTimings | null; readonly displayStackType: boolean; }; @@ -158,6 +159,7 @@ class ConnectedFlameGraphImpl weightType, ctssSamples, ctssSampleCategoriesAndSubcategories, + ctssSampleCallNodes, tracedTiming, displayStackType, } = this.props; @@ -186,6 +188,7 @@ class ConnectedFlameGraphImpl ctssSampleCategoriesAndSubcategories={ ctssSampleCategoriesAndSubcategories } + ctssSampleCallNodes={ctssSampleCallNodes} tracedTiming={tracedTiming} displayStackType={displayStackType} onSelectedCallNodeChange={this._onSelectedCallNodeChange} @@ -228,6 +231,8 @@ export const ConnectedFlameGraph = explicitConnectWithForwardRef< selectedThreadSelectors.getPreviewFilteredCtssSampleCategoriesAndSubcategories( state ), + ctssSampleCallNodes: + selectedThreadSelectors.getPreviewFilteredCtssSampleCallNodes(state), tracedTiming: selectedThreadSelectors.getTracedTiming(state), displayStackType: getProfileUsesMultipleStackTypes(state), }), diff --git a/src/components/flame-graph/FlameGraph.tsx b/src/components/flame-graph/FlameGraph.tsx index 6e3e87aac7..a6999b3ad5 100644 --- a/src/components/flame-graph/FlameGraph.tsx +++ b/src/components/flame-graph/FlameGraph.tsx @@ -64,6 +64,7 @@ export type Props = { readonly callTreeSummaryStrategy: CallTreeSummaryStrategy; readonly ctssSamples: SamplesLikeTable; readonly ctssSampleCategoriesAndSubcategories: SampleCategoriesAndSubcategories; + readonly ctssSampleCallNodes: Array; readonly tracedTiming: CallTreeTimings | null; readonly displayStackType: boolean; readonly contextMenuId?: string; @@ -281,6 +282,7 @@ export class FlameGraph weightType, ctssSamples, ctssSampleCategoriesAndSubcategories, + ctssSampleCallNodes, tracedTiming, displayStackType, contextMenuId = 'CallNodeContextMenu', @@ -337,6 +339,7 @@ export class FlameGraph startsAtBottom, ctssSamples, ctssSampleCategoriesAndSubcategories, + ctssSampleCallNodes, tracedTiming, displayStackType, }} diff --git a/src/components/shared/thread/ActivityGraph.tsx b/src/components/shared/thread/ActivityGraph.tsx index 5310970e54..65f1aed588 100644 --- a/src/components/shared/thread/ActivityGraph.tsx +++ b/src/components/shared/thread/ActivityGraph.tsx @@ -24,6 +24,7 @@ import type { Milliseconds, CssPixels, } from 'firefox-profiler/types'; +import type { SampleRelations } from 'firefox-profiler/profile-logic/profile-data'; import type { ActivityFillGraphQuerier, CpuRatioInTimeRange, @@ -43,7 +44,7 @@ export type Props = { sampleIndex: IndexIntoSamplesTable | null ) => void; readonly categories: CategoryList; - readonly sampleSelectedStates: Uint8Array; + readonly sampleRelations: SampleRelations; readonly treeOrderSampleComparator: ( a: IndexIntoSamplesTable, b: IndexIntoSamplesTable @@ -131,7 +132,7 @@ class ThreadActivityGraphImpl extends React.PureComponent { rangeStart, rangeEnd, sampleIndexOffset, - sampleSelectedStates, + sampleRelations, treeOrderSampleComparator, implementationFilter, width, @@ -158,7 +159,7 @@ class ThreadActivityGraphImpl extends React.PureComponent { rangeStart={rangeStart} rangeEnd={rangeEnd} sampleIndexOffset={sampleIndexOffset} - sampleSelectedStates={sampleSelectedStates} + sampleRelations={sampleRelations} treeOrderSampleComparator={treeOrderSampleComparator} categories={categories} passFillsQuerier={this._setFillsQuerier} diff --git a/src/components/shared/thread/ActivityGraphCanvas.tsx b/src/components/shared/thread/ActivityGraphCanvas.tsx index 36356a762b..1e4584a25a 100644 --- a/src/components/shared/thread/ActivityGraphCanvas.tsx +++ b/src/components/shared/thread/ActivityGraphCanvas.tsx @@ -18,6 +18,7 @@ import type { IndexIntoSamplesTable, CategoryList, } from 'firefox-profiler/types'; +import type { SampleRelations } from 'firefox-profiler/profile-logic/profile-data'; import type { SizeProps } from 'firefox-profiler/components/shared/WithSize'; type CanvasProps = { @@ -29,7 +30,7 @@ type CanvasProps = { readonly rangeStart: Milliseconds; readonly rangeEnd: Milliseconds; readonly sampleIndexOffset: number; - readonly sampleSelectedStates: Uint8Array; + readonly sampleRelations: SampleRelations; readonly treeOrderSampleComparator: ( a: IndexIntoSamplesTable, b: IndexIntoSamplesTable @@ -129,7 +130,7 @@ export class ActivityGraphCanvas extends React.PureComponent { rangeStart, rangeEnd, sampleIndexOffset, - sampleSelectedStates, + sampleRelations, treeOrderSampleComparator, width, height, @@ -150,7 +151,7 @@ export class ActivityGraphCanvas extends React.PureComponent { rangeStart, rangeEnd, sampleIndexOffset, - sampleSelectedStates, + sampleRelations, xPixelsPerMs: canvasPixelWidth / (rangeEnd - rangeStart), treeOrderSampleComparator, categoryDrawStyles: this._getCategoryDrawStyles(ctx!), diff --git a/src/components/shared/thread/ActivityGraphFills.tsx b/src/components/shared/thread/ActivityGraphFills.tsx index 0b01e803dd..faf8eade15 100644 --- a/src/components/shared/thread/ActivityGraphFills.tsx +++ b/src/components/shared/thread/ActivityGraphFills.tsx @@ -13,7 +13,8 @@ import type { DevicePixels, CssPixels, } from 'firefox-profiler/types'; -import { SelectedState } from 'firefox-profiler/types'; +import { FillBucket } from 'firefox-profiler/types'; +import type { SampleRelations } from 'firefox-profiler/profile-logic/profile-data'; import type { HoveredPixelState } from './ActivityGraph'; /** @@ -39,7 +40,7 @@ type RenderedComponentSettings = { readonly treeOrderSampleComparator: | ((a: IndexIntoSamplesTable, b: IndexIntoSamplesTable) => number) | null; - readonly sampleSelectedStates: Uint8Array; + readonly sampleRelations: SampleRelations; readonly categoryDrawStyles: CategoryDrawStyles; }; @@ -76,17 +77,17 @@ export type CategoryDrawStyles = ReadonlyArray<{ readonly filteredOutByTransformFillStyle: CanvasPattern | string; }>; +const FILL_BUCKET_COUNT = 4; + // These Float32Arrays are mutated in place during the computation step. -// buffers[selectedState] is the buffer for the given SelectedState enum value. -type SelectedPercentageAtPixelBuffers = Float32Array[]; +// buffers[fillBucket] is the buffer for the given FillBucket value. +type PercentageAtPixelBuffers = Float32Array[]; export type CpuRatioInTimeRange = { readonly cpuRatio: number; readonly timeRange: Milliseconds; }; -const SELECTED_STATE_BUFFER_COUNT = 4; - const BOX_BLUR_RADII = [3, 2, 2]; const SMOOTHING_RADIUS = 3 + 2 + 2; const SMOOTHING_KERNEL: Float32Array = _getSmoothingKernel( @@ -97,7 +98,7 @@ const SMOOTHING_KERNEL: Float32Array = _getSmoothingKernel( export function computeActivityGraphFills( renderedComponentSettings: RenderedComponentSettings ) { - const mutablePercentageBuffers = _createSelectedPercentageAtPixelBuffers( + const mutablePercentageBuffers = _createPercentageAtPixelBuffers( renderedComponentSettings ); const mutableFills = _getCategoryFills( @@ -132,12 +133,12 @@ export function computeActivityGraphFills( export class ActivityGraphFillComputer { readonly renderedComponentSettings: RenderedComponentSettings; // The fills and percentages are mutated in place. - readonly mutablePercentageBuffers: SelectedPercentageAtPixelBuffers[]; + readonly mutablePercentageBuffers: PercentageAtPixelBuffers[]; readonly mutableFills: CategoryFill[]; constructor( renderedComponentSettings: RenderedComponentSettings, - mutablePercentageBuffers: SelectedPercentageAtPixelBuffers[], + mutablePercentageBuffers: PercentageAtPixelBuffers[], mutableFills: CategoryFill[] ) { this.renderedComponentSettings = renderedComponentSettings; @@ -216,7 +217,7 @@ export class ActivityGraphFillComputer { interval, sampleIndexOffset, rangeStart, - sampleSelectedStates, + sampleRelations, } = this.renderedComponentSettings; if (samples.length === 0) { @@ -245,8 +246,7 @@ export class ActivityGraphFillComputer { const afterSampleCpuPercent = threadCPUPercent[i + 1]; const percentageBuffers = this.mutablePercentageBuffers[category]; - const selectedState = sampleSelectedStates[i]; - const percentageBuffer = percentageBuffers[selectedState]; + const percentageBuffer = percentageBuffers[sampleRelations.fillBucket(i)]; _accumulateInBuffer( percentageBuffer, @@ -273,8 +273,8 @@ export class ActivityGraphFillComputer { const nextSampleTime = sampleTime + interval; const percentageBuffers = this.mutablePercentageBuffers[lastSampleCategory]; - const selectedState = sampleSelectedStates[lastIdx]; - const percentageBuffer = percentageBuffers[selectedState]; + const percentageBuffer = + percentageBuffers[sampleRelations.fillBucket(lastIdx)]; _accumulateInBuffer( percentageBuffer, @@ -652,16 +652,16 @@ function _getSmoothingKernel( * These buffers can only be used once per fill computation. The buffer values are * updated across various method calls. */ -function _createSelectedPercentageAtPixelBuffers({ +function _createPercentageAtPixelBuffers({ categoryDrawStyles, canvasPixelWidth, }: { categoryDrawStyles: CategoryDrawStyles; canvasPixelWidth: number; -}): SelectedPercentageAtPixelBuffers[] { +}): PercentageAtPixelBuffers[] { return categoryDrawStyles.map(() => { const percentageBuffers = []; - for (let i = 0; i < SELECTED_STATE_BUFFER_COUNT; i++) { + for (let i = 0; i < FILL_BUCKET_COUNT; i++) { percentageBuffers[i] = new Float32Array(canvasPixelWidth); } return percentageBuffers; @@ -669,17 +669,17 @@ function _createSelectedPercentageAtPixelBuffers({ } /** - * For each category, create a fill style for each of 4 draw states. These fill styles - * are sorted by their gravity. + * For each category, create a fill style for each of the 4 fill buckets. These + * fill styles are sorted by their gravity. * - * SelectedState.UnselectedOrderedBeforeSelected, - * SelectedState.Selected, - * SelectedState.UnselectedOrderedAfterSelected, - * SelectedState.FilteredOutByTransform + * FillBucket.UnselectedOrderedBeforeSelected, + * FillBucket.Selected, + * FillBucket.UnselectedOrderedAfterSelected, + * FillBucket.FilteredOutByTransform */ function _getCategoryFills( categoryDrawStyles: CategoryDrawStyles, - percentageBuffers: SelectedPercentageAtPixelBuffers[] + percentageBuffers: PercentageAtPixelBuffers[] ): CategoryFill[] { // Sort all of the categories by their gravity. const categoryIndexesByGravity = categoryDrawStyles @@ -693,33 +693,33 @@ function _getCategoryFills( const categoryDrawStyle = categoryDrawStyles[categoryIndex]; const buffer = percentageBuffers[categoryIndex]; const canvasPixelWidth = - buffer[SelectedState.UnselectedOrderedBeforeSelected].length; - // For every category we draw four fills, for the four selection kinds: + buffer[FillBucket.UnselectedOrderedBeforeSelected].length; + // For every category we draw one fill per fill bucket: return [ { category: categoryDrawStyle.category, fillStyle: categoryDrawStyle.getUnselectedFillStyle(), perPixelContribution: - buffer[SelectedState.UnselectedOrderedBeforeSelected], + buffer[FillBucket.UnselectedOrderedBeforeSelected], accumulatedUpperEdge: new Float32Array(canvasPixelWidth), }, { category: categoryDrawStyle.category, fillStyle: categoryDrawStyle.getSelectedFillStyle(), - perPixelContribution: buffer[SelectedState.Selected], + perPixelContribution: buffer[FillBucket.Selected], accumulatedUpperEdge: new Float32Array(canvasPixelWidth), }, { category: categoryDrawStyle.category, fillStyle: categoryDrawStyle.getUnselectedFillStyle(), perPixelContribution: - buffer[SelectedState.UnselectedOrderedAfterSelected], + buffer[FillBucket.UnselectedOrderedAfterSelected], accumulatedUpperEdge: new Float32Array(canvasPixelWidth), }, { category: categoryDrawStyle.category, fillStyle: categoryDrawStyle.filteredOutByTransformFillStyle, - perPixelContribution: buffer[SelectedState.FilteredOutByTransform], + perPixelContribution: buffer[FillBucket.FilteredOutByTransform], accumulatedUpperEdge: new Float32Array(canvasPixelWidth), }, ]; diff --git a/src/components/shared/thread/CPUGraph.tsx b/src/components/shared/thread/CPUGraph.tsx index 6b24cfc716..517c640a5b 100644 --- a/src/components/shared/thread/CPUGraph.tsx +++ b/src/components/shared/thread/CPUGraph.tsx @@ -11,12 +11,13 @@ import type { IndexIntoSamplesTable, Milliseconds, } from 'firefox-profiler/types'; +import type { SampleRelations } from 'firefox-profiler/profile-logic/profile-data'; import type { CallNodeInfo } from 'firefox-profiler/profile-logic/call-node-info'; type Props = { readonly className: string; readonly thread: Thread; - readonly sampleSelectedStates: Uint8Array; + readonly sampleRelations: SampleRelations; readonly interval: Milliseconds; readonly rangeStart: Milliseconds; readonly rangeEnd: Milliseconds; @@ -49,7 +50,7 @@ export class ThreadCPUGraph extends PureComponent { const { className, thread, - sampleSelectedStates, + sampleRelations, interval, rangeStart, rangeEnd, @@ -69,7 +70,7 @@ export class ThreadCPUGraph extends PureComponent { trackName={trackName} interval={interval} thread={thread} - sampleSelectedStates={sampleSelectedStates} + sampleRelations={sampleRelations} rangeStart={rangeStart} rangeEnd={rangeEnd} categories={categories} diff --git a/src/components/shared/thread/HeightGraph.tsx b/src/components/shared/thread/HeightGraph.tsx index 29a1c57926..beee3fb286 100644 --- a/src/components/shared/thread/HeightGraph.tsx +++ b/src/components/shared/thread/HeightGraph.tsx @@ -15,14 +15,14 @@ import type { IndexIntoSamplesTable, Milliseconds, } from 'firefox-profiler/types'; -import { SelectedState } from 'firefox-profiler/types'; +import type { SampleRelations } from 'firefox-profiler/profile-logic/profile-data'; type Props = { readonly heightFunc: (param: IndexIntoSamplesTable) => number | null; readonly maxValue: number; readonly className: string; readonly thread: Thread; - readonly sampleSelectedStates: Uint8Array; + readonly sampleRelations: SampleRelations; readonly interval: Milliseconds; readonly rangeStart: Milliseconds; readonly rangeEnd: Milliseconds; @@ -64,7 +64,7 @@ export class ThreadHeightGraph extends PureComponent { drawCanvas(canvas: HTMLCanvasElement) { const { thread, - sampleSelectedStates, + sampleRelations, interval, rangeStart, rangeEnd, @@ -130,8 +130,7 @@ export class ThreadHeightGraph extends PureComponent { continue; } - const state = sampleSelectedStates[i] as SelectedState; - if (state === SelectedState.FilteredOutByTransform) { + if (sampleRelations.isFilteredOut(i)) { continue; } @@ -144,7 +143,7 @@ export class ThreadHeightGraph extends PureComponent { const xPos = (sampleTime - range[0]) * xPixelsPerMs; let samplesBucket; - if (state === SelectedState.Selected) { + if (sampleRelations.contributesToTotal(i)) { samplesBucket = highlightedSamples; } else { const categoryIndex = thread.samples.category[i]; diff --git a/src/components/shared/thread/SampleGraph.tsx b/src/components/shared/thread/SampleGraph.tsx index 344b006d46..202341aa35 100644 --- a/src/components/shared/thread/SampleGraph.tsx +++ b/src/components/shared/thread/SampleGraph.tsx @@ -27,7 +27,7 @@ import type { CssPixels, ImplementationFilter, } from 'firefox-profiler/types'; -import { SelectedState } from 'firefox-profiler/types'; +import type { SampleRelations } from 'firefox-profiler/profile-logic/profile-data'; import type { SizeProps } from 'firefox-profiler/components/shared/WithSize'; import { lightDark } from 'firefox-profiler/utils/dark-mode'; @@ -38,7 +38,7 @@ export type HoveredPixelState = { type Props = { readonly className: string; readonly thread: Thread; - readonly sampleSelectedStates: Uint8Array; + readonly sampleRelations: SampleRelations; readonly interval: Milliseconds; readonly rangeStart: Milliseconds; readonly rangeEnd: Milliseconds; @@ -62,7 +62,7 @@ type State = { type CanvasProps = { readonly className: string; readonly thread: Thread; - readonly sampleSelectedStates: Uint8Array; + readonly sampleRelations: SampleRelations; readonly interval: Milliseconds; readonly rangeStart: Milliseconds; readonly rangeEnd: Milliseconds; @@ -137,7 +137,7 @@ class ThreadSampleGraphCanvas extends React.PureComponent { interval, rangeStart, rangeEnd, - sampleSelectedStates, + sampleRelations, categories, width, height, @@ -187,14 +187,13 @@ class ThreadSampleGraphCanvas extends React.PureComponent { if (sampleTime < nextMinTime) { continue; } - const state = sampleSelectedStates[i] as SelectedState; - if (state === SelectedState.FilteredOutByTransform) { + if (sampleRelations.isFilteredOut(i)) { continue; } const xPos = (sampleTime - rangeStart) * xPixelsPerMs - drawnSampleWidth / 2; let samplesBucket; - if (state === SelectedState.Selected) { + if (sampleRelations.contributesToTotal(i)) { samplesBucket = highlightedSamples; } else { const categoryIndex = thread.samples.category[i]; @@ -343,7 +342,7 @@ export class ThreadSampleGraphImpl extends PureComponent { interval, rangeStart, rangeEnd, - sampleSelectedStates, + sampleRelations, width, height, zeroAt, @@ -365,7 +364,7 @@ export class ThreadSampleGraphImpl extends PureComponent { thread={thread} rangeStart={rangeStart} rangeEnd={rangeEnd} - sampleSelectedStates={sampleSelectedStates} + sampleRelations={sampleRelations} categories={categories} width={width} height={height} diff --git a/src/components/shared/thread/StackGraph.tsx b/src/components/shared/thread/StackGraph.tsx index 1ace89ac3e..d48be60b7a 100644 --- a/src/components/shared/thread/StackGraph.tsx +++ b/src/components/shared/thread/StackGraph.tsx @@ -12,12 +12,13 @@ import type { Milliseconds, IndexIntoCallNodeTable, } from 'firefox-profiler/types'; +import type { SampleRelations } from 'firefox-profiler/profile-logic/profile-data'; import type { CallNodeInfo } from 'firefox-profiler/profile-logic/call-node-info'; type Props = { readonly className: string; readonly thread: Thread; - readonly sampleSelectedStates: Uint8Array; + readonly sampleRelations: SampleRelations; readonly sampleNonInvertedCallNodes: Array; readonly interval: Milliseconds; readonly rangeStart: Milliseconds; @@ -49,7 +50,7 @@ export class ThreadStackGraph extends PureComponent { const { className, thread, - sampleSelectedStates, + sampleRelations, interval, rangeStart, rangeEnd, @@ -75,7 +76,7 @@ export class ThreadStackGraph extends PureComponent { trackName={trackName} interval={interval} thread={thread} - sampleSelectedStates={sampleSelectedStates} + sampleRelations={sampleRelations} rangeStart={rangeStart} rangeEnd={rangeEnd} categories={categories} diff --git a/src/components/sidebar/CallTreeSidebar.tsx b/src/components/sidebar/CallTreeSidebar.tsx index e93028c5a0..fe03d9dc5a 100644 --- a/src/components/sidebar/CallTreeSidebar.tsx +++ b/src/components/sidebar/CallTreeSidebar.tsx @@ -299,7 +299,11 @@ class CallTreeSidebarImpl extends React.PureComponent { const totalTimePercent = Math.round((totalTime.value / rootTime) * 100); const selfTimePercent = Math.round((selfTime.value / rootTime) * 100); const totalTimeBreakdownByCategory = totalTime.breakdownByCategory; - const selfTimeBreakdownByCategory = selfTime.breakdownByCategory; + // For inverted root nodes, self === total, so showing a separate self + // breakdown would be redundant. + const selfTimeBreakdownByCategory = timings.isInvertedRoot + ? null + : selfTime.breakdownByCategory; return (