@parca/profile 0.16.373 → 0.16.375
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.js +1 -1
- package/dist/GraphTooltipArrow/DockedGraphTooltip/index.js +1 -1
- package/dist/ProfileIcicleGraph/IcicleGraph/useColoredGraph.js +1 -1
- package/dist/ProfileIcicleGraph/IcicleGraph/utils.d.ts +1 -1
- package/dist/ProfileIcicleGraph/IcicleGraph/utils.js +1 -5
- package/dist/ProfileIcicleGraph/IcicleGraphArrow/ColorStackLegend.js +23 -9
- package/dist/ProfileIcicleGraph/IcicleGraphArrow/ContextMenu.d.ts +2 -1
- package/dist/ProfileIcicleGraph/IcicleGraphArrow/ContextMenu.js +3 -2
- package/dist/ProfileIcicleGraph/IcicleGraphArrow/IcicleGraphNodes.js +0 -1
- package/dist/ProfileIcicleGraph/IcicleGraphArrow/index.d.ts +1 -0
- package/dist/ProfileIcicleGraph/IcicleGraphArrow/index.js +29 -47
- package/dist/ProfileIcicleGraph/IcicleGraphArrow/useNodeColor.d.ts +1 -2
- package/dist/ProfileIcicleGraph/IcicleGraphArrow/useNodeColor.js +2 -7
- package/dist/ProfileIcicleGraph/IcicleGraphArrow/utils.js +0 -3
- package/dist/ProfileIcicleGraph/index.d.ts +2 -1
- package/dist/ProfileIcicleGraph/index.js +26 -22
- package/dist/ProfileSource.js +2 -0
- package/dist/ProfileView/index.d.ts +2 -0
- package/dist/ProfileView/index.js +2 -2
- package/dist/ProfileViewWithData.js +17 -10
- package/dist/useQuery.d.ts +1 -3
- package/dist/useQuery.js +21 -8
- package/package.json +7 -7
- package/src/GraphTooltipArrow/Content.tsx +1 -5
- package/src/GraphTooltipArrow/DockedGraphTooltip/index.tsx +1 -1
- package/src/ProfileIcicleGraph/IcicleGraph/useColoredGraph.ts +1 -1
- package/src/ProfileIcicleGraph/IcicleGraph/utils.ts +1 -7
- package/src/ProfileIcicleGraph/IcicleGraphArrow/ColorStackLegend.tsx +26 -9
- package/src/ProfileIcicleGraph/IcicleGraphArrow/ContextMenu.tsx +21 -1
- package/src/ProfileIcicleGraph/IcicleGraphArrow/IcicleGraphNodes.tsx +0 -1
- package/src/ProfileIcicleGraph/IcicleGraphArrow/index.tsx +39 -48
- package/src/ProfileIcicleGraph/IcicleGraphArrow/useNodeColor.ts +1 -8
- package/src/ProfileIcicleGraph/IcicleGraphArrow/utils.ts +0 -5
- package/src/ProfileIcicleGraph/index.tsx +65 -50
- package/src/ProfileSource.tsx +2 -0
- package/src/ProfileView/index.tsx +4 -1
- package/src/ProfileViewWithData.tsx +26 -10
- package/src/useQuery.tsx +22 -11
- package/dist/ProfileIcicleGraph/ActionButtons/RuntimeFilterDropdown.d.ts +0 -9
- package/dist/ProfileIcicleGraph/ActionButtons/RuntimeFilterDropdown.js +0 -23
- package/src/ProfileIcicleGraph/ActionButtons/RuntimeFilterDropdown.tsx +0 -123
package/dist/useQuery.d.ts
CHANGED
|
@@ -13,10 +13,8 @@ interface UseQueryOptions {
|
|
|
13
13
|
sourceBuildID?: string;
|
|
14
14
|
sourceFilename?: string;
|
|
15
15
|
sourceOnly?: boolean;
|
|
16
|
-
showRuntimeRuby?: boolean;
|
|
17
|
-
showRuntimePython?: boolean;
|
|
18
|
-
showInterpretedOnly?: boolean;
|
|
19
16
|
invertCallStack?: boolean;
|
|
17
|
+
binaryFrameFilter?: string[];
|
|
20
18
|
}
|
|
21
19
|
export declare const useQuery: (client: QueryServiceClient, profileSource: ProfileSource, reportType: QueryRequest_ReportType, options?: UseQueryOptions) => IQueryResult;
|
|
22
20
|
export {};
|
package/dist/useQuery.js
CHANGED
|
@@ -25,10 +25,8 @@ export const useQuery = (client, profileSource, reportType, options) => {
|
|
|
25
25
|
options?.sourceBuildID,
|
|
26
26
|
options?.sourceOnly,
|
|
27
27
|
options?.sourceOnly === true ? '' : options?.sourceFilename,
|
|
28
|
-
options?.showRuntimeRuby ?? false,
|
|
29
|
-
options?.showRuntimePython ?? false,
|
|
30
|
-
options?.showInterpretedOnly ?? false,
|
|
31
28
|
options?.invertCallStack ?? false,
|
|
29
|
+
options?.binaryFrameFilter ?? '',
|
|
32
30
|
],
|
|
33
31
|
queryFn: async () => {
|
|
34
32
|
const req = profileSource.QueryRequest();
|
|
@@ -44,12 +42,27 @@ export const useQuery = (client, profileSource, reportType, options) => {
|
|
|
44
42
|
sourceOnly: options?.sourceOnly ?? false,
|
|
45
43
|
};
|
|
46
44
|
}
|
|
47
|
-
req.runtimeFilter = {
|
|
48
|
-
showRuby: options?.showRuntimeRuby ?? false,
|
|
49
|
-
showPython: options?.showRuntimePython ?? false,
|
|
50
|
-
showInterpretedOnly: options?.showInterpretedOnly ?? false,
|
|
51
|
-
};
|
|
52
45
|
req.invertCallStack = options?.invertCallStack ?? false;
|
|
46
|
+
if (options?.binaryFrameFilter !== undefined && options?.binaryFrameFilter.length > 0) {
|
|
47
|
+
req.filter = [
|
|
48
|
+
{
|
|
49
|
+
filter: {
|
|
50
|
+
oneofKind: 'frameFilter',
|
|
51
|
+
frameFilter: {
|
|
52
|
+
filter: {
|
|
53
|
+
oneofKind: 'binaryFrameFilter',
|
|
54
|
+
binaryFrameFilter: {
|
|
55
|
+
includeBinaries: options?.binaryFrameFilter ?? [],
|
|
56
|
+
},
|
|
57
|
+
},
|
|
58
|
+
},
|
|
59
|
+
},
|
|
60
|
+
},
|
|
61
|
+
];
|
|
62
|
+
}
|
|
63
|
+
else {
|
|
64
|
+
req.filter = [];
|
|
65
|
+
}
|
|
53
66
|
try {
|
|
54
67
|
const { response } = await client.query(req, { meta: metadata });
|
|
55
68
|
return response;
|
package/package.json
CHANGED
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@parca/profile",
|
|
3
|
-
"version": "0.16.
|
|
3
|
+
"version": "0.16.375",
|
|
4
4
|
"description": "Profile viewing libraries",
|
|
5
5
|
"dependencies": {
|
|
6
6
|
"@headlessui/react": "^1.7.19",
|
|
7
7
|
"@iconify/react": "^4.0.0",
|
|
8
|
-
"@parca/client": "^0.16.
|
|
9
|
-
"@parca/components": "^0.16.
|
|
8
|
+
"@parca/client": "^0.16.115",
|
|
9
|
+
"@parca/components": "^0.16.278",
|
|
10
10
|
"@parca/dynamicsize": "^0.16.65",
|
|
11
|
-
"@parca/hooks": "^0.0.
|
|
11
|
+
"@parca/hooks": "^0.0.57",
|
|
12
12
|
"@parca/icons": "^0.16.69",
|
|
13
13
|
"@parca/parser": "^0.16.74",
|
|
14
|
-
"@parca/store": "^0.16.
|
|
15
|
-
"@parca/utilities": "^0.0.
|
|
14
|
+
"@parca/store": "^0.16.146",
|
|
15
|
+
"@parca/utilities": "^0.0.74",
|
|
16
16
|
"@popperjs/core": "^2.11.8",
|
|
17
17
|
"@protobuf-ts/runtime-rpc": "^2.5.0",
|
|
18
18
|
"@tanstack/react-query": "^4.0.5",
|
|
@@ -71,5 +71,5 @@
|
|
|
71
71
|
"access": "public",
|
|
72
72
|
"registry": "https://registry.npmjs.org/"
|
|
73
73
|
},
|
|
74
|
-
"gitHead": "
|
|
74
|
+
"gitHead": "1c9338c7294c1df88345032cee964653ce4e349b"
|
|
75
75
|
}
|
|
@@ -201,11 +201,7 @@ const TooltipMetaInfo = ({
|
|
|
201
201
|
<tr>
|
|
202
202
|
<td className="w-1/4">Build Id</td>
|
|
203
203
|
<td className="w-3/4 break-all">
|
|
204
|
-
{isMappingBuildIDAvailable ? (
|
|
205
|
-
<div>{truncateString(getLastItem(mappingBuildID) as string, 28)}</div>
|
|
206
|
-
) : (
|
|
207
|
-
<NoData />
|
|
208
|
-
)}
|
|
204
|
+
{isMappingBuildIDAvailable ? <div>{truncateString(mappingBuildID, 28)}</div> : <NoData />}
|
|
209
205
|
</td>
|
|
210
206
|
</tr>
|
|
211
207
|
{labelPairs.length > 0 && (
|
|
@@ -145,7 +145,7 @@ export const DockedGraphTooltip = ({
|
|
|
145
145
|
title="Build ID"
|
|
146
146
|
value={
|
|
147
147
|
isMappingBuildIDAvailable ? (
|
|
148
|
-
<div>{truncateString(
|
|
148
|
+
<div>{truncateString(mappingBuildID, 28)}</div>
|
|
149
149
|
) : (
|
|
150
150
|
<NoData />
|
|
151
151
|
)
|
|
@@ -71,7 +71,7 @@ const colorNodes = (
|
|
|
71
71
|
features
|
|
72
72
|
);
|
|
73
73
|
}
|
|
74
|
-
const feature = extractFeature(node, mappings, locations, strings
|
|
74
|
+
const feature = extractFeature(node, mappings, locations, strings);
|
|
75
75
|
coloredNode.feature = feature.name;
|
|
76
76
|
features[feature.name] = feature.type;
|
|
77
77
|
return coloredNode;
|
|
@@ -91,14 +91,8 @@ export const extractFeature = (
|
|
|
91
91
|
data: FlamegraphNode,
|
|
92
92
|
mappings: Mapping[],
|
|
93
93
|
locations: Location[],
|
|
94
|
-
strings: string[]
|
|
95
|
-
functions: ParcaFunction[]
|
|
94
|
+
strings: string[]
|
|
96
95
|
): Feature => {
|
|
97
|
-
const name = nodeLabel(data, strings, mappings, locations, functions, false).trim();
|
|
98
|
-
if (name.startsWith('runtime') || name === 'root') {
|
|
99
|
-
return {name: 'runtime', type: FEATURE_TYPES.Runtime};
|
|
100
|
-
}
|
|
101
|
-
|
|
102
96
|
const binaryName = getBinaryName(data, mappings, locations, strings);
|
|
103
97
|
if (binaryName != null) {
|
|
104
98
|
return {name: binaryName, type: FEATURE_TYPES.Binary};
|
|
@@ -37,7 +37,10 @@ const ColorStackLegend = ({
|
|
|
37
37
|
const [colorProfileName] = useUserPreference<string>(
|
|
38
38
|
USER_PREFERENCES.FLAMEGRAPH_COLOR_PROFILE.key
|
|
39
39
|
);
|
|
40
|
-
const [currentSearchString, setSearchString] = useURLState({
|
|
40
|
+
const [currentSearchString, setSearchString] = useURLState({
|
|
41
|
+
param: 'binary_frame_filter',
|
|
42
|
+
navigateTo,
|
|
43
|
+
});
|
|
41
44
|
|
|
42
45
|
const stackColorArray = useMemo(() => {
|
|
43
46
|
return Object.entries(mappingColors).sort(([featureA], [featureB]) => {
|
|
@@ -67,7 +70,8 @@ const ColorStackLegend = ({
|
|
|
67
70
|
<div className="my-4 flex w-full flex-wrap justify-start">
|
|
68
71
|
{stackColorArray.map(([feature, color]) => {
|
|
69
72
|
const filteringAllowed = feature !== EVERYTHING_ELSE;
|
|
70
|
-
const isHighlighted =
|
|
73
|
+
const isHighlighted =
|
|
74
|
+
currentSearchString !== undefined ? currentSearchString.includes(feature) : false;
|
|
71
75
|
return (
|
|
72
76
|
<div
|
|
73
77
|
key={feature}
|
|
@@ -79,14 +83,19 @@ const ColorStackLegend = ({
|
|
|
79
83
|
}
|
|
80
84
|
)}
|
|
81
85
|
onClick={() => {
|
|
82
|
-
if (!filteringAllowed) {
|
|
86
|
+
if (!filteringAllowed || isHighlighted) {
|
|
83
87
|
return;
|
|
84
88
|
}
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
89
|
+
|
|
90
|
+
// Check if the current search string is defined and an array
|
|
91
|
+
const updatedSearchString = Array.isArray(currentSearchString)
|
|
92
|
+
? [...currentSearchString, feature] // If array, append the feature
|
|
93
|
+
: // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
|
|
94
|
+
currentSearchString // If not array, preserve current value
|
|
95
|
+
? currentSearchString.split(',') // If string, split by commas
|
|
96
|
+
: [feature]; // If undefined, initialize array with feature
|
|
97
|
+
|
|
98
|
+
setSearchString(updatedSearchString);
|
|
90
99
|
}}
|
|
91
100
|
>
|
|
92
101
|
<div className="flex w-11/12 items-center justify-start">
|
|
@@ -102,7 +111,15 @@ const ColorStackLegend = ({
|
|
|
102
111
|
<Icon
|
|
103
112
|
icon="radix-icons:cross-circled"
|
|
104
113
|
onClick={e => {
|
|
105
|
-
|
|
114
|
+
let searchString: string[] = [];
|
|
115
|
+
if (typeof currentSearchString === 'string') {
|
|
116
|
+
searchString.push(currentSearchString);
|
|
117
|
+
} else {
|
|
118
|
+
searchString = currentSearchString;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// remove the current feature from the search string array of strings
|
|
122
|
+
setSearchString(searchString.filter((f: string) => f !== feature));
|
|
106
123
|
e.stopPropagation();
|
|
107
124
|
}}
|
|
108
125
|
/>
|
|
@@ -19,7 +19,7 @@ import {Tooltip} from 'react-tooltip';
|
|
|
19
19
|
import {useParcaContext} from '@parca/components';
|
|
20
20
|
import {USER_PREFERENCES, useUserPreference} from '@parca/hooks';
|
|
21
21
|
import {ProfileType} from '@parca/parser';
|
|
22
|
-
import {type NavigateFunction} from '@parca/utilities';
|
|
22
|
+
import {getLastItem, type NavigateFunction} from '@parca/utilities';
|
|
23
23
|
|
|
24
24
|
import {useGraphTooltip} from '../../GraphTooltipArrow/useGraphTooltip';
|
|
25
25
|
import {useGraphTooltipMetaInfo} from '../../GraphTooltipArrow/useGraphTooltipMetaInfo';
|
|
@@ -38,6 +38,7 @@ interface ContextMenuProps {
|
|
|
38
38
|
curPath: string[];
|
|
39
39
|
setCurPath: (path: string[]) => void;
|
|
40
40
|
hideMenu: () => void;
|
|
41
|
+
hideBinary: (binaryToRemove: string) => void;
|
|
41
42
|
}
|
|
42
43
|
|
|
43
44
|
const ContextMenu = ({
|
|
@@ -53,6 +54,7 @@ const ContextMenu = ({
|
|
|
53
54
|
setCurPath,
|
|
54
55
|
hideMenu,
|
|
55
56
|
profileType,
|
|
57
|
+
hideBinary,
|
|
56
58
|
}: ContextMenuProps): JSX.Element => {
|
|
57
59
|
const {isDarkMode} = useParcaContext();
|
|
58
60
|
const {enableSourcesView} = useParcaContext();
|
|
@@ -157,6 +159,24 @@ const ContextMenu = ({
|
|
|
157
159
|
<div>Reset view</div>
|
|
158
160
|
</div>
|
|
159
161
|
</Item>
|
|
162
|
+
<Item
|
|
163
|
+
id="hide-binary"
|
|
164
|
+
onClick={() => hideBinary(getLastItem(mappingFile) as string)}
|
|
165
|
+
disabled={mappingFile === null || mappingFile === ''}
|
|
166
|
+
>
|
|
167
|
+
<div
|
|
168
|
+
data-tooltip-id="hide-binary-help"
|
|
169
|
+
data-tooltip-content="Hide all frames for this binary"
|
|
170
|
+
>
|
|
171
|
+
<div className="flex w-full items-center gap-2">
|
|
172
|
+
<Icon icon="bx:bxs-hide" />
|
|
173
|
+
<div>
|
|
174
|
+
Hide Binary {mappingFile !== null && `(${getLastItem(mappingFile) as string})`}
|
|
175
|
+
</div>
|
|
176
|
+
</div>
|
|
177
|
+
</div>
|
|
178
|
+
<Tooltip place="left" id="hide-binary-help" />
|
|
179
|
+
</Item>
|
|
160
180
|
<Submenu
|
|
161
181
|
label={
|
|
162
182
|
<div className="flex w-full items-center gap-2">
|
|
@@ -362,7 +362,6 @@ export const IcicleNode = React.memo(function IcicleNodeNoMemo({
|
|
|
362
362
|
diffPerSecond,
|
|
363
363
|
mappingColors,
|
|
364
364
|
mappingFile,
|
|
365
|
-
functionName,
|
|
366
365
|
});
|
|
367
366
|
const name = useMemo(() => {
|
|
368
367
|
return isRoot ? 'root' : nodeLabel(table, row, level, binaries.length > 1);
|
|
@@ -13,10 +13,11 @@
|
|
|
13
13
|
|
|
14
14
|
import React, {memo, useCallback, useEffect, useMemo, useRef, useState} from 'react';
|
|
15
15
|
|
|
16
|
-
import {
|
|
16
|
+
import {Table, tableFromIPC} from 'apache-arrow';
|
|
17
17
|
import {useContextMenu} from 'react-contexify';
|
|
18
18
|
|
|
19
19
|
import {FlamegraphArrow} from '@parca/client';
|
|
20
|
+
import {useURLState} from '@parca/components';
|
|
20
21
|
import {USER_PREFERENCES, useCurrentColorProfile, useUserPreference} from '@parca/hooks';
|
|
21
22
|
import {ProfileType} from '@parca/parser';
|
|
22
23
|
import {
|
|
@@ -35,7 +36,7 @@ import {useProfileViewContext} from '../../ProfileView/ProfileViewContext';
|
|
|
35
36
|
import ColorStackLegend from './ColorStackLegend';
|
|
36
37
|
import ContextMenu from './ContextMenu';
|
|
37
38
|
import {IcicleNode, RowHeight, mappingColors} from './IcicleGraphNodes';
|
|
38
|
-
import {
|
|
39
|
+
import {extractFeature} from './utils';
|
|
39
40
|
|
|
40
41
|
export const FIELD_LABELS_ONLY = 'labels_only';
|
|
41
42
|
export const FIELD_MAPPING_FILE = 'mapping_file';
|
|
@@ -64,6 +65,7 @@ interface IcicleGraphArrowProps {
|
|
|
64
65
|
setCurPath: (path: string[]) => void;
|
|
65
66
|
navigateTo?: NavigateFunction;
|
|
66
67
|
sortBy: string;
|
|
68
|
+
mappings?: string[];
|
|
67
69
|
}
|
|
68
70
|
|
|
69
71
|
export const IcicleGraphArrow = memo(function IcicleGraphArrow({
|
|
@@ -76,6 +78,7 @@ export const IcicleGraphArrow = memo(function IcicleGraphArrow({
|
|
|
76
78
|
profileType,
|
|
77
79
|
navigateTo,
|
|
78
80
|
sortBy,
|
|
81
|
+
mappings,
|
|
79
82
|
}: IcicleGraphArrowProps): React.JSX.Element {
|
|
80
83
|
const [isContextMenuOpen, setIsContextMenuOpen] = useState<boolean>(false);
|
|
81
84
|
const dispatch = useAppDispatch();
|
|
@@ -96,68 +99,39 @@ export const IcicleGraphArrow = memo(function IcicleGraphArrow({
|
|
|
96
99
|
const svg = useRef(null);
|
|
97
100
|
const ref = useRef<SVGGElement>(null);
|
|
98
101
|
|
|
102
|
+
const [binaryFrameFilter, setBinaryFrameFilter] = useURLState({
|
|
103
|
+
param: 'binary_frame_filter',
|
|
104
|
+
navigateTo,
|
|
105
|
+
});
|
|
106
|
+
|
|
99
107
|
const currentSearchString = (selectQueryParam('search_string') as string) ?? '';
|
|
100
108
|
const {compareMode} = useProfileViewContext();
|
|
101
109
|
const isColorStackLegendEnabled = selectQueryParam('color_stack_legend') === 'true';
|
|
102
110
|
const currentColorProfile = useCurrentColorProfile();
|
|
103
111
|
const colorForSimilarNodes = currentColorProfile.colorForSimilarNodes;
|
|
104
112
|
|
|
105
|
-
const
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
const mappings =
|
|
111
|
-
mappingsDict?.data
|
|
112
|
-
.map(mapping => {
|
|
113
|
-
if (mapping.dictionary == null) {
|
|
114
|
-
return [];
|
|
115
|
-
}
|
|
116
|
-
const len = mapping.dictionary.length;
|
|
117
|
-
const entries: string[] = [];
|
|
118
|
-
for (let i = 0; i < len; i++) {
|
|
119
|
-
const fn = arrowToString(mapping.dictionary.get(i));
|
|
120
|
-
entries.push(getLastItem(fn) ?? '');
|
|
121
|
-
}
|
|
122
|
-
return entries;
|
|
113
|
+
const mappingsList = useMemo(() => {
|
|
114
|
+
const list =
|
|
115
|
+
mappings
|
|
116
|
+
?.map(mapping => {
|
|
117
|
+
return getLastItem(mapping) as string;
|
|
123
118
|
})
|
|
124
119
|
.flat() ?? [];
|
|
125
120
|
|
|
126
121
|
// We add a EVERYTHING ELSE mapping to the list.
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
// We look through the function names to find out if there's a runtime function.
|
|
130
|
-
// Again, we only read through the dictionary, which is much faster than reading through all the rows.
|
|
131
|
-
// We stop as soon as we find a runtime function.
|
|
132
|
-
const functionNamesDict: Vector<Dictionary> | null = table.getChild(FIELD_FUNCTION_NAME);
|
|
133
|
-
functionNamesDict?.data.forEach(fn => {
|
|
134
|
-
if (fn.dictionary == null) {
|
|
135
|
-
return;
|
|
136
|
-
}
|
|
137
|
-
const len = fn.dictionary.length;
|
|
138
|
-
for (let i = 0; i < len; i++) {
|
|
139
|
-
const fn: string | null = arrowToString(functionNamesDict?.get(i));
|
|
140
|
-
if (fn?.startsWith('runtime') === true) {
|
|
141
|
-
mappings.push('runtime');
|
|
142
|
-
break;
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
});
|
|
122
|
+
list.push('');
|
|
146
123
|
|
|
147
124
|
// We sort the mappings alphabetically to make sure that the order is always the same.
|
|
148
|
-
|
|
149
|
-
return mappings;
|
|
150
|
-
}, [table]);
|
|
125
|
+
list.sort((a, b) => a.localeCompare(b));
|
|
151
126
|
|
|
152
|
-
|
|
153
|
-
// Potentially read the function name dictionary and check if it contains strings starting with runtime.
|
|
154
|
-
const mappingFeatures = useMemo(() => {
|
|
155
|
-
return mappings.map(mapping => extractFeature(mapping));
|
|
127
|
+
return list;
|
|
156
128
|
}, [mappings]);
|
|
157
129
|
|
|
158
|
-
// TODO: Unify with mappingFeatures
|
|
159
130
|
const mappingColors = useMemo(() => {
|
|
131
|
+
const mappingFeatures = mappingsList.map(mapping => extractFeature(mapping));
|
|
132
|
+
|
|
160
133
|
const colors: mappingColors = {};
|
|
134
|
+
|
|
161
135
|
Object.entries(mappingFeatures).forEach(([_, feature]) => {
|
|
162
136
|
colors[feature.name] = getColorForFeature(
|
|
163
137
|
feature.name,
|
|
@@ -165,8 +139,9 @@ export const IcicleGraphArrow = memo(function IcicleGraphArrow({
|
|
|
165
139
|
currentColorProfile.colors
|
|
166
140
|
);
|
|
167
141
|
});
|
|
142
|
+
|
|
168
143
|
return colors;
|
|
169
|
-
}, [
|
|
144
|
+
}, [mappingsList, isDarkMode, currentColorProfile]);
|
|
170
145
|
|
|
171
146
|
useEffect(() => {
|
|
172
147
|
if (ref.current != null) {
|
|
@@ -198,6 +173,21 @@ export const IcicleGraphArrow = memo(function IcicleGraphArrow({
|
|
|
198
173
|
setIsContextMenuOpen(isVisible);
|
|
199
174
|
};
|
|
200
175
|
|
|
176
|
+
const hideBinary = (binaryToRemove: string): void => {
|
|
177
|
+
// second/subsequent time filtering out a binary i.e. a binary has already been hidden
|
|
178
|
+
// and we want to hide more binaries, we simply remove the binary from the binaryFrameFilter array in the URL.
|
|
179
|
+
if (Array.isArray(binaryFrameFilter) && binaryFrameFilter.length > 0) {
|
|
180
|
+
const newMappingsList = binaryFrameFilter.filter(mapping => mapping !== binaryToRemove);
|
|
181
|
+
|
|
182
|
+
setBinaryFrameFilter(newMappingsList);
|
|
183
|
+
return;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
// first time hiding a binary
|
|
187
|
+
const newMappingsList = mappingsList.filter(mapping => mapping !== binaryToRemove);
|
|
188
|
+
setBinaryFrameFilter(newMappingsList);
|
|
189
|
+
};
|
|
190
|
+
|
|
201
191
|
// useMemo for the root graph as it otherwise renders the whole graph if the hoveringRow changes.
|
|
202
192
|
const root = useMemo(() => {
|
|
203
193
|
return (
|
|
@@ -286,6 +276,7 @@ export const IcicleGraphArrow = memo(function IcicleGraphArrow({
|
|
|
286
276
|
curPath={curPath}
|
|
287
277
|
setCurPath={setCurPath}
|
|
288
278
|
hideMenu={hideAll}
|
|
279
|
+
hideBinary={hideBinary}
|
|
289
280
|
/>
|
|
290
281
|
{isColorStackLegendEnabled && (
|
|
291
282
|
<ColorStackLegend
|
|
@@ -26,7 +26,6 @@ interface Props {
|
|
|
26
26
|
diff: bigint | null;
|
|
27
27
|
diffPerSecond: number | null;
|
|
28
28
|
mappingColors: mappingColors;
|
|
29
|
-
functionName: string | null;
|
|
30
29
|
mappingFile: string | null;
|
|
31
30
|
}
|
|
32
31
|
|
|
@@ -38,7 +37,6 @@ const useNodeColor = ({
|
|
|
38
37
|
diff,
|
|
39
38
|
diffPerSecond,
|
|
40
39
|
mappingColors,
|
|
41
|
-
functionName,
|
|
42
40
|
mappingFile,
|
|
43
41
|
}: Props): string => {
|
|
44
42
|
if (compareMode) {
|
|
@@ -49,12 +47,7 @@ const useNodeColor = ({
|
|
|
49
47
|
return diffColor(diff ?? 0n, cumulative, isDarkMode);
|
|
50
48
|
}
|
|
51
49
|
|
|
52
|
-
|
|
53
|
-
// If it does, we color it as runtime. Otherwise, we check the mapping file.
|
|
54
|
-
// If there is no mapping file, we color it as 'everything else'.
|
|
55
|
-
return functionName?.startsWith('runtime') === true
|
|
56
|
-
? mappingColors.runtime
|
|
57
|
-
: mappingColors[getLastItem(mappingFile ?? '') ?? EVERYTHING_ELSE];
|
|
50
|
+
return mappingColors[getLastItem(mappingFile ?? '') ?? EVERYTHING_ELSE];
|
|
58
51
|
};
|
|
59
52
|
|
|
60
53
|
export default useNodeColor;
|
|
@@ -19,7 +19,6 @@ import {divide, getLastItem, valueFormatter} from '@parca/utilities';
|
|
|
19
19
|
import {hexifyAddress} from '../../utils';
|
|
20
20
|
import {
|
|
21
21
|
FIELD_FUNCTION_NAME,
|
|
22
|
-
FIELD_LABELS,
|
|
23
22
|
FIELD_LABELS_ONLY,
|
|
24
23
|
FIELD_LOCATION_ADDRESS,
|
|
25
24
|
FIELD_MAPPING_FILE,
|
|
@@ -66,10 +65,6 @@ export function nodeLabel(
|
|
|
66
65
|
}
|
|
67
66
|
|
|
68
67
|
export const extractFeature = (mapping: string): Feature => {
|
|
69
|
-
if (mapping === 'runtime' || mapping === 'root') {
|
|
70
|
-
return {name: 'runtime', type: FEATURE_TYPES.Runtime};
|
|
71
|
-
}
|
|
72
|
-
|
|
73
68
|
if (mapping != null && mapping !== '') {
|
|
74
69
|
return {name: mapping, type: FEATURE_TYPES.Binary};
|
|
75
70
|
}
|