@parca/profile 0.16.56 → 0.16.58
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/Callgraph/Edge/index.d.ts +1 -0
- package/dist/Callgraph/Node/index.d.ts +1 -0
- package/dist/Callgraph/index.d.ts +1 -0
- package/dist/GraphTooltip/index.d.ts +10 -4
- package/dist/GraphTooltip/index.js +31 -5
- package/dist/IcicleGraph.d.ts +13 -3
- package/dist/IcicleGraph.js +23 -19
- package/dist/MatchersInput/index.d.ts +1 -0
- package/dist/MetricsCircle/index.d.ts +1 -0
- package/dist/MetricsGraph/index.d.ts +1 -0
- package/dist/MetricsSeries/index.d.ts +1 -0
- package/dist/ProfileExplorer/ProfileExplorerCompare.d.ts +1 -0
- package/dist/ProfileExplorer/ProfileExplorerSingle.d.ts +1 -0
- package/dist/ProfileExplorer/index.d.ts +1 -0
- package/dist/ProfileIcicleGraph.d.ts +1 -0
- package/dist/ProfileMetricsGraph/index.d.ts +1 -0
- package/dist/ProfileSelector/CompareButton.d.ts +1 -0
- package/dist/ProfileSelector/MergeButton.d.ts +1 -0
- package/dist/ProfileSelector/index.d.ts +1 -0
- package/dist/ProfileSource.d.ts +1 -0
- package/dist/ProfileTypeSelector/index.d.ts +1 -0
- package/dist/ProfileView.d.ts +1 -0
- package/dist/ProfileViewWithData.d.ts +1 -0
- package/dist/ProfileViewWithData.js +1 -1
- package/dist/TopTable.d.ts +1 -0
- package/dist/TopTable.js +8 -4
- package/dist/components/DiffLegend.d.ts +1 -0
- package/dist/components/ProfileShareButton/ResultBox.d.ts +1 -0
- package/dist/components/ProfileShareButton/index.d.ts +1 -0
- package/package.json +4 -4
- package/src/GraphTooltip/index.tsx +74 -4
- package/src/IcicleGraph.tsx +63 -15
- package/src/ProfileViewWithData.tsx +1 -1
- package/src/TopTable.tsx +18 -4
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.58](https://github.com/parca-dev/parca/compare/@parca/profile@0.16.57...@parca/profile@0.16.58) (2022-11-02)
|
|
7
|
+
|
|
8
|
+
**Note:** Version bump only for package @parca/profile
|
|
9
|
+
|
|
10
|
+
## [0.16.57](https://github.com/parca-dev/parca/compare/@parca/profile@0.16.56...@parca/profile@0.16.57) (2022-11-02)
|
|
11
|
+
|
|
12
|
+
**Note:** Version bump only for package @parca/profile
|
|
13
|
+
|
|
6
14
|
## 0.16.56 (2022-10-31)
|
|
7
15
|
|
|
8
16
|
**Note:** Version bump only for package @parca/profile
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
|
|
1
|
+
/// <reference types="react" />
|
|
2
|
+
import { CallgraphNode, FlamegraphNode, FlamegraphNodeMeta, FlamegraphRootNode } from '@parca/client';
|
|
3
|
+
import { Function, Location, Mapping } from '@parca/client/dist/parca/metastore/v1alpha1/metastore';
|
|
2
4
|
interface GraphTooltipProps {
|
|
3
5
|
x: number;
|
|
4
6
|
y: number;
|
|
@@ -8,12 +10,16 @@ interface GraphTooltipProps {
|
|
|
8
10
|
contextElement: Element | null;
|
|
9
11
|
isFixed?: boolean;
|
|
10
12
|
virtualContextElement?: boolean;
|
|
13
|
+
strings?: string[];
|
|
14
|
+
mappings?: Mapping[];
|
|
15
|
+
locations?: Location[];
|
|
16
|
+
functions?: Function[];
|
|
11
17
|
}
|
|
12
|
-
export interface HoveringNode extends CallgraphNode, FlamegraphRootNode {
|
|
18
|
+
export interface HoveringNode extends CallgraphNode, FlamegraphRootNode, FlamegraphNode {
|
|
13
19
|
diff: string;
|
|
14
|
-
meta?: {
|
|
20
|
+
meta?: FlamegraphNodeMeta | {
|
|
15
21
|
[key: string]: any;
|
|
16
22
|
};
|
|
17
23
|
}
|
|
18
|
-
declare const GraphTooltip: ({ x, y, unit, total, hoveringNode, contextElement, isFixed, virtualContextElement, }: GraphTooltipProps) => JSX.Element;
|
|
24
|
+
declare const GraphTooltip: ({ x, y, unit, total, hoveringNode, contextElement, isFixed, virtualContextElement, strings, mappings, locations, functions, }: GraphTooltipProps) => JSX.Element;
|
|
19
25
|
export default GraphTooltip;
|
|
@@ -70,9 +70,33 @@ function generateGetBoundingClientRect(contextElement, x, y) {
|
|
|
70
70
|
}
|
|
71
71
|
var TooltipMetaInfo = function (_a) {
|
|
72
72
|
var _b, _c, _d, _e;
|
|
73
|
-
var hoveringNode = _a.hoveringNode, onCopy = _a.onCopy;
|
|
73
|
+
var hoveringNode = _a.hoveringNode, onCopy = _a.onCopy, strings = _a.strings, mappings = _a.mappings, locations = _a.locations, functions = _a.functions;
|
|
74
74
|
if (hoveringNode.meta === undefined)
|
|
75
75
|
return _jsx(_Fragment, {});
|
|
76
|
+
// populate meta from the flamegraph metadata tables
|
|
77
|
+
if (locations !== undefined) {
|
|
78
|
+
var location_1 = locations[hoveringNode.meta.locationIndex];
|
|
79
|
+
hoveringNode.meta.location = location_1;
|
|
80
|
+
if (mappings !== undefined) {
|
|
81
|
+
var mapping = mappings[location_1.mappingIndex];
|
|
82
|
+
if (strings !== undefined) {
|
|
83
|
+
mapping.file = strings[mapping.fileStringIndex];
|
|
84
|
+
mapping.buildId = strings[mapping.buildIdStringIndex];
|
|
85
|
+
}
|
|
86
|
+
hoveringNode.meta.mapping = mapping;
|
|
87
|
+
}
|
|
88
|
+
location_1.lines.forEach(function (line) {
|
|
89
|
+
if (functions !== undefined && hoveringNode.meta !== undefined) {
|
|
90
|
+
var func = functions[line.functionIndex];
|
|
91
|
+
if (strings !== undefined) {
|
|
92
|
+
func.name = strings[func.nameStringIndex];
|
|
93
|
+
func.systemName = strings[func.systemNameStringIndex];
|
|
94
|
+
func.filename = strings[func.filenameStringIndex];
|
|
95
|
+
}
|
|
96
|
+
hoveringNode.meta.function = func;
|
|
97
|
+
}
|
|
98
|
+
});
|
|
99
|
+
}
|
|
76
100
|
var getTextForFile = function (hoveringNode) {
|
|
77
101
|
var _a, _b, _c, _d;
|
|
78
102
|
if (hoveringNode.meta === undefined)
|
|
@@ -91,7 +115,7 @@ var TooltipMetaInfo = function (_a) {
|
|
|
91
115
|
};
|
|
92
116
|
var timeoutHandle = null;
|
|
93
117
|
var GraphTooltipContent = function (_a) {
|
|
94
|
-
var hoveringNode = _a.hoveringNode, unit = _a.unit, total = _a.total, isFixed = _a.isFixed;
|
|
118
|
+
var hoveringNode = _a.hoveringNode, unit = _a.unit, total = _a.total, isFixed = _a.isFixed, strings = _a.strings, mappings = _a.mappings, locations = _a.locations, functions = _a.functions;
|
|
95
119
|
var _b = useState(false), isCopied = _b[0], setIsCopied = _b[1];
|
|
96
120
|
var onCopy = function () {
|
|
97
121
|
setIsCopied(true);
|
|
@@ -108,7 +132,9 @@ var GraphTooltipContent = function (_a) {
|
|
|
108
132
|
var diffValueText = diffSign + valueFormatter(diff, unit, 1);
|
|
109
133
|
var diffPercentageText = diffSign + (diffRatio * 100).toFixed(2) + '%';
|
|
110
134
|
var diffText = "".concat(diffValueText, " (").concat(diffPercentageText, ")");
|
|
111
|
-
var metaRows = hoveringNode.meta === undefined ? (_jsx(_Fragment, {})) : (_jsx(TooltipMetaInfo, { onCopy: onCopy,
|
|
135
|
+
var metaRows = hoveringNode.meta === undefined ? (_jsx(_Fragment, {})) : (_jsx(TooltipMetaInfo, { onCopy: onCopy,
|
|
136
|
+
// @ts-expect-error
|
|
137
|
+
hoveringNode: hoveringNode, strings: strings, mappings: mappings, locations: locations, functions: functions }));
|
|
112
138
|
var getTextForCumulative = function (hoveringNodeCumulative) {
|
|
113
139
|
return "".concat(valueFormatter(hoveringNodeCumulative, unit, 2), " (\n ").concat(((hoveringNodeCumulative * 100) / total).toFixed(2), "%)");
|
|
114
140
|
};
|
|
@@ -117,7 +143,7 @@ var GraphTooltipContent = function (_a) {
|
|
|
117
143
|
parseInt(hoveringNode.meta.location.address, 10) !== 0 ? (_jsx(CopyToClipboard, __assign({ onCopy: onCopy, text: hexifyAddress(hoveringNode.meta.location.address) }, { children: _jsx("button", __assign({ className: "cursor-pointer text-left" }, { children: hexifyAddress(hoveringNode.meta.location.address) })) }))) : (_jsx("p", { children: "unknown" })) })) })) })), _jsx("span", __assign({ className: "text-gray-700 dark:text-gray-300 my-2" }, { children: _jsx("table", __assign({ className: "table-fixed" }, { children: _jsxs("tbody", { children: [_jsxs("tr", { children: [_jsx("td", __assign({ className: "w-1/5" }, { children: "Cumulative" })), _jsx("td", __assign({ className: "w-4/5" }, { children: _jsx(CopyToClipboard, __assign({ onCopy: onCopy, text: getTextForCumulative(hoveringNodeCumulative) }, { children: _jsx("button", __assign({ className: "cursor-pointer" }, { children: getTextForCumulative(hoveringNodeCumulative) })) })) }))] }), hoveringNode.diff !== undefined && diff !== 0 && (_jsxs("tr", { children: [_jsx("td", __assign({ className: "w-1/5" }, { children: "Diff" })), _jsx("td", __assign({ className: "w-4/5" }, { children: _jsx(CopyToClipboard, __assign({ onCopy: onCopy, text: diffText }, { children: _jsx("button", __assign({ className: "cursor-pointer" }, { children: diffText })) })) }))] })), metaRows] }) })) })), _jsx("span", __assign({ className: "block text-gray-500 text-xs mt-2" }, { children: isCopied ? 'Copied!' : 'Hold shift and click on a value to copy.' }))] })) })) })) })) })));
|
|
118
144
|
};
|
|
119
145
|
var GraphTooltip = function (_a) {
|
|
120
|
-
var x = _a.x, y = _a.y, unit = _a.unit, total = _a.total, hoveringNode = _a.hoveringNode, contextElement = _a.contextElement, _b = _a.isFixed, isFixed = _b === void 0 ? false : _b, _c = _a.virtualContextElement, virtualContextElement = _c === void 0 ? true : _c;
|
|
146
|
+
var x = _a.x, y = _a.y, unit = _a.unit, total = _a.total, hoveringNode = _a.hoveringNode, contextElement = _a.contextElement, _b = _a.isFixed, isFixed = _b === void 0 ? false : _b, _c = _a.virtualContextElement, virtualContextElement = _c === void 0 ? true : _c, strings = _a.strings, mappings = _a.mappings, locations = _a.locations, functions = _a.functions;
|
|
121
147
|
var _d = useState(null), popperElement = _d[0], setPopperElement = _d[1];
|
|
122
148
|
var _e = usePopper(virtualContextElement ? virtualElement : contextElement, popperElement, {
|
|
123
149
|
placement: 'auto-start',
|
|
@@ -150,6 +176,6 @@ var GraphTooltip = function (_a) {
|
|
|
150
176
|
}, [x, y, contextElement, update, isShiftDown]);
|
|
151
177
|
if (hoveringNode === undefined || hoveringNode == null)
|
|
152
178
|
return _jsx(_Fragment, {});
|
|
153
|
-
return isFixed ? (_jsx(GraphTooltipContent, { hoveringNode: hoveringNode, unit: unit, total: total, isFixed: isFixed })) : (_jsx("div", __assign({ ref: setPopperElement, style: styles.popper }, attributes.popper, { children: _jsx(GraphTooltipContent, { hoveringNode: hoveringNode, unit: unit, total: total, isFixed: isFixed }) })));
|
|
179
|
+
return isFixed ? (_jsx(GraphTooltipContent, { hoveringNode: hoveringNode, unit: unit, total: total, isFixed: isFixed })) : (_jsx("div", __assign({ ref: setPopperElement, style: styles.popper }, attributes.popper, { children: _jsx(GraphTooltipContent, { hoveringNode: hoveringNode, unit: unit, total: total, isFixed: isFixed, strings: strings, mappings: mappings, locations: locations, functions: functions }) })));
|
|
154
180
|
};
|
|
155
181
|
export default GraphTooltip;
|
package/dist/IcicleGraph.d.ts
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
|
+
/// <reference types="react" />
|
|
1
2
|
import { Flamegraph, FlamegraphNode, FlamegraphRootNode } from '@parca/client';
|
|
3
|
+
import { Mapping, Function, Location } from '@parca/client/dist/parca/metastore/v1alpha1/metastore';
|
|
2
4
|
interface IcicleGraphProps {
|
|
3
5
|
graph: Flamegraph;
|
|
4
6
|
sampleUnit: string;
|
|
@@ -8,6 +10,10 @@ interface IcicleGraphProps {
|
|
|
8
10
|
}
|
|
9
11
|
interface IcicleGraphNodesProps {
|
|
10
12
|
data: FlamegraphNode[];
|
|
13
|
+
strings: string[];
|
|
14
|
+
mappings: Mapping[];
|
|
15
|
+
locations: Location[];
|
|
16
|
+
functions: Function[];
|
|
11
17
|
x: number;
|
|
12
18
|
y: number;
|
|
13
19
|
total: number;
|
|
@@ -21,6 +27,10 @@ interface IcicleGraphNodesProps {
|
|
|
21
27
|
}
|
|
22
28
|
interface IcicleGraphRootNodeProps {
|
|
23
29
|
node: FlamegraphRootNode;
|
|
30
|
+
strings: string[];
|
|
31
|
+
mappings: Mapping[];
|
|
32
|
+
locations: Location[];
|
|
33
|
+
functions: Function[];
|
|
24
34
|
xScale: (value: number) => number;
|
|
25
35
|
total: number;
|
|
26
36
|
totalWidth: number;
|
|
@@ -28,8 +38,8 @@ interface IcicleGraphRootNodeProps {
|
|
|
28
38
|
setCurPath: (path: string[]) => void;
|
|
29
39
|
setHoveringNode: (node: FlamegraphNode | FlamegraphRootNode | undefined) => void;
|
|
30
40
|
}
|
|
31
|
-
export declare function nodeLabel(node: FlamegraphNode): string;
|
|
32
|
-
export declare function IcicleGraphNodes({ data, x, y, xScale, total, totalWidth, level, setHoveringNode, path, setCurPath, curPath, }: IcicleGraphNodesProps): JSX.Element;
|
|
33
|
-
export declare function IcicleGraphRootNode({ node, xScale, total, totalWidth, setHoveringNode, setCurPath, curPath, }: IcicleGraphRootNodeProps): JSX.Element;
|
|
41
|
+
export declare function nodeLabel(node: FlamegraphNode, strings: string[], mappings: Mapping[], locations: Location[], functions: Function[]): string;
|
|
42
|
+
export declare function IcicleGraphNodes({ data, strings, mappings, locations, functions, x, y, xScale, total, totalWidth, level, setHoveringNode, path, setCurPath, curPath, }: IcicleGraphNodesProps): JSX.Element;
|
|
43
|
+
export declare function IcicleGraphRootNode({ node, strings, mappings, locations, functions, xScale, total, totalWidth, setHoveringNode, setCurPath, curPath, }: IcicleGraphRootNodeProps): JSX.Element;
|
|
34
44
|
export default function IcicleGraph({ graph, width, setCurPath, curPath, sampleUnit, }: IcicleGraphProps): JSX.Element;
|
|
35
45
|
export {};
|
package/dist/IcicleGraph.js
CHANGED
|
@@ -27,8 +27,8 @@ import { throttle } from 'lodash';
|
|
|
27
27
|
import { pointer } from 'd3-selection';
|
|
28
28
|
import { scaleLinear } from 'd3-scale';
|
|
29
29
|
import GraphTooltip from './GraphTooltip';
|
|
30
|
-
import {
|
|
31
|
-
import {
|
|
30
|
+
import { diffColor, getLastItem, isSearchMatch } from '@parca/functions';
|
|
31
|
+
import { selectDarkMode, selectSearchNodeString, useAppSelector } from '@parca/store';
|
|
32
32
|
import useIsShiftDown from '@parca/components/src/hooks/useIsShiftDown';
|
|
33
33
|
import { hexifyAddress } from './utils';
|
|
34
34
|
var RowHeight = 26;
|
|
@@ -55,24 +55,28 @@ function IcicleRect(_a) {
|
|
|
55
55
|
fill: color,
|
|
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
|
-
export function nodeLabel(node) {
|
|
59
|
-
var _a, _b
|
|
60
|
-
if (node.meta === undefined)
|
|
58
|
+
export function nodeLabel(node, strings, mappings, locations, functions) {
|
|
59
|
+
var _a, _b;
|
|
60
|
+
if (((_a = node.meta) === null || _a === void 0 ? void 0 : _a.locationIndex) === undefined)
|
|
61
61
|
return '<unknown>';
|
|
62
|
-
var
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
if (
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
62
|
+
var location = locations[node.meta.locationIndex];
|
|
63
|
+
var mappingFile = strings[mappings[location.mappingIndex].fileStringIndex];
|
|
64
|
+
var mappingString = "".concat(mappingFile !== '' ? '[' + ((_b = getLastItem(mappingFile)) !== null && _b !== void 0 ? _b : '') + '] ' : '');
|
|
65
|
+
if (location.lines.length > 0) {
|
|
66
|
+
var funcName = strings[functions[location.lines[0].functionIndex].nameStringIndex];
|
|
67
|
+
return "".concat(mappingString, " ").concat(funcName);
|
|
68
|
+
}
|
|
69
|
+
var address = hexifyAddress(location.address);
|
|
70
|
+
var fallback = "".concat(mappingString).concat(address);
|
|
69
71
|
return fallback === '' ? '<unknown>' : fallback;
|
|
70
72
|
}
|
|
71
73
|
export function IcicleGraphNodes(_a) {
|
|
72
|
-
var data = _a.data, 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;
|
|
74
|
+
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;
|
|
73
75
|
var isDarkMode = useAppSelector(selectDarkMode);
|
|
74
76
|
var isShiftDown = useIsShiftDown();
|
|
75
|
-
var nodes = curPath.length === 0
|
|
77
|
+
var nodes = curPath.length === 0
|
|
78
|
+
? data
|
|
79
|
+
: data.filter(function (d) { return d != null && curPath[0] === nodeLabel(d, strings, mappings, locations, functions); });
|
|
76
80
|
var nextLevel = level + 1;
|
|
77
81
|
return (_jsx("g", __assign({ transform: "translate(".concat(x, ", ").concat(y, ")") }, { children: nodes.map(function (d, i) {
|
|
78
82
|
var cumulative = parseFloat(d.cumulative);
|
|
@@ -85,7 +89,7 @@ export function IcicleGraphNodes(_a) {
|
|
|
85
89
|
if (width <= 1) {
|
|
86
90
|
return null;
|
|
87
91
|
}
|
|
88
|
-
var name = nodeLabel(d);
|
|
92
|
+
var name = nodeLabel(d, strings, mappings, locations, functions);
|
|
89
93
|
var key = "".concat(level, "-").concat(i);
|
|
90
94
|
var nextPath = path.concat([name]);
|
|
91
95
|
var color = diffColor(diff, cumulative, isDarkMode);
|
|
@@ -106,12 +110,12 @@ export function IcicleGraphNodes(_a) {
|
|
|
106
110
|
return;
|
|
107
111
|
setHoveringNode(undefined);
|
|
108
112
|
};
|
|
109
|
-
return (_jsxs(React.Fragment, { children: [_jsx(IcicleRect, { x: xStart, y: 0, width: width, height: RowHeight, name: name, color: color, onClick: onClick, onMouseEnter: onMouseEnter, onMouseLeave: onMouseLeave, curPath: curPath }, "rect-".concat(key)), data !== undefined && data.length > 0 && (_jsx(IcicleGraphNodes, { data: d.children, x: xStart, y: RowHeight, xScale: newXScale, total: total, totalWidth: totalWidth, level: nextLevel, setHoveringNode: setHoveringNode, path: nextPath, curPath: nextCurPath, setCurPath: setCurPath }, "node-".concat(key)))] }, "node-".concat(key)));
|
|
113
|
+
return (_jsxs(React.Fragment, { children: [_jsx(IcicleRect, { x: xStart, y: 0, width: width, height: RowHeight, name: name, color: color, onClick: onClick, onMouseEnter: onMouseEnter, onMouseLeave: onMouseLeave, curPath: curPath }, "rect-".concat(key)), data !== undefined && data.length > 0 && (_jsx(IcicleGraphNodes, { data: d.children, strings: strings, mappings: mappings, locations: locations, functions: functions, x: xStart, y: RowHeight, xScale: newXScale, total: total, totalWidth: totalWidth, level: nextLevel, setHoveringNode: setHoveringNode, path: nextPath, curPath: nextCurPath, setCurPath: setCurPath }, "node-".concat(key)))] }, "node-".concat(key)));
|
|
110
114
|
}) })));
|
|
111
115
|
}
|
|
112
116
|
var MemoizedIcicleGraphNodes = React.memo(IcicleGraphNodes);
|
|
113
117
|
export function IcicleGraphRootNode(_a) {
|
|
114
|
-
var node = _a.node, xScale = _a.xScale, total = _a.total, totalWidth = _a.totalWidth, setHoveringNode = _a.setHoveringNode, setCurPath = _a.setCurPath, curPath = _a.curPath;
|
|
118
|
+
var node = _a.node, strings = _a.strings, mappings = _a.mappings, locations = _a.locations, functions = _a.functions, xScale = _a.xScale, total = _a.total, totalWidth = _a.totalWidth, setHoveringNode = _a.setHoveringNode, setCurPath = _a.setCurPath, curPath = _a.curPath;
|
|
115
119
|
var isDarkMode = useAppSelector(selectDarkMode);
|
|
116
120
|
var isShiftDown = useIsShiftDown();
|
|
117
121
|
var cumulative = parseFloat(node.cumulative);
|
|
@@ -129,7 +133,7 @@ export function IcicleGraphRootNode(_a) {
|
|
|
129
133
|
setHoveringNode(undefined);
|
|
130
134
|
};
|
|
131
135
|
var path = [];
|
|
132
|
-
return (_jsxs("g", __assign({ transform: 'translate(0, 0)' }, { children: [_jsx(IcicleRect, { x: 0, y: 0, width: totalWidth, height: RowHeight, name: 'root', color: color, onClick: onClick, onMouseEnter: onMouseEnter, onMouseLeave: onMouseLeave, curPath: curPath }), _jsx(MemoizedIcicleGraphNodes, { data: node.children, x: 0, y: RowHeight, xScale: xScale, total: total, totalWidth: totalWidth, level: 0, setHoveringNode: setHoveringNode, path: path, curPath: curPath, setCurPath: setCurPath })] })));
|
|
136
|
+
return (_jsxs("g", __assign({ transform: 'translate(0, 0)' }, { children: [_jsx(IcicleRect, { x: 0, y: 0, width: totalWidth, height: RowHeight, name: 'root', color: color, onClick: onClick, onMouseEnter: onMouseEnter, onMouseLeave: onMouseLeave, curPath: curPath }), _jsx(MemoizedIcicleGraphNodes, { data: node.children, strings: strings, mappings: mappings, locations: locations, functions: functions, x: 0, y: RowHeight, xScale: xScale, total: total, totalWidth: totalWidth, level: 0, setHoveringNode: setHoveringNode, path: path, curPath: curPath, setCurPath: setCurPath })] })));
|
|
133
137
|
}
|
|
134
138
|
var MemoizedIcicleGraphRootNode = React.memo(IcicleGraphRootNode);
|
|
135
139
|
export default function IcicleGraph(_a) {
|
|
@@ -154,5 +158,5 @@ export default function IcicleGraph(_a) {
|
|
|
154
158
|
};
|
|
155
159
|
var total = parseFloat(graph.total);
|
|
156
160
|
var xScale = scaleLinear().domain([0, total]).range([0, width]);
|
|
157
|
-
return (_jsxs("div", __assign({ onMouseLeave: function () { return setHoveringNode(undefined); } }, { children: [_jsx(GraphTooltip, { unit: sampleUnit, total: total, x: pos[0], y: pos[1], hoveringNode: hoveringNode, contextElement: svg.current }), _jsx("svg", __assign({ className: "font-robotoMono", width: width, height: height, onMouseMove: onMouseMove, preserveAspectRatio: "xMinYMid", ref: svg }, { children: _jsx("g", __assign({ ref: ref }, { children: _jsx(MemoizedIcicleGraphRootNode, { node: graph.root, setHoveringNode: setHoveringNode, curPath: curPath, setCurPath: setCurPath, xScale: xScale, total: total, totalWidth: width }) })) }))] })));
|
|
161
|
+
return (_jsxs("div", __assign({ onMouseLeave: function () { return setHoveringNode(undefined); } }, { children: [_jsx(GraphTooltip, { unit: sampleUnit, total: total, x: pos[0], y: pos[1], hoveringNode: hoveringNode, contextElement: svg.current, strings: graph.stringTable, mappings: graph.mapping, locations: graph.locations, functions: graph.function }), _jsx("svg", __assign({ className: "font-robotoMono", width: width, height: height, onMouseMove: onMouseMove, preserveAspectRatio: "xMinYMid", ref: svg }, { children: _jsx("g", __assign({ ref: ref }, { children: _jsx(MemoizedIcicleGraphRootNode, { node: graph.root, strings: graph.stringTable, mappings: graph.mapping, locations: graph.locations, functions: graph.function, setHoveringNode: setHoveringNode, curPath: curPath, setCurPath: setCurPath, xScale: xScale, total: total, totalWidth: width }) })) }))] })));
|
|
158
162
|
}
|
package/dist/ProfileSource.d.ts
CHANGED
package/dist/ProfileView.d.ts
CHANGED
|
@@ -59,7 +59,7 @@ export var ProfileViewWithData = function (_a) {
|
|
|
59
59
|
var profileVisState = useProfileVisState();
|
|
60
60
|
var metadata = useGrpcMetadata();
|
|
61
61
|
var currentView = profileVisState.currentView;
|
|
62
|
-
var _d = useQuery(queryClient, profileSource, QueryRequest_ReportType.
|
|
62
|
+
var _d = useQuery(queryClient, profileSource, QueryRequest_ReportType.FLAMEGRAPH_TABLE, {
|
|
63
63
|
skip: currentView !== 'icicle' && currentView !== 'both',
|
|
64
64
|
}), flamegraphLoading = _d.isLoading, flamegraphResponse = _d.response, flamegraphError = _d.error;
|
|
65
65
|
var _e = useQuery(queryClient, profileSource, QueryRequest_ReportType.TOP, {
|
package/dist/TopTable.d.ts
CHANGED
package/dist/TopTable.js
CHANGED
|
@@ -33,7 +33,7 @@ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-run
|
|
|
33
33
|
// limitations under the License.
|
|
34
34
|
import React from 'react';
|
|
35
35
|
import { getLastItem, valueFormatter, isSearchMatch } from '@parca/functions';
|
|
36
|
-
import { useAppSelector, selectCompareMode, selectSearchNodeString } from '@parca/store';
|
|
36
|
+
import { useAppSelector, selectCompareMode, selectSearchNodeString, setSearchNodeString, useAppDispatch, } from '@parca/store';
|
|
37
37
|
import { hexifyAddress } from './utils';
|
|
38
38
|
import './TopTable.styles.css';
|
|
39
39
|
var Arrow = function (_a) {
|
|
@@ -110,6 +110,7 @@ export var TopTable = function (_a) {
|
|
|
110
110
|
var _f = useSortableData(top), items = _f.items, requestSort = _f.requestSort, sortConfig = _f.sortConfig;
|
|
111
111
|
var currentSearchString = useAppSelector(selectSearchNodeString);
|
|
112
112
|
var compareMode = useAppSelector(selectCompareMode);
|
|
113
|
+
var dispatch = useAppDispatch();
|
|
113
114
|
var unit = sampleUnit;
|
|
114
115
|
var total = top != null ? top.list.length : 0;
|
|
115
116
|
if (total === 0)
|
|
@@ -126,15 +127,18 @@ export var TopTable = function (_a) {
|
|
|
126
127
|
}
|
|
127
128
|
return "+".concat(num);
|
|
128
129
|
};
|
|
129
|
-
|
|
130
|
+
var selectSpan = function (span) {
|
|
131
|
+
dispatch(setSearchNodeString(span.trim()));
|
|
132
|
+
};
|
|
133
|
+
return (_jsx(_Fragment, { children: _jsx("div", __assign({ className: "w-full font-robotoMono" }, { children: _jsxs("table", __assign({ className: "iciclegraph-table table-fixed text-left w-full divide-y divide-gray-200 dark:divide-gray-700", tabIndex: 1 }, { children: [_jsx("thead", __assign({ className: "bg-gray-50 dark:bg-gray-800" }, { children: _jsxs("tr", { children: [_jsxs("th", __assign({ className: "text-sm cursor-pointer pt-2 pb-2 pl-2", onClick: function () { return requestSort('name'); } }, { children: ["Name", _jsx("span", __assign({ className: "inline-block align-middle ml-2 ".concat((_b = getClassNamesFor('name')) !== null && _b !== void 0 ? _b : '') }, { children: _jsx(Arrow, { direction: getClassNamesFor('name') }) }))] })), _jsxs("th", __assign({ className: "text-right text-sm cursor-pointer pt-2 pb-2 w-[150px]", onClick: function () { return requestSort('flat'); } }, { children: ["Flat", _jsx("span", __assign({ className: "inline-block align-middle ml-2 ".concat((_c = getClassNamesFor('flat')) !== null && _c !== void 0 ? _c : '') }, { children: _jsx(Arrow, { direction: getClassNamesFor('flat') }) }))] })), _jsxs("th", __assign({ className: "text-right text-sm cursor-pointer pt-2 pb-2 pr-2 w-[150px]", onClick: function () { return requestSort('cumulative'); } }, { children: ["Cumulative", _jsx("span", __assign({ className: "inline-block align-middle ml-2 ".concat((_d = getClassNamesFor('cumulative')) !== null && _d !== void 0 ? _d : '') }, { children: _jsx(Arrow, { direction: getClassNamesFor('cumulative') }) }))] })), compareMode && (_jsxs("th", __assign({ className: "text-right text-sm cursor-pointer pt-2 pb-2 pr-2 w-[150px]", onClick: function () { return requestSort('diff'); } }, { children: ["Diff", _jsx("span", __assign({ className: "inline-block align-middle ml-2 ".concat((_e = getClassNamesFor('diff')) !== null && _e !== void 0 ? _e : '') }, { children: _jsx(Arrow, { direction: getClassNamesFor('diff') }) }))] })))] }) })), _jsx("tbody", __assign({ className: "bg-white divide-y divide-gray-200 dark:bg-gray-900 dark:divide-gray-700" }, { children: items === null || items === void 0 ? void 0 : items.map(function (report, index) {
|
|
130
134
|
var name = RowLabel(report.meta);
|
|
131
|
-
return (_jsxs("tr", __assign({ className: "hover:bg-[#62626212] dark:hover:bg-[#ffffff12]", style: {
|
|
135
|
+
return (_jsxs("tr", __assign({ className: "hover:bg-[#62626212] dark:hover:bg-[#ffffff12] cursor-pointer", style: {
|
|
132
136
|
opacity: currentSearchString !== undefined &&
|
|
133
137
|
currentSearchString !== '' &&
|
|
134
138
|
!isSearchMatch(currentSearchString, name)
|
|
135
139
|
? 0.5
|
|
136
140
|
: 1,
|
|
137
|
-
} }, { children: [_jsx("td", __assign({ className: "text-xs py-1.5 pl-2" }, { children: name })), _jsx("td", __assign({ className: "text-xs py-1.5 text-right" }, { children: valueFormatter(report.flat, unit, 2) })), _jsx("td", __assign({ className: "text-xs py-1.5 text-right pr-2" }, { children: valueFormatter(report.cumulative, unit, 2) })), compareMode && (_jsx("td", __assign({ className: "text-xs py-1.5 text-right pr-2" }, { children: addPlusSign(valueFormatter(report.diff, unit, 2)) })))] }), index));
|
|
141
|
+
}, onClick: function () { return selectSpan(name); } }, { children: [_jsx("td", __assign({ className: "text-xs py-1.5 pl-2" }, { children: name })), _jsx("td", __assign({ className: "text-xs py-1.5 text-right" }, { children: valueFormatter(report.flat, unit, 2) })), _jsx("td", __assign({ className: "text-xs py-1.5 text-right pr-2" }, { children: valueFormatter(report.cumulative, unit, 2) })), compareMode && (_jsx("td", __assign({ className: "text-xs py-1.5 text-right pr-2" }, { children: addPlusSign(valueFormatter(report.diff, unit, 2)) })))] }), index));
|
|
138
142
|
}) }))] })) })) }));
|
|
139
143
|
};
|
|
140
144
|
export default TopTable;
|
package/package.json
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@parca/profile",
|
|
3
|
-
"version": "0.16.
|
|
3
|
+
"version": "0.16.58",
|
|
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.53",
|
|
8
|
+
"@parca/components": "^0.16.54",
|
|
9
9
|
"@parca/dynamicsize": "^0.16.51",
|
|
10
10
|
"@parca/functions": "^0.16.51",
|
|
11
11
|
"@parca/parser": "^0.16.49",
|
|
@@ -39,5 +39,5 @@
|
|
|
39
39
|
"access": "public",
|
|
40
40
|
"registry": "https://registry.npmjs.org/"
|
|
41
41
|
},
|
|
42
|
-
"gitHead": "
|
|
42
|
+
"gitHead": "eee07852940670c11af89dffde8136d5ab177e6c"
|
|
43
43
|
}
|
|
@@ -15,10 +15,16 @@ import {CopyToClipboard} from 'react-copy-to-clipboard';
|
|
|
15
15
|
import {useState, useEffect} from 'react';
|
|
16
16
|
import {usePopper} from 'react-popper';
|
|
17
17
|
|
|
18
|
-
import {CallgraphNode, FlamegraphNode, FlamegraphRootNode} from '@parca/client';
|
|
18
|
+
import {CallgraphNode, FlamegraphNode, FlamegraphNodeMeta, FlamegraphRootNode} from '@parca/client';
|
|
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
28
|
|
|
23
29
|
interface GraphTooltipProps {
|
|
24
30
|
x: number;
|
|
@@ -29,6 +35,10 @@ interface GraphTooltipProps {
|
|
|
29
35
|
contextElement: Element | null;
|
|
30
36
|
isFixed?: boolean;
|
|
31
37
|
virtualContextElement?: boolean;
|
|
38
|
+
strings?: string[];
|
|
39
|
+
mappings?: Mapping[];
|
|
40
|
+
locations?: Location[];
|
|
41
|
+
functions?: Function[];
|
|
32
42
|
}
|
|
33
43
|
|
|
34
44
|
const virtualElement = {
|
|
@@ -61,12 +71,47 @@ function generateGetBoundingClientRect(contextElement: Element, x = 0, y = 0): (
|
|
|
61
71
|
const TooltipMetaInfo = ({
|
|
62
72
|
hoveringNode,
|
|
63
73
|
onCopy,
|
|
74
|
+
strings,
|
|
75
|
+
mappings,
|
|
76
|
+
locations,
|
|
77
|
+
functions,
|
|
64
78
|
}: {
|
|
65
79
|
hoveringNode: FlamegraphNode;
|
|
66
80
|
onCopy: () => void;
|
|
81
|
+
strings?: string[];
|
|
82
|
+
mappings?: Mapping[];
|
|
83
|
+
locations?: Location[];
|
|
84
|
+
functions?: Function[];
|
|
67
85
|
}): JSX.Element => {
|
|
68
86
|
if (hoveringNode.meta === undefined) return <></>;
|
|
69
87
|
|
|
88
|
+
// populate meta from the flamegraph metadata tables
|
|
89
|
+
if (locations !== undefined) {
|
|
90
|
+
const location = locations[hoveringNode.meta.locationIndex];
|
|
91
|
+
hoveringNode.meta.location = location;
|
|
92
|
+
|
|
93
|
+
if (mappings !== undefined) {
|
|
94
|
+
const mapping = mappings[location.mappingIndex];
|
|
95
|
+
if (strings !== undefined) {
|
|
96
|
+
mapping.file = strings[mapping.fileStringIndex];
|
|
97
|
+
mapping.buildId = strings[mapping.buildIdStringIndex];
|
|
98
|
+
}
|
|
99
|
+
hoveringNode.meta.mapping = mapping;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
location.lines.forEach((line: Line) => {
|
|
103
|
+
if (functions !== undefined && hoveringNode.meta !== undefined) {
|
|
104
|
+
const func = functions[line.functionIndex];
|
|
105
|
+
if (strings !== undefined) {
|
|
106
|
+
func.name = strings[func.nameStringIndex];
|
|
107
|
+
func.systemName = strings[func.systemNameStringIndex];
|
|
108
|
+
func.filename = strings[func.filenameStringIndex];
|
|
109
|
+
}
|
|
110
|
+
hoveringNode.meta.function = func;
|
|
111
|
+
}
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
|
|
70
115
|
const getTextForFile = (hoveringNode: FlamegraphNode): string => {
|
|
71
116
|
if (hoveringNode.meta === undefined) return '<unknown>';
|
|
72
117
|
|
|
@@ -140,9 +185,10 @@ const TooltipMetaInfo = ({
|
|
|
140
185
|
);
|
|
141
186
|
};
|
|
142
187
|
|
|
143
|
-
|
|
188
|
+
// @ts-expect-error
|
|
189
|
+
export interface HoveringNode extends CallgraphNode, FlamegraphRootNode, FlamegraphNode {
|
|
144
190
|
diff: string;
|
|
145
|
-
meta?: {[key: string]: any};
|
|
191
|
+
meta?: FlamegraphNodeMeta | {[key: string]: any};
|
|
146
192
|
}
|
|
147
193
|
|
|
148
194
|
let timeoutHandle: ReturnType<typeof setTimeout> | null = null;
|
|
@@ -152,11 +198,19 @@ const GraphTooltipContent = ({
|
|
|
152
198
|
unit,
|
|
153
199
|
total,
|
|
154
200
|
isFixed,
|
|
201
|
+
strings,
|
|
202
|
+
mappings,
|
|
203
|
+
locations,
|
|
204
|
+
functions,
|
|
155
205
|
}: {
|
|
156
206
|
hoveringNode: HoveringNode;
|
|
157
207
|
unit: string;
|
|
158
208
|
total: number;
|
|
159
209
|
isFixed: boolean;
|
|
210
|
+
strings?: string[];
|
|
211
|
+
mappings?: Mapping[];
|
|
212
|
+
locations?: Location[];
|
|
213
|
+
functions?: Function[];
|
|
160
214
|
}): JSX.Element => {
|
|
161
215
|
const [isCopied, setIsCopied] = useState<boolean>(false);
|
|
162
216
|
|
|
@@ -181,7 +235,15 @@ const GraphTooltipContent = ({
|
|
|
181
235
|
hoveringNode.meta === undefined ? (
|
|
182
236
|
<></>
|
|
183
237
|
) : (
|
|
184
|
-
<TooltipMetaInfo
|
|
238
|
+
<TooltipMetaInfo
|
|
239
|
+
onCopy={onCopy}
|
|
240
|
+
// @ts-expect-error
|
|
241
|
+
hoveringNode={hoveringNode}
|
|
242
|
+
strings={strings}
|
|
243
|
+
mappings={mappings}
|
|
244
|
+
locations={locations}
|
|
245
|
+
functions={functions}
|
|
246
|
+
/>
|
|
185
247
|
);
|
|
186
248
|
|
|
187
249
|
const getTextForCumulative = (hoveringNodeCumulative: number): string => {
|
|
@@ -282,6 +344,10 @@ const GraphTooltip = ({
|
|
|
282
344
|
contextElement,
|
|
283
345
|
isFixed = false,
|
|
284
346
|
virtualContextElement = true,
|
|
347
|
+
strings,
|
|
348
|
+
mappings,
|
|
349
|
+
locations,
|
|
350
|
+
functions,
|
|
285
351
|
}: GraphTooltipProps): JSX.Element => {
|
|
286
352
|
const [popperElement, setPopperElement] = useState<HTMLDivElement | null>(null);
|
|
287
353
|
|
|
@@ -332,6 +398,10 @@ const GraphTooltip = ({
|
|
|
332
398
|
unit={unit}
|
|
333
399
|
total={total}
|
|
334
400
|
isFixed={isFixed}
|
|
401
|
+
strings={strings}
|
|
402
|
+
mappings={mappings}
|
|
403
|
+
locations={locations}
|
|
404
|
+
functions={functions}
|
|
335
405
|
/>
|
|
336
406
|
</div>
|
|
337
407
|
);
|
package/src/IcicleGraph.tsx
CHANGED
|
@@ -18,12 +18,13 @@ import {pointer} from 'd3-selection';
|
|
|
18
18
|
import {scaleLinear} from 'd3-scale';
|
|
19
19
|
|
|
20
20
|
import {Flamegraph, FlamegraphNode, FlamegraphRootNode} from '@parca/client';
|
|
21
|
+
import {Mapping, Function, Location} from '@parca/client/dist/parca/metastore/v1alpha1/metastore';
|
|
22
|
+
import type {HoveringNode} from './GraphTooltip';
|
|
21
23
|
import GraphTooltip from './GraphTooltip';
|
|
22
|
-
import {
|
|
23
|
-
import {
|
|
24
|
+
import {diffColor, getLastItem, isSearchMatch} from '@parca/functions';
|
|
25
|
+
import {selectDarkMode, selectSearchNodeString, useAppSelector} from '@parca/store';
|
|
24
26
|
import useIsShiftDown from '@parca/components/src/hooks/useIsShiftDown';
|
|
25
27
|
import {hexifyAddress} from './utils';
|
|
26
|
-
import type {HoveringNode} from './GraphTooltip';
|
|
27
28
|
|
|
28
29
|
interface IcicleGraphProps {
|
|
29
30
|
graph: Flamegraph;
|
|
@@ -35,6 +36,10 @@ interface IcicleGraphProps {
|
|
|
35
36
|
|
|
36
37
|
interface IcicleGraphNodesProps {
|
|
37
38
|
data: FlamegraphNode[];
|
|
39
|
+
strings: string[];
|
|
40
|
+
mappings: Mapping[];
|
|
41
|
+
locations: Location[];
|
|
42
|
+
functions: Function[];
|
|
38
43
|
x: number;
|
|
39
44
|
y: number;
|
|
40
45
|
total: number;
|
|
@@ -49,6 +54,10 @@ interface IcicleGraphNodesProps {
|
|
|
49
54
|
|
|
50
55
|
interface IcicleGraphRootNodeProps {
|
|
51
56
|
node: FlamegraphRootNode;
|
|
57
|
+
strings: string[];
|
|
58
|
+
mappings: Mapping[];
|
|
59
|
+
locations: Location[];
|
|
60
|
+
functions: Function[];
|
|
52
61
|
xScale: (value: number) => number;
|
|
53
62
|
total: number;
|
|
54
63
|
totalWidth: number;
|
|
@@ -132,24 +141,39 @@ function IcicleRect({
|
|
|
132
141
|
);
|
|
133
142
|
}
|
|
134
143
|
|
|
135
|
-
export function nodeLabel(
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
144
|
+
export function nodeLabel(
|
|
145
|
+
node: FlamegraphNode,
|
|
146
|
+
strings: string[],
|
|
147
|
+
mappings: Mapping[],
|
|
148
|
+
locations: Location[],
|
|
149
|
+
functions: Function[]
|
|
150
|
+
): string {
|
|
151
|
+
if (node.meta?.locationIndex === undefined) return '<unknown>';
|
|
152
|
+
|
|
153
|
+
const location = locations[node.meta.locationIndex];
|
|
154
|
+
const mappingFile = strings[mappings[location.mappingIndex].fileStringIndex];
|
|
155
|
+
|
|
156
|
+
const mappingString: string = `${
|
|
157
|
+
mappingFile !== '' ? '[' + (getLastItem(mappingFile) ?? '') + '] ' : ''
|
|
141
158
|
}`;
|
|
142
|
-
if (node.meta.function?.name !== undefined && node.meta.function?.name !== '')
|
|
143
|
-
return mapping + node.meta.function.name;
|
|
144
159
|
|
|
145
|
-
|
|
146
|
-
|
|
160
|
+
if (location.lines.length > 0) {
|
|
161
|
+
const funcName = strings[functions[location.lines[0].functionIndex].nameStringIndex];
|
|
162
|
+
return `${mappingString} ${funcName}`;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
const address = hexifyAddress(location.address);
|
|
166
|
+
const fallback = `${mappingString}${address}`;
|
|
147
167
|
|
|
148
168
|
return fallback === '' ? '<unknown>' : fallback;
|
|
149
169
|
}
|
|
150
170
|
|
|
151
171
|
export function IcicleGraphNodes({
|
|
152
172
|
data,
|
|
173
|
+
strings,
|
|
174
|
+
mappings,
|
|
175
|
+
locations,
|
|
176
|
+
functions,
|
|
153
177
|
x,
|
|
154
178
|
y,
|
|
155
179
|
xScale,
|
|
@@ -165,7 +189,11 @@ export function IcicleGraphNodes({
|
|
|
165
189
|
const isShiftDown = useIsShiftDown();
|
|
166
190
|
|
|
167
191
|
const nodes =
|
|
168
|
-
curPath.length === 0
|
|
192
|
+
curPath.length === 0
|
|
193
|
+
? data
|
|
194
|
+
: data.filter(
|
|
195
|
+
d => d != null && curPath[0] === nodeLabel(d, strings, mappings, locations, functions)
|
|
196
|
+
);
|
|
169
197
|
|
|
170
198
|
const nextLevel = level + 1;
|
|
171
199
|
|
|
@@ -186,7 +214,7 @@ export function IcicleGraphNodes({
|
|
|
186
214
|
return null;
|
|
187
215
|
}
|
|
188
216
|
|
|
189
|
-
const name = nodeLabel(d);
|
|
217
|
+
const name = nodeLabel(d, strings, mappings, locations, functions);
|
|
190
218
|
const key = `${level}-${i}`;
|
|
191
219
|
const nextPath = path.concat([name]);
|
|
192
220
|
|
|
@@ -232,6 +260,10 @@ export function IcicleGraphNodes({
|
|
|
232
260
|
<IcicleGraphNodes
|
|
233
261
|
key={`node-${key}`}
|
|
234
262
|
data={d.children}
|
|
263
|
+
strings={strings}
|
|
264
|
+
mappings={mappings}
|
|
265
|
+
locations={locations}
|
|
266
|
+
functions={functions}
|
|
235
267
|
x={xStart}
|
|
236
268
|
y={RowHeight}
|
|
237
269
|
xScale={newXScale}
|
|
@@ -255,6 +287,10 @@ const MemoizedIcicleGraphNodes = React.memo(IcicleGraphNodes);
|
|
|
255
287
|
|
|
256
288
|
export function IcicleGraphRootNode({
|
|
257
289
|
node,
|
|
290
|
+
strings,
|
|
291
|
+
mappings,
|
|
292
|
+
locations,
|
|
293
|
+
functions,
|
|
258
294
|
xScale,
|
|
259
295
|
total,
|
|
260
296
|
totalWidth,
|
|
@@ -299,6 +335,10 @@ export function IcicleGraphRootNode({
|
|
|
299
335
|
/>
|
|
300
336
|
<MemoizedIcicleGraphNodes
|
|
301
337
|
data={node.children}
|
|
338
|
+
strings={strings}
|
|
339
|
+
mappings={mappings}
|
|
340
|
+
locations={locations}
|
|
341
|
+
functions={functions}
|
|
302
342
|
x={0}
|
|
303
343
|
y={RowHeight}
|
|
304
344
|
xScale={xScale}
|
|
@@ -359,6 +399,10 @@ export default function IcicleGraph({
|
|
|
359
399
|
y={pos[1]}
|
|
360
400
|
hoveringNode={hoveringNode as HoveringNode}
|
|
361
401
|
contextElement={svg.current}
|
|
402
|
+
strings={graph.stringTable}
|
|
403
|
+
mappings={graph.mapping}
|
|
404
|
+
locations={graph.locations}
|
|
405
|
+
functions={graph.function}
|
|
362
406
|
/>
|
|
363
407
|
<svg
|
|
364
408
|
className="font-robotoMono"
|
|
@@ -371,6 +415,10 @@ export default function IcicleGraph({
|
|
|
371
415
|
<g ref={ref}>
|
|
372
416
|
<MemoizedIcicleGraphRootNode
|
|
373
417
|
node={graph.root}
|
|
418
|
+
strings={graph.stringTable}
|
|
419
|
+
mappings={graph.mapping}
|
|
420
|
+
locations={graph.locations}
|
|
421
|
+
functions={graph.function}
|
|
374
422
|
setHoveringNode={setHoveringNode}
|
|
375
423
|
curPath={curPath}
|
|
376
424
|
setCurPath={setCurPath}
|
|
@@ -41,7 +41,7 @@ export const ProfileViewWithData = ({
|
|
|
41
41
|
isLoading: flamegraphLoading,
|
|
42
42
|
response: flamegraphResponse,
|
|
43
43
|
error: flamegraphError,
|
|
44
|
-
} = useQuery(queryClient, profileSource, QueryRequest_ReportType.
|
|
44
|
+
} = useQuery(queryClient, profileSource, QueryRequest_ReportType.FLAMEGRAPH_TABLE, {
|
|
45
45
|
skip: currentView !== 'icicle' && currentView !== 'both',
|
|
46
46
|
});
|
|
47
47
|
|
package/src/TopTable.tsx
CHANGED
|
@@ -14,7 +14,13 @@
|
|
|
14
14
|
import React from 'react';
|
|
15
15
|
|
|
16
16
|
import {getLastItem, valueFormatter, isSearchMatch} from '@parca/functions';
|
|
17
|
-
import {
|
|
17
|
+
import {
|
|
18
|
+
useAppSelector,
|
|
19
|
+
selectCompareMode,
|
|
20
|
+
selectSearchNodeString,
|
|
21
|
+
setSearchNodeString,
|
|
22
|
+
useAppDispatch,
|
|
23
|
+
} from '@parca/store';
|
|
18
24
|
import {TopNode, TopNodeMeta, Top} from '@parca/client';
|
|
19
25
|
|
|
20
26
|
import {hexifyAddress} from './utils';
|
|
@@ -136,8 +142,8 @@ export const RowLabel = (meta: TopNodeMeta | undefined): string => {
|
|
|
136
142
|
export const TopTable = ({data: top, sampleUnit}: TopTableProps): JSX.Element => {
|
|
137
143
|
const {items, requestSort, sortConfig} = useSortableData(top);
|
|
138
144
|
const currentSearchString = useAppSelector(selectSearchNodeString);
|
|
139
|
-
|
|
140
145
|
const compareMode = useAppSelector(selectCompareMode);
|
|
146
|
+
const dispatch = useAppDispatch();
|
|
141
147
|
|
|
142
148
|
const unit = sampleUnit;
|
|
143
149
|
|
|
@@ -159,10 +165,17 @@ export const TopTable = ({data: top, sampleUnit}: TopTableProps): JSX.Element =>
|
|
|
159
165
|
return `+${num}`;
|
|
160
166
|
};
|
|
161
167
|
|
|
168
|
+
const selectSpan = (span: string): void => {
|
|
169
|
+
dispatch(setSearchNodeString(span.trim()));
|
|
170
|
+
};
|
|
171
|
+
|
|
162
172
|
return (
|
|
163
173
|
<>
|
|
164
174
|
<div className="w-full font-robotoMono">
|
|
165
|
-
<table
|
|
175
|
+
<table
|
|
176
|
+
className="iciclegraph-table table-fixed text-left w-full divide-y divide-gray-200 dark:divide-gray-700"
|
|
177
|
+
tabIndex={1}
|
|
178
|
+
>
|
|
166
179
|
<thead className="bg-gray-50 dark:bg-gray-800">
|
|
167
180
|
<tr>
|
|
168
181
|
<th
|
|
@@ -221,7 +234,7 @@ export const TopTable = ({data: top, sampleUnit}: TopTableProps): JSX.Element =>
|
|
|
221
234
|
return (
|
|
222
235
|
<tr
|
|
223
236
|
key={index}
|
|
224
|
-
className="hover:bg-[#62626212] dark:hover:bg-[#ffffff12]"
|
|
237
|
+
className="hover:bg-[#62626212] dark:hover:bg-[#ffffff12] cursor-pointer"
|
|
225
238
|
style={{
|
|
226
239
|
opacity:
|
|
227
240
|
currentSearchString !== undefined &&
|
|
@@ -230,6 +243,7 @@ export const TopTable = ({data: top, sampleUnit}: TopTableProps): JSX.Element =>
|
|
|
230
243
|
? 0.5
|
|
231
244
|
: 1,
|
|
232
245
|
}}
|
|
246
|
+
onClick={() => selectSpan(name)}
|
|
233
247
|
>
|
|
234
248
|
<td className="text-xs py-1.5 pl-2">{name}</td>
|
|
235
249
|
<td className="text-xs py-1.5 text-right">
|