@parca/profile 0.16.144 → 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 +8 -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 +12 -10
- package/dist/ProfileView/index.js +1 -1
- package/package.json +8 -8
- 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 +20 -24
- package/src/ProfileView/index.tsx +2 -2
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.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
|
+
|
|
10
|
+
## [0.16.145](https://github.com/parca-dev/parca/compare/@parca/profile@0.16.144...@parca/profile@0.16.145) (2023-03-21)
|
|
11
|
+
|
|
12
|
+
**Note:** Version bump only for package @parca/profile
|
|
13
|
+
|
|
6
14
|
## [0.16.144](https://github.com/parca-dev/parca/compare/@parca/profile@0.16.143...@parca/profile@0.16.144) (2023-03-21)
|
|
7
15
|
|
|
8
16
|
# 0.16.0 (2023-03-01)
|
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,21 +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(
|
|
59
|
-
numberFormatter.format((filtered * BigInt(100)) / rawTotalDivisor),
|
|
58
|
+
numberFormatter.format((total * 100) / totalUnfilteredDivisor),
|
|
60
59
|
];
|
|
61
|
-
}, [
|
|
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];
|
|
62
61
|
useEffect(function () {
|
|
63
62
|
if (setActionButtons === undefined) {
|
|
64
63
|
return;
|
|
@@ -67,8 +66,11 @@ var ProfileIcicleGraph = function (_a) {
|
|
|
67
66
|
}, [setNewCurPath, curPath, setActionButtons]);
|
|
68
67
|
if (graph === undefined)
|
|
69
68
|
return _jsx("div", { children: "no data..." });
|
|
70
|
-
if (total ===
|
|
69
|
+
if (total === 0 && !loading)
|
|
71
70
|
return _jsx(_Fragment, { children: "Profile has no samples" });
|
|
72
|
-
|
|
71
|
+
if (isTrimmed) {
|
|
72
|
+
console.info("Trimmed ".concat(trimmedFormatted, " (").concat(trimmedPercentage, "%) too small values."));
|
|
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, 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.", ' '] }))] })));
|
|
73
75
|
};
|
|
74
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,16 +1,16 @@
|
|
|
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
|
-
"@parca/client": "^0.16.
|
|
7
|
-
"@parca/components": "^0.16.
|
|
6
|
+
"@parca/client": "^0.16.69",
|
|
7
|
+
"@parca/components": "^0.16.119",
|
|
8
8
|
"@parca/dynamicsize": "^0.16.54",
|
|
9
|
-
"@parca/functions": "^0.16.
|
|
10
|
-
"@parca/hooks": "^0.0.
|
|
9
|
+
"@parca/functions": "^0.16.70",
|
|
10
|
+
"@parca/hooks": "^0.0.3",
|
|
11
11
|
"@parca/parser": "^0.16.55",
|
|
12
|
-
"@parca/store": "^0.16.
|
|
13
|
-
"@parca/utilities": "^0.0.
|
|
12
|
+
"@parca/store": "^0.16.69",
|
|
13
|
+
"@parca/utilities": "^0.0.3",
|
|
14
14
|
"@types/react-beautiful-dnd": "^13.1.3",
|
|
15
15
|
"d3": "7.8.2",
|
|
16
16
|
"d3-scale": "^4.0.2",
|
|
@@ -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,36 +64,33 @@ const ProfileIcicleGraph = ({
|
|
|
64
64
|
|
|
65
65
|
const [
|
|
66
66
|
totalFormatted,
|
|
67
|
-
|
|
67
|
+
totalUnfilteredFormatted,
|
|
68
68
|
isTrimmed,
|
|
69
69
|
trimmedFormatted,
|
|
70
70
|
trimmedPercentage,
|
|
71
71
|
isFiltered,
|
|
72
|
-
filteredFormatted,
|
|
73
72
|
filteredPercentage,
|
|
74
73
|
] = useMemo(() => {
|
|
75
74
|
if (graph === undefined) {
|
|
76
75
|
return ['0', '0', false, '0', '0', false, '0', '0'];
|
|
77
76
|
}
|
|
78
77
|
|
|
79
|
-
const trimmed =
|
|
80
|
-
|
|
81
|
-
const rawTotal = total + filtered + trimmed;
|
|
78
|
+
const trimmed = parseInt(graph.trimmed);
|
|
82
79
|
|
|
80
|
+
const totalUnfiltered = total + filtered;
|
|
83
81
|
// safeguard against division by zero
|
|
84
|
-
const
|
|
82
|
+
const totalUnfilteredDivisor = totalUnfiltered > 0 ? totalUnfiltered : 1;
|
|
85
83
|
|
|
86
84
|
return [
|
|
87
85
|
numberFormatter.format(total),
|
|
88
|
-
numberFormatter.format(
|
|
86
|
+
numberFormatter.format(totalUnfiltered),
|
|
89
87
|
trimmed > 0,
|
|
90
88
|
numberFormatter.format(trimmed),
|
|
91
|
-
numberFormatter.format((trimmed *
|
|
89
|
+
numberFormatter.format((trimmed * 100) / totalUnfilteredDivisor),
|
|
92
90
|
filtered > 0,
|
|
93
|
-
numberFormatter.format(
|
|
94
|
-
numberFormatter.format((filtered * BigInt(100)) / rawTotalDivisor),
|
|
91
|
+
numberFormatter.format((total * 100) / totalUnfilteredDivisor),
|
|
95
92
|
];
|
|
96
|
-
}, [
|
|
93
|
+
}, [graph, filtered, total]);
|
|
97
94
|
|
|
98
95
|
useEffect(() => {
|
|
99
96
|
if (setActionButtons === undefined) {
|
|
@@ -116,7 +113,11 @@ const ProfileIcicleGraph = ({
|
|
|
116
113
|
|
|
117
114
|
if (graph === undefined) return <div>no data...</div>;
|
|
118
115
|
|
|
119
|
-
if (total ===
|
|
116
|
+
if (total === 0 && !loading) return <>Profile has no samples</>;
|
|
117
|
+
|
|
118
|
+
if (isTrimmed) {
|
|
119
|
+
console.info(`Trimmed ${trimmedFormatted} (${trimmedPercentage}%) too small values.`);
|
|
120
|
+
}
|
|
120
121
|
|
|
121
122
|
return (
|
|
122
123
|
<div className="relative">
|
|
@@ -125,6 +126,8 @@ const ProfileIcicleGraph = ({
|
|
|
125
126
|
<IcicleGraph
|
|
126
127
|
width={dimensions?.width}
|
|
127
128
|
graph={graph}
|
|
129
|
+
total={total}
|
|
130
|
+
filtered={filtered}
|
|
128
131
|
curPath={curPath}
|
|
129
132
|
setCurPath={setNewCurPath}
|
|
130
133
|
sampleUnit={sampleUnit}
|
|
@@ -132,22 +135,15 @@ const ProfileIcicleGraph = ({
|
|
|
132
135
|
/>
|
|
133
136
|
</div>
|
|
134
137
|
<p className="my-2 text-xs">
|
|
135
|
-
Showing {totalFormatted}
|
|
136
|
-
samples.{' '}
|
|
138
|
+
Showing {totalFormatted}{' '}
|
|
137
139
|
{isFiltered ? (
|
|
138
140
|
<span>
|
|
139
|
-
|
|
140
|
-
</span>
|
|
141
|
-
) : (
|
|
142
|
-
<></>
|
|
143
|
-
)}
|
|
144
|
-
{isTrimmed ? (
|
|
145
|
-
<span>
|
|
146
|
-
Trimmed {trimmedFormatted} ({trimmedPercentage}%) too small samples.
|
|
141
|
+
({filteredPercentage}%) filtered of {totalUnfilteredFormatted}{' '}
|
|
147
142
|
</span>
|
|
148
143
|
) : (
|
|
149
144
|
<></>
|
|
150
145
|
)}
|
|
146
|
+
values.{' '}
|
|
151
147
|
</p>
|
|
152
148
|
</div>
|
|
153
149
|
);
|
|
@@ -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}
|