@parca/profile 0.16.145 → 0.16.146
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 +4 -0
- package/dist/Callgraph/index.js +1 -1
- package/dist/GraphTooltip/index.d.ts +4 -2
- package/dist/GraphTooltip/index.js +7 -4
- package/dist/ProfileIcicleGraph/IcicleGraph/index.d.ts +2 -0
- package/dist/ProfileIcicleGraph/IcicleGraph/index.js +5 -4
- package/dist/ProfileIcicleGraph/index.d.ts +2 -2
- package/dist/ProfileIcicleGraph/index.js +9 -9
- package/dist/ProfileView/index.js +1 -1
- package/package.json +2 -2
- package/src/Callgraph/index.tsx +1 -0
- package/src/GraphTooltip/index.tsx +12 -2
- package/src/ProfileIcicleGraph/IcicleGraph/index.tsx +8 -2
- package/src/ProfileIcicleGraph/index.tsx +14 -13
- package/src/ProfileView/index.tsx +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,10 @@
|
|
|
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.146](https://github.com/parca-dev/parca/compare/@parca/profile@0.16.145...@parca/profile@0.16.146) (2023-03-22)
|
|
7
|
+
|
|
8
|
+
**Note:** Version bump only for package @parca/profile
|
|
9
|
+
|
|
6
10
|
## [0.16.145](https://github.com/parca-dev/parca/compare/@parca/profile@0.16.144...@parca/profile@0.16.145) (2023-03-21)
|
|
7
11
|
|
|
8
12
|
**Note:** Version bump only for package @parca/profile
|
package/dist/Callgraph/index.js
CHANGED
|
@@ -109,6 +109,6 @@ var Callgraph = function (_a) {
|
|
|
109
109
|
var isResetViewButtonEnabled = view.scale !== originalView.scale ||
|
|
110
110
|
view.translation.x !== originalView.translation.x ||
|
|
111
111
|
view.translation.y !== originalView.translation.y;
|
|
112
|
-
return (_jsxs("div", __assign({ className: "w-full relative" }, { children: [_jsxs("div", __assign({ ref: containerRef, className: "w-full overflow-hidden" }, { children: [_jsx(MapInteractionCSS, __assign({ showControls: true, minScale: 1, maxScale: 5, value: view, onChange: function (value) { return setView(value); } }, { children: _jsx(SVG, { ref: svgWrapper, src: svgString, width: width, height: "auto", title: "Callgraph", innerRef: svgRef }) })), svgRef.current !== null && (_jsx(GraphTooltip, { type: "callgraph", unit: sampleUnit, total: parseInt(data.cumulative), contextElement: containerRef.current }))] })), _jsx("div", __assign({ className: cx(dashboardItems.length > 1 ? 'left-[25px]' : 'left-0', 'w-auto absolute top-[-46px]') }, { children: _jsx(Button, __assign({ variant: "neutral", onClick: resetView, className: "z-50", disabled: !isResetViewButtonEnabled }, { children: "Reset View" })) }))] })));
|
|
112
|
+
return (_jsxs("div", __assign({ className: "w-full relative" }, { children: [_jsxs("div", __assign({ ref: containerRef, className: "w-full overflow-hidden" }, { children: [_jsx(MapInteractionCSS, __assign({ showControls: true, minScale: 1, maxScale: 5, value: view, onChange: function (value) { return setView(value); } }, { children: _jsx(SVG, { ref: svgWrapper, src: svgString, width: width, height: "auto", title: "Callgraph", innerRef: svgRef }) })), svgRef.current !== null && (_jsx(GraphTooltip, { type: "callgraph", unit: sampleUnit, total: parseInt(data.cumulative), totalUnfiltered: parseInt(data.cumulative), contextElement: containerRef.current }))] })), _jsx("div", __assign({ className: cx(dashboardItems.length > 1 ? 'left-[25px]' : 'left-0', 'w-auto absolute top-[-46px]') }, { children: _jsx(Button, __assign({ variant: "neutral", onClick: resetView, className: "z-50", disabled: !isResetViewButtonEnabled }, { children: "Reset View" })) }))] })));
|
|
113
113
|
};
|
|
114
114
|
export default Callgraph;
|
|
@@ -14,6 +14,7 @@ interface GraphTooltipProps {
|
|
|
14
14
|
y?: number;
|
|
15
15
|
unit: string;
|
|
16
16
|
total: number;
|
|
17
|
+
totalUnfiltered: number;
|
|
17
18
|
hoveringNode?: HoveringNode;
|
|
18
19
|
contextElement: Element | null;
|
|
19
20
|
isFixed?: boolean;
|
|
@@ -24,10 +25,11 @@ interface GraphTooltipProps {
|
|
|
24
25
|
functions?: ParcaFunction[];
|
|
25
26
|
type?: string;
|
|
26
27
|
}
|
|
27
|
-
export declare const GraphTooltipContent: ({ hoveringNode, unit, total, isFixed, strings, mappings, locations, functions, type, }: {
|
|
28
|
+
export declare const GraphTooltipContent: ({ hoveringNode, unit, total, totalUnfiltered, isFixed, strings, mappings, locations, functions, type, }: {
|
|
28
29
|
hoveringNode: HoveringNode;
|
|
29
30
|
unit: string;
|
|
30
31
|
total: number;
|
|
32
|
+
totalUnfiltered: number;
|
|
31
33
|
isFixed: boolean;
|
|
32
34
|
strings?: string[] | undefined;
|
|
33
35
|
mappings?: Mapping[] | undefined;
|
|
@@ -35,5 +37,5 @@ export declare const GraphTooltipContent: ({ hoveringNode, unit, total, isFixed,
|
|
|
35
37
|
functions?: ParcaFunction[] | undefined;
|
|
36
38
|
type?: string | undefined;
|
|
37
39
|
}) => JSX.Element;
|
|
38
|
-
declare const GraphTooltip: ({ x, y, unit, total, hoveringNode: hoveringNodeProp, contextElement, isFixed, virtualContextElement, strings, mappings, locations, functions, type, }: GraphTooltipProps) => JSX.Element;
|
|
40
|
+
declare const GraphTooltip: ({ x, y, unit, total, totalUnfiltered, hoveringNode: hoveringNodeProp, contextElement, isFixed, virtualContextElement, strings, mappings, locations, functions, type, }: GraphTooltipProps) => JSX.Element;
|
|
39
41
|
export default GraphTooltip;
|
|
@@ -129,7 +129,7 @@ var TooltipMetaInfo = function (_a) {
|
|
|
129
129
|
};
|
|
130
130
|
var timeoutHandle = null;
|
|
131
131
|
export var GraphTooltipContent = function (_a) {
|
|
132
|
-
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, _b = _a.type, type = _b === void 0 ? 'flamegraph' : _b;
|
|
132
|
+
var hoveringNode = _a.hoveringNode, unit = _a.unit, total = _a.total, totalUnfiltered = _a.totalUnfiltered, isFixed = _a.isFixed, strings = _a.strings, mappings = _a.mappings, locations = _a.locations, functions = _a.functions, _b = _a.type, type = _b === void 0 ? 'flamegraph' : _b;
|
|
133
133
|
var _c = useState(false), isCopied = _c[0], setIsCopied = _c[1];
|
|
134
134
|
var onCopy = function () {
|
|
135
135
|
setIsCopied(true);
|
|
@@ -147,14 +147,17 @@ export var GraphTooltipContent = function (_a) {
|
|
|
147
147
|
var diffPercentageText = diffSign + (diffRatio * 100).toFixed(2) + '%';
|
|
148
148
|
var diffText = "".concat(diffValueText, " (").concat(diffPercentageText, ")");
|
|
149
149
|
var getTextForCumulative = function (hoveringNodeCumulative) {
|
|
150
|
-
|
|
150
|
+
var filtered = totalUnfiltered > total
|
|
151
|
+
? " / ".concat(((hoveringNodeCumulative * 100) / total).toFixed(2), "% of filtered")
|
|
152
|
+
: '';
|
|
153
|
+
return "".concat(valueFormatter(hoveringNodeCumulative, unit, 2), "\n (").concat(((hoveringNodeCumulative * 100) / totalUnfiltered).toFixed(2), "%").concat(filtered, ")");
|
|
151
154
|
};
|
|
152
155
|
return (_jsx("div", __assign({ className: "text-sm flex ".concat(isFixed ? 'w-full' : '') }, { children: _jsx("div", __assign({ className: "m-auto w-full ".concat(isFixed ? 'w-full' : '') }, { children: _jsxs("div", __assign({ className: "border border-gray-300 dark:border-gray-500 bg-gray-50 dark:bg-gray-900 rounded-lg p-3 shadow-lg min-h-52 w-[500px] flex justify-between flex-col" }, { children: [_jsx("div", __assign({ className: "flex flex-row" }, { children: _jsxs("div", __assign({ className: "mx-2" }, { children: [_jsx("div", __assign({ className: "font-semibold break-all h-10 flex items-center" }, { children: hoveringNode.meta === undefined ? (_jsx("p", { children: "root" })) : (_jsx(_Fragment, { children: hoveringNode.meta.function !== undefined &&
|
|
153
156
|
hoveringNode.meta.function.name !== '' ? (_jsx(CopyToClipboard, __assign({ onCopy: onCopy, text: hoveringNode.meta.function.name }, { children: _jsx("button", __assign({ className: "cursor-pointer text-left" }, { children: hoveringNode.meta.function.name })) }))) : (_jsx(_Fragment, { children: hoveringNode.meta.location !== undefined &&
|
|
154
157
|
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("table", __assign({ className: "table-fixed pr-0 text-gray-700 dark:text-gray-300 my-2 w-full" }, { children: _jsxs("tbody", { children: [_jsxs("tr", { children: [_jsx("td", __assign({ className: "w-1/4" }, { children: "Cumulative" })), _jsx("td", __assign({ className: "w-3/4" }, { 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/4" }, { children: "Diff" })), _jsx("td", __assign({ className: "w-3/4" }, { children: _jsx(CopyToClipboard, __assign({ onCopy: onCopy, text: diffText }, { children: _jsx("button", __assign({ className: "cursor-pointer" }, { children: diffText })) })) }))] })), _jsx(TooltipMetaInfo, { onCopy: onCopy, hoveringNode: hoveringNode, strings: strings, mappings: mappings, locations: locations, functions: functions, type: type })] }) }))] })) })), _jsx("span", __assign({ className: "block text-gray-500 text-xs mx-2" }, { children: isCopied ? 'Copied!' : 'Hold shift and click on a value to copy.' }))] })) })) })));
|
|
155
158
|
};
|
|
156
159
|
var GraphTooltip = function (_a) {
|
|
157
|
-
var x = _a.x, y = _a.y, unit = _a.unit, total = _a.total, hoveringNodeProp = _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, _d = _a.type, type = _d === void 0 ? 'flamegraph' : _d;
|
|
160
|
+
var x = _a.x, y = _a.y, unit = _a.unit, total = _a.total, totalUnfiltered = _a.totalUnfiltered, hoveringNodeProp = _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, _d = _a.type, type = _d === void 0 ? 'flamegraph' : _d;
|
|
158
161
|
var hoveringNodeState = useAppSelector(selectHoveringNode);
|
|
159
162
|
// @ts-expect-error
|
|
160
163
|
var hoveringNode = useMemo(function () {
|
|
@@ -211,6 +214,6 @@ var GraphTooltip = function (_a) {
|
|
|
211
214
|
}, [contextElement, popperProps, isShiftDown, x, y]);
|
|
212
215
|
if (hoveringNode === undefined || hoveringNode == null)
|
|
213
216
|
return _jsx(_Fragment, {});
|
|
214
|
-
return isFixed ? (_jsx(GraphTooltipContent, { hoveringNode: hoveringNode, unit: unit, total: total, isFixed: isFixed, type: type })) : (_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, type: type }) })));
|
|
217
|
+
return isFixed ? (_jsx(GraphTooltipContent, { hoveringNode: hoveringNode, unit: unit, total: total, totalUnfiltered: totalUnfiltered, isFixed: isFixed, type: type })) : (_jsx("div", __assign({ ref: setPopperElement, style: styles.popper }, attributes.popper, { children: _jsx(GraphTooltipContent, { hoveringNode: hoveringNode, unit: unit, total: total, totalUnfiltered: totalUnfiltered, isFixed: isFixed, strings: strings, mappings: mappings, locations: locations, functions: functions, type: type }) })));
|
|
215
218
|
};
|
|
216
219
|
export default GraphTooltip;
|
|
@@ -32,7 +32,7 @@ import { IcicleNode, RowHeight } from './IcicleGraphNodes';
|
|
|
32
32
|
import useColoredGraph from './useColoredGraph';
|
|
33
33
|
export var IcicleGraph = memo(function IcicleGraph(_a) {
|
|
34
34
|
var _b;
|
|
35
|
-
var graph = _a.graph, width = _a.width, setCurPath = _a.setCurPath, curPath = _a.curPath, sampleUnit = _a.sampleUnit, navigateTo = _a.navigateTo;
|
|
35
|
+
var graph = _a.graph, total = _a.total, filtered = _a.filtered, width = _a.width, setCurPath = _a.setCurPath, curPath = _a.curPath, sampleUnit = _a.sampleUnit, navigateTo = _a.navigateTo;
|
|
36
36
|
var dispatch = useAppDispatch();
|
|
37
37
|
var _c = useState(0), height = _c[0], setHeight = _c[1];
|
|
38
38
|
var svg = useRef(null);
|
|
@@ -45,16 +45,17 @@ export var IcicleGraph = memo(function IcicleGraph(_a) {
|
|
|
45
45
|
setHeight(ref === null || ref === void 0 ? void 0 : ref.current.getBoundingClientRect().height);
|
|
46
46
|
}
|
|
47
47
|
}, [width, coloredGraph]);
|
|
48
|
-
var total = useMemo(function () { return parseFloat(coloredGraph.total); }, [coloredGraph.total]);
|
|
49
48
|
var xScale = useMemo(function () {
|
|
50
49
|
if (width === undefined) {
|
|
51
50
|
return function () { return 0; };
|
|
52
51
|
}
|
|
53
|
-
return scaleLinear()
|
|
52
|
+
return scaleLinear()
|
|
53
|
+
.domain([0, Number(total)])
|
|
54
|
+
.range([0, width]);
|
|
54
55
|
}, [total, width]);
|
|
55
56
|
if (coloredGraph.root === undefined || width === undefined) {
|
|
56
57
|
return _jsx(_Fragment, {});
|
|
57
58
|
}
|
|
58
|
-
return (_jsxs("div", __assign({ onMouseLeave: function () { return dispatch(setHoveringNode(undefined)); } }, { children: [_jsx(ColorStackLegend, { navigateTo: navigateTo, compareMode: compareMode }), _jsx(GraphTooltip, { unit: sampleUnit, total: total, contextElement: svg.current, strings: coloredGraph.stringTable, mappings: coloredGraph.mapping, locations: coloredGraph.locations, functions: coloredGraph.function }), _jsx("svg", __assign({ className: "font-robotoMono", width: width, height: height, preserveAspectRatio: "xMinYMid", ref: svg }, { children: _jsx("g", __assign({ ref: ref }, { children: _jsx("g", __assign({ transform: 'translate(0, 0)' }, { children: _jsx(IcicleNode, { x: 0, y: 0, totalWidth: width, height: RowHeight, setCurPath: setCurPath, curPath: curPath, data: coloredGraph.root, strings: coloredGraph.stringTable, mappings: coloredGraph.mapping, locations: coloredGraph.locations, functions: coloredGraph.function, total: total, xScale: xScale, path: [], level: 0, isRoot: true, searchString: currentSearchString, compareMode: compareMode }) })) })) }))] })));
|
|
59
|
+
return (_jsxs("div", __assign({ onMouseLeave: function () { return dispatch(setHoveringNode(undefined)); } }, { children: [_jsx(ColorStackLegend, { navigateTo: navigateTo, compareMode: compareMode }), _jsx(GraphTooltip, { unit: sampleUnit, total: total, totalUnfiltered: total + filtered, contextElement: svg.current, strings: coloredGraph.stringTable, mappings: coloredGraph.mapping, locations: coloredGraph.locations, functions: coloredGraph.function }), _jsx("svg", __assign({ className: "font-robotoMono", width: width, height: height, preserveAspectRatio: "xMinYMid", ref: svg }, { children: _jsx("g", __assign({ ref: ref }, { children: _jsx("g", __assign({ transform: 'translate(0, 0)' }, { children: _jsx(IcicleNode, { x: 0, y: 0, totalWidth: width, height: RowHeight, setCurPath: setCurPath, curPath: curPath, data: coloredGraph.root, strings: coloredGraph.stringTable, mappings: coloredGraph.mapping, locations: coloredGraph.locations, functions: coloredGraph.function, total: total, xScale: xScale, path: [], level: 0, isRoot: true, searchString: currentSearchString, compareMode: compareMode }) })) })) }))] })));
|
|
59
60
|
});
|
|
60
61
|
export default IcicleGraph;
|
|
@@ -5,8 +5,8 @@ export type ResizeHandler = (width: number, height: number) => void;
|
|
|
5
5
|
interface ProfileIcicleGraphProps {
|
|
6
6
|
width?: number;
|
|
7
7
|
graph: Flamegraph | undefined;
|
|
8
|
-
total:
|
|
9
|
-
filtered:
|
|
8
|
+
total: number;
|
|
9
|
+
filtered: number;
|
|
10
10
|
sampleUnit: string;
|
|
11
11
|
curPath: string[] | [];
|
|
12
12
|
setNewCurPath: (path: string[]) => void;
|
|
@@ -44,20 +44,20 @@ var ProfileIcicleGraph = function (_a) {
|
|
|
44
44
|
if (graph === undefined) {
|
|
45
45
|
return ['0', '0', false, '0', '0', false, '0', '0'];
|
|
46
46
|
}
|
|
47
|
-
var trimmed =
|
|
48
|
-
var
|
|
47
|
+
var trimmed = parseInt(graph.trimmed);
|
|
48
|
+
var totalUnfiltered = total + filtered;
|
|
49
49
|
// safeguard against division by zero
|
|
50
|
-
var
|
|
50
|
+
var totalUnfilteredDivisor = totalUnfiltered > 0 ? totalUnfiltered : 1;
|
|
51
51
|
return [
|
|
52
52
|
numberFormatter.format(total),
|
|
53
|
-
numberFormatter.format(
|
|
53
|
+
numberFormatter.format(totalUnfiltered),
|
|
54
54
|
trimmed > 0,
|
|
55
55
|
numberFormatter.format(trimmed),
|
|
56
|
-
numberFormatter.format((trimmed *
|
|
56
|
+
numberFormatter.format((trimmed * 100) / totalUnfilteredDivisor),
|
|
57
57
|
filtered > 0,
|
|
58
|
-
numberFormatter.format((total *
|
|
58
|
+
numberFormatter.format((total * 100) / totalUnfilteredDivisor),
|
|
59
59
|
];
|
|
60
|
-
}, [
|
|
60
|
+
}, [graph, filtered, total]), totalFormatted = _c[0], totalUnfilteredFormatted = _c[1], isTrimmed = _c[2], trimmedFormatted = _c[3], trimmedPercentage = _c[4], isFiltered = _c[5], filteredPercentage = _c[6];
|
|
61
61
|
useEffect(function () {
|
|
62
62
|
if (setActionButtons === undefined) {
|
|
63
63
|
return;
|
|
@@ -66,11 +66,11 @@ var ProfileIcicleGraph = function (_a) {
|
|
|
66
66
|
}, [setNewCurPath, curPath, setActionButtons]);
|
|
67
67
|
if (graph === undefined)
|
|
68
68
|
return _jsx("div", { children: "no data..." });
|
|
69
|
-
if (total ===
|
|
69
|
+
if (total === 0 && !loading)
|
|
70
70
|
return _jsx(_Fragment, { children: "Profile has no samples" });
|
|
71
71
|
if (isTrimmed) {
|
|
72
72
|
console.info("Trimmed ".concat(trimmedFormatted, " (").concat(trimmedPercentage, "%) too small values."));
|
|
73
73
|
}
|
|
74
|
-
return (_jsxs("div", __assign({ className: "relative" }, { children: [compareMode && _jsx(DiffLegend, {}), _jsx("div", __assign({ ref: ref }, { children: _jsx(IcicleGraph, { width: dimensions === null || dimensions === void 0 ? void 0 : dimensions.width, graph: graph, curPath: curPath, setCurPath: setNewCurPath, sampleUnit: sampleUnit, navigateTo: navigateTo }) })), _jsxs("p", __assign({ className: "my-2 text-xs" }, { children: ["Showing ", totalFormatted, ' ', isFiltered ? (_jsxs("span", { children: ["(", filteredPercentage, "%) filtered of ",
|
|
74
|
+
return (_jsxs("div", __assign({ className: "relative" }, { children: [compareMode && _jsx(DiffLegend, {}), _jsx("div", __assign({ ref: ref }, { children: _jsx(IcicleGraph, { width: dimensions === null || dimensions === void 0 ? void 0 : dimensions.width, graph: graph, total: total, filtered: filtered, curPath: curPath, setCurPath: setNewCurPath, sampleUnit: sampleUnit, navigateTo: navigateTo }) })), _jsxs("p", __assign({ className: "my-2 text-xs" }, { children: ["Showing ", totalFormatted, ' ', isFiltered ? (_jsxs("span", { children: ["(", filteredPercentage, "%) filtered of ", totalUnfilteredFormatted, ' '] })) : (_jsx(_Fragment, {})), "values.", ' '] }))] })));
|
|
75
75
|
};
|
|
76
76
|
export default ProfileIcicleGraph;
|
|
@@ -209,7 +209,7 @@ export var ProfileView = function (_a) {
|
|
|
209
209
|
return (flamegraphData === null || flamegraphData === void 0 ? void 0 : flamegraphData.data) != null ? (_jsx(ConditionalWrapper, __assign({ condition: (perf === null || perf === void 0 ? void 0 : perf.onRender) != null, WrapperComponent: Profiler, wrapperProps: {
|
|
210
210
|
id: 'icicleGraph',
|
|
211
211
|
onRender: perf === null || perf === void 0 ? void 0 : perf.onRender,
|
|
212
|
-
} }, { children: _jsx(ProfileIcicleGraph, { curPath: curPath, setNewCurPath: setNewCurPath, graph: flamegraphData.data, total: (_b = flamegraphData
|
|
212
|
+
} }, { children: _jsx(ProfileIcicleGraph, { curPath: curPath, setNewCurPath: setNewCurPath, graph: flamegraphData.data, total: (_b = Number(flamegraphData.total)) !== null && _b !== void 0 ? _b : 0, filtered: (_c = Number(flamegraphData === null || flamegraphData === void 0 ? void 0 : flamegraphData.filtered)) !== null && _c !== void 0 ? _c : 0, sampleUnit: sampleUnit, onContainerResize: onFlamegraphContainerResize, navigateTo: navigateTo, loading: flamegraphData.loading, setActionButtons: setActionButtons }) }))) : (_jsx(_Fragment, { children: " " }));
|
|
213
213
|
}
|
|
214
214
|
case 'callgraph': {
|
|
215
215
|
return (callgraphData === null || callgraphData === void 0 ? void 0 : callgraphData.data) !== undefined &&
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@parca/profile",
|
|
3
|
-
"version": "0.16.
|
|
3
|
+
"version": "0.16.146",
|
|
4
4
|
"description": "Profile viewing libraries",
|
|
5
5
|
"dependencies": {
|
|
6
6
|
"@parca/client": "^0.16.69",
|
|
@@ -47,5 +47,5 @@
|
|
|
47
47
|
"access": "public",
|
|
48
48
|
"registry": "https://registry.npmjs.org/"
|
|
49
49
|
},
|
|
50
|
-
"gitHead": "
|
|
50
|
+
"gitHead": "2f8627eddd61139ce8af75dc40cf5909397e05f0"
|
|
51
51
|
}
|
package/src/Callgraph/index.tsx
CHANGED
|
@@ -149,6 +149,7 @@ const Callgraph = ({data, svgString, sampleUnit, width}: Props): JSX.Element =>
|
|
|
149
149
|
type="callgraph"
|
|
150
150
|
unit={sampleUnit}
|
|
151
151
|
total={parseInt(data.cumulative)}
|
|
152
|
+
totalUnfiltered={parseInt(data.cumulative)}
|
|
152
153
|
contextElement={containerRef.current}
|
|
153
154
|
/>
|
|
154
155
|
)}
|
|
@@ -55,6 +55,7 @@ interface GraphTooltipProps {
|
|
|
55
55
|
y?: number;
|
|
56
56
|
unit: string;
|
|
57
57
|
total: number;
|
|
58
|
+
totalUnfiltered: number;
|
|
58
59
|
hoveringNode?: HoveringNode;
|
|
59
60
|
contextElement: Element | null;
|
|
60
61
|
isFixed?: boolean;
|
|
@@ -244,6 +245,7 @@ export const GraphTooltipContent = ({
|
|
|
244
245
|
hoveringNode,
|
|
245
246
|
unit,
|
|
246
247
|
total,
|
|
248
|
+
totalUnfiltered,
|
|
247
249
|
isFixed,
|
|
248
250
|
strings,
|
|
249
251
|
mappings,
|
|
@@ -254,6 +256,7 @@ export const GraphTooltipContent = ({
|
|
|
254
256
|
hoveringNode: HoveringNode;
|
|
255
257
|
unit: string;
|
|
256
258
|
total: number;
|
|
259
|
+
totalUnfiltered: number;
|
|
257
260
|
isFixed: boolean;
|
|
258
261
|
strings?: string[];
|
|
259
262
|
mappings?: Mapping[];
|
|
@@ -282,8 +285,12 @@ export const GraphTooltipContent = ({
|
|
|
282
285
|
const diffText = `${diffValueText} (${diffPercentageText})`;
|
|
283
286
|
|
|
284
287
|
const getTextForCumulative = (hoveringNodeCumulative: number): string => {
|
|
285
|
-
|
|
286
|
-
|
|
288
|
+
const filtered =
|
|
289
|
+
totalUnfiltered > total
|
|
290
|
+
? ` / ${((hoveringNodeCumulative * 100) / total).toFixed(2)}% of filtered`
|
|
291
|
+
: '';
|
|
292
|
+
return `${valueFormatter(hoveringNodeCumulative, unit, 2)}
|
|
293
|
+
(${((hoveringNodeCumulative * 100) / totalUnfiltered).toFixed(2)}%${filtered})`;
|
|
287
294
|
};
|
|
288
295
|
|
|
289
296
|
return (
|
|
@@ -377,6 +384,7 @@ const GraphTooltip = ({
|
|
|
377
384
|
y,
|
|
378
385
|
unit,
|
|
379
386
|
total,
|
|
387
|
+
totalUnfiltered,
|
|
380
388
|
hoveringNode: hoveringNodeProp,
|
|
381
389
|
contextElement,
|
|
382
390
|
isFixed = false,
|
|
@@ -468,6 +476,7 @@ const GraphTooltip = ({
|
|
|
468
476
|
hoveringNode={hoveringNode}
|
|
469
477
|
unit={unit}
|
|
470
478
|
total={total}
|
|
479
|
+
totalUnfiltered={totalUnfiltered}
|
|
471
480
|
isFixed={isFixed}
|
|
472
481
|
type={type}
|
|
473
482
|
/>
|
|
@@ -477,6 +486,7 @@ const GraphTooltip = ({
|
|
|
477
486
|
hoveringNode={hoveringNode}
|
|
478
487
|
unit={unit}
|
|
479
488
|
total={total}
|
|
489
|
+
totalUnfiltered={totalUnfiltered}
|
|
480
490
|
isFixed={isFixed}
|
|
481
491
|
strings={strings}
|
|
482
492
|
mappings={mappings}
|
|
@@ -26,6 +26,8 @@ import useColoredGraph from './useColoredGraph';
|
|
|
26
26
|
|
|
27
27
|
interface IcicleGraphProps {
|
|
28
28
|
graph: Flamegraph;
|
|
29
|
+
total: number;
|
|
30
|
+
filtered: number;
|
|
29
31
|
sampleUnit: string;
|
|
30
32
|
width?: number;
|
|
31
33
|
curPath: string[];
|
|
@@ -35,6 +37,8 @@ interface IcicleGraphProps {
|
|
|
35
37
|
|
|
36
38
|
export const IcicleGraph = memo(function IcicleGraph({
|
|
37
39
|
graph,
|
|
40
|
+
total,
|
|
41
|
+
filtered,
|
|
38
42
|
width,
|
|
39
43
|
setCurPath,
|
|
40
44
|
curPath,
|
|
@@ -57,12 +61,13 @@ export const IcicleGraph = memo(function IcicleGraph({
|
|
|
57
61
|
}
|
|
58
62
|
}, [width, coloredGraph]);
|
|
59
63
|
|
|
60
|
-
const total = useMemo(() => parseFloat(coloredGraph.total), [coloredGraph.total]);
|
|
61
64
|
const xScale = useMemo(() => {
|
|
62
65
|
if (width === undefined) {
|
|
63
66
|
return () => 0;
|
|
64
67
|
}
|
|
65
|
-
return scaleLinear()
|
|
68
|
+
return scaleLinear()
|
|
69
|
+
.domain([0, Number(total)])
|
|
70
|
+
.range([0, width]);
|
|
66
71
|
}, [total, width]);
|
|
67
72
|
|
|
68
73
|
if (coloredGraph.root === undefined || width === undefined) {
|
|
@@ -75,6 +80,7 @@ export const IcicleGraph = memo(function IcicleGraph({
|
|
|
75
80
|
<GraphTooltip
|
|
76
81
|
unit={sampleUnit}
|
|
77
82
|
total={total}
|
|
83
|
+
totalUnfiltered={total + filtered}
|
|
78
84
|
contextElement={svg.current}
|
|
79
85
|
strings={coloredGraph.stringTable}
|
|
80
86
|
mappings={coloredGraph.mapping}
|
|
@@ -28,8 +28,8 @@ export type ResizeHandler = (width: number, height: number) => void;
|
|
|
28
28
|
interface ProfileIcicleGraphProps {
|
|
29
29
|
width?: number;
|
|
30
30
|
graph: Flamegraph | undefined;
|
|
31
|
-
total:
|
|
32
|
-
filtered:
|
|
31
|
+
total: number;
|
|
32
|
+
filtered: number;
|
|
33
33
|
sampleUnit: string;
|
|
34
34
|
curPath: string[] | [];
|
|
35
35
|
setNewCurPath: (path: string[]) => void;
|
|
@@ -64,7 +64,7 @@ const ProfileIcicleGraph = ({
|
|
|
64
64
|
|
|
65
65
|
const [
|
|
66
66
|
totalFormatted,
|
|
67
|
-
|
|
67
|
+
totalUnfilteredFormatted,
|
|
68
68
|
isTrimmed,
|
|
69
69
|
trimmedFormatted,
|
|
70
70
|
trimmedPercentage,
|
|
@@ -75,23 +75,22 @@ const ProfileIcicleGraph = ({
|
|
|
75
75
|
return ['0', '0', false, '0', '0', false, '0', '0'];
|
|
76
76
|
}
|
|
77
77
|
|
|
78
|
-
const trimmed =
|
|
79
|
-
|
|
80
|
-
const rawTotal = total + filtered + trimmed;
|
|
78
|
+
const trimmed = parseInt(graph.trimmed);
|
|
81
79
|
|
|
80
|
+
const totalUnfiltered = total + filtered;
|
|
82
81
|
// safeguard against division by zero
|
|
83
|
-
const
|
|
82
|
+
const totalUnfilteredDivisor = totalUnfiltered > 0 ? totalUnfiltered : 1;
|
|
84
83
|
|
|
85
84
|
return [
|
|
86
85
|
numberFormatter.format(total),
|
|
87
|
-
numberFormatter.format(
|
|
86
|
+
numberFormatter.format(totalUnfiltered),
|
|
88
87
|
trimmed > 0,
|
|
89
88
|
numberFormatter.format(trimmed),
|
|
90
|
-
numberFormatter.format((trimmed *
|
|
89
|
+
numberFormatter.format((trimmed * 100) / totalUnfilteredDivisor),
|
|
91
90
|
filtered > 0,
|
|
92
|
-
numberFormatter.format((total *
|
|
91
|
+
numberFormatter.format((total * 100) / totalUnfilteredDivisor),
|
|
93
92
|
];
|
|
94
|
-
}, [
|
|
93
|
+
}, [graph, filtered, total]);
|
|
95
94
|
|
|
96
95
|
useEffect(() => {
|
|
97
96
|
if (setActionButtons === undefined) {
|
|
@@ -114,7 +113,7 @@ const ProfileIcicleGraph = ({
|
|
|
114
113
|
|
|
115
114
|
if (graph === undefined) return <div>no data...</div>;
|
|
116
115
|
|
|
117
|
-
if (total ===
|
|
116
|
+
if (total === 0 && !loading) return <>Profile has no samples</>;
|
|
118
117
|
|
|
119
118
|
if (isTrimmed) {
|
|
120
119
|
console.info(`Trimmed ${trimmedFormatted} (${trimmedPercentage}%) too small values.`);
|
|
@@ -127,6 +126,8 @@ const ProfileIcicleGraph = ({
|
|
|
127
126
|
<IcicleGraph
|
|
128
127
|
width={dimensions?.width}
|
|
129
128
|
graph={graph}
|
|
129
|
+
total={total}
|
|
130
|
+
filtered={filtered}
|
|
130
131
|
curPath={curPath}
|
|
131
132
|
setCurPath={setNewCurPath}
|
|
132
133
|
sampleUnit={sampleUnit}
|
|
@@ -137,7 +138,7 @@ const ProfileIcicleGraph = ({
|
|
|
137
138
|
Showing {totalFormatted}{' '}
|
|
138
139
|
{isFiltered ? (
|
|
139
140
|
<span>
|
|
140
|
-
({filteredPercentage}%) filtered of {
|
|
141
|
+
({filteredPercentage}%) filtered of {totalUnfilteredFormatted}{' '}
|
|
141
142
|
</span>
|
|
142
143
|
) : (
|
|
143
144
|
<></>
|
|
@@ -235,8 +235,8 @@ export const ProfileView = ({
|
|
|
235
235
|
curPath={curPath}
|
|
236
236
|
setNewCurPath={setNewCurPath}
|
|
237
237
|
graph={flamegraphData.data}
|
|
238
|
-
total={flamegraphData
|
|
239
|
-
filtered={flamegraphData?.filtered ??
|
|
238
|
+
total={Number(flamegraphData.total) ?? 0}
|
|
239
|
+
filtered={Number(flamegraphData?.filtered) ?? 0}
|
|
240
240
|
sampleUnit={sampleUnit}
|
|
241
241
|
onContainerResize={onFlamegraphContainerResize}
|
|
242
242
|
navigateTo={navigateTo}
|