@parca/profile 0.16.59 → 0.16.60

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.
Files changed (43) hide show
  1. package/CHANGELOG.md +4 -0
  2. package/dist/Callgraph/constants.d.ts +2 -0
  3. package/dist/Callgraph/constants.js +14 -0
  4. package/dist/Callgraph/index.d.ts +2 -2
  5. package/dist/Callgraph/index.js +106 -35
  6. package/dist/Callgraph/utils.d.ts +6 -6
  7. package/dist/Callgraph/utils.js +55 -29
  8. package/dist/GraphTooltip/index.d.ts +0 -1
  9. package/dist/IcicleGraph.d.ts +0 -1
  10. package/dist/MatchersInput/index.d.ts +0 -1
  11. package/dist/MetricsCircle/index.d.ts +0 -1
  12. package/dist/MetricsGraph/index.d.ts +0 -1
  13. package/dist/MetricsSeries/index.d.ts +0 -1
  14. package/dist/ProfileExplorer/ProfileExplorerCompare.d.ts +0 -1
  15. package/dist/ProfileExplorer/ProfileExplorerSingle.d.ts +0 -1
  16. package/dist/ProfileExplorer/index.d.ts +0 -1
  17. package/dist/ProfileIcicleGraph.d.ts +0 -1
  18. package/dist/ProfileMetricsGraph/index.d.ts +0 -1
  19. package/dist/ProfileSelector/CompareButton.d.ts +0 -1
  20. package/dist/ProfileSelector/MergeButton.d.ts +0 -1
  21. package/dist/ProfileSelector/index.d.ts +0 -1
  22. package/dist/ProfileSource.d.ts +0 -1
  23. package/dist/ProfileTypeSelector/index.d.ts +0 -1
  24. package/dist/ProfileView.d.ts +2 -3
  25. package/dist/ProfileView.js +15 -7
  26. package/dist/ProfileViewWithData.d.ts +0 -1
  27. package/dist/TopTable.d.ts +0 -1
  28. package/dist/components/DiffLegend.d.ts +0 -1
  29. package/dist/components/ProfileShareButton/ResultBox.d.ts +0 -1
  30. package/dist/components/ProfileShareButton/index.d.ts +0 -1
  31. package/dist/index.d.ts +1 -1
  32. package/dist/styles.css +1 -1
  33. package/package.json +7 -6
  34. package/src/Callgraph/constants.ts +15 -0
  35. package/src/Callgraph/index.tsx +232 -66
  36. package/src/Callgraph/utils.ts +68 -39
  37. package/src/ProfileView.tsx +128 -114
  38. package/dist/Callgraph/Edge/index.d.ts +0 -23
  39. package/dist/Callgraph/Edge/index.js +0 -30
  40. package/dist/Callgraph/Node/index.d.ts +0 -20
  41. package/dist/Callgraph/Node/index.js +0 -37
  42. package/src/Callgraph/Edge/index.tsx +0 -59
  43. package/src/Callgraph/Node/index.tsx +0 -66
@@ -13,18 +13,20 @@
13
13
 
14
14
  import React, {useEffect, useMemo, useState} from 'react';
15
15
 
16
- import {parseParams} from '@parca/functions';
16
+ import {getNewSpanColor, parseParams} from '@parca/functions';
17
17
  import useUIFeatureFlag from '@parca/functions/useUIFeatureFlag';
18
- import {QueryServiceClient, Flamegraph, Top, Callgraph} from '@parca/client';
18
+ import {QueryServiceClient, Flamegraph, Top, Callgraph as CallgraphType} from '@parca/client';
19
19
  import {Button, Card, SearchNodes, useParcaTheme} from '@parca/components';
20
- import {Callgraph as CallgraphComponent} from './';
20
+ import {Callgraph} from './';
21
21
  import {useContainerDimensions} from '@parca/dynamicsize';
22
+ import {useAppSelector, selectDarkMode, selectSearchNodeString} from '@parca/store';
22
23
 
23
24
  import ProfileShareButton from './components/ProfileShareButton';
24
25
  import ProfileIcicleGraph from './ProfileIcicleGraph';
25
26
  import {ProfileSource} from './ProfileSource';
26
27
  import TopTable from './TopTable';
27
28
  import useDelayedLoader from './useDelayedLoader';
29
+ import {scaleLinear} from 'd3';
28
30
 
29
31
  import './ProfileView.styles.css';
30
32
 
@@ -44,7 +46,7 @@ export interface TopTableData {
44
46
 
45
47
  interface CallgraphData {
46
48
  loading: boolean;
47
- data?: Callgraph;
49
+ data?: CallgraphType;
48
50
  error?: any;
49
51
  }
50
52
 
@@ -107,6 +109,8 @@ export const ProfileView = ({
107
109
  const {ref, dimensions} = useContainerDimensions();
108
110
  const [curPath, setCurPath] = useState<string[]>([]);
109
111
  const {currentView, setCurrentView} = profileVisState;
112
+ const isDarkMode = useAppSelector(selectDarkMode);
113
+ const currentSearchString = useAppSelector(selectSearchNodeString);
110
114
 
111
115
  const [callgraphEnabled] = useUIFeatureFlag('callgraph');
112
116
 
@@ -166,138 +170,148 @@ export const ProfileView = ({
166
170
  return;
167
171
  }
168
172
  const router = parseParams(window.location.search);
169
- navigateTo('/', {...router, ...{currentProfileView: view}});
173
+ navigateTo('/', {
174
+ ...router,
175
+ ...{currentProfileView: view},
176
+ ...{searchString: currentSearchString},
177
+ });
170
178
  };
171
179
 
180
+ const maxColor: string = getNewSpanColor(isDarkMode);
181
+ // TODO: fix colors for dark mode
182
+ const minColor: string = scaleLinear([isDarkMode ? 'black' : 'white', maxColor])(0.3);
183
+
184
+ const colorRange: [string, string] = [minColor, maxColor];
185
+
172
186
  return (
173
- <div className="py-3">
174
- <Card>
175
- <Card.Body>
176
- <div className="flex py-3 w-full">
177
- <div className="w-2/5 flex space-x-4">
178
- <div className="flex space-x-1">
179
- {profileSource != null && queryClient != null ? (
180
- <ProfileShareButton
181
- queryRequest={profileSource.QueryRequest()}
182
- queryClient={queryClient}
183
- />
187
+ <>
188
+ <div className="py-3">
189
+ <Card>
190
+ <Card.Body>
191
+ <div className="flex py-3 w-full">
192
+ <div className="w-2/5 flex space-x-4">
193
+ <div className="flex space-x-1">
194
+ {profileSource != null && queryClient != null ? (
195
+ <ProfileShareButton
196
+ queryRequest={profileSource.QueryRequest()}
197
+ queryClient={queryClient}
198
+ />
199
+ ) : null}
200
+
201
+ <Button
202
+ color="neutral"
203
+ onClick={e => {
204
+ e.preventDefault();
205
+ onDownloadPProf();
206
+ }}
207
+ >
208
+ Download pprof
209
+ </Button>
210
+ </div>
211
+
212
+ <SearchNodes />
213
+ </div>
214
+
215
+ <div className="flex ml-auto">
216
+ <div className="mr-3">
217
+ <Button
218
+ color="neutral"
219
+ onClick={resetIcicleGraph}
220
+ disabled={curPath.length === 0}
221
+ className="whitespace-nowrap text-ellipsis"
222
+ >
223
+ Reset View
224
+ </Button>
225
+ </div>
226
+
227
+ {callgraphEnabled ? (
228
+ <div className="mr-3">
229
+ <Button
230
+ variant={`${currentView === 'callgraph' ? 'primary' : 'neutral'}`}
231
+ onClick={() => switchProfileView('callgraph')}
232
+ className="whitespace-nowrap text-ellipsis"
233
+ >
234
+ Callgraph
235
+ </Button>
236
+ </div>
184
237
  ) : null}
185
238
 
186
239
  <Button
187
- color="neutral"
188
- onClick={e => {
189
- e.preventDefault();
190
- onDownloadPProf();
191
- }}
240
+ variant={`${currentView === 'table' ? 'primary' : 'neutral'}`}
241
+ className="items-center rounded-tr-none rounded-br-none w-auto px-8 whitespace-nowrap text-ellipsis no-outline-on-buttons"
242
+ onClick={() => switchProfileView('table')}
192
243
  >
193
- Download pprof
244
+ Table
194
245
  </Button>
195
- </div>
196
246
 
197
- <SearchNodes />
198
- </div>
247
+ <Button
248
+ variant={`${currentView === 'both' ? 'primary' : 'neutral'}`}
249
+ 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"
250
+ onClick={() => switchProfileView('both')}
251
+ >
252
+ Both
253
+ </Button>
199
254
 
200
- <div className="flex ml-auto">
201
- <div className="mr-3">
202
255
  <Button
203
- color="neutral"
204
- onClick={resetIcicleGraph}
205
- disabled={curPath.length === 0}
206
- className="whitespace-nowrap text-ellipsis"
256
+ variant={`${currentView === 'icicle' ? 'primary' : 'neutral'}`}
257
+ className="items-center rounded-tl-none rounded-bl-none w-auto px-8 whitespace-nowrap text-ellipsis no-outline-on-buttons"
258
+ onClick={() => switchProfileView('icicle')}
207
259
  >
208
- Reset View
260
+ Icicle Graph
209
261
  </Button>
210
262
  </div>
211
-
212
- {callgraphEnabled ? (
213
- <div className="mr-3">
214
- <Button
215
- variant={`${currentView === 'callgraph' ? 'primary' : 'neutral'}`}
216
- onClick={() => switchProfileView('callgraph')}
217
- className="whitespace-nowrap text-ellipsis"
218
- >
219
- Call Graph
220
- </Button>
221
- </div>
222
- ) : null}
223
-
224
- <Button
225
- variant={`${currentView === 'table' ? 'primary' : 'neutral'}`}
226
- className="items-center rounded-tr-none rounded-br-none w-auto px-8 whitespace-nowrap text-ellipsis no-outline-on-buttons"
227
- onClick={() => switchProfileView('table')}
228
- >
229
- Table
230
- </Button>
231
-
232
- <Button
233
- variant={`${currentView === 'both' ? 'primary' : 'neutral'}`}
234
- 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"
235
- onClick={() => switchProfileView('both')}
236
- >
237
- Both
238
- </Button>
239
-
240
- <Button
241
- variant={`${currentView === 'icicle' ? 'primary' : 'neutral'}`}
242
- className="items-center rounded-tl-none rounded-bl-none w-auto px-8 whitespace-nowrap text-ellipsis no-outline-on-buttons"
243
- onClick={() => switchProfileView('icicle')}
244
- >
245
- Icicle Graph
246
- </Button>
247
263
  </div>
248
- </div>
249
-
250
- <div ref={ref} className="flex space-x-4 justify-between w-full">
251
- {currentView === 'icicle' && flamegraphData?.data != null && (
252
- <div className="w-full">
253
- <ProfileIcicleGraph
254
- curPath={curPath}
255
- setNewCurPath={setNewCurPath}
256
- graph={flamegraphData.data}
257
- sampleUnit={sampleUnit}
258
- />
259
- </div>
260
- )}
261
264
 
262
- {currentView === 'callgraph' && callgraphData?.data != null && (
263
- <div className="w-full">
264
- {dimensions?.width !== undefined && (
265
- <CallgraphComponent
266
- graph={callgraphData.data}
265
+ <div ref={ref} className="flex space-x-4 justify-between w-full">
266
+ {currentView === 'icicle' && flamegraphData?.data != null && (
267
+ <div className="w-full">
268
+ <ProfileIcicleGraph
269
+ curPath={curPath}
270
+ setNewCurPath={setNewCurPath}
271
+ graph={flamegraphData.data}
267
272
  sampleUnit={sampleUnit}
268
- width={dimensions?.width}
269
273
  />
270
- )}
271
- </div>
272
- )}
273
-
274
- {currentView === 'table' && topTableData != null && (
275
- <div className="w-full">
276
- <TopTable data={topTableData.data} sampleUnit={sampleUnit} />
277
- </div>
278
- )}
279
-
280
- {currentView === 'both' && (
281
- <>
282
- <div className="w-1/2">
283
- <TopTable data={topTableData?.data} sampleUnit={sampleUnit} />
284
274
  </div>
285
-
286
- <div className="w-1/2">
287
- {flamegraphData != null && (
288
- <ProfileIcicleGraph
289
- curPath={curPath}
290
- setNewCurPath={setNewCurPath}
291
- graph={flamegraphData.data}
275
+ )}
276
+ {currentView === 'callgraph' && callgraphData?.data != null && (
277
+ <div className="w-full">
278
+ {dimensions?.width !== undefined && (
279
+ <Callgraph
280
+ graph={callgraphData.data}
292
281
  sampleUnit={sampleUnit}
282
+ width={dimensions?.width}
283
+ colorRange={colorRange}
293
284
  />
294
285
  )}
295
286
  </div>
296
- </>
297
- )}
298
- </div>
299
- </Card.Body>
300
- </Card>
301
- </div>
287
+ )}
288
+ {currentView === 'table' && topTableData != null && (
289
+ <div className="w-full">
290
+ <TopTable data={topTableData.data} sampleUnit={sampleUnit} />
291
+ </div>
292
+ )}
293
+ {currentView === 'both' && (
294
+ <>
295
+ <div className="w-1/2">
296
+ <TopTable data={topTableData?.data} sampleUnit={sampleUnit} />
297
+ </div>
298
+
299
+ <div className="w-1/2">
300
+ {flamegraphData != null && (
301
+ <ProfileIcicleGraph
302
+ curPath={curPath}
303
+ setNewCurPath={setNewCurPath}
304
+ graph={flamegraphData.data}
305
+ sampleUnit={sampleUnit}
306
+ />
307
+ )}
308
+ </div>
309
+ </>
310
+ )}
311
+ </div>
312
+ </Card.Body>
313
+ </Card>
314
+ </div>
315
+ </>
302
316
  );
303
317
  };
@@ -1,23 +0,0 @@
1
- /// <reference types="react" />
2
- export interface IEdge {
3
- source: number;
4
- target: number;
5
- color: string;
6
- points: string;
7
- }
8
- interface Props {
9
- edge: IEdge;
10
- sourceNode: {
11
- x: number;
12
- y: number;
13
- };
14
- targetNode: {
15
- x: number;
16
- y: number;
17
- };
18
- xScale: (x: number) => number;
19
- yScale: (y: number) => number;
20
- nodeRadius: number;
21
- }
22
- declare const Edge: ({ edge, sourceNode, targetNode, xScale, yScale, nodeRadius }: Props) => JSX.Element;
23
- export default Edge;
@@ -1,30 +0,0 @@
1
- import { jsx as _jsx } from "react/jsx-runtime";
2
- // Copyright 2022 The Parca Authors
3
- // Licensed under the Apache License, Version 2.0 (the "License");
4
- // you may not use this file except in compliance with the License.
5
- // You may obtain a copy of the License at
6
- //
7
- // http://www.apache.org/licenses/LICENSE-2.0
8
- //
9
- // Unless required by applicable law or agreed to in writing, software
10
- // distributed under the License is distributed on an "AS IS" BASIS,
11
- // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
- // See the License for the specific language governing permissions and
13
- // limitations under the License.
14
- import { Arrow } from 'react-konva';
15
- import { parseEdgePos } from '../utils';
16
- var Edge = function (_a) {
17
- var edge = _a.edge, sourceNode = _a.sourceNode, targetNode = _a.targetNode, xScale = _a.xScale, yScale = _a.yScale, nodeRadius = _a.nodeRadius;
18
- var points = edge.points, color = edge.color, source = edge.source, target = edge.target;
19
- var scaledPoints = parseEdgePos({
20
- pos: points,
21
- xScale: xScale,
22
- yScale: yScale,
23
- source: [sourceNode.x, sourceNode.y],
24
- target: [targetNode.x, targetNode.y],
25
- nodeRadius: nodeRadius,
26
- isSelfLoop: source === target,
27
- });
28
- return (_jsx(Arrow, { points: scaledPoints, bezier: true, stroke: color, strokeWidth: 3, pointerLength: 10, pointerWidth: 10, fill: color, opacity: 0.8 }));
29
- };
30
- export default Edge;
@@ -1,20 +0,0 @@
1
- /// <reference types="react" />
2
- export interface INode {
3
- id: number;
4
- x: number;
5
- y: number;
6
- data: {
7
- id: string;
8
- };
9
- color: string;
10
- mouseX?: number;
11
- mouseY?: number;
12
- }
13
- interface Props {
14
- node: INode;
15
- hoveredNode: INode | null;
16
- setHoveredNode: (node: INode | null) => void;
17
- nodeRadius: number;
18
- }
19
- declare const Node: ({ node, hoveredNode, setHoveredNode, nodeRadius: defaultRadius, }: Props) => JSX.Element;
20
- export default Node;
@@ -1,37 +0,0 @@
1
- var __assign = (this && this.__assign) || function () {
2
- __assign = Object.assign || function(t) {
3
- for (var s, i = 1, n = arguments.length; i < n; i++) {
4
- s = arguments[i];
5
- for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
6
- t[p] = s[p];
7
- }
8
- return t;
9
- };
10
- return __assign.apply(this, arguments);
11
- };
12
- import { 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 { Circle } from 'react-konva';
26
- var Node = function (_a) {
27
- var node = _a.node, hoveredNode = _a.hoveredNode, setHoveredNode = _a.setHoveredNode, defaultRadius = _a.nodeRadius;
28
- var id = node.data.id, x = node.x, y = node.y, color = node.color;
29
- var hoverRadius = defaultRadius + 3;
30
- var isHovered = Boolean(hoveredNode) && (hoveredNode === null || hoveredNode === void 0 ? void 0 : hoveredNode.data.id) === id;
31
- return (_jsx(Circle, { x: +x, y: +y, draggable: true, radius: isHovered ? hoverRadius : defaultRadius, fill: color, onMouseOver: function () {
32
- setHoveredNode(__assign(__assign({}, node), { mouseX: x, mouseY: y }));
33
- }, onMouseOut: function () {
34
- setHoveredNode(null);
35
- } }));
36
- };
37
- export default Node;
@@ -1,59 +0,0 @@
1
- // Copyright 2022 The Parca Authors
2
- // Licensed under the Apache License, Version 2.0 (the "License");
3
- // you may not use this file except in compliance with the License.
4
- // You may obtain a copy of the License at
5
- //
6
- // http://www.apache.org/licenses/LICENSE-2.0
7
- //
8
- // Unless required by applicable law or agreed to in writing, software
9
- // distributed under the License is distributed on an "AS IS" BASIS,
10
- // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11
- // See the License for the specific language governing permissions and
12
- // limitations under the License.
13
-
14
- import {Arrow} from 'react-konva';
15
- import {parseEdgePos} from '../utils';
16
-
17
- export interface IEdge {
18
- source: number;
19
- target: number;
20
- color: string;
21
- points: string;
22
- }
23
- interface Props {
24
- edge: IEdge;
25
- sourceNode: {x: number; y: number};
26
- targetNode: {x: number; y: number};
27
- xScale: (x: number) => number;
28
- yScale: (y: number) => number;
29
- nodeRadius: number;
30
- }
31
-
32
- const Edge = ({edge, sourceNode, targetNode, xScale, yScale, nodeRadius}: Props): JSX.Element => {
33
- const {points, color, source, target} = edge;
34
-
35
- const scaledPoints = parseEdgePos({
36
- pos: points,
37
- xScale,
38
- yScale,
39
- source: [sourceNode.x, sourceNode.y],
40
- target: [targetNode.x, targetNode.y],
41
- nodeRadius,
42
- isSelfLoop: source === target,
43
- });
44
-
45
- return (
46
- <Arrow
47
- points={scaledPoints}
48
- bezier={true}
49
- stroke={color}
50
- strokeWidth={3}
51
- pointerLength={10}
52
- pointerWidth={10}
53
- fill={color}
54
- opacity={0.8}
55
- />
56
- );
57
- };
58
-
59
- export default Edge;
@@ -1,66 +0,0 @@
1
- // Copyright 2022 The Parca Authors
2
- // Licensed under the Apache License, Version 2.0 (the "License");
3
- // you may not use this file except in compliance with the License.
4
- // You may obtain a copy of the License at
5
- //
6
- // http://www.apache.org/licenses/LICENSE-2.0
7
- //
8
- // Unless required by applicable law or agreed to in writing, software
9
- // distributed under the License is distributed on an "AS IS" BASIS,
10
- // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11
- // See the License for the specific language governing permissions and
12
- // limitations under the License.
13
-
14
- import {Circle} from 'react-konva';
15
-
16
- export interface INode {
17
- id: number;
18
- x: number;
19
- y: number;
20
- data: {id: string};
21
- color: string;
22
- mouseX?: number;
23
- mouseY?: number;
24
- }
25
-
26
- interface Props {
27
- node: INode;
28
- hoveredNode: INode | null;
29
- setHoveredNode: (node: INode | null) => void;
30
- nodeRadius: number;
31
- }
32
-
33
- const Node = ({
34
- node,
35
- hoveredNode,
36
- setHoveredNode,
37
- nodeRadius: defaultRadius,
38
- }: Props): JSX.Element => {
39
- const {
40
- data: {id},
41
- x,
42
- y,
43
- color,
44
- } = node;
45
-
46
- const hoverRadius = defaultRadius + 3;
47
- const isHovered = Boolean(hoveredNode) && hoveredNode?.data.id === id;
48
-
49
- return (
50
- <Circle
51
- x={+x}
52
- y={+y}
53
- draggable
54
- radius={isHovered ? hoverRadius : defaultRadius}
55
- fill={color}
56
- onMouseOver={() => {
57
- setHoveredNode({...node, mouseX: x, mouseY: y});
58
- }}
59
- onMouseOut={() => {
60
- setHoveredNode(null);
61
- }}
62
- />
63
- );
64
- };
65
-
66
- export default Node;