@parca/profile 0.14.37 → 0.15.0
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 +46 -0
- package/package.json +6 -5
- package/src/IcicleGraph.tsx +2 -2
- package/src/ProfileView.tsx +52 -5
- package/src/ProfileViewWithData.tsx +16 -0
- package/src/testdata/link_data.json +56 -0
- package/src/testdata/tabular.json +30 -0
- package/src/testdata/test_graph.json +53 -0
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,52 @@
|
|
|
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.15.0](https://github.com/parca-dev/parca/compare/ui-v0.14.37...ui-v0.15.0) (2022-08-24)
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
## [0.14.32](https://github.com/parca-dev/parca/compare/ui-v0.14.30...ui-v0.14.32) (2022-08-18)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
## [0.14.30](https://github.com/parca-dev/parca/compare/ui-v0.14.24...ui-v0.14.30) (2022-08-17)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
### Features
|
|
18
|
+
|
|
19
|
+
* implement callgraph report api ([83c81c6](https://github.com/parca-dev/parca/commit/83c81c67a140b4b723094ee0d6c2308b112b800c))
|
|
20
|
+
* tooltip for callgraph ([c1d0195](https://github.com/parca-dev/parca/commit/c1d0195e45a5aa065a89c936861646f1455336ff))
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
## [0.14.16](https://github.com/parca-dev/parca/compare/ui-v0.14.11...ui-v0.14.16) (2022-08-03)
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
## [0.14.3-alpha.0](https://github.com/parca-dev/parca/compare/ui-v0.14.1...ui-v0.14.3-alpha.0) (2022-07-26)
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
## [0.13.14](https://github.com/parca-dev/parca/compare/ui-v0.13.12...ui-v0.13.14) (2022-06-29)
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
### Features
|
|
36
|
+
|
|
37
|
+
* add tooltip to callgraph ([b261a48](https://github.com/parca-dev/parca/commit/b261a48a92739d5fb957957da929495cb206417e))
|
|
38
|
+
* connect callgraph component to actual data ([b7dd5d8](https://github.com/parca-dev/parca/commit/b7dd5d8b0851d11010f66a3a5ca03d50902636a1))
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
## [0.13.10](https://github.com/parca-dev/parca/compare/ui-v0.13.2...ui-v0.13.10) (2022-06-22)
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
## [0.13.2](https://github.com/parca-dev/parca/compare/ui-v0.13.1...ui-v0.13.2) (2022-05-31)
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
|
|
6
52
|
## [0.14.37](https://github.com/parca-dev/parca/compare/ui-v0.14.36...ui-v0.14.37) (2022-08-24)
|
|
7
53
|
|
|
8
54
|
**Note:** Version bump only for package @parca/profile
|
package/package.json
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@parca/profile",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.15.0",
|
|
4
4
|
"description": "Profile viewing libraries",
|
|
5
5
|
"dependencies": {
|
|
6
6
|
"@iconify/react": "^3.2.2",
|
|
7
|
-
"@parca/client": "^0.
|
|
8
|
-
"@parca/dynamicsize": "^0.
|
|
9
|
-
"@parca/
|
|
7
|
+
"@parca/client": "^0.15.0",
|
|
8
|
+
"@parca/dynamicsize": "^0.15.0",
|
|
9
|
+
"@parca/functions": "^0.15.0",
|
|
10
|
+
"@parca/parser": "^0.15.0",
|
|
10
11
|
"d3-scale": "^4.0.2",
|
|
11
12
|
"d3-selection": "3.0.0",
|
|
12
13
|
"react-copy-to-clipboard": "^5.1.0"
|
|
@@ -22,5 +23,5 @@
|
|
|
22
23
|
"access": "public",
|
|
23
24
|
"registry": "https://registry.npmjs.org/"
|
|
24
25
|
},
|
|
25
|
-
"gitHead": "
|
|
26
|
+
"gitHead": "9bba12f8523b8d5763d9fb6d81c9df971a83f6fa"
|
|
26
27
|
}
|
package/src/IcicleGraph.tsx
CHANGED
|
@@ -17,7 +17,7 @@ import {throttle} from 'lodash';
|
|
|
17
17
|
import {pointer} from 'd3-selection';
|
|
18
18
|
import {scaleLinear} from 'd3-scale';
|
|
19
19
|
import {Flamegraph, FlamegraphNode, FlamegraphRootNode} from '@parca/client';
|
|
20
|
-
import {
|
|
20
|
+
import {GraphTooltip} from '@parca/components';
|
|
21
21
|
import {getLastItem, diffColor, isSearchMatch} from '@parca/functions';
|
|
22
22
|
import {useAppSelector, selectDarkMode, selectSearchNodeString} from '@parca/store';
|
|
23
23
|
|
|
@@ -331,7 +331,7 @@ export default function IcicleGraph({
|
|
|
331
331
|
|
|
332
332
|
return (
|
|
333
333
|
<div onMouseLeave={() => setHoveringNode(undefined)}>
|
|
334
|
-
<
|
|
334
|
+
<GraphTooltip
|
|
335
335
|
unit={sampleUnit}
|
|
336
336
|
total={total}
|
|
337
337
|
x={pos[0]}
|
package/src/ProfileView.tsx
CHANGED
|
@@ -14,8 +14,17 @@
|
|
|
14
14
|
import React, {useEffect, useMemo, useState} from 'react';
|
|
15
15
|
|
|
16
16
|
import {parseParams} from '@parca/functions';
|
|
17
|
-
import
|
|
18
|
-
import {
|
|
17
|
+
import useUIFeatureFlag from '@parca/functions/useUIFeatureFlag';
|
|
18
|
+
import {QueryServiceClient, Flamegraph, Top, Callgraph} from '@parca/client';
|
|
19
|
+
import {
|
|
20
|
+
Button,
|
|
21
|
+
Card,
|
|
22
|
+
SearchNodes,
|
|
23
|
+
useGrpcMetadata,
|
|
24
|
+
useParcaTheme,
|
|
25
|
+
Callgraph as CallgraphComponent,
|
|
26
|
+
} from '@parca/components';
|
|
27
|
+
import {useContainerDimensions} from '@parca/dynamicsize';
|
|
19
28
|
|
|
20
29
|
import ProfileShareButton from './components/ProfileShareButton';
|
|
21
30
|
import ProfileIcicleGraph from './ProfileIcicleGraph';
|
|
@@ -40,7 +49,13 @@ interface TopTableData {
|
|
|
40
49
|
error?: any;
|
|
41
50
|
}
|
|
42
51
|
|
|
43
|
-
|
|
52
|
+
interface CallgraphData {
|
|
53
|
+
loading: boolean;
|
|
54
|
+
data?: Callgraph;
|
|
55
|
+
error?: any;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
type VisualizationType = 'icicle' | 'table' | 'callgraph' | 'both';
|
|
44
59
|
|
|
45
60
|
interface ProfileVisState {
|
|
46
61
|
currentView: VisualizationType;
|
|
@@ -50,6 +65,7 @@ interface ProfileVisState {
|
|
|
50
65
|
interface ProfileViewProps {
|
|
51
66
|
flamegraphData?: FlamegraphData;
|
|
52
67
|
topTableData?: TopTableData;
|
|
68
|
+
callgraphData?: CallgraphData;
|
|
53
69
|
sampleUnit: string;
|
|
54
70
|
profileVisState: ProfileVisState;
|
|
55
71
|
profileSource?: ProfileSource;
|
|
@@ -79,15 +95,19 @@ export const useProfileVisState = (): ProfileVisState => {
|
|
|
79
95
|
export const ProfileView = ({
|
|
80
96
|
flamegraphData,
|
|
81
97
|
topTableData,
|
|
98
|
+
callgraphData,
|
|
82
99
|
sampleUnit,
|
|
83
100
|
profileSource,
|
|
84
101
|
queryClient,
|
|
85
102
|
navigateTo,
|
|
86
103
|
profileVisState,
|
|
87
104
|
}: ProfileViewProps): JSX.Element => {
|
|
105
|
+
const {ref, dimensions} = useContainerDimensions();
|
|
88
106
|
const [curPath, setCurPath] = useState<string[]>([]);
|
|
89
107
|
const {currentView, setCurrentView} = profileVisState;
|
|
90
108
|
|
|
109
|
+
const [callgraphEnabled] = useUIFeatureFlag('callgraph');
|
|
110
|
+
|
|
91
111
|
const metadata = useGrpcMetadata();
|
|
92
112
|
const {loader} = useParcaTheme();
|
|
93
113
|
|
|
@@ -100,6 +120,9 @@ export const ProfileView = ({
|
|
|
100
120
|
if (currentView === 'icicle') {
|
|
101
121
|
return Boolean(flamegraphData?.loading);
|
|
102
122
|
}
|
|
123
|
+
if (currentView === 'callgraph') {
|
|
124
|
+
return !!callgraphData?.loading;
|
|
125
|
+
}
|
|
103
126
|
if (currentView === 'table') {
|
|
104
127
|
return Boolean(topTableData?.loading);
|
|
105
128
|
}
|
|
@@ -107,7 +130,7 @@ export const ProfileView = ({
|
|
|
107
130
|
return Boolean(flamegraphData?.loading) || Boolean(topTableData?.loading);
|
|
108
131
|
}
|
|
109
132
|
return false;
|
|
110
|
-
}, [currentView, flamegraphData?.loading, topTableData?.loading]);
|
|
133
|
+
}, [currentView, callgraphData?.loading, flamegraphData?.loading, topTableData?.loading]);
|
|
111
134
|
|
|
112
135
|
const isLoaderVisible = useDelayedLoader(isLoading);
|
|
113
136
|
|
|
@@ -196,6 +219,18 @@ export const ProfileView = ({
|
|
|
196
219
|
</Button>
|
|
197
220
|
</div>
|
|
198
221
|
|
|
222
|
+
{callgraphEnabled ? (
|
|
223
|
+
<div className="mr-3">
|
|
224
|
+
<Button
|
|
225
|
+
variant={`${currentView === 'callgraph' ? 'primary' : 'neutral'}`}
|
|
226
|
+
onClick={() => switchProfileView('callgraph')}
|
|
227
|
+
className="whitespace-nowrap text-ellipsis"
|
|
228
|
+
>
|
|
229
|
+
Call Graph
|
|
230
|
+
</Button>
|
|
231
|
+
</div>
|
|
232
|
+
) : null}
|
|
233
|
+
|
|
199
234
|
<Button
|
|
200
235
|
variant={`${currentView === 'table' ? 'primary' : 'neutral'}`}
|
|
201
236
|
className="items-center rounded-tr-none rounded-br-none w-auto px-8 whitespace-nowrap text-ellipsis no-outline-on-buttons"
|
|
@@ -222,7 +257,7 @@ export const ProfileView = ({
|
|
|
222
257
|
</div>
|
|
223
258
|
</div>
|
|
224
259
|
|
|
225
|
-
<div className="flex space-x-4 justify-between">
|
|
260
|
+
<div ref={ref} className="flex space-x-4 justify-between w-full">
|
|
226
261
|
{currentView === 'icicle' && flamegraphData?.data != null && (
|
|
227
262
|
<div className="w-full">
|
|
228
263
|
<ProfileIcicleGraph
|
|
@@ -234,6 +269,18 @@ export const ProfileView = ({
|
|
|
234
269
|
</div>
|
|
235
270
|
)}
|
|
236
271
|
|
|
272
|
+
{currentView === 'callgraph' && callgraphData?.data != null && (
|
|
273
|
+
<div className="w-full">
|
|
274
|
+
{dimensions?.width && (
|
|
275
|
+
<CallgraphComponent
|
|
276
|
+
graph={callgraphData.data}
|
|
277
|
+
sampleUnit={sampleUnit}
|
|
278
|
+
width={dimensions?.width}
|
|
279
|
+
/>
|
|
280
|
+
)}
|
|
281
|
+
</div>
|
|
282
|
+
)}
|
|
283
|
+
|
|
237
284
|
{currentView === 'table' && topTableData != null && (
|
|
238
285
|
<div className="w-full">
|
|
239
286
|
<TopTable data={topTableData.data} sampleUnit={sampleUnit} />
|
|
@@ -49,6 +49,14 @@ export const ProfileViewWithData = ({
|
|
|
49
49
|
skip: currentView !== 'table' && currentView !== 'both',
|
|
50
50
|
});
|
|
51
51
|
|
|
52
|
+
const {
|
|
53
|
+
isLoading: callgraphLoading,
|
|
54
|
+
response: callgraphResponse,
|
|
55
|
+
error: callgraphError,
|
|
56
|
+
} = useQuery(queryClient, profileSource, QueryRequest_ReportType.CALLGRAPH, {
|
|
57
|
+
skip: currentView != 'callgraph',
|
|
58
|
+
});
|
|
59
|
+
|
|
52
60
|
const sampleUnit = profileSource.ProfileType().sampleUnit;
|
|
53
61
|
|
|
54
62
|
return (
|
|
@@ -67,6 +75,14 @@ export const ProfileViewWithData = ({
|
|
|
67
75
|
topTableResponse?.report.oneofKind === 'top' ? topTableResponse.report.top : undefined,
|
|
68
76
|
error: topTableError,
|
|
69
77
|
}}
|
|
78
|
+
callgraphData={{
|
|
79
|
+
loading: callgraphLoading,
|
|
80
|
+
data:
|
|
81
|
+
callgraphResponse?.report.oneofKind === 'callgraph'
|
|
82
|
+
? callgraphResponse?.report?.callgraph
|
|
83
|
+
: undefined,
|
|
84
|
+
error: callgraphError,
|
|
85
|
+
}}
|
|
70
86
|
profileVisState={profileVisState}
|
|
71
87
|
sampleUnit={sampleUnit}
|
|
72
88
|
profileSource={profileSource}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
{
|
|
2
|
+
"total": "4358676",
|
|
3
|
+
"unit": "count",
|
|
4
|
+
"height": 27,
|
|
5
|
+
"data": {
|
|
6
|
+
"nodes": {
|
|
7
|
+
"root": {
|
|
8
|
+
"id": "root",
|
|
9
|
+
"cumulative": "10",
|
|
10
|
+
"diff": "0"
|
|
11
|
+
},
|
|
12
|
+
"1": {
|
|
13
|
+
"id": "1",
|
|
14
|
+
"cumulative": "2",
|
|
15
|
+
"diff": "0"
|
|
16
|
+
},
|
|
17
|
+
"2": {
|
|
18
|
+
"id": "2",
|
|
19
|
+
"cumulative": "9",
|
|
20
|
+
"diff": "0"
|
|
21
|
+
},
|
|
22
|
+
"3": {
|
|
23
|
+
"id": "3",
|
|
24
|
+
"cumulative": "8"
|
|
25
|
+
},
|
|
26
|
+
"4": {
|
|
27
|
+
"id": "4",
|
|
28
|
+
"cumulative": "2"
|
|
29
|
+
}
|
|
30
|
+
},
|
|
31
|
+
"links": [
|
|
32
|
+
{
|
|
33
|
+
"source": "root",
|
|
34
|
+
"target": "1"
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
"source": "root",
|
|
38
|
+
"target": "4"
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
"source": "1",
|
|
42
|
+
"target": "2"
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
"source": "2",
|
|
46
|
+
"target": "3"
|
|
47
|
+
}
|
|
48
|
+
],
|
|
49
|
+
"reversedLinks": [
|
|
50
|
+
{
|
|
51
|
+
"source": "3",
|
|
52
|
+
"target": "1"
|
|
53
|
+
}
|
|
54
|
+
]
|
|
55
|
+
}
|
|
56
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
{
|
|
2
|
+
"total": "4358676",
|
|
3
|
+
"unit": "count",
|
|
4
|
+
"height": 27,
|
|
5
|
+
"data": [
|
|
6
|
+
{
|
|
7
|
+
"id": "root"
|
|
8
|
+
},
|
|
9
|
+
{
|
|
10
|
+
"id": "child_1",
|
|
11
|
+
"parentIds": ["root", "loop_child"]
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
"id": "child_2",
|
|
15
|
+
"parentIds": ["root"]
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
"id": "grandchild_1",
|
|
19
|
+
"parentIds": ["child_1"]
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
"id": "grandchild_2",
|
|
23
|
+
"parentIds": ["child_1"]
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
"id": "loop_child",
|
|
27
|
+
"parentIds": ["grandchild_1"]
|
|
28
|
+
}
|
|
29
|
+
]
|
|
30
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
{
|
|
2
|
+
"total": "4358676",
|
|
3
|
+
"unit": "count",
|
|
4
|
+
"height": 27,
|
|
5
|
+
"root": {
|
|
6
|
+
"id": "root",
|
|
7
|
+
"cumulative": "4358676",
|
|
8
|
+
"diff": "0",
|
|
9
|
+
"children": [
|
|
10
|
+
{
|
|
11
|
+
"id": "child_1",
|
|
12
|
+
"cumulative": "1",
|
|
13
|
+
"diff": "0",
|
|
14
|
+
"children": [
|
|
15
|
+
{
|
|
16
|
+
"id": "child_2",
|
|
17
|
+
"cumulative": "1",
|
|
18
|
+
"diff": "0",
|
|
19
|
+
"children": [
|
|
20
|
+
{
|
|
21
|
+
"id": "root",
|
|
22
|
+
"cumulative": "4358676",
|
|
23
|
+
"diff": "0",
|
|
24
|
+
"children": [
|
|
25
|
+
{
|
|
26
|
+
"id": "child_1",
|
|
27
|
+
"cumulative": "1",
|
|
28
|
+
"diff": "0",
|
|
29
|
+
"children": [
|
|
30
|
+
{
|
|
31
|
+
"id": "child_2",
|
|
32
|
+
"cumulative": "1",
|
|
33
|
+
"diff": "0",
|
|
34
|
+
"children": [
|
|
35
|
+
{
|
|
36
|
+
"id": "child_1",
|
|
37
|
+
"cumulative": "1",
|
|
38
|
+
"diff": "0",
|
|
39
|
+
"children": []
|
|
40
|
+
}
|
|
41
|
+
]
|
|
42
|
+
}
|
|
43
|
+
]
|
|
44
|
+
}
|
|
45
|
+
]
|
|
46
|
+
}
|
|
47
|
+
]
|
|
48
|
+
}
|
|
49
|
+
]
|
|
50
|
+
}
|
|
51
|
+
]
|
|
52
|
+
}
|
|
53
|
+
}
|