@parca/profile 0.17.1 → 0.17.3
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 -5
- 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 -17
- 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 +108 -216
- package/src/ProfileIcicleGraph/IcicleGraphArrow/utils.ts +8 -15
- package/src/ProfileIcicleGraph/index.tsx +7 -38
- 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';
|
|
@@ -19,26 +19,24 @@ import {useContextMenu} from 'react-contexify';
|
|
|
19
19
|
import {FlamegraphArrow} from '@parca/client';
|
|
20
20
|
import {useURLState} from '@parca/components';
|
|
21
21
|
import {USER_PREFERENCES, useCurrentColorProfile, useUserPreference} from '@parca/hooks';
|
|
22
|
-
import {
|
|
23
|
-
import {
|
|
24
|
-
|
|
25
|
-
selectDarkMode,
|
|
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';
|
|
22
|
+
import {getColorForFeature, selectDarkMode, useAppSelector} from '@parca/store';
|
|
23
|
+
import {getLastItem, type ColorConfig} from '@parca/utilities';
|
|
24
|
+
|
|
35
25
|
import {ProfileSource} from '../../ProfileSource';
|
|
36
26
|
import {useProfileViewContext} from '../../ProfileView/context/ProfileViewContext';
|
|
37
|
-
import
|
|
38
|
-
import {IcicleChartRootNode} from './IcicleChartRootNode';
|
|
27
|
+
import ContextMenuWrapper, {ContextMenuWrapperRef} from './ContextMenuWrapper';
|
|
39
28
|
import {IcicleNode, RowHeight, colorByColors} from './IcicleGraphNodes';
|
|
29
|
+
import {MemoizedTooltip} from './MemoizedTooltip';
|
|
30
|
+
import {TooltipProvider} from './TooltipContext';
|
|
40
31
|
import {useFilenamesList} from './useMappingList';
|
|
41
|
-
import {
|
|
32
|
+
import {
|
|
33
|
+
CurrentPathFrame,
|
|
34
|
+
arrowToString,
|
|
35
|
+
extractFeature,
|
|
36
|
+
extractFilenameFeature,
|
|
37
|
+
getCurrentPathFrameData,
|
|
38
|
+
isCurrentPathFrameMatch,
|
|
39
|
+
} from './utils';
|
|
42
40
|
|
|
43
41
|
export const FIELD_LABELS_ONLY = 'labels_only';
|
|
44
42
|
export const FIELD_MAPPING_FILE = 'mapping_file';
|
|
@@ -58,18 +56,18 @@ export const FIELD_LABELS = 'labels';
|
|
|
58
56
|
export const FIELD_CUMULATIVE = 'cumulative';
|
|
59
57
|
export const FIELD_FLAT = 'flat';
|
|
60
58
|
export const FIELD_DIFF = 'diff';
|
|
59
|
+
export const FIELD_PARENT = 'parent';
|
|
60
|
+
export const FIELD_DEPTH = 'depth';
|
|
61
|
+
export const FIELD_VALUE_OFFSET = 'value_offset';
|
|
61
62
|
|
|
62
63
|
interface IcicleGraphArrowProps {
|
|
63
64
|
arrow: FlamegraphArrow;
|
|
64
65
|
total: bigint;
|
|
65
66
|
filtered: bigint;
|
|
66
|
-
|
|
67
|
-
profileSource?: ProfileSource;
|
|
67
|
+
profileSource: ProfileSource;
|
|
68
68
|
width?: number;
|
|
69
69
|
curPath: CurrentPathFrame[];
|
|
70
70
|
setCurPath: (path: CurrentPathFrame[]) => void;
|
|
71
|
-
sortBy: string;
|
|
72
|
-
flamegraphLoading: boolean;
|
|
73
71
|
isHalfScreen: boolean;
|
|
74
72
|
mappingsListFromMetadata: string[];
|
|
75
73
|
compareAbsolute: boolean;
|
|
@@ -113,32 +111,22 @@ export const IcicleGraphArrow = memo(function IcicleGraphArrow({
|
|
|
113
111
|
width,
|
|
114
112
|
setCurPath,
|
|
115
113
|
curPath,
|
|
116
|
-
profileType,
|
|
117
114
|
profileSource,
|
|
118
|
-
sortBy,
|
|
119
|
-
flamegraphLoading,
|
|
120
115
|
mappingsListFromMetadata,
|
|
121
116
|
compareAbsolute,
|
|
122
117
|
isIcicleChart = false,
|
|
123
118
|
}: IcicleGraphArrowProps): React.JSX.Element {
|
|
124
|
-
const [isContextMenuOpen, setIsContextMenuOpen] = useState<boolean>(false);
|
|
125
|
-
const dispatch = useAppDispatch();
|
|
126
119
|
const [highlightSimilarStacksPreference] = useUserPreference<boolean>(
|
|
127
120
|
USER_PREFERENCES.HIGHLIGHT_SIMILAR_STACKS.key
|
|
128
121
|
);
|
|
122
|
+
const [hoveringRow, setHoveringRow] = useState<number | undefined>(undefined);
|
|
129
123
|
const [dockedMetainfo] = useUserPreference<boolean>(USER_PREFERENCES.GRAPH_METAINFO_DOCKED.key);
|
|
130
124
|
const isDarkMode = useAppSelector(selectDarkMode);
|
|
131
125
|
|
|
132
126
|
const table: Table<any> = useMemo(() => {
|
|
133
127
|
return tableFromIPC(arrow.record);
|
|
134
128
|
}, [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
129
|
const svg = useRef(null);
|
|
141
|
-
const ref = useRef<SVGGElement>(null);
|
|
142
130
|
|
|
143
131
|
const [binaryFrameFilter, setBinaryFrameFilter] = useURLState('binary_frame_filter');
|
|
144
132
|
|
|
@@ -200,29 +188,14 @@ export const IcicleGraphArrow = memo(function IcicleGraphArrow({
|
|
|
200
188
|
|
|
201
189
|
const colorByColors: colorByColors = colorByList[colorByValue as ColorByKey];
|
|
202
190
|
|
|
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
191
|
const MENU_ID = 'icicle-graph-context-menu';
|
|
192
|
+
const contextMenuRef = useRef<ContextMenuWrapperRef>(null);
|
|
221
193
|
const {show, hideAll} = useContextMenu({
|
|
222
194
|
id: MENU_ID,
|
|
223
195
|
});
|
|
224
196
|
const displayMenu = useCallback(
|
|
225
|
-
(e: React.MouseEvent): void => {
|
|
197
|
+
(e: React.MouseEvent, row: number): void => {
|
|
198
|
+
contextMenuRef.current?.setRow(row);
|
|
226
199
|
show({
|
|
227
200
|
event: e,
|
|
228
201
|
});
|
|
@@ -230,10 +203,6 @@ export const IcicleGraphArrow = memo(function IcicleGraphArrow({
|
|
|
230
203
|
[show]
|
|
231
204
|
);
|
|
232
205
|
|
|
233
|
-
const trackVisibility = (isVisible: boolean): void => {
|
|
234
|
-
setIsContextMenuOpen(isVisible);
|
|
235
|
-
};
|
|
236
|
-
|
|
237
206
|
const hideBinary = (binaryToRemove: string): void => {
|
|
238
207
|
// second/subsequent time filtering out a binary i.e. a binary has already been hidden
|
|
239
208
|
// and we want to hide more binaries, we simply remove the binary from the binaryFrameFilter array in the URL.
|
|
@@ -249,187 +218,110 @@ export const IcicleGraphArrow = memo(function IcicleGraphArrow({
|
|
|
249
218
|
setBinaryFrameFilter(newMappingsList);
|
|
250
219
|
};
|
|
251
220
|
|
|
252
|
-
const
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
221
|
+
const handleRowClick = (row: number): void => {
|
|
222
|
+
// Walk down the stack starting at row until we reach the root (row 0).
|
|
223
|
+
const path: CurrentPathFrame[] = [];
|
|
224
|
+
let currentRow = row;
|
|
225
|
+
while (currentRow > 0) {
|
|
226
|
+
const frame = getCurrentPathFrameData(table, currentRow);
|
|
227
|
+
path.push(frame);
|
|
228
|
+
currentRow = table.getChild(FIELD_PARENT)?.get(currentRow) ?? 0;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
// Reverse the path so that the root is first.
|
|
232
|
+
path.reverse();
|
|
233
|
+
setCurPath(path);
|
|
234
|
+
};
|
|
235
|
+
|
|
236
|
+
const depthColumn = table.getChild(FIELD_DEPTH);
|
|
237
|
+
const maxDepth = depthColumn === null ? 0 : Math.max(...depthColumn.toArray());
|
|
238
|
+
const height = maxDepth * RowHeight;
|
|
239
|
+
|
|
240
|
+
// To find the selected row, we must walk the current path and look at which
|
|
241
|
+
// children of the current frame matches the path element exactly. Until the
|
|
242
|
+
// end, the row we find at the end is our selected row.
|
|
243
|
+
let currentRow = 0;
|
|
244
|
+
for (const frame of curPath) {
|
|
245
|
+
let childRows: number[] = Array.from(table.getChild(FIELD_CHILDREN)?.get(currentRow) ?? []);
|
|
246
|
+
if (childRows.length === 0) {
|
|
247
|
+
// If there are no children, we can stop here.
|
|
248
|
+
break;
|
|
249
|
+
}
|
|
250
|
+
childRows = childRows.filter(c => isCurrentPathFrameMatch(table, c, frame));
|
|
251
|
+
if (childRows.length === 0) {
|
|
252
|
+
// If there are no children that match the current path frame, we can stop here.
|
|
253
|
+
break;
|
|
254
|
+
}
|
|
255
|
+
if (childRows.length > 1) {
|
|
256
|
+
// If there are multiple children that match the current path frame, we can stop here.
|
|
257
|
+
// This is a case where the path is ambiguous and we cannot determine a single row.
|
|
258
|
+
break;
|
|
259
|
+
}
|
|
260
|
+
// If there is exactly one child that matches the current path frame, we can continue.
|
|
261
|
+
currentRow = childRows[0];
|
|
262
|
+
}
|
|
263
|
+
const selectedRow = currentRow;
|
|
264
|
+
|
|
265
|
+
return (
|
|
266
|
+
<TooltipProvider
|
|
267
|
+
table={table}
|
|
268
|
+
total={total}
|
|
269
|
+
totalUnfiltered={total + filtered}
|
|
270
|
+
unit={arrow.unit}
|
|
271
|
+
compareAbsolute={compareAbsolute}
|
|
272
|
+
>
|
|
273
|
+
<div className="relative">
|
|
274
|
+
<ContextMenuWrapper
|
|
275
|
+
ref={contextMenuRef}
|
|
276
|
+
menuId={MENU_ID}
|
|
277
|
+
table={table}
|
|
278
|
+
total={total}
|
|
279
|
+
totalUnfiltered={total + filtered}
|
|
280
|
+
compareAbsolute={compareAbsolute}
|
|
281
|
+
resetPath={() => setCurPath([])}
|
|
282
|
+
hideMenu={hideAll}
|
|
283
|
+
hideBinary={hideBinary}
|
|
284
|
+
unit={arrow.unit}
|
|
285
|
+
/>
|
|
286
|
+
<MemoizedTooltip contextElement={svg.current} dockedMetainfo={dockedMetainfo} />
|
|
265
287
|
<svg
|
|
266
288
|
className="font-robotoMono"
|
|
267
289
|
width={width}
|
|
268
290
|
height={height}
|
|
269
291
|
preserveAspectRatio="xMinYMid"
|
|
270
292
|
ref={svg}
|
|
271
|
-
onContextMenu={displayMenu}
|
|
272
293
|
>
|
|
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)'}>
|
|
294
|
+
{Array.from({length: table.numRows}, (_, row) => (
|
|
322
295
|
<IcicleNode
|
|
296
|
+
key={row}
|
|
323
297
|
table={table}
|
|
324
|
-
row={
|
|
298
|
+
row={row} // root is always row 0 in the arrow record
|
|
325
299
|
colors={colorByColors}
|
|
326
300
|
colorBy={colorByValue}
|
|
327
|
-
x={0}
|
|
328
|
-
y={0}
|
|
329
301
|
totalWidth={width ?? 1}
|
|
330
302
|
height={RowHeight}
|
|
331
|
-
setCurPath={setCurPath}
|
|
332
|
-
curPath={curPath}
|
|
333
|
-
total={total}
|
|
334
|
-
xScale={xScale}
|
|
335
|
-
path={path}
|
|
336
|
-
level={0}
|
|
337
|
-
isRoot={true}
|
|
338
303
|
searchString={(currentSearchString as string) ?? ''}
|
|
339
|
-
setHoveringRow={setHoveringRow}
|
|
340
|
-
setHoveringLevel={setHoveringLevel}
|
|
341
|
-
sortBy={sortBy}
|
|
342
304
|
darkMode={isDarkMode}
|
|
343
305
|
compareMode={compareMode}
|
|
344
|
-
profileType={profileType}
|
|
345
|
-
isContextMenuOpen={isContextMenuOpen}
|
|
346
|
-
hoveringName={highlightSimilarStacksName}
|
|
347
|
-
setHoveringName={highlightSimilarStacksSetName}
|
|
348
|
-
hoveringRow={highlightSimilarStacksRow}
|
|
349
306
|
colorForSimilarNodes={colorForSimilarNodes}
|
|
350
|
-
|
|
307
|
+
selectedRow={selectedRow}
|
|
308
|
+
onClick={() => {
|
|
309
|
+
if (isIcicleChart) {
|
|
310
|
+
// We don't want to expand in icicle charts.
|
|
311
|
+
return;
|
|
312
|
+
}
|
|
313
|
+
handleRowClick(row);
|
|
314
|
+
}}
|
|
315
|
+
onContextMenu={displayMenu}
|
|
316
|
+
hoveringRow={highlightSimilarStacksPreference ? hoveringRow : undefined}
|
|
317
|
+
setHoveringRow={highlightSimilarStacksPreference ? setHoveringRow : noop}
|
|
318
|
+
isIcicleChart={isIcicleChart}
|
|
319
|
+
profileSource={profileSource}
|
|
351
320
|
/>
|
|
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}
|
|
321
|
+
))}
|
|
322
|
+
</svg>
|
|
431
323
|
</div>
|
|
432
|
-
|
|
324
|
+
</TooltipProvider>
|
|
433
325
|
);
|
|
434
326
|
});
|
|
435
327
|
|
|
@@ -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">
|
|
@@ -258,9 +235,6 @@ const ProfileIcicleGraph = function ProfileIcicleGraphNonMemo({
|
|
|
258
235
|
filtered={filtered}
|
|
259
236
|
curPath={curPathArrow}
|
|
260
237
|
setCurPath={setNewCurPathArrow}
|
|
261
|
-
profileType={profileType}
|
|
262
|
-
sortBy={storeSortBy as string}
|
|
263
|
-
flamegraphLoading={isLoading}
|
|
264
238
|
isHalfScreen={isHalfScreen}
|
|
265
239
|
mappingsListFromMetadata={mappingsList}
|
|
266
240
|
compareAbsolute={isCompareAbsolute}
|
|
@@ -273,18 +247,13 @@ const ProfileIcicleGraph = function ProfileIcicleGraphNonMemo({
|
|
|
273
247
|
}
|
|
274
248
|
}, [
|
|
275
249
|
isLoading,
|
|
276
|
-
graph,
|
|
277
250
|
arrow,
|
|
278
251
|
total,
|
|
279
252
|
loading,
|
|
280
253
|
width,
|
|
281
254
|
filtered,
|
|
282
|
-
curPath,
|
|
283
|
-
setNewCurPath,
|
|
284
255
|
curPathArrow,
|
|
285
256
|
setNewCurPathArrow,
|
|
286
|
-
profileType,
|
|
287
|
-
storeSortBy,
|
|
288
257
|
isHalfScreen,
|
|
289
258
|
isDarkMode,
|
|
290
259
|
mappingsList,
|