@parca/profile 0.16.111 → 0.16.113
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/ProfileExplorer/index.js +23 -2
- package/dist/ProfileIcicleGraph/IcicleGraph/IcicleGraphNodes.js +12 -3
- package/dist/ProfileIcicleGraph/IcicleGraph/useColoredGraph.js +5 -4
- package/dist/ProfileIcicleGraph/IcicleGraph/utils.d.ts +3 -2
- package/dist/ProfileIcicleGraph/IcicleGraph/utils.js +13 -9
- package/package.json +4 -4
- package/src/ProfileExplorer/index.tsx +18 -2
- package/src/ProfileIcicleGraph/IcicleGraph/IcicleGraphNodes.tsx +11 -4
- package/src/ProfileIcicleGraph/IcicleGraph/useColoredGraph.ts +9 -7
- package/src/ProfileIcicleGraph/IcicleGraph/utils.ts +15 -10
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,14 @@
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
|
5
5
|
|
|
6
|
+
## [0.16.113](https://github.com/parca-dev/parca/compare/@parca/profile@0.16.112...@parca/profile@0.16.113) (2023-02-13)
|
|
7
|
+
|
|
8
|
+
**Note:** Version bump only for package @parca/profile
|
|
9
|
+
|
|
10
|
+
## [0.16.112](https://github.com/parca-dev/parca/compare/@parca/profile@0.16.111...@parca/profile@0.16.112) (2023-02-09)
|
|
11
|
+
|
|
12
|
+
**Note:** Version bump only for package @parca/profile
|
|
13
|
+
|
|
6
14
|
## [0.16.111](https://github.com/parca-dev/parca/compare/@parca/profile@0.16.109...@parca/profile@0.16.111) (2023-02-09)
|
|
7
15
|
|
|
8
16
|
**Note:** Version bump only for package @parca/profile
|
|
@@ -9,13 +9,26 @@ var __assign = (this && this.__assign) || function () {
|
|
|
9
9
|
};
|
|
10
10
|
return __assign.apply(this, arguments);
|
|
11
11
|
};
|
|
12
|
-
import { jsx as _jsx } from "react/jsx-runtime";
|
|
12
|
+
import { Fragment as _Fragment, jsx as _jsx } from "react/jsx-runtime";
|
|
13
|
+
// Copyright 2022 The Parca Authors
|
|
14
|
+
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
15
|
+
// you may not use this file except in compliance with the License.
|
|
16
|
+
// You may obtain a copy of the License at
|
|
17
|
+
//
|
|
18
|
+
// http://www.apache.org/licenses/LICENSE-2.0
|
|
19
|
+
//
|
|
20
|
+
// Unless required by applicable law or agreed to in writing, software
|
|
21
|
+
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
22
|
+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
23
|
+
// See the License for the specific language governing permissions and
|
|
24
|
+
// limitations under the License.
|
|
25
|
+
import { useProfileTypes } from '../ProfileSelector';
|
|
13
26
|
import { ProfileSelectionFromParams, SuffixParams } from '..';
|
|
14
27
|
import ProfileExplorerSingle from './ProfileExplorerSingle';
|
|
15
28
|
import ProfileExplorerCompare from './ProfileExplorerCompare';
|
|
16
29
|
import { store } from '@parca/store';
|
|
17
30
|
import { Provider } from 'react-redux';
|
|
18
|
-
import { DateTimeRange } from '@parca/components';
|
|
31
|
+
import { DateTimeRange, useParcaContext } from '@parca/components';
|
|
19
32
|
var getExpressionAsAString = function (expression) {
|
|
20
33
|
var x = Array.isArray(expression) ? expression.join() : expression;
|
|
21
34
|
return x;
|
|
@@ -49,6 +62,8 @@ var swapQueryParameters = function (o) {
|
|
|
49
62
|
var ProfileExplorerApp = function (_a) {
|
|
50
63
|
var _b, _c;
|
|
51
64
|
var queryClient = _a.queryClient, queryParams = _a.queryParams, navigateTo = _a.navigateTo;
|
|
65
|
+
var _d = useProfileTypes(queryClient), profileTypesLoading = _d.loading, profileTypesData = _d.data, error = _d.error;
|
|
66
|
+
var _e = useParcaContext(), loader = _e.loader, noDataPrompt = _e.noDataPrompt;
|
|
52
67
|
/* eslint-disable @typescript-eslint/naming-convention */
|
|
53
68
|
var from_a = queryParams.from_a, to_a = queryParams.to_a, merge_a = queryParams.merge_a, profile_name_a = queryParams.profile_name_a, labels_a = queryParams.labels_a, time_a = queryParams.time_a, time_selection_a = queryParams.time_selection_a, compare_a = queryParams.compare_a, from_b = queryParams.from_b, to_b = queryParams.to_b, merge_b = queryParams.merge_b, profile_name_b = queryParams.profile_name_b, labels_b = queryParams.labels_b, time_b = queryParams.time_b, time_selection_b = queryParams.time_selection_b, compare_b = queryParams.compare_b, filter_by_function = queryParams.filter_by_function, dashboard_items = queryParams.dashboard_items;
|
|
54
69
|
/* eslint-enable @typescript-eslint/naming-convention */
|
|
@@ -75,6 +90,12 @@ var ProfileExplorerApp = function (_a) {
|
|
|
75
90
|
var selectProfileB = function (p) {
|
|
76
91
|
return selectProfile(p, '_b');
|
|
77
92
|
};
|
|
93
|
+
if (profileTypesLoading) {
|
|
94
|
+
return _jsx(_Fragment, { children: loader });
|
|
95
|
+
}
|
|
96
|
+
if ((profileTypesData === null || profileTypesData === void 0 ? void 0 : profileTypesData.types.length) === 0) {
|
|
97
|
+
return _jsx(_Fragment, { children: noDataPrompt });
|
|
98
|
+
}
|
|
78
99
|
// Show the SingleProfileExplorer when not comparing
|
|
79
100
|
if (compare_a !== 'true' && compare_b !== 'true') {
|
|
80
101
|
var query_1 = {
|
|
@@ -26,15 +26,21 @@ import React, { useMemo } from 'react';
|
|
|
26
26
|
import cx from 'classnames';
|
|
27
27
|
import { scaleLinear } from 'd3-scale';
|
|
28
28
|
import { isSearchMatch } from '@parca/functions';
|
|
29
|
+
import { useAppSelector, selectBinaries } from '@parca/store';
|
|
29
30
|
import { nodeLabel } from './utils';
|
|
30
31
|
import useNodeColor from './useNodeColor';
|
|
31
32
|
import { useKeyDown } from '@parca/components';
|
|
32
33
|
export var RowHeight = 26;
|
|
33
34
|
export var IcicleGraphNodes = React.memo(function IcicleGraphNodes(_a) {
|
|
34
35
|
var data = _a.data, strings = _a.strings, mappings = _a.mappings, locations = _a.locations, functions = _a.functions, x = _a.x, y = _a.y, xScale = _a.xScale, total = _a.total, totalWidth = _a.totalWidth, level = _a.level, setHoveringNode = _a.setHoveringNode, path = _a.path, setCurPath = _a.setCurPath, curPath = _a.curPath, searchString = _a.searchString, compareMode = _a.compareMode;
|
|
36
|
+
var binaries = useAppSelector(selectBinaries);
|
|
35
37
|
var nodes = curPath.length === 0
|
|
36
38
|
? data
|
|
37
|
-
: data.filter(function (d) {
|
|
39
|
+
: data.filter(function (d) {
|
|
40
|
+
return d != null &&
|
|
41
|
+
curPath[0] ===
|
|
42
|
+
nodeLabel(d, strings, mappings, locations, functions, binaries.length > 1);
|
|
43
|
+
});
|
|
38
44
|
return (_jsx("g", __assign({ transform: "translate(".concat(x, ", ").concat(y, ")") }, { children: nodes.map(function (d, i) {
|
|
39
45
|
var start = nodes.slice(0, i).reduce(function (sum, d) { return sum + parseFloat(d.cumulative); }, 0);
|
|
40
46
|
var xStart = xScale(start);
|
|
@@ -52,11 +58,14 @@ var fadedIcicleRectStyles = {
|
|
|
52
58
|
};
|
|
53
59
|
export var IcicleNode = React.memo(function IcicleNode(_a) {
|
|
54
60
|
var x = _a.x, y = _a.y, height = _a.height, setCurPath = _a.setCurPath, setHoveringNode = _a.setHoveringNode, curPath = _a.curPath, level = _a.level, path = _a.path, data = _a.data, strings = _a.strings, mappings = _a.mappings, locations = _a.locations, functions = _a.functions, total = _a.total, totalWidth = _a.totalWidth, xScale = _a.xScale, _b = _a.isRoot, isRoot = _b === void 0 ? false : _b, searchString = _a.searchString, compareMode = _a.compareMode;
|
|
61
|
+
var binaries = useAppSelector(selectBinaries);
|
|
55
62
|
var isShiftDown = useKeyDown().isShiftDown;
|
|
56
63
|
var colorResult = useNodeColor({ data: data, compareMode: compareMode });
|
|
57
64
|
var name = useMemo(function () {
|
|
58
|
-
return isRoot
|
|
59
|
-
|
|
65
|
+
return isRoot
|
|
66
|
+
? 'root'
|
|
67
|
+
: nodeLabel(data, strings, mappings, locations, functions, binaries.length > 1);
|
|
68
|
+
}, [data, strings, mappings, locations, functions, isRoot, binaries]);
|
|
60
69
|
var nextPath = path.concat([name]);
|
|
61
70
|
var isFaded = curPath.length > 0 && name !== curPath[curPath.length - 1];
|
|
62
71
|
var styles = isFaded ? fadedIcicleRectStyles : icicleRectStyles;
|
|
@@ -34,8 +34,9 @@ var colorNodes = function (nodes, strings, mappings, locations, functions, featu
|
|
|
34
34
|
if (node.children != null) {
|
|
35
35
|
coloredNode.children = colorNodes(node.children, strings, mappings, locations, functions, features);
|
|
36
36
|
}
|
|
37
|
-
|
|
38
|
-
|
|
37
|
+
var feature = extractFeature(node, mappings, locations, strings, functions);
|
|
38
|
+
coloredNode.feature = feature.name;
|
|
39
|
+
features[feature.name] = feature.type;
|
|
39
40
|
return coloredNode;
|
|
40
41
|
});
|
|
41
42
|
};
|
|
@@ -46,11 +47,11 @@ var useColoredGraph = function (graph) {
|
|
|
46
47
|
var _a = useMemo(function () {
|
|
47
48
|
var _a;
|
|
48
49
|
if (graph.root == null) {
|
|
49
|
-
return [graph,
|
|
50
|
+
return [graph, {}];
|
|
50
51
|
}
|
|
51
52
|
var features = {};
|
|
52
53
|
var coloredGraph = __assign(__assign({}, graph), { root: __assign(__assign({}, graph.root), { children: colorNodes((_a = graph.root.children) !== null && _a !== void 0 ? _a : [], graph.stringTable, graph.mapping, graph.locations, graph.function, features) }) });
|
|
53
|
-
return [coloredGraph,
|
|
54
|
+
return [coloredGraph, features];
|
|
54
55
|
}, [graph]), coloredGraph = _a[0], features = _a[1];
|
|
55
56
|
useEffect(function () {
|
|
56
57
|
dispatch(setFeatures({ features: features, colorProfileName: colorProfile, isDarkMode: isDarkMode }));
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { FlamegraphNode } from '@parca/client';
|
|
2
2
|
import { Mapping, Function as ParcaFunction, Location } from '@parca/client/dist/parca/metastore/v1alpha1/metastore';
|
|
3
|
+
import type { Feature } from '@parca/store';
|
|
3
4
|
export declare const getBinaryName: (node: FlamegraphNode, mappings: Mapping[], locations: Location[], strings: string[]) => string | undefined;
|
|
4
|
-
export declare function nodeLabel(node: FlamegraphNode, strings: string[], mappings: Mapping[], locations: Location[], functions: ParcaFunction[]): string;
|
|
5
|
-
export declare const extractFeature: (data: FlamegraphNode, mappings: Mapping[], locations: Location[], strings: string[], functions: ParcaFunction[]) =>
|
|
5
|
+
export declare function nodeLabel(node: FlamegraphNode, strings: string[], mappings: Mapping[], locations: Location[], functions: ParcaFunction[], showBinaryName: boolean): string;
|
|
6
|
+
export declare const extractFeature: (data: FlamegraphNode, mappings: Mapping[], locations: Location[], strings: string[], functions: ParcaFunction[]) => Feature;
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
// limitations under the License.
|
|
13
13
|
import { getLastItem } from '@parca/functions';
|
|
14
14
|
import { hexifyAddress } from '../../utils';
|
|
15
|
-
import { EVERYTHING_ELSE } from '@parca/store';
|
|
15
|
+
import { EVERYTHING_ELSE, FEATURE_TYPES } from '@parca/store';
|
|
16
16
|
export var getBinaryName = function (node, mappings, locations, strings) {
|
|
17
17
|
var _a, _b;
|
|
18
18
|
if (((_a = node.meta) === null || _a === void 0 ? void 0 : _a.locationIndex) === undefined || ((_b = node.meta) === null || _b === void 0 ? void 0 : _b.locationIndex) === 0) {
|
|
@@ -29,31 +29,35 @@ export var getBinaryName = function (node, mappings, locations, strings) {
|
|
|
29
29
|
var mappingFile = strings[mapping.fileStringIndex];
|
|
30
30
|
return getLastItem(mappingFile);
|
|
31
31
|
};
|
|
32
|
-
export function nodeLabel(node, strings, mappings, locations, functions) {
|
|
32
|
+
export function nodeLabel(node, strings, mappings, locations, functions, showBinaryName) {
|
|
33
33
|
var _a, _b;
|
|
34
34
|
if (((_a = node.meta) === null || _a === void 0 ? void 0 : _a.locationIndex) === undefined)
|
|
35
35
|
return '<unknown>';
|
|
36
36
|
if (((_b = node.meta) === null || _b === void 0 ? void 0 : _b.locationIndex) === 0)
|
|
37
37
|
return '<unknown>';
|
|
38
38
|
var location = locations[node.meta.locationIndex - 1];
|
|
39
|
-
var
|
|
40
|
-
|
|
39
|
+
var mappingString = '';
|
|
40
|
+
if (showBinaryName) {
|
|
41
|
+
var binary = getBinaryName(node, mappings, locations, strings);
|
|
42
|
+
if (binary != null)
|
|
43
|
+
mappingString = "[".concat(binary, "]");
|
|
44
|
+
}
|
|
41
45
|
if (location.lines.length > 0) {
|
|
42
46
|
var funcName = strings[functions[location.lines[node.meta.lineIndex].functionIndex - 1].nameStringIndex];
|
|
43
|
-
return "".concat(mappingString, " ").concat(funcName);
|
|
47
|
+
return "".concat(mappingString.length > 0 ? "".concat(mappingString, " ") : '').concat(funcName);
|
|
44
48
|
}
|
|
45
49
|
var address = hexifyAddress(location.address);
|
|
46
50
|
var fallback = "".concat(mappingString).concat(address);
|
|
47
51
|
return fallback === '' ? '<unknown>' : fallback;
|
|
48
52
|
}
|
|
49
53
|
export var extractFeature = function (data, mappings, locations, strings, functions) {
|
|
50
|
-
var name = nodeLabel(data, strings, mappings, locations, functions).trim();
|
|
54
|
+
var name = nodeLabel(data, strings, mappings, locations, functions, false).trim();
|
|
51
55
|
if (name.startsWith('runtime') || name === 'root') {
|
|
52
|
-
return 'runtime';
|
|
56
|
+
return { name: 'runtime', type: FEATURE_TYPES.Runtime };
|
|
53
57
|
}
|
|
54
58
|
var binaryName = getBinaryName(data, mappings, locations, strings);
|
|
55
59
|
if (binaryName != null) {
|
|
56
|
-
return binaryName;
|
|
60
|
+
return { name: binaryName, type: FEATURE_TYPES.Binary };
|
|
57
61
|
}
|
|
58
|
-
return EVERYTHING_ELSE;
|
|
62
|
+
return { name: EVERYTHING_ELSE, type: FEATURE_TYPES.Misc };
|
|
59
63
|
};
|
package/package.json
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@parca/profile",
|
|
3
|
-
"version": "0.16.
|
|
3
|
+
"version": "0.16.113",
|
|
4
4
|
"description": "Profile viewing libraries",
|
|
5
5
|
"dependencies": {
|
|
6
6
|
"@parca/client": "^0.16.62",
|
|
7
|
-
"@parca/components": "^0.16.
|
|
7
|
+
"@parca/components": "^0.16.95",
|
|
8
8
|
"@parca/dynamicsize": "^0.16.52",
|
|
9
9
|
"@parca/functions": "^0.16.60",
|
|
10
10
|
"@parca/parser": "^0.16.53",
|
|
11
|
-
"@parca/store": "^0.16.
|
|
11
|
+
"@parca/store": "^0.16.56",
|
|
12
12
|
"@types/react-beautiful-dnd": "^13.1.3",
|
|
13
13
|
"d3": "7.8.2",
|
|
14
14
|
"d3-scale": "^4.0.2",
|
|
@@ -45,5 +45,5 @@
|
|
|
45
45
|
"access": "public",
|
|
46
46
|
"registry": "https://registry.npmjs.org/"
|
|
47
47
|
},
|
|
48
|
-
"gitHead": "
|
|
48
|
+
"gitHead": "425c828b992528c8588ad6992fcda1d9f160f170"
|
|
49
49
|
}
|
|
@@ -11,14 +11,14 @@
|
|
|
11
11
|
// See the License for the specific language governing permissions and
|
|
12
12
|
// limitations under the License.
|
|
13
13
|
|
|
14
|
-
import {QuerySelection} from '../ProfileSelector';
|
|
14
|
+
import {QuerySelection, useProfileTypes} from '../ProfileSelector';
|
|
15
15
|
import {ProfileSelection, ProfileSelectionFromParams, SuffixParams} from '..';
|
|
16
16
|
import ProfileExplorerSingle from './ProfileExplorerSingle';
|
|
17
17
|
import ProfileExplorerCompare from './ProfileExplorerCompare';
|
|
18
18
|
import {QueryServiceClient} from '@parca/client';
|
|
19
19
|
import {store} from '@parca/store';
|
|
20
20
|
import {Provider} from 'react-redux';
|
|
21
|
-
import {DateTimeRange} from '@parca/components';
|
|
21
|
+
import {DateTimeRange, useParcaContext} from '@parca/components';
|
|
22
22
|
import type {NavigateFunction} from '@parca/functions';
|
|
23
23
|
|
|
24
24
|
interface ProfileExplorerProps {
|
|
@@ -71,6 +71,14 @@ const ProfileExplorerApp = ({
|
|
|
71
71
|
queryParams,
|
|
72
72
|
navigateTo,
|
|
73
73
|
}: ProfileExplorerProps): JSX.Element => {
|
|
74
|
+
const {
|
|
75
|
+
loading: profileTypesLoading,
|
|
76
|
+
data: profileTypesData,
|
|
77
|
+
error,
|
|
78
|
+
} = useProfileTypes(queryClient);
|
|
79
|
+
|
|
80
|
+
const {loader, noDataPrompt} = useParcaContext();
|
|
81
|
+
|
|
74
82
|
/* eslint-disable @typescript-eslint/naming-convention */
|
|
75
83
|
let {
|
|
76
84
|
from_a,
|
|
@@ -126,6 +134,14 @@ const ProfileExplorerApp = ({
|
|
|
126
134
|
return selectProfile(p, '_b');
|
|
127
135
|
};
|
|
128
136
|
|
|
137
|
+
if (profileTypesLoading) {
|
|
138
|
+
return <>{loader}</>;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
if (profileTypesData?.types.length === 0) {
|
|
142
|
+
return <>{noDataPrompt}</>;
|
|
143
|
+
}
|
|
144
|
+
|
|
129
145
|
// Show the SingleProfileExplorer when not comparing
|
|
130
146
|
if (compare_a !== 'true' && compare_b !== 'true') {
|
|
131
147
|
const query = {
|
|
@@ -22,7 +22,7 @@ import {
|
|
|
22
22
|
} from '@parca/client/dist/parca/metastore/v1alpha1/metastore';
|
|
23
23
|
import {isSearchMatch} from '@parca/functions';
|
|
24
24
|
import {FlamegraphNode, FlamegraphRootNode} from '@parca/client';
|
|
25
|
-
|
|
25
|
+
import {useAppSelector, selectBinaries} from '@parca/store';
|
|
26
26
|
import {nodeLabel} from './utils';
|
|
27
27
|
import useNodeColor from './useNodeColor';
|
|
28
28
|
import {useKeyDown} from '@parca/components';
|
|
@@ -68,11 +68,15 @@ export const IcicleGraphNodes = React.memo(function IcicleGraphNodes({
|
|
|
68
68
|
searchString,
|
|
69
69
|
compareMode,
|
|
70
70
|
}: IcicleGraphNodesProps): JSX.Element {
|
|
71
|
+
const binaries = useAppSelector(selectBinaries);
|
|
71
72
|
const nodes =
|
|
72
73
|
curPath.length === 0
|
|
73
74
|
? data
|
|
74
75
|
: data.filter(
|
|
75
|
-
d =>
|
|
76
|
+
d =>
|
|
77
|
+
d != null &&
|
|
78
|
+
curPath[0] ===
|
|
79
|
+
nodeLabel(d, strings, mappings, locations, functions, binaries.length > 1)
|
|
76
80
|
);
|
|
77
81
|
|
|
78
82
|
return (
|
|
@@ -162,11 +166,14 @@ export const IcicleNode = React.memo(function IcicleNode({
|
|
|
162
166
|
searchString,
|
|
163
167
|
compareMode,
|
|
164
168
|
}: IcicleNodeProps): JSX.Element {
|
|
169
|
+
const binaries = useAppSelector(selectBinaries);
|
|
165
170
|
const {isShiftDown} = useKeyDown();
|
|
166
171
|
const colorResult = useNodeColor({data, compareMode});
|
|
167
172
|
const name = useMemo(() => {
|
|
168
|
-
return isRoot
|
|
169
|
-
|
|
173
|
+
return isRoot
|
|
174
|
+
? 'root'
|
|
175
|
+
: nodeLabel(data, strings, mappings, locations, functions, binaries.length > 1);
|
|
176
|
+
}, [data, strings, mappings, locations, functions, isRoot, binaries]);
|
|
170
177
|
const nextPath = path.concat([name]);
|
|
171
178
|
const isFaded = curPath.length > 0 && name !== curPath[curPath.length - 1];
|
|
172
179
|
const styles = isFaded ? fadedIcicleRectStyles : icicleRectStyles;
|
|
@@ -20,6 +20,7 @@ import {
|
|
|
20
20
|
import type {ColorProfileName} from '@parca/functions';
|
|
21
21
|
import useUserPreference, {USER_PREFERENCES} from '@parca/functions/useUserPreference';
|
|
22
22
|
import {setFeatures, useAppDispatch, useAppSelector, selectDarkMode} from '@parca/store';
|
|
23
|
+
import type {FeatureType, FeaturesMap} from '@parca/store';
|
|
23
24
|
import {useEffect, useMemo} from 'react';
|
|
24
25
|
import {extractFeature} from './utils';
|
|
25
26
|
|
|
@@ -43,7 +44,7 @@ const colorNodes = (
|
|
|
43
44
|
mappings: Mapping[],
|
|
44
45
|
locations: Location[],
|
|
45
46
|
functions: ParcaFunction[],
|
|
46
|
-
features: {[key: string]:
|
|
47
|
+
features: {[key: string]: FeatureType}
|
|
47
48
|
): ColoredFlamegraphNode[] => {
|
|
48
49
|
if (nodes === undefined) {
|
|
49
50
|
return [];
|
|
@@ -62,8 +63,9 @@ const colorNodes = (
|
|
|
62
63
|
features
|
|
63
64
|
);
|
|
64
65
|
}
|
|
65
|
-
|
|
66
|
-
|
|
66
|
+
const feature = extractFeature(node, mappings, locations, strings, functions);
|
|
67
|
+
coloredNode.feature = feature.name;
|
|
68
|
+
features[feature.name] = feature.type;
|
|
67
69
|
return coloredNode;
|
|
68
70
|
});
|
|
69
71
|
};
|
|
@@ -75,11 +77,11 @@ const useColoredGraph = (graph: Flamegraph): ColoredFlamegraph => {
|
|
|
75
77
|
);
|
|
76
78
|
const isDarkMode = useAppSelector(selectDarkMode);
|
|
77
79
|
|
|
78
|
-
const [coloredGraph, features]: [ColoredFlamegraph,
|
|
80
|
+
const [coloredGraph, features]: [ColoredFlamegraph, FeaturesMap] = useMemo(() => {
|
|
79
81
|
if (graph.root == null) {
|
|
80
|
-
return [graph as ColoredFlamegraph,
|
|
82
|
+
return [graph as ColoredFlamegraph, {}];
|
|
81
83
|
}
|
|
82
|
-
const features:
|
|
84
|
+
const features: FeaturesMap = {};
|
|
83
85
|
const coloredGraph = {
|
|
84
86
|
...graph,
|
|
85
87
|
root: {
|
|
@@ -94,7 +96,7 @@ const useColoredGraph = (graph: Flamegraph): ColoredFlamegraph => {
|
|
|
94
96
|
),
|
|
95
97
|
},
|
|
96
98
|
};
|
|
97
|
-
return [coloredGraph,
|
|
99
|
+
return [coloredGraph, features];
|
|
98
100
|
}, [graph]);
|
|
99
101
|
|
|
100
102
|
useEffect(() => {
|
|
@@ -19,7 +19,8 @@ import {
|
|
|
19
19
|
Location,
|
|
20
20
|
} from '@parca/client/dist/parca/metastore/v1alpha1/metastore';
|
|
21
21
|
import {hexifyAddress} from '../../utils';
|
|
22
|
-
import {EVERYTHING_ELSE} from '@parca/store';
|
|
22
|
+
import {EVERYTHING_ELSE, FEATURE_TYPES} from '@parca/store';
|
|
23
|
+
import type {Feature} from '@parca/store';
|
|
23
24
|
|
|
24
25
|
export const getBinaryName = (
|
|
25
26
|
node: FlamegraphNode,
|
|
@@ -50,21 +51,25 @@ export function nodeLabel(
|
|
|
50
51
|
strings: string[],
|
|
51
52
|
mappings: Mapping[],
|
|
52
53
|
locations: Location[],
|
|
53
|
-
functions: ParcaFunction[]
|
|
54
|
+
functions: ParcaFunction[],
|
|
55
|
+
showBinaryName: boolean
|
|
54
56
|
): string {
|
|
55
57
|
if (node.meta?.locationIndex === undefined) return '<unknown>';
|
|
56
58
|
if (node.meta?.locationIndex === 0) return '<unknown>';
|
|
57
59
|
|
|
58
60
|
const location = locations[node.meta.locationIndex - 1];
|
|
59
61
|
|
|
60
|
-
|
|
62
|
+
let mappingString = '';
|
|
61
63
|
|
|
62
|
-
|
|
64
|
+
if (showBinaryName) {
|
|
65
|
+
const binary = getBinaryName(node, mappings, locations, strings);
|
|
66
|
+
if (binary != null) mappingString = `[${binary}]`;
|
|
67
|
+
}
|
|
63
68
|
|
|
64
69
|
if (location.lines.length > 0) {
|
|
65
70
|
const funcName =
|
|
66
71
|
strings[functions[location.lines[node.meta.lineIndex].functionIndex - 1].nameStringIndex];
|
|
67
|
-
return `${mappingString} ${funcName}`;
|
|
72
|
+
return `${mappingString.length > 0 ? `${mappingString} ` : ''}${funcName}`;
|
|
68
73
|
}
|
|
69
74
|
|
|
70
75
|
const address = hexifyAddress(location.address);
|
|
@@ -79,16 +84,16 @@ export const extractFeature = (
|
|
|
79
84
|
locations: Location[],
|
|
80
85
|
strings: string[],
|
|
81
86
|
functions: ParcaFunction[]
|
|
82
|
-
):
|
|
83
|
-
const name = nodeLabel(data, strings, mappings, locations, functions).trim();
|
|
87
|
+
): Feature => {
|
|
88
|
+
const name = nodeLabel(data, strings, mappings, locations, functions, false).trim();
|
|
84
89
|
if (name.startsWith('runtime') || name === 'root') {
|
|
85
|
-
return 'runtime';
|
|
90
|
+
return {name: 'runtime', type: FEATURE_TYPES.Runtime};
|
|
86
91
|
}
|
|
87
92
|
|
|
88
93
|
const binaryName = getBinaryName(data, mappings, locations, strings);
|
|
89
94
|
if (binaryName != null) {
|
|
90
|
-
return binaryName;
|
|
95
|
+
return {name: binaryName, type: FEATURE_TYPES.Binary};
|
|
91
96
|
}
|
|
92
97
|
|
|
93
|
-
return EVERYTHING_ELSE;
|
|
98
|
+
return {name: EVERYTHING_ELSE, type: FEATURE_TYPES.Misc};
|
|
94
99
|
};
|