@parca/profile 0.16.63 → 0.16.65
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/GraphTooltip/index.js +22 -13
- package/dist/IcicleGraph.js +10 -5
- package/dist/MatchersInput/index.js +2 -2
- package/dist/ProfileMetricsGraph/index.js +2 -2
- package/dist/ProfileView.js +6 -6
- package/dist/ProfileViewWithData.js +9 -1
- package/dist/useQuery.js +0 -1
- package/package.json +4 -4
- package/src/GraphTooltip/index.tsx +29 -19
- package/src/IcicleGraph.tsx +11 -3
- package/src/MatchersInput/index.tsx +3 -2
- package/src/ProfileMetricsGraph/index.tsx +2 -2
- package/src/ProfileView.tsx +13 -11
- package/src/ProfileViewWithData.tsx +10 -1
- package/src/useQuery.tsx +0 -1
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.65 (2022-11-09)
|
|
7
|
+
|
|
8
|
+
**Note:** Version bump only for package @parca/profile
|
|
9
|
+
|
|
10
|
+
## [0.16.64](https://github.com/parca-dev/parca/compare/@parca/profile@0.16.63...@parca/profile@0.16.64) (2022-11-08)
|
|
11
|
+
|
|
12
|
+
**Note:** Version bump only for package @parca/profile
|
|
13
|
+
|
|
6
14
|
## [0.16.63](https://github.com/parca-dev/parca/compare/@parca/profile@0.16.62...@parca/profile@0.16.63) (2022-11-08)
|
|
7
15
|
|
|
8
16
|
**Note:** Version bump only for package @parca/profile
|
|
@@ -74,20 +74,29 @@ var TooltipMetaInfo = function (_a) {
|
|
|
74
74
|
if (hoveringNode.meta === undefined)
|
|
75
75
|
return _jsx(_Fragment, {});
|
|
76
76
|
// populate meta from the flamegraph metadata tables
|
|
77
|
-
if (locations !== undefined
|
|
78
|
-
|
|
77
|
+
if (locations !== undefined &&
|
|
78
|
+
hoveringNode.meta.locationIndex !== undefined &&
|
|
79
|
+
hoveringNode.meta.locationIndex !== 0) {
|
|
80
|
+
var location_1 = locations[hoveringNode.meta.locationIndex - 1];
|
|
79
81
|
hoveringNode.meta.location = location_1;
|
|
80
|
-
if (
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
mapping
|
|
82
|
+
if (location_1 !== undefined) {
|
|
83
|
+
if (mappings !== undefined &&
|
|
84
|
+
location_1.mappingIndex !== undefined &&
|
|
85
|
+
location_1.mappingIndex !== 0) {
|
|
86
|
+
var mapping = mappings[location_1.mappingIndex - 1];
|
|
87
|
+
if (strings !== undefined && mapping !== undefined) {
|
|
88
|
+
mapping.file =
|
|
89
|
+
(mapping === null || mapping === void 0 ? void 0 : mapping.fileStringIndex) !== undefined ? strings[mapping.fileStringIndex] : '';
|
|
90
|
+
mapping.buildId =
|
|
91
|
+
(mapping === null || mapping === void 0 ? void 0 : mapping.buildIdStringIndex) !== undefined ? strings[mapping.buildIdStringIndex] : '';
|
|
92
|
+
}
|
|
93
|
+
hoveringNode.meta.mapping = mapping;
|
|
85
94
|
}
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
var func = functions[
|
|
95
|
+
if (functions !== undefined &&
|
|
96
|
+
location_1.lines !== undefined &&
|
|
97
|
+
hoveringNode.meta.lineIndex !== undefined &&
|
|
98
|
+
hoveringNode.meta.lineIndex < location_1.lines.length) {
|
|
99
|
+
var func = functions[location_1.lines[hoveringNode.meta.lineIndex].functionIndex - 1];
|
|
91
100
|
if (strings !== undefined) {
|
|
92
101
|
func.name = strings[func.nameStringIndex];
|
|
93
102
|
func.systemName = strings[func.systemNameStringIndex];
|
|
@@ -95,7 +104,7 @@ var TooltipMetaInfo = function (_a) {
|
|
|
95
104
|
}
|
|
96
105
|
hoveringNode.meta.function = func;
|
|
97
106
|
}
|
|
98
|
-
}
|
|
107
|
+
}
|
|
99
108
|
}
|
|
100
109
|
var getTextForFile = function (hoveringNode) {
|
|
101
110
|
var _a, _b, _c, _d;
|
package/dist/IcicleGraph.js
CHANGED
|
@@ -56,14 +56,19 @@ function IcicleRect(_a) {
|
|
|
56
56
|
} }), width > 5 && (_jsx("svg", __assign({ width: width - 5, height: height }, { children: _jsx("text", __assign({ x: 5, y: 15, style: { fontSize: '12px' } }, { children: name })) })))] })));
|
|
57
57
|
}
|
|
58
58
|
export function nodeLabel(node, strings, mappings, locations, functions) {
|
|
59
|
-
var _a, _b;
|
|
59
|
+
var _a, _b, _c;
|
|
60
60
|
if (((_a = node.meta) === null || _a === void 0 ? void 0 : _a.locationIndex) === undefined)
|
|
61
61
|
return '<unknown>';
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
var
|
|
62
|
+
if (((_b = node.meta) === null || _b === void 0 ? void 0 : _b.locationIndex) === 0)
|
|
63
|
+
return '<unknown>';
|
|
64
|
+
var location = locations[node.meta.locationIndex - 1];
|
|
65
|
+
var mapping = location.mappingIndex !== undefined || location.mappingIndex !== 0
|
|
66
|
+
? mappings[location.mappingIndex - 1]
|
|
67
|
+
: undefined;
|
|
68
|
+
var mappingFile = (mapping === null || mapping === void 0 ? void 0 : mapping.fileStringIndex) !== undefined ? strings[mapping.fileStringIndex] : '';
|
|
69
|
+
var mappingString = "".concat(mappingFile !== '' ? '[' + ((_c = getLastItem(mappingFile)) !== null && _c !== void 0 ? _c : '') + '] ' : '');
|
|
65
70
|
if (location.lines.length > 0) {
|
|
66
|
-
var funcName = strings[functions[location.lines[
|
|
71
|
+
var funcName = strings[functions[location.lines[node.meta.lineIndex].functionIndex - 1].nameStringIndex];
|
|
67
72
|
return "".concat(mappingString, " ").concat(funcName);
|
|
68
73
|
}
|
|
69
74
|
var address = hexifyAddress(location.address);
|
|
@@ -27,7 +27,7 @@ import { Transition } from '@headlessui/react';
|
|
|
27
27
|
import { Query } from '@parca/parser';
|
|
28
28
|
import { usePopper } from 'react-popper';
|
|
29
29
|
import cx from 'classnames';
|
|
30
|
-
import {
|
|
30
|
+
import { useParcaContext, useGrpcMetadata } from '@parca/components';
|
|
31
31
|
export var useLabelNames = function (client) {
|
|
32
32
|
var _a = useState(true), loading = _a[0], setLoading = _a[1];
|
|
33
33
|
var _b = useState({}), result = _b[0], setResult = _b[1];
|
|
@@ -73,7 +73,7 @@ var MatchersInput = function (_a) {
|
|
|
73
73
|
placement: 'bottom-start',
|
|
74
74
|
}), styles = _l.styles, attributes = _l.attributes;
|
|
75
75
|
var metadata = useGrpcMetadata();
|
|
76
|
-
var Spinner =
|
|
76
|
+
var Spinner = useParcaContext().loader;
|
|
77
77
|
var _m = useLabelNames(queryClient), labelNamesLoading = _m.loading, result = _m.result;
|
|
78
78
|
var labelNamesResponse = result.response, labelNamesError = result.error;
|
|
79
79
|
var LoadingSpinner = function () {
|
|
@@ -62,7 +62,7 @@ import { useState, useEffect } from 'react';
|
|
|
62
62
|
import MetricsGraph from '../MetricsGraph';
|
|
63
63
|
import { SingleProfileSelection } from '..';
|
|
64
64
|
import { Timestamp } from '@parca/client';
|
|
65
|
-
import { useGrpcMetadata,
|
|
65
|
+
import { useGrpcMetadata, useParcaContext } from '@parca/components';
|
|
66
66
|
import { Query } from '@parca/parser';
|
|
67
67
|
import useDelayedLoader from '../useDelayedLoader';
|
|
68
68
|
export var useQueryRange = function (client, queryExpression, start, end) {
|
|
@@ -100,7 +100,7 @@ var ProfileMetricsGraph = function (_a) {
|
|
|
100
100
|
var queryClient = _a.queryClient, queryExpression = _a.queryExpression, profile = _a.profile, from = _a.from, to = _a.to, select = _a.select, setTimeRange = _a.setTimeRange, addLabelMatcher = _a.addLabelMatcher;
|
|
101
101
|
var _b = useQueryRange(queryClient, queryExpression, from, to), isLoading = _b.isLoading, response = _b.response, error = _b.error;
|
|
102
102
|
var isLoaderVisible = useDelayedLoader(isLoading);
|
|
103
|
-
var loader =
|
|
103
|
+
var loader = useParcaContext().loader;
|
|
104
104
|
if (isLoaderVisible) {
|
|
105
105
|
return _jsx(_Fragment, { children: loader });
|
|
106
106
|
}
|
package/dist/ProfileView.js
CHANGED
|
@@ -22,18 +22,18 @@ import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-run
|
|
|
22
22
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
23
23
|
// See the License for the specific language governing permissions and
|
|
24
24
|
// limitations under the License.
|
|
25
|
-
import { useEffect, useMemo, useState } from 'react';
|
|
25
|
+
import { Profiler, useEffect, useMemo, useState } from 'react';
|
|
26
|
+
import { scaleLinear } from 'd3';
|
|
26
27
|
import { getNewSpanColor, parseParams } from '@parca/functions';
|
|
27
28
|
import useUIFeatureFlag from '@parca/functions/useUIFeatureFlag';
|
|
28
|
-
import { Button, Card, SearchNodes,
|
|
29
|
-
import { Callgraph } from './';
|
|
29
|
+
import { Button, Card, SearchNodes, useParcaContext } from '@parca/components';
|
|
30
30
|
import { useContainerDimensions } from '@parca/dynamicsize';
|
|
31
31
|
import { useAppSelector, selectDarkMode, selectSearchNodeString } from '@parca/store';
|
|
32
|
+
import { Callgraph } from './';
|
|
32
33
|
import ProfileShareButton from './components/ProfileShareButton';
|
|
33
34
|
import ProfileIcicleGraph from './ProfileIcicleGraph';
|
|
34
35
|
import TopTable from './TopTable';
|
|
35
36
|
import useDelayedLoader from './useDelayedLoader';
|
|
36
|
-
import { scaleLinear } from 'd3';
|
|
37
37
|
import './ProfileView.styles.css';
|
|
38
38
|
function arrayEquals(a, b) {
|
|
39
39
|
return (Array.isArray(a) &&
|
|
@@ -63,7 +63,7 @@ export var ProfileView = function (_a) {
|
|
|
63
63
|
var isDarkMode = useAppSelector(selectDarkMode);
|
|
64
64
|
var currentSearchString = useAppSelector(selectSearchNodeString);
|
|
65
65
|
var callgraphEnabled = useUIFeatureFlag('callgraph')[0];
|
|
66
|
-
var
|
|
66
|
+
var _d = useParcaContext(), loader = _d.loader, perf = _d.perf;
|
|
67
67
|
useEffect(function () {
|
|
68
68
|
// Reset the current path when the profile source changes
|
|
69
69
|
setCurPath([]);
|
|
@@ -115,5 +115,5 @@ export var ProfileView = function (_a) {
|
|
|
115
115
|
return (_jsx(_Fragment, { children: _jsx("div", __assign({ className: "py-3" }, { children: _jsx(Card, { children: _jsxs(Card.Body, { children: [_jsxs("div", __assign({ className: "flex py-3 w-full" }, { children: [_jsxs("div", __assign({ className: "w-2/5 flex space-x-4" }, { children: [_jsxs("div", __assign({ className: "flex space-x-1" }, { children: [profileSource != null && queryClient != null ? (_jsx(ProfileShareButton, { queryRequest: profileSource.QueryRequest(), queryClient: queryClient })) : null, _jsx(Button, __assign({ color: "neutral", onClick: function (e) {
|
|
116
116
|
e.preventDefault();
|
|
117
117
|
onDownloadPProf();
|
|
118
|
-
} }, { children: "Download pprof" }))] })), _jsx(SearchNodes, {})] })), _jsxs("div", __assign({ className: "flex ml-auto" }, { children: [_jsx("div", __assign({ className: "mr-3" }, { children: _jsx(Button, __assign({ color: "neutral", onClick: resetIcicleGraph, disabled: curPath.length === 0, className: "whitespace-nowrap text-ellipsis" }, { children: "Reset View" })) })), callgraphEnabled ? (_jsx("div", __assign({ className: "mr-3" }, { children: _jsx(Button, __assign({ variant: "".concat(currentView === 'callgraph' ? 'primary' : 'neutral'), onClick: function () { return switchProfileView('callgraph'); }, className: "whitespace-nowrap text-ellipsis" }, { children: "Callgraph" })) }))) : null, _jsx(Button, __assign({ variant: "".concat(currentView === 'table' ? 'primary' : 'neutral'), className: "items-center rounded-tr-none rounded-br-none w-auto px-8 whitespace-nowrap text-ellipsis no-outline-on-buttons", onClick: function () { return switchProfileView('table'); } }, { children: "Table" })), _jsx(Button, __assign({ variant: "".concat(currentView === 'both' ? 'primary' : 'neutral'), className: "items-center rounded-tl-none rounded-tr-none rounded-bl-none rounded-br-none border-l-0 border-r-0 w-auto px-8 whitespace-nowrap no-outline-on-buttons text-ellipsis", onClick: function () { return switchProfileView('both'); } }, { children: "Both" })), _jsx(Button, __assign({ variant: "".concat(currentView === 'icicle' ? 'primary' : 'neutral'), className: "items-center rounded-tl-none rounded-bl-none w-auto px-8 whitespace-nowrap text-ellipsis no-outline-on-buttons", onClick: function () { return switchProfileView('icicle'); } }, { children: "Icicle Graph" }))] }))] })), _jsxs("div", __assign({ ref: ref, className: "flex space-x-4 justify-between w-full" }, { children: [currentView === 'icicle' && (flamegraphData === null || flamegraphData === void 0 ? void 0 : flamegraphData.data) != null && (_jsx("div", __assign({ className: "w-full" }, { children: _jsx(ProfileIcicleGraph, { curPath: curPath, setNewCurPath: setNewCurPath, graph: flamegraphData.data, sampleUnit: sampleUnit }) }))), currentView === 'callgraph' && (callgraphData === null || callgraphData === void 0 ? void 0 : callgraphData.data) != null && (_jsx("div", __assign({ className: "w-full" }, { children: (dimensions === null || dimensions === void 0 ? void 0 : dimensions.width) !== undefined && (_jsx(Callgraph, { graph: callgraphData.data, sampleUnit: sampleUnit, width: dimensions === null || dimensions === void 0 ? void 0 : dimensions.width, colorRange: colorRange })) }))), currentView === 'table' && topTableData != null && (_jsx("div", __assign({ className: "w-full" }, { children: _jsx(TopTable, { data: topTableData.data, sampleUnit: sampleUnit }) }))), currentView === 'both' && (_jsxs(_Fragment, { children: [_jsx("div", __assign({ className: "w-1/2" }, { children: _jsx(TopTable, { data: topTableData === null || topTableData === void 0 ? void 0 : topTableData.data, sampleUnit: sampleUnit }) })), _jsx("div", __assign({ className: "w-1/2" }, { children: flamegraphData != null && (_jsx(ProfileIcicleGraph, { curPath: curPath, setNewCurPath: setNewCurPath, graph: flamegraphData.data, sampleUnit: sampleUnit })) }))] }))] }))] }) }) })) }));
|
|
118
|
+
} }, { children: "Download pprof" }))] })), _jsx(SearchNodes, {})] })), _jsxs("div", __assign({ className: "flex ml-auto" }, { children: [_jsx("div", __assign({ className: "mr-3" }, { children: _jsx(Button, __assign({ color: "neutral", onClick: resetIcicleGraph, disabled: curPath.length === 0, className: "whitespace-nowrap text-ellipsis" }, { children: "Reset View" })) })), callgraphEnabled ? (_jsx("div", __assign({ className: "mr-3" }, { children: _jsx(Button, __assign({ variant: "".concat(currentView === 'callgraph' ? 'primary' : 'neutral'), onClick: function () { return switchProfileView('callgraph'); }, className: "whitespace-nowrap text-ellipsis" }, { children: "Callgraph" })) }))) : null, _jsx(Button, __assign({ variant: "".concat(currentView === 'table' ? 'primary' : 'neutral'), className: "items-center rounded-tr-none rounded-br-none w-auto px-8 whitespace-nowrap text-ellipsis no-outline-on-buttons", onClick: function () { return switchProfileView('table'); } }, { children: "Table" })), _jsx(Button, __assign({ variant: "".concat(currentView === 'both' ? 'primary' : 'neutral'), className: "items-center rounded-tl-none rounded-tr-none rounded-bl-none rounded-br-none border-l-0 border-r-0 w-auto px-8 whitespace-nowrap no-outline-on-buttons text-ellipsis", onClick: function () { return switchProfileView('both'); } }, { children: "Both" })), _jsx(Button, __assign({ variant: "".concat(currentView === 'icicle' ? 'primary' : 'neutral'), className: "items-center rounded-tl-none rounded-bl-none w-auto px-8 whitespace-nowrap text-ellipsis no-outline-on-buttons", onClick: function () { return switchProfileView('icicle'); } }, { children: "Icicle Graph" }))] }))] })), _jsxs("div", __assign({ ref: ref, className: "flex space-x-4 justify-between w-full" }, { children: [currentView === 'icicle' && (flamegraphData === null || flamegraphData === void 0 ? void 0 : flamegraphData.data) != null && (_jsx("div", __assign({ className: "w-full" }, { children: _jsx(Profiler, __assign({ id: "icicleGraph", onRender: perf.onRender }, { children: _jsx(ProfileIcicleGraph, { curPath: curPath, setNewCurPath: setNewCurPath, graph: flamegraphData.data, sampleUnit: sampleUnit }) })) }))), currentView === 'callgraph' && (callgraphData === null || callgraphData === void 0 ? void 0 : callgraphData.data) != null && (_jsx("div", __assign({ className: "w-full" }, { children: (dimensions === null || dimensions === void 0 ? void 0 : dimensions.width) !== undefined && (_jsx(Callgraph, { graph: callgraphData.data, sampleUnit: sampleUnit, width: dimensions === null || dimensions === void 0 ? void 0 : dimensions.width, colorRange: colorRange })) }))), currentView === 'table' && topTableData != null && (_jsx("div", __assign({ className: "w-full" }, { children: _jsx(TopTable, { data: topTableData.data, sampleUnit: sampleUnit }) }))), currentView === 'both' && (_jsxs(_Fragment, { children: [_jsx("div", __assign({ className: "w-1/2" }, { children: _jsx(TopTable, { data: topTableData === null || topTableData === void 0 ? void 0 : topTableData.data, sampleUnit: sampleUnit }) })), _jsx("div", __assign({ className: "w-1/2" }, { children: flamegraphData != null && (_jsx(ProfileIcicleGraph, { curPath: curPath, setNewCurPath: setNewCurPath, graph: flamegraphData.data, sampleUnit: sampleUnit })) }))] }))] }))] }) }) })) }));
|
|
119
119
|
};
|
|
@@ -51,8 +51,9 @@ import { QueryRequest_ReportType } from '@parca/client';
|
|
|
51
51
|
import { useQuery } from './useQuery';
|
|
52
52
|
import { ProfileView, useProfileVisState } from './ProfileView';
|
|
53
53
|
import { downloadPprof } from './utils';
|
|
54
|
-
import { useGrpcMetadata } from '@parca/components';
|
|
54
|
+
import { useGrpcMetadata, useParcaContext } from '@parca/components';
|
|
55
55
|
import { saveAsBlob } from '@parca/functions';
|
|
56
|
+
import { useEffect } from 'react';
|
|
56
57
|
export var ProfileViewWithData = function (_a) {
|
|
57
58
|
var _b, _c;
|
|
58
59
|
var queryClient = _a.queryClient, profileSource = _a.profileSource, navigateTo = _a.navigateTo;
|
|
@@ -62,6 +63,13 @@ export var ProfileViewWithData = function (_a) {
|
|
|
62
63
|
var _d = useQuery(queryClient, profileSource, QueryRequest_ReportType.FLAMEGRAPH_TABLE, {
|
|
63
64
|
skip: currentView !== 'icicle' && currentView !== 'both',
|
|
64
65
|
}), flamegraphLoading = _d.isLoading, flamegraphResponse = _d.response, flamegraphError = _d.error;
|
|
66
|
+
var perf = useParcaContext().perf;
|
|
67
|
+
useEffect(function () {
|
|
68
|
+
if (flamegraphLoading) {
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
perf.markInteraction('Flamegraph Render');
|
|
72
|
+
}, [flamegraphLoading, flamegraphResponse, perf]);
|
|
65
73
|
var _e = useQuery(queryClient, profileSource, QueryRequest_ReportType.TOP, {
|
|
66
74
|
skip: currentView !== 'table' && currentView !== 'both',
|
|
67
75
|
}), topTableLoading = _e.isLoading, topTableResponse = _e.response, topTableError = _e.error;
|
package/dist/useQuery.js
CHANGED
|
@@ -30,7 +30,6 @@ export var useQuery = function (client, profileSource, reportType, options) {
|
|
|
30
30
|
isLoading: true,
|
|
31
31
|
});
|
|
32
32
|
var req = profileSource.QueryRequest();
|
|
33
|
-
console.log('req', req);
|
|
34
33
|
req.reportType = reportType;
|
|
35
34
|
var call = client.query(req, { meta: metadata });
|
|
36
35
|
call.response
|
package/package.json
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@parca/profile",
|
|
3
|
-
"version": "0.16.
|
|
3
|
+
"version": "0.16.65",
|
|
4
4
|
"description": "Profile viewing libraries",
|
|
5
5
|
"dependencies": {
|
|
6
6
|
"@iconify/react": "^3.2.2",
|
|
7
|
-
"@parca/client": "^0.16.
|
|
8
|
-
"@parca/components": "^0.16.
|
|
7
|
+
"@parca/client": "^0.16.54",
|
|
8
|
+
"@parca/components": "^0.16.60",
|
|
9
9
|
"@parca/dynamicsize": "^0.16.51",
|
|
10
10
|
"@parca/functions": "^0.16.51",
|
|
11
11
|
"@parca/parser": "^0.16.50",
|
|
@@ -40,5 +40,5 @@
|
|
|
40
40
|
"access": "public",
|
|
41
41
|
"registry": "https://registry.npmjs.org/"
|
|
42
42
|
},
|
|
43
|
-
"gitHead": "
|
|
43
|
+
"gitHead": "0b1285b6be9aee7b2716d230e1d4bdc5a0cea4d2"
|
|
44
44
|
}
|
|
@@ -19,12 +19,7 @@ import {CallgraphNode, FlamegraphNode, FlamegraphNodeMeta, FlamegraphRootNode} f
|
|
|
19
19
|
import {getLastItem, valueFormatter} from '@parca/functions';
|
|
20
20
|
import useIsShiftDown from '@parca/components/src/hooks/useIsShiftDown';
|
|
21
21
|
import {hexifyAddress, truncateString} from '../';
|
|
22
|
-
import {
|
|
23
|
-
Function,
|
|
24
|
-
Location,
|
|
25
|
-
Mapping,
|
|
26
|
-
Line,
|
|
27
|
-
} from '@parca/client/dist/parca/metastore/v1alpha1/metastore';
|
|
22
|
+
import {Function, Location, Mapping} from '@parca/client/dist/parca/metastore/v1alpha1/metastore';
|
|
28
23
|
|
|
29
24
|
interface GraphTooltipProps {
|
|
30
25
|
x: number;
|
|
@@ -86,22 +81,37 @@ const TooltipMetaInfo = ({
|
|
|
86
81
|
if (hoveringNode.meta === undefined) return <></>;
|
|
87
82
|
|
|
88
83
|
// populate meta from the flamegraph metadata tables
|
|
89
|
-
if (
|
|
90
|
-
|
|
84
|
+
if (
|
|
85
|
+
locations !== undefined &&
|
|
86
|
+
hoveringNode.meta.locationIndex !== undefined &&
|
|
87
|
+
hoveringNode.meta.locationIndex !== 0
|
|
88
|
+
) {
|
|
89
|
+
const location = locations[hoveringNode.meta.locationIndex - 1];
|
|
91
90
|
hoveringNode.meta.location = location;
|
|
92
91
|
|
|
93
|
-
if (
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
92
|
+
if (location !== undefined) {
|
|
93
|
+
if (
|
|
94
|
+
mappings !== undefined &&
|
|
95
|
+
location.mappingIndex !== undefined &&
|
|
96
|
+
location.mappingIndex !== 0
|
|
97
|
+
) {
|
|
98
|
+
const mapping = mappings[location.mappingIndex - 1];
|
|
99
|
+
if (strings !== undefined && mapping !== undefined) {
|
|
100
|
+
mapping.file =
|
|
101
|
+
mapping?.fileStringIndex !== undefined ? strings[mapping.fileStringIndex] : '';
|
|
102
|
+
mapping.buildId =
|
|
103
|
+
mapping?.buildIdStringIndex !== undefined ? strings[mapping.buildIdStringIndex] : '';
|
|
104
|
+
}
|
|
105
|
+
hoveringNode.meta.mapping = mapping;
|
|
98
106
|
}
|
|
99
|
-
hoveringNode.meta.mapping = mapping;
|
|
100
|
-
}
|
|
101
107
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
108
|
+
if (
|
|
109
|
+
functions !== undefined &&
|
|
110
|
+
location.lines !== undefined &&
|
|
111
|
+
hoveringNode.meta.lineIndex !== undefined &&
|
|
112
|
+
hoveringNode.meta.lineIndex < location.lines.length
|
|
113
|
+
) {
|
|
114
|
+
const func = functions[location.lines[hoveringNode.meta.lineIndex].functionIndex - 1];
|
|
105
115
|
if (strings !== undefined) {
|
|
106
116
|
func.name = strings[func.nameStringIndex];
|
|
107
117
|
func.systemName = strings[func.systemNameStringIndex];
|
|
@@ -109,7 +119,7 @@ const TooltipMetaInfo = ({
|
|
|
109
119
|
}
|
|
110
120
|
hoveringNode.meta.function = func;
|
|
111
121
|
}
|
|
112
|
-
}
|
|
122
|
+
}
|
|
113
123
|
}
|
|
114
124
|
|
|
115
125
|
const getTextForFile = (hoveringNode: FlamegraphNode): string => {
|
package/src/IcicleGraph.tsx
CHANGED
|
@@ -149,16 +149,24 @@ export function nodeLabel(
|
|
|
149
149
|
functions: Function[]
|
|
150
150
|
): string {
|
|
151
151
|
if (node.meta?.locationIndex === undefined) return '<unknown>';
|
|
152
|
+
if (node.meta?.locationIndex === 0) return '<unknown>';
|
|
152
153
|
|
|
153
|
-
const location = locations[node.meta.locationIndex];
|
|
154
|
-
const
|
|
154
|
+
const location = locations[node.meta.locationIndex - 1];
|
|
155
|
+
const mapping =
|
|
156
|
+
location.mappingIndex !== undefined || location.mappingIndex !== 0
|
|
157
|
+
? mappings[location.mappingIndex - 1]
|
|
158
|
+
: undefined;
|
|
159
|
+
|
|
160
|
+
const mappingFile =
|
|
161
|
+
mapping?.fileStringIndex !== undefined ? strings[mapping.fileStringIndex] : '';
|
|
155
162
|
|
|
156
163
|
const mappingString: string = `${
|
|
157
164
|
mappingFile !== '' ? '[' + (getLastItem(mappingFile) ?? '') + '] ' : ''
|
|
158
165
|
}`;
|
|
159
166
|
|
|
160
167
|
if (location.lines.length > 0) {
|
|
161
|
-
const funcName =
|
|
168
|
+
const funcName =
|
|
169
|
+
strings[functions[location.lines[node.meta.lineIndex].functionIndex - 1].nameStringIndex];
|
|
162
170
|
return `${mappingString} ${funcName}`;
|
|
163
171
|
}
|
|
164
172
|
|
|
@@ -17,7 +17,8 @@ import {Query} from '@parca/parser';
|
|
|
17
17
|
import {LabelsResponse, QueryServiceClient} from '@parca/client';
|
|
18
18
|
import {usePopper} from 'react-popper';
|
|
19
19
|
import cx from 'classnames';
|
|
20
|
-
|
|
20
|
+
|
|
21
|
+
import {useParcaContext, useGrpcMetadata} from '@parca/components';
|
|
21
22
|
|
|
22
23
|
interface MatchersInputProps {
|
|
23
24
|
queryClient: QueryServiceClient;
|
|
@@ -97,7 +98,7 @@ const MatchersInput = ({
|
|
|
97
98
|
placement: 'bottom-start',
|
|
98
99
|
});
|
|
99
100
|
const metadata = useGrpcMetadata();
|
|
100
|
-
const {loader: Spinner} =
|
|
101
|
+
const {loader: Spinner} = useParcaContext();
|
|
101
102
|
|
|
102
103
|
const {loading: labelNamesLoading, result} = useLabelNames(queryClient);
|
|
103
104
|
const {response: labelNamesResponse, error: labelNamesError} = result;
|
|
@@ -16,7 +16,7 @@ import MetricsGraph from '../MetricsGraph';
|
|
|
16
16
|
import {ProfileSelection, SingleProfileSelection} from '..';
|
|
17
17
|
import {QueryServiceClient, QueryRangeResponse, Label, Timestamp} from '@parca/client';
|
|
18
18
|
import {RpcError} from '@protobuf-ts/runtime-rpc';
|
|
19
|
-
import {DateTimeRange, useGrpcMetadata,
|
|
19
|
+
import {DateTimeRange, useGrpcMetadata, useParcaContext} from '@parca/components';
|
|
20
20
|
import {Query} from '@parca/parser';
|
|
21
21
|
import useDelayedLoader from '../useDelayedLoader';
|
|
22
22
|
|
|
@@ -89,7 +89,7 @@ const ProfileMetricsGraph = ({
|
|
|
89
89
|
}: ProfileMetricsGraphProps): JSX.Element => {
|
|
90
90
|
const {isLoading, response, error} = useQueryRange(queryClient, queryExpression, from, to);
|
|
91
91
|
const isLoaderVisible = useDelayedLoader(isLoading);
|
|
92
|
-
const {loader} =
|
|
92
|
+
const {loader} = useParcaContext();
|
|
93
93
|
|
|
94
94
|
if (isLoaderVisible) {
|
|
95
95
|
return <>{loader}</>;
|
package/src/ProfileView.tsx
CHANGED
|
@@ -11,22 +11,22 @@
|
|
|
11
11
|
// See the License for the specific language governing permissions and
|
|
12
12
|
// limitations under the License.
|
|
13
13
|
|
|
14
|
-
import
|
|
14
|
+
import {Profiler, useEffect, useMemo, useState} from 'react';
|
|
15
|
+
import {scaleLinear} from 'd3';
|
|
15
16
|
|
|
16
17
|
import {getNewSpanColor, parseParams} from '@parca/functions';
|
|
17
18
|
import useUIFeatureFlag from '@parca/functions/useUIFeatureFlag';
|
|
18
19
|
import {QueryServiceClient, Flamegraph, Top, Callgraph as CallgraphType} from '@parca/client';
|
|
19
|
-
import {Button, Card, SearchNodes,
|
|
20
|
-
import {Callgraph} from './';
|
|
20
|
+
import {Button, Card, SearchNodes, useParcaContext} from '@parca/components';
|
|
21
21
|
import {useContainerDimensions} from '@parca/dynamicsize';
|
|
22
22
|
import {useAppSelector, selectDarkMode, selectSearchNodeString} from '@parca/store';
|
|
23
23
|
|
|
24
|
+
import {Callgraph} from './';
|
|
24
25
|
import ProfileShareButton from './components/ProfileShareButton';
|
|
25
26
|
import ProfileIcicleGraph from './ProfileIcicleGraph';
|
|
26
27
|
import {ProfileSource} from './ProfileSource';
|
|
27
28
|
import TopTable from './TopTable';
|
|
28
29
|
import useDelayedLoader from './useDelayedLoader';
|
|
29
|
-
import {scaleLinear} from 'd3';
|
|
30
30
|
|
|
31
31
|
import './ProfileView.styles.css';
|
|
32
32
|
|
|
@@ -114,7 +114,7 @@ export const ProfileView = ({
|
|
|
114
114
|
|
|
115
115
|
const [callgraphEnabled] = useUIFeatureFlag('callgraph');
|
|
116
116
|
|
|
117
|
-
const {loader} =
|
|
117
|
+
const {loader, perf} = useParcaContext();
|
|
118
118
|
|
|
119
119
|
useEffect(() => {
|
|
120
120
|
// Reset the current path when the profile source changes
|
|
@@ -265,12 +265,14 @@ export const ProfileView = ({
|
|
|
265
265
|
<div ref={ref} className="flex space-x-4 justify-between w-full">
|
|
266
266
|
{currentView === 'icicle' && flamegraphData?.data != null && (
|
|
267
267
|
<div className="w-full">
|
|
268
|
-
<
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
268
|
+
<Profiler id="icicleGraph" onRender={perf.onRender}>
|
|
269
|
+
<ProfileIcicleGraph
|
|
270
|
+
curPath={curPath}
|
|
271
|
+
setNewCurPath={setNewCurPath}
|
|
272
|
+
graph={flamegraphData.data}
|
|
273
|
+
sampleUnit={sampleUnit}
|
|
274
|
+
/>
|
|
275
|
+
</Profiler>
|
|
274
276
|
</div>
|
|
275
277
|
)}
|
|
276
278
|
{currentView === 'callgraph' && callgraphData?.data != null && (
|
|
@@ -17,8 +17,9 @@ import {useQuery} from './useQuery';
|
|
|
17
17
|
import {ProfileView, useProfileVisState} from './ProfileView';
|
|
18
18
|
import {ProfileSource} from './ProfileSource';
|
|
19
19
|
import {downloadPprof} from './utils';
|
|
20
|
-
import {useGrpcMetadata} from '@parca/components';
|
|
20
|
+
import {useGrpcMetadata, useParcaContext} from '@parca/components';
|
|
21
21
|
import {saveAsBlob} from '@parca/functions';
|
|
22
|
+
import {useEffect} from 'react';
|
|
22
23
|
|
|
23
24
|
type NavigateFunction = (path: string, queryParams: any) => void;
|
|
24
25
|
|
|
@@ -44,6 +45,14 @@ export const ProfileViewWithData = ({
|
|
|
44
45
|
} = useQuery(queryClient, profileSource, QueryRequest_ReportType.FLAMEGRAPH_TABLE, {
|
|
45
46
|
skip: currentView !== 'icicle' && currentView !== 'both',
|
|
46
47
|
});
|
|
48
|
+
const {perf} = useParcaContext();
|
|
49
|
+
|
|
50
|
+
useEffect(() => {
|
|
51
|
+
if (flamegraphLoading) {
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
perf.markInteraction('Flamegraph Render');
|
|
55
|
+
}, [flamegraphLoading, flamegraphResponse, perf]);
|
|
47
56
|
|
|
48
57
|
const {
|
|
49
58
|
isLoading: topTableLoading,
|