@parca/profile 0.17.2 → 0.17.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +8 -0
- package/dist/GraphTooltipArrow/Content.d.ts +1 -2
- package/dist/GraphTooltipArrow/Content.d.ts.map +1 -1
- package/dist/GraphTooltipArrow/Content.js +1 -2
- package/dist/GraphTooltipArrow/DockedGraphTooltip/index.d.ts +1 -2
- package/dist/GraphTooltipArrow/DockedGraphTooltip/index.d.ts.map +1 -1
- package/dist/GraphTooltipArrow/DockedGraphTooltip/index.js +1 -2
- package/dist/GraphTooltipArrow/useGraphTooltip/index.d.ts +1 -2
- package/dist/GraphTooltipArrow/useGraphTooltip/index.d.ts.map +1 -1
- package/dist/GraphTooltipArrow/useGraphTooltip/index.js +2 -2
- package/dist/ProfileIcicleGraph/IcicleGraphArrow/ContextMenu.d.ts +2 -6
- package/dist/ProfileIcicleGraph/IcicleGraphArrow/ContextMenu.d.ts.map +1 -1
- package/dist/ProfileIcicleGraph/IcicleGraphArrow/ContextMenu.js +4 -5
- package/dist/ProfileIcicleGraph/IcicleGraphArrow/ContextMenuWrapper.d.ts +20 -0
- package/dist/ProfileIcicleGraph/IcicleGraphArrow/ContextMenuWrapper.d.ts.map +1 -0
- package/{src/Callgraph/constants.ts → dist/ProfileIcicleGraph/IcicleGraphArrow/ContextMenuWrapper.js} +12 -3
- package/dist/ProfileIcicleGraph/IcicleGraphArrow/IcicleGraphNodes.d.ts +8 -51
- package/dist/ProfileIcicleGraph/IcicleGraphArrow/IcicleGraphNodes.d.ts.map +1 -1
- package/dist/ProfileIcicleGraph/IcicleGraphArrow/IcicleGraphNodes.js +59 -136
- package/dist/ProfileIcicleGraph/IcicleGraphArrow/MemoizedTooltip.d.ts +8 -0
- package/dist/ProfileIcicleGraph/IcicleGraphArrow/MemoizedTooltip.d.ts.map +1 -0
- package/dist/ProfileIcicleGraph/IcicleGraphArrow/MemoizedTooltip.js +40 -0
- package/dist/ProfileIcicleGraph/IcicleGraphArrow/TooltipContext.d.ts +32 -0
- package/dist/ProfileIcicleGraph/IcicleGraphArrow/TooltipContext.d.ts.map +1 -0
- package/dist/ProfileIcicleGraph/IcicleGraphArrow/TooltipContext.js +40 -0
- package/dist/ProfileIcicleGraph/IcicleGraphArrow/index.d.ts +4 -3
- package/dist/ProfileIcicleGraph/IcicleGraphArrow/index.d.ts.map +1 -1
- package/dist/ProfileIcicleGraph/IcicleGraphArrow/index.js +62 -76
- package/dist/ProfileIcicleGraph/IcicleGraphArrow/utils.d.ts +3 -3
- package/dist/ProfileIcicleGraph/IcicleGraphArrow/utils.d.ts.map +1 -1
- package/dist/ProfileIcicleGraph/IcicleGraphArrow/utils.js +9 -7
- package/dist/ProfileIcicleGraph/index.d.ts +3 -6
- package/dist/ProfileIcicleGraph/index.d.ts.map +1 -1
- package/dist/ProfileIcicleGraph/index.js +8 -16
- package/dist/ProfileView/components/DashboardItems/index.d.ts +3 -5
- package/dist/ProfileView/components/DashboardItems/index.d.ts.map +1 -1
- package/dist/ProfileView/components/DashboardItems/index.js +4 -9
- package/dist/ProfileView/components/Toolbars/index.d.ts.map +1 -1
- package/dist/ProfileView/components/Toolbars/index.js +1 -2
- package/dist/ProfileView/index.d.ts +1 -1
- package/dist/ProfileView/index.d.ts.map +1 -1
- package/dist/ProfileView/index.js +1 -13
- package/dist/ProfileView/types/visualization.d.ts +1 -1
- package/dist/ProfileView/types/visualization.d.ts.map +1 -1
- package/dist/index.d.ts +0 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +0 -2
- package/dist/styles.css +1 -1
- package/package.json +5 -5
- package/src/GraphTooltipArrow/Content.tsx +0 -3
- package/src/GraphTooltipArrow/DockedGraphTooltip/index.tsx +0 -3
- package/src/GraphTooltipArrow/useGraphTooltip/index.ts +1 -3
- package/src/ProfileIcicleGraph/IcicleGraphArrow/ContextMenu.tsx +5 -13
- package/src/ProfileIcicleGraph/IcicleGraphArrow/ContextMenuWrapper.tsx +53 -0
- package/src/ProfileIcicleGraph/IcicleGraphArrow/IcicleGraphNodes.tsx +96 -310
- package/src/ProfileIcicleGraph/IcicleGraphArrow/MemoizedTooltip.tsx +78 -0
- package/src/ProfileIcicleGraph/IcicleGraphArrow/TooltipContext.tsx +93 -0
- package/src/ProfileIcicleGraph/IcicleGraphArrow/index.tsx +110 -213
- package/src/ProfileIcicleGraph/IcicleGraphArrow/utils.ts +8 -15
- package/src/ProfileIcicleGraph/index.tsx +7 -36
- package/src/ProfileView/components/DashboardItems/index.tsx +2 -27
- package/src/ProfileView/components/Toolbars/index.tsx +0 -2
- package/src/ProfileView/index.tsx +0 -14
- package/src/ProfileView/types/visualization.ts +1 -1
- package/src/index.tsx +0 -5
- package/dist/Callgraph/constants.d.ts +0 -3
- package/dist/Callgraph/constants.d.ts.map +0 -1
- package/dist/Callgraph/constants.js +0 -14
- package/dist/Callgraph/index.d.ts +0 -11
- package/dist/Callgraph/index.d.ts.map +0 -1
- package/dist/Callgraph/index.js +0 -104
- package/dist/Callgraph/mockData/index.d.ts +0 -149
- package/dist/Callgraph/mockData/index.d.ts.map +0 -1
- package/dist/Callgraph/mockData/index.js +0 -594
- package/dist/Callgraph/utils.d.ts +0 -20
- package/dist/Callgraph/utils.d.ts.map +0 -1
- package/dist/Callgraph/utils.js +0 -97
- package/dist/GraphTooltip/ExpandOnHoverValue.d.ts +0 -7
- package/dist/GraphTooltip/ExpandOnHoverValue.d.ts.map +0 -1
- package/dist/GraphTooltip/ExpandOnHoverValue.js +0 -4
- package/dist/GraphTooltip/index.d.ts +0 -41
- package/dist/GraphTooltip/index.d.ts.map +0 -1
- package/dist/GraphTooltip/index.js +0 -201
- package/dist/ProfileIcicleGraph/IcicleGraph/ColorStackLegend.d.ts +0 -6
- package/dist/ProfileIcicleGraph/IcicleGraph/ColorStackLegend.d.ts.map +0 -1
- package/dist/ProfileIcicleGraph/IcicleGraph/ColorStackLegend.js +0 -59
- package/dist/ProfileIcicleGraph/IcicleGraph/IcicleGraphNodes.d.ts +0 -47
- package/dist/ProfileIcicleGraph/IcicleGraph/IcicleGraphNodes.d.ts.map +0 -1
- package/dist/ProfileIcicleGraph/IcicleGraph/IcicleGraphNodes.js +0 -93
- package/dist/ProfileIcicleGraph/IcicleGraph/index.d.ts +0 -14
- package/dist/ProfileIcicleGraph/IcicleGraph/index.d.ts.map +0 -1
- package/dist/ProfileIcicleGraph/IcicleGraph/index.js +0 -48
- package/dist/ProfileIcicleGraph/IcicleGraph/useColoredGraph.d.ts +0 -15
- package/dist/ProfileIcicleGraph/IcicleGraph/useColoredGraph.d.ts.map +0 -1
- package/dist/ProfileIcicleGraph/IcicleGraph/useColoredGraph.js +0 -57
- package/dist/ProfileIcicleGraph/IcicleGraph/useNodeColor.d.ts +0 -8
- package/dist/ProfileIcicleGraph/IcicleGraph/useNodeColor.d.ts.map +0 -1
- package/dist/ProfileIcicleGraph/IcicleGraph/useNodeColor.js +0 -32
- package/dist/ProfileIcicleGraph/IcicleGraph/utils.d.ts +0 -7
- package/dist/ProfileIcicleGraph/IcicleGraph/utils.d.ts.map +0 -1
- package/dist/ProfileIcicleGraph/IcicleGraph/utils.js +0 -66
- package/dist/ProfileIcicleGraph/IcicleGraphArrow/IcicleChartRootNode.d.ts +0 -9
- package/dist/ProfileIcicleGraph/IcicleGraphArrow/IcicleChartRootNode.d.ts.map +0 -1
- package/dist/ProfileIcicleGraph/IcicleGraphArrow/IcicleChartRootNode.js +0 -45
- package/dist/ProfileView/hooks/useGraphviz.d.ts +0 -12
- package/dist/ProfileView/hooks/useGraphviz.d.ts.map +0 -1
- package/dist/ProfileView/hooks/useGraphviz.js +0 -42
- package/src/Callgraph/index.tsx +0 -177
- package/src/Callgraph/mockData/index.ts +0 -605
- package/src/Callgraph/utils.ts +0 -141
- package/src/GraphTooltip/ExpandOnHoverValue.tsx +0 -30
- package/src/GraphTooltip/index.tsx +0 -509
- package/src/ProfileIcicleGraph/IcicleGraph/ColorStackLegend.tsx +0 -96
- package/src/ProfileIcicleGraph/IcicleGraph/IcicleGraphNodes.tsx +0 -266
- package/src/ProfileIcicleGraph/IcicleGraph/index.tsx +0 -123
- package/src/ProfileIcicleGraph/IcicleGraph/useColoredGraph.ts +0 -117
- package/src/ProfileIcicleGraph/IcicleGraph/useNodeColor.ts +0 -54
- package/src/ProfileIcicleGraph/IcicleGraph/utils.ts +0 -102
- package/src/ProfileIcicleGraph/IcicleGraphArrow/IcicleChartRootNode.tsx +0 -130
- package/src/ProfileView/hooks/useGraphviz.ts +0 -69
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
// See the License for the specific language governing permissions and
|
|
12
12
|
// limitations under the License.
|
|
13
13
|
|
|
14
|
-
import React, {memo, useCallback,
|
|
14
|
+
import React, {memo, useCallback, useMemo, useRef, useState} from 'react';
|
|
15
15
|
|
|
16
16
|
import {Dictionary, Table, Vector, tableFromIPC} from 'apache-arrow';
|
|
17
17
|
import {useContextMenu} from 'react-contexify';
|
|
@@ -20,25 +20,24 @@ import {FlamegraphArrow} from '@parca/client';
|
|
|
20
20
|
import {useURLState} from '@parca/components';
|
|
21
21
|
import {USER_PREFERENCES, useCurrentColorProfile, useUserPreference} from '@parca/hooks';
|
|
22
22
|
import {ProfileType} from '@parca/parser';
|
|
23
|
-
import {
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
setHoveringNode,
|
|
27
|
-
useAppDispatch,
|
|
28
|
-
useAppSelector,
|
|
29
|
-
} from '@parca/store';
|
|
30
|
-
import {getLastItem, scaleLinear, type ColorConfig} from '@parca/utilities';
|
|
31
|
-
|
|
32
|
-
import GraphTooltipArrow from '../../GraphTooltipArrow';
|
|
33
|
-
import GraphTooltipArrowContent from '../../GraphTooltipArrow/Content';
|
|
34
|
-
import {DockedGraphTooltip} from '../../GraphTooltipArrow/DockedGraphTooltip';
|
|
23
|
+
import {getColorForFeature, selectDarkMode, useAppSelector} from '@parca/store';
|
|
24
|
+
import {getLastItem, type ColorConfig} from '@parca/utilities';
|
|
25
|
+
|
|
35
26
|
import {ProfileSource} from '../../ProfileSource';
|
|
36
27
|
import {useProfileViewContext} from '../../ProfileView/context/ProfileViewContext';
|
|
37
|
-
import
|
|
38
|
-
import {IcicleChartRootNode} from './IcicleChartRootNode';
|
|
28
|
+
import ContextMenuWrapper, {ContextMenuWrapperRef} from './ContextMenuWrapper';
|
|
39
29
|
import {IcicleNode, RowHeight, colorByColors} from './IcicleGraphNodes';
|
|
30
|
+
import {MemoizedTooltip} from './MemoizedTooltip';
|
|
31
|
+
import {TooltipProvider} from './TooltipContext';
|
|
40
32
|
import {useFilenamesList} from './useMappingList';
|
|
41
|
-
import {
|
|
33
|
+
import {
|
|
34
|
+
CurrentPathFrame,
|
|
35
|
+
arrowToString,
|
|
36
|
+
extractFeature,
|
|
37
|
+
extractFilenameFeature,
|
|
38
|
+
getCurrentPathFrameData,
|
|
39
|
+
isCurrentPathFrameMatch,
|
|
40
|
+
} from './utils';
|
|
42
41
|
|
|
43
42
|
export const FIELD_LABELS_ONLY = 'labels_only';
|
|
44
43
|
export const FIELD_MAPPING_FILE = 'mapping_file';
|
|
@@ -58,18 +57,19 @@ export const FIELD_LABELS = 'labels';
|
|
|
58
57
|
export const FIELD_CUMULATIVE = 'cumulative';
|
|
59
58
|
export const FIELD_FLAT = 'flat';
|
|
60
59
|
export const FIELD_DIFF = 'diff';
|
|
60
|
+
export const FIELD_PARENT = 'parent';
|
|
61
|
+
export const FIELD_DEPTH = 'depth';
|
|
62
|
+
export const FIELD_VALUE_OFFSET = 'value_offset';
|
|
61
63
|
|
|
62
64
|
interface IcicleGraphArrowProps {
|
|
63
65
|
arrow: FlamegraphArrow;
|
|
64
66
|
total: bigint;
|
|
65
67
|
filtered: bigint;
|
|
66
68
|
profileType?: ProfileType;
|
|
67
|
-
profileSource
|
|
69
|
+
profileSource: ProfileSource;
|
|
68
70
|
width?: number;
|
|
69
71
|
curPath: CurrentPathFrame[];
|
|
70
72
|
setCurPath: (path: CurrentPathFrame[]) => void;
|
|
71
|
-
sortBy: string;
|
|
72
|
-
flamegraphLoading: boolean;
|
|
73
73
|
isHalfScreen: boolean;
|
|
74
74
|
mappingsListFromMetadata: string[];
|
|
75
75
|
compareAbsolute: boolean;
|
|
@@ -115,30 +115,21 @@ export const IcicleGraphArrow = memo(function IcicleGraphArrow({
|
|
|
115
115
|
curPath,
|
|
116
116
|
profileType,
|
|
117
117
|
profileSource,
|
|
118
|
-
sortBy,
|
|
119
|
-
flamegraphLoading,
|
|
120
118
|
mappingsListFromMetadata,
|
|
121
119
|
compareAbsolute,
|
|
122
120
|
isIcicleChart = false,
|
|
123
121
|
}: IcicleGraphArrowProps): React.JSX.Element {
|
|
124
|
-
const [isContextMenuOpen, setIsContextMenuOpen] = useState<boolean>(false);
|
|
125
|
-
const dispatch = useAppDispatch();
|
|
126
122
|
const [highlightSimilarStacksPreference] = useUserPreference<boolean>(
|
|
127
123
|
USER_PREFERENCES.HIGHLIGHT_SIMILAR_STACKS.key
|
|
128
124
|
);
|
|
125
|
+
const [hoveringRow, setHoveringRow] = useState<number | undefined>(undefined);
|
|
129
126
|
const [dockedMetainfo] = useUserPreference<boolean>(USER_PREFERENCES.GRAPH_METAINFO_DOCKED.key);
|
|
130
127
|
const isDarkMode = useAppSelector(selectDarkMode);
|
|
131
128
|
|
|
132
129
|
const table: Table<any> = useMemo(() => {
|
|
133
130
|
return tableFromIPC(arrow.record);
|
|
134
131
|
}, [arrow]);
|
|
135
|
-
|
|
136
|
-
const [height, setHeight] = useState(0);
|
|
137
|
-
const [hoveringRow, setHoveringRow] = useState<number | null>(null);
|
|
138
|
-
const [hoveringLevel, setHoveringLevel] = useState<number | null>(null);
|
|
139
|
-
const [hoveringName, setHoveringName] = useState<string | null>(null);
|
|
140
132
|
const svg = useRef(null);
|
|
141
|
-
const ref = useRef<SVGGElement>(null);
|
|
142
133
|
|
|
143
134
|
const [binaryFrameFilter, setBinaryFrameFilter] = useURLState('binary_frame_filter');
|
|
144
135
|
|
|
@@ -200,29 +191,14 @@ export const IcicleGraphArrow = memo(function IcicleGraphArrow({
|
|
|
200
191
|
|
|
201
192
|
const colorByColors: colorByColors = colorByList[colorByValue as ColorByKey];
|
|
202
193
|
|
|
203
|
-
useEffect(() => {
|
|
204
|
-
if (ref.current != null) {
|
|
205
|
-
setHeight(ref?.current.getBoundingClientRect().height);
|
|
206
|
-
}
|
|
207
|
-
}, [width, flamegraphLoading]);
|
|
208
|
-
|
|
209
|
-
const xScale = useMemo(() => {
|
|
210
|
-
if (total === 0n) {
|
|
211
|
-
return () => 0;
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
if (width === undefined) {
|
|
215
|
-
return () => 0;
|
|
216
|
-
}
|
|
217
|
-
return scaleLinear([0n, total], [0, width]);
|
|
218
|
-
}, [total, width]);
|
|
219
|
-
|
|
220
194
|
const MENU_ID = 'icicle-graph-context-menu';
|
|
195
|
+
const contextMenuRef = useRef<ContextMenuWrapperRef>(null);
|
|
221
196
|
const {show, hideAll} = useContextMenu({
|
|
222
197
|
id: MENU_ID,
|
|
223
198
|
});
|
|
224
199
|
const displayMenu = useCallback(
|
|
225
|
-
(e: React.MouseEvent): void => {
|
|
200
|
+
(e: React.MouseEvent, row: number): void => {
|
|
201
|
+
contextMenuRef.current?.setRow(row);
|
|
226
202
|
show({
|
|
227
203
|
event: e,
|
|
228
204
|
});
|
|
@@ -230,10 +206,6 @@ export const IcicleGraphArrow = memo(function IcicleGraphArrow({
|
|
|
230
206
|
[show]
|
|
231
207
|
);
|
|
232
208
|
|
|
233
|
-
const trackVisibility = (isVisible: boolean): void => {
|
|
234
|
-
setIsContextMenuOpen(isVisible);
|
|
235
|
-
};
|
|
236
|
-
|
|
237
209
|
const hideBinary = (binaryToRemove: string): void => {
|
|
238
210
|
// second/subsequent time filtering out a binary i.e. a binary has already been hidden
|
|
239
211
|
// and we want to hide more binaries, we simply remove the binary from the binaryFrameFilter array in the URL.
|
|
@@ -249,187 +221,112 @@ export const IcicleGraphArrow = memo(function IcicleGraphArrow({
|
|
|
249
221
|
setBinaryFrameFilter(newMappingsList);
|
|
250
222
|
};
|
|
251
223
|
|
|
252
|
-
const
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
224
|
+
const handleRowClick = (row: number): void => {
|
|
225
|
+
// Walk down the stack starting at row until we reach the root (row 0).
|
|
226
|
+
const path: CurrentPathFrame[] = [];
|
|
227
|
+
let currentRow = row;
|
|
228
|
+
while (currentRow > 0) {
|
|
229
|
+
const frame = getCurrentPathFrameData(table, currentRow);
|
|
230
|
+
path.push(frame);
|
|
231
|
+
currentRow = table.getChild(FIELD_PARENT)?.get(currentRow) ?? 0;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
// Reverse the path so that the root is first.
|
|
235
|
+
path.reverse();
|
|
236
|
+
setCurPath(path);
|
|
237
|
+
};
|
|
238
|
+
|
|
239
|
+
const depthColumn = table.getChild(FIELD_DEPTH);
|
|
240
|
+
const maxDepth = depthColumn === null ? 0 : Math.max(...depthColumn.toArray());
|
|
241
|
+
const height = maxDepth * RowHeight;
|
|
242
|
+
|
|
243
|
+
// To find the selected row, we must walk the current path and look at which
|
|
244
|
+
// children of the current frame matches the path element exactly. Until the
|
|
245
|
+
// end, the row we find at the end is our selected row.
|
|
246
|
+
let currentRow = 0;
|
|
247
|
+
for (const frame of curPath) {
|
|
248
|
+
let childRows: number[] = Array.from(table.getChild(FIELD_CHILDREN)?.get(currentRow) ?? []);
|
|
249
|
+
if (childRows.length === 0) {
|
|
250
|
+
// If there are no children, we can stop here.
|
|
251
|
+
break;
|
|
252
|
+
}
|
|
253
|
+
childRows = childRows.filter(c => isCurrentPathFrameMatch(table, c, frame));
|
|
254
|
+
if (childRows.length === 0) {
|
|
255
|
+
// If there are no children that match the current path frame, we can stop here.
|
|
256
|
+
break;
|
|
257
|
+
}
|
|
258
|
+
if (childRows.length > 1) {
|
|
259
|
+
// If there are multiple children that match the current path frame, we can stop here.
|
|
260
|
+
// This is a case where the path is ambiguous and we cannot determine a single row.
|
|
261
|
+
break;
|
|
262
|
+
}
|
|
263
|
+
// If there is exactly one child that matches the current path frame, we can continue.
|
|
264
|
+
currentRow = childRows[0];
|
|
265
|
+
}
|
|
266
|
+
const selectedRow = currentRow;
|
|
267
|
+
|
|
268
|
+
return (
|
|
269
|
+
<TooltipProvider
|
|
270
|
+
table={table}
|
|
271
|
+
total={total}
|
|
272
|
+
totalUnfiltered={total + filtered}
|
|
273
|
+
profileType={profileType}
|
|
274
|
+
unit={arrow.unit}
|
|
275
|
+
compareAbsolute={compareAbsolute}
|
|
276
|
+
>
|
|
277
|
+
<div className="relative">
|
|
278
|
+
<ContextMenuWrapper
|
|
279
|
+
ref={contextMenuRef}
|
|
280
|
+
menuId={MENU_ID}
|
|
281
|
+
table={table}
|
|
282
|
+
total={total}
|
|
283
|
+
totalUnfiltered={total + filtered}
|
|
284
|
+
compareAbsolute={compareAbsolute}
|
|
285
|
+
resetPath={() => setCurPath([])}
|
|
286
|
+
hideMenu={hideAll}
|
|
287
|
+
hideBinary={hideBinary}
|
|
288
|
+
unit={arrow.unit}
|
|
289
|
+
profileType={profileType}
|
|
290
|
+
/>
|
|
291
|
+
<MemoizedTooltip contextElement={svg.current} dockedMetainfo={dockedMetainfo} />
|
|
265
292
|
<svg
|
|
266
293
|
className="font-robotoMono"
|
|
267
294
|
width={width}
|
|
268
295
|
height={height}
|
|
269
296
|
preserveAspectRatio="xMinYMid"
|
|
270
297
|
ref={svg}
|
|
271
|
-
onContextMenu={displayMenu}
|
|
272
298
|
>
|
|
273
|
-
|
|
274
|
-
<g transform={'translate(0, 0)'}>
|
|
275
|
-
<IcicleChartRootNode
|
|
276
|
-
table={table}
|
|
277
|
-
row={0}
|
|
278
|
-
colors={colorByColors}
|
|
279
|
-
colorBy={colorByValue}
|
|
280
|
-
x={0}
|
|
281
|
-
y={0}
|
|
282
|
-
totalWidth={width ?? 1}
|
|
283
|
-
height={RowHeight}
|
|
284
|
-
setCurPath={setCurPath}
|
|
285
|
-
curPath={curPath}
|
|
286
|
-
total={total}
|
|
287
|
-
xScale={xScale}
|
|
288
|
-
path={path}
|
|
289
|
-
level={0}
|
|
290
|
-
isRoot={true}
|
|
291
|
-
searchString={(currentSearchString as string) ?? ''}
|
|
292
|
-
setHoveringRow={setHoveringRow}
|
|
293
|
-
setHoveringLevel={setHoveringLevel}
|
|
294
|
-
sortBy={sortBy}
|
|
295
|
-
darkMode={isDarkMode}
|
|
296
|
-
compareMode={compareMode}
|
|
297
|
-
profileType={profileType}
|
|
298
|
-
isContextMenuOpen={isContextMenuOpen}
|
|
299
|
-
hoveringName={highlightSimilarStacksName}
|
|
300
|
-
setHoveringName={highlightSimilarStacksSetName}
|
|
301
|
-
hoveringRow={highlightSimilarStacksRow}
|
|
302
|
-
colorForSimilarNodes={colorForSimilarNodes}
|
|
303
|
-
highlightSimilarStacksPreference={highlightSimilarStacksPreference}
|
|
304
|
-
profileSource={profileSource}
|
|
305
|
-
/>
|
|
306
|
-
</g>
|
|
307
|
-
</g>
|
|
308
|
-
</svg>
|
|
309
|
-
);
|
|
310
|
-
}
|
|
311
|
-
return (
|
|
312
|
-
<svg
|
|
313
|
-
className="font-robotoMono"
|
|
314
|
-
width={width}
|
|
315
|
-
height={height}
|
|
316
|
-
preserveAspectRatio="xMinYMid"
|
|
317
|
-
ref={svg}
|
|
318
|
-
onContextMenu={displayMenu}
|
|
319
|
-
>
|
|
320
|
-
<g ref={ref}>
|
|
321
|
-
<g transform={'translate(0, 0)'}>
|
|
299
|
+
{Array.from({length: table.numRows}, (_, row) => (
|
|
322
300
|
<IcicleNode
|
|
301
|
+
key={row}
|
|
323
302
|
table={table}
|
|
324
|
-
row={
|
|
303
|
+
row={row} // root is always row 0 in the arrow record
|
|
325
304
|
colors={colorByColors}
|
|
326
305
|
colorBy={colorByValue}
|
|
327
|
-
x={0}
|
|
328
|
-
y={0}
|
|
329
306
|
totalWidth={width ?? 1}
|
|
330
307
|
height={RowHeight}
|
|
331
|
-
setCurPath={setCurPath}
|
|
332
|
-
curPath={curPath}
|
|
333
|
-
total={total}
|
|
334
|
-
xScale={xScale}
|
|
335
|
-
path={path}
|
|
336
|
-
level={0}
|
|
337
|
-
isRoot={true}
|
|
338
308
|
searchString={(currentSearchString as string) ?? ''}
|
|
339
|
-
setHoveringRow={setHoveringRow}
|
|
340
|
-
setHoveringLevel={setHoveringLevel}
|
|
341
|
-
sortBy={sortBy}
|
|
342
309
|
darkMode={isDarkMode}
|
|
343
310
|
compareMode={compareMode}
|
|
344
|
-
profileType={profileType}
|
|
345
|
-
isContextMenuOpen={isContextMenuOpen}
|
|
346
|
-
hoveringName={highlightSimilarStacksName}
|
|
347
|
-
setHoveringName={highlightSimilarStacksSetName}
|
|
348
|
-
hoveringRow={highlightSimilarStacksRow}
|
|
349
311
|
colorForSimilarNodes={colorForSimilarNodes}
|
|
350
|
-
|
|
312
|
+
selectedRow={selectedRow}
|
|
313
|
+
onClick={() => {
|
|
314
|
+
if (isIcicleChart) {
|
|
315
|
+
// We don't want to expand in icicle charts.
|
|
316
|
+
return;
|
|
317
|
+
}
|
|
318
|
+
handleRowClick(row);
|
|
319
|
+
}}
|
|
320
|
+
onContextMenu={displayMenu}
|
|
321
|
+
hoveringRow={highlightSimilarStacksPreference ? hoveringRow : undefined}
|
|
322
|
+
setHoveringRow={highlightSimilarStacksPreference ? setHoveringRow : noop}
|
|
323
|
+
isIcicleChart={isIcicleChart}
|
|
324
|
+
profileSource={profileSource}
|
|
351
325
|
/>
|
|
352
|
-
|
|
353
|
-
</
|
|
354
|
-
</svg>
|
|
355
|
-
);
|
|
356
|
-
}, [
|
|
357
|
-
width,
|
|
358
|
-
height,
|
|
359
|
-
displayMenu,
|
|
360
|
-
table,
|
|
361
|
-
colorByColors,
|
|
362
|
-
colorByValue,
|
|
363
|
-
setCurPath,
|
|
364
|
-
curPath,
|
|
365
|
-
total,
|
|
366
|
-
xScale,
|
|
367
|
-
currentSearchString,
|
|
368
|
-
sortBy,
|
|
369
|
-
isDarkMode,
|
|
370
|
-
compareMode,
|
|
371
|
-
profileType,
|
|
372
|
-
isContextMenuOpen,
|
|
373
|
-
highlightSimilarStacksName,
|
|
374
|
-
highlightSimilarStacksRow,
|
|
375
|
-
colorForSimilarNodes,
|
|
376
|
-
highlightSimilarStacksPreference,
|
|
377
|
-
path,
|
|
378
|
-
highlightSimilarStacksSetName,
|
|
379
|
-
isIcicleChart,
|
|
380
|
-
profileSource,
|
|
381
|
-
]);
|
|
382
|
-
|
|
383
|
-
return (
|
|
384
|
-
<>
|
|
385
|
-
<div className="relative" onMouseLeave={() => dispatch(setHoveringNode(undefined))}>
|
|
386
|
-
<ContextMenu
|
|
387
|
-
menuId={MENU_ID}
|
|
388
|
-
table={table}
|
|
389
|
-
row={hoveringRow ?? 0}
|
|
390
|
-
level={hoveringLevel ?? 0}
|
|
391
|
-
total={total}
|
|
392
|
-
totalUnfiltered={total + filtered}
|
|
393
|
-
profileType={profileType}
|
|
394
|
-
compareAbsolute={compareAbsolute}
|
|
395
|
-
trackVisibility={trackVisibility}
|
|
396
|
-
curPath={curPath}
|
|
397
|
-
setCurPath={setCurPath}
|
|
398
|
-
hideMenu={hideAll}
|
|
399
|
-
hideBinary={hideBinary}
|
|
400
|
-
unit={arrow.unit}
|
|
401
|
-
/>
|
|
402
|
-
{dockedMetainfo ? (
|
|
403
|
-
<DockedGraphTooltip
|
|
404
|
-
table={table}
|
|
405
|
-
row={hoveringRow}
|
|
406
|
-
level={hoveringLevel ?? 0}
|
|
407
|
-
total={total}
|
|
408
|
-
totalUnfiltered={total + filtered}
|
|
409
|
-
profileType={profileType}
|
|
410
|
-
unit={arrow.unit}
|
|
411
|
-
compareAbsolute={compareAbsolute}
|
|
412
|
-
/>
|
|
413
|
-
) : (
|
|
414
|
-
!isContextMenuOpen && (
|
|
415
|
-
<GraphTooltipArrow contextElement={svg.current} isContextMenuOpen={isContextMenuOpen}>
|
|
416
|
-
<GraphTooltipArrowContent
|
|
417
|
-
table={table}
|
|
418
|
-
row={hoveringRow}
|
|
419
|
-
level={hoveringLevel ?? 0}
|
|
420
|
-
isFixed={false}
|
|
421
|
-
total={total}
|
|
422
|
-
totalUnfiltered={total + filtered}
|
|
423
|
-
profileType={profileType}
|
|
424
|
-
unit={arrow.unit}
|
|
425
|
-
compareAbsolute={compareAbsolute}
|
|
426
|
-
/>
|
|
427
|
-
</GraphTooltipArrow>
|
|
428
|
-
)
|
|
429
|
-
)}
|
|
430
|
-
{root}
|
|
326
|
+
))}
|
|
327
|
+
</svg>
|
|
431
328
|
</div>
|
|
432
|
-
|
|
329
|
+
</TooltipProvider>
|
|
433
330
|
);
|
|
434
331
|
});
|
|
435
332
|
|
|
@@ -25,6 +25,7 @@ import {divide, getLastItem, valueFormatter} from '@parca/utilities';
|
|
|
25
25
|
import {MergedProfileSource, ProfileSource} from '../../ProfileSource';
|
|
26
26
|
import {BigIntDuo, hexifyAddress} from '../../utils';
|
|
27
27
|
import {
|
|
28
|
+
FIELD_DEPTH,
|
|
28
29
|
FIELD_FUNCTION_NAME,
|
|
29
30
|
FIELD_FUNCTION_START_LINE,
|
|
30
31
|
FIELD_INLINED,
|
|
@@ -33,14 +34,10 @@ import {
|
|
|
33
34
|
FIELD_MAPPING_FILE,
|
|
34
35
|
} from './index';
|
|
35
36
|
|
|
36
|
-
export function nodeLabel(
|
|
37
|
-
table: Table<any>,
|
|
38
|
-
row: number,
|
|
39
|
-
level: number,
|
|
40
|
-
showBinaryName: boolean
|
|
41
|
-
): string {
|
|
37
|
+
export function nodeLabel(table: Table<any>, row: number, showBinaryName: boolean): string {
|
|
42
38
|
const labelsOnly: boolean | null = table.getChild(FIELD_LABELS_ONLY)?.get(row);
|
|
43
|
-
|
|
39
|
+
const depth: number = table.getChild(FIELD_DEPTH)?.get(row) ?? 0;
|
|
40
|
+
if (depth === 1 && labelsOnly !== null && labelsOnly) {
|
|
44
41
|
return getLabelSet(table, row);
|
|
45
42
|
}
|
|
46
43
|
|
|
@@ -150,11 +147,7 @@ export interface CurrentPathFrame {
|
|
|
150
147
|
labels?: string;
|
|
151
148
|
}
|
|
152
149
|
|
|
153
|
-
export const getCurrentPathFrameData = (
|
|
154
|
-
table: Table<any>,
|
|
155
|
-
row: number,
|
|
156
|
-
level: number
|
|
157
|
-
): CurrentPathFrame => {
|
|
150
|
+
export const getCurrentPathFrameData = (table: Table<any>, row: number): CurrentPathFrame => {
|
|
158
151
|
const functionName: string | null = arrowToString(table.getChild(FIELD_FUNCTION_NAME)?.get(row));
|
|
159
152
|
const systemName: string | null = arrowToString(table.getChild(FIELD_FUNCTION_NAME)?.get(row));
|
|
160
153
|
const fileName: string | null = arrowToString(table.getChild(FIELD_MAPPING_FILE)?.get(row));
|
|
@@ -163,8 +156,9 @@ export const getCurrentPathFrameData = (
|
|
|
163
156
|
const address = hexifyAddress(addressBigInt);
|
|
164
157
|
const inlined: boolean | null = table.getChild(FIELD_INLINED)?.get(row);
|
|
165
158
|
const labelsOnly: boolean | null = table.getChild(FIELD_LABELS_ONLY)?.get(row);
|
|
159
|
+
const depth = table.getChild(FIELD_DEPTH)?.get(row) ?? 0;
|
|
166
160
|
let labels: undefined | string;
|
|
167
|
-
if (
|
|
161
|
+
if (depth === 1 && labelsOnly !== null && labelsOnly) {
|
|
168
162
|
labels = getLabelSet(table, row);
|
|
169
163
|
}
|
|
170
164
|
|
|
@@ -196,10 +190,9 @@ function getLabelSet(table: Table<any>, row: number): string {
|
|
|
196
190
|
export function isCurrentPathFrameMatch(
|
|
197
191
|
table: Table<any>,
|
|
198
192
|
row: number,
|
|
199
|
-
level: number,
|
|
200
193
|
b: CurrentPathFrame
|
|
201
194
|
): boolean {
|
|
202
|
-
const a = getCurrentPathFrameData(table, row
|
|
195
|
+
const a = getCurrentPathFrameData(table, row);
|
|
203
196
|
return (
|
|
204
197
|
a.functionName === b.functionName &&
|
|
205
198
|
a.systemName === b.systemName &&
|
|
@@ -16,7 +16,7 @@ import React, {LegacyRef, ReactNode, useEffect, useMemo, useState} from 'react';
|
|
|
16
16
|
import {AnimatePresence, motion} from 'framer-motion';
|
|
17
17
|
import {useMeasure} from 'react-use';
|
|
18
18
|
|
|
19
|
-
import {
|
|
19
|
+
import {FlamegraphArrow} from '@parca/client';
|
|
20
20
|
import {IcicleGraphSkeleton, useParcaContext, useURLState} from '@parca/components';
|
|
21
21
|
import {ProfileType} from '@parca/parser';
|
|
22
22
|
import {capitalizeOnlyFirstLetter, divide} from '@parca/utilities';
|
|
@@ -25,7 +25,6 @@ import {MergedProfileSource, ProfileSource} from '../ProfileSource';
|
|
|
25
25
|
import DiffLegend from '../ProfileView/components/DiffLegend';
|
|
26
26
|
import {useProfileViewContext} from '../ProfileView/context/ProfileViewContext';
|
|
27
27
|
import {TimelineGuide} from '../TimelineGuide';
|
|
28
|
-
import {IcicleGraph} from './IcicleGraph';
|
|
29
28
|
import {FIELD_FUNCTION_NAME, IcicleGraphArrow} from './IcicleGraphArrow';
|
|
30
29
|
import useMappingList from './IcicleGraphArrow/useMappingList';
|
|
31
30
|
import {CurrentPathFrame, boundsFromProfileSource} from './IcicleGraphArrow/utils';
|
|
@@ -36,14 +35,11 @@ export type ResizeHandler = (width: number, height: number) => void;
|
|
|
36
35
|
|
|
37
36
|
interface ProfileIcicleGraphProps {
|
|
38
37
|
width: number;
|
|
39
|
-
graph?: Flamegraph;
|
|
40
38
|
arrow?: FlamegraphArrow;
|
|
41
39
|
total: bigint;
|
|
42
40
|
filtered: bigint;
|
|
43
41
|
profileType?: ProfileType;
|
|
44
|
-
profileSource
|
|
45
|
-
curPath: string[] | [];
|
|
46
|
-
setNewCurPath: (path: string[]) => void;
|
|
42
|
+
profileSource: ProfileSource;
|
|
47
43
|
curPathArrow: CurrentPathFrame[] | [];
|
|
48
44
|
setNewCurPathArrow: (path: CurrentPathFrame[]) => void;
|
|
49
45
|
loading: boolean;
|
|
@@ -72,12 +68,9 @@ export const validateIcicleChartQuery = (
|
|
|
72
68
|
};
|
|
73
69
|
|
|
74
70
|
const ProfileIcicleGraph = function ProfileIcicleGraphNonMemo({
|
|
75
|
-
graph,
|
|
76
71
|
arrow,
|
|
77
72
|
total,
|
|
78
73
|
filtered,
|
|
79
|
-
curPath,
|
|
80
|
-
setNewCurPath,
|
|
81
74
|
curPathArrow,
|
|
82
75
|
setNewCurPathArrow,
|
|
83
76
|
profileType,
|
|
@@ -96,7 +89,6 @@ const ProfileIcicleGraph = function ProfileIcicleGraphNonMemo({
|
|
|
96
89
|
|
|
97
90
|
const mappingsList = useMappingList(metadataMappingFiles);
|
|
98
91
|
|
|
99
|
-
const [storeSortBy = FIELD_FUNCTION_NAME] = useURLState('sort_by');
|
|
100
92
|
const [colorBy, setColorBy] = useURLState('color_by');
|
|
101
93
|
|
|
102
94
|
// By default, we want delta profiles (CPU) to be relatively compared.
|
|
@@ -120,11 +112,11 @@ const ProfileIcicleGraph = function ProfileIcicleGraphNonMemo({
|
|
|
120
112
|
isFiltered,
|
|
121
113
|
filteredPercentage,
|
|
122
114
|
] = useMemo(() => {
|
|
123
|
-
if (
|
|
115
|
+
if (arrow === undefined) {
|
|
124
116
|
return ['0', '0', false, '0', '0', false, '0', '0'];
|
|
125
117
|
}
|
|
126
118
|
|
|
127
|
-
const trimmed: bigint =
|
|
119
|
+
const trimmed: bigint = arrow?.trimmed ?? 0n;
|
|
128
120
|
|
|
129
121
|
const totalUnfiltered = total + filtered;
|
|
130
122
|
// safeguard against division by zero
|
|
@@ -139,10 +131,9 @@ const ProfileIcicleGraph = function ProfileIcicleGraphNonMemo({
|
|
|
139
131
|
filtered > 0,
|
|
140
132
|
numberFormatter.format(divide(total * 100n, totalUnfilteredDivisor)),
|
|
141
133
|
];
|
|
142
|
-
}, [
|
|
134
|
+
}, [arrow, filtered, total]);
|
|
143
135
|
|
|
144
|
-
const loadingState =
|
|
145
|
-
!loading && (arrow !== undefined || graph !== undefined) && metadataMappingFiles !== undefined;
|
|
136
|
+
const loadingState = !loading && arrow !== undefined && metadataMappingFiles !== undefined;
|
|
146
137
|
|
|
147
138
|
// If there is only one mapping file, we want to color by filename by default.
|
|
148
139
|
useEffect(() => {
|
|
@@ -218,25 +209,11 @@ const ProfileIcicleGraph = function ProfileIcicleGraphNonMemo({
|
|
|
218
209
|
}
|
|
219
210
|
}
|
|
220
211
|
|
|
221
|
-
if (
|
|
222
|
-
return <div className="mx-auto text-center">No data...</div>;
|
|
212
|
+
if (arrow === undefined) return <div className="mx-auto text-center">No data...</div>;
|
|
223
213
|
|
|
224
214
|
if (total === 0n && !loading)
|
|
225
215
|
return <div className="mx-auto text-center">Profile has no samples</div>;
|
|
226
216
|
|
|
227
|
-
if (graph !== undefined)
|
|
228
|
-
return (
|
|
229
|
-
<IcicleGraph
|
|
230
|
-
width={width}
|
|
231
|
-
graph={graph}
|
|
232
|
-
total={total}
|
|
233
|
-
filtered={filtered}
|
|
234
|
-
curPath={curPath}
|
|
235
|
-
setCurPath={setNewCurPath}
|
|
236
|
-
profileType={profileType}
|
|
237
|
-
/>
|
|
238
|
-
);
|
|
239
|
-
|
|
240
217
|
if (arrow !== undefined) {
|
|
241
218
|
return (
|
|
242
219
|
<div className="relative">
|
|
@@ -259,8 +236,6 @@ const ProfileIcicleGraph = function ProfileIcicleGraphNonMemo({
|
|
|
259
236
|
curPath={curPathArrow}
|
|
260
237
|
setCurPath={setNewCurPathArrow}
|
|
261
238
|
profileType={profileType}
|
|
262
|
-
sortBy={storeSortBy as string}
|
|
263
|
-
flamegraphLoading={isLoading}
|
|
264
239
|
isHalfScreen={isHalfScreen}
|
|
265
240
|
mappingsListFromMetadata={mappingsList}
|
|
266
241
|
compareAbsolute={isCompareAbsolute}
|
|
@@ -273,18 +248,14 @@ const ProfileIcicleGraph = function ProfileIcicleGraphNonMemo({
|
|
|
273
248
|
}
|
|
274
249
|
}, [
|
|
275
250
|
isLoading,
|
|
276
|
-
graph,
|
|
277
251
|
arrow,
|
|
278
252
|
total,
|
|
279
253
|
loading,
|
|
280
254
|
width,
|
|
281
255
|
filtered,
|
|
282
|
-
curPath,
|
|
283
|
-
setNewCurPath,
|
|
284
256
|
curPathArrow,
|
|
285
257
|
setNewCurPathArrow,
|
|
286
258
|
profileType,
|
|
287
|
-
storeSortBy,
|
|
288
259
|
isHalfScreen,
|
|
289
260
|
isDarkMode,
|
|
290
261
|
mappingsList,
|