@parca/profile 0.16.0 → 0.16.43
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 +52 -25
- package/dist/Callgraph/Edge/index.d.ts +23 -0
- package/dist/Callgraph/Edge/index.js +30 -0
- package/dist/Callgraph/Node/index.d.ts +20 -0
- package/dist/Callgraph/Node/index.js +37 -0
- package/dist/Callgraph/index.d.ts +9 -0
- package/dist/Callgraph/index.js +137 -0
- package/dist/Callgraph/mockData/index.d.ts +148 -0
- package/dist/Callgraph/mockData/index.js +577 -0
- package/dist/Callgraph/utils.d.ts +19 -0
- package/dist/Callgraph/utils.js +82 -0
- package/dist/GraphTooltip/index.d.ts +20 -0
- package/dist/GraphTooltip/index.js +155 -0
- package/dist/IcicleGraph.d.ts +36 -0
- package/dist/IcicleGraph.js +158 -0
- package/dist/MatchersInput/index.d.ts +24 -0
- package/dist/MatchersInput/index.js +479 -0
- package/dist/MetricsCircle/index.d.ts +8 -0
- package/dist/MetricsCircle/index.js +18 -0
- package/dist/MetricsGraph/index.d.ts +36 -0
- package/dist/MetricsGraph/index.js +327 -0
- package/dist/MetricsSeries/index.d.ts +12 -0
- package/dist/MetricsSeries/index.js +21 -0
- package/dist/ProfileExplorer/ProfileExplorerCompare.d.ts +20 -0
- package/dist/ProfileExplorer/ProfileExplorerCompare.js +38 -0
- package/dist/ProfileExplorer/ProfileExplorerSingle.d.ts +16 -0
- package/dist/ProfileExplorer/ProfileExplorerSingle.js +19 -0
- package/dist/ProfileExplorer/index.d.ts +10 -0
- package/dist/ProfileExplorer/index.js +203 -0
- package/dist/ProfileIcicleGraph.d.ts +11 -0
- package/dist/ProfileIcicleGraph.js +28 -0
- package/dist/ProfileMetricsGraph/index.d.ts +23 -0
- package/dist/ProfileMetricsGraph/index.js +127 -0
- package/dist/ProfileSVG.module.css +3 -0
- package/dist/ProfileSelector/CompareButton.d.ts +6 -0
- package/dist/ProfileSelector/CompareButton.js +41 -0
- package/dist/ProfileSelector/MergeButton.d.ts +6 -0
- package/dist/ProfileSelector/MergeButton.js +41 -0
- package/dist/ProfileSelector/index.d.ts +30 -0
- package/dist/ProfileSelector/index.js +133 -0
- package/dist/ProfileSource.d.ts +89 -0
- package/dist/ProfileSource.js +239 -0
- package/dist/ProfileTypeSelector/index.d.ts +21 -0
- package/dist/ProfileTypeSelector/index.js +138 -0
- package/dist/ProfileView.d.ts +40 -0
- package/dist/ProfileView.js +111 -0
- package/dist/ProfileView.styles.css +3 -0
- package/dist/ProfileViewWithData.d.ts +12 -0
- package/dist/ProfileViewWithData.js +116 -0
- package/dist/TopTable.d.ts +10 -0
- package/dist/TopTable.js +140 -0
- package/dist/TopTable.styles.css +7 -0
- package/dist/components/DiffLegend.d.ts +3 -0
- package/dist/components/DiffLegend.js +62 -0
- package/dist/components/ProfileShareButton/ResultBox.d.ts +7 -0
- package/dist/components/ProfileShareButton/ResultBox.js +46 -0
- package/dist/components/ProfileShareButton/index.d.ts +8 -0
- package/dist/components/ProfileShareButton/index.js +119 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.js +64 -0
- package/dist/stories/ProfileTypeSelector.stories.d.ts +5 -0
- package/dist/stories/ProfileTypeSelector.stories.js +77 -0
- package/dist/stories/ProfileView.stories.d.ts +5 -0
- package/dist/stories/ProfileView.stories.js +22 -0
- package/dist/stories/mockdata/flamegraphData.json +7960 -0
- package/dist/styles.css +1 -0
- package/dist/useDelayedLoader.d.ts +5 -0
- package/dist/useDelayedLoader.js +33 -0
- package/dist/useQuery.d.ts +13 -0
- package/dist/useQuery.js +41 -0
- package/dist/utils.d.ts +4 -0
- package/dist/utils.js +83 -0
- package/package.json +13 -8
- package/src/Callgraph/Edge/index.tsx +59 -0
- package/src/Callgraph/Node/index.tsx +66 -0
- package/src/Callgraph/index.tsx +169 -0
- package/src/Callgraph/mockData/index.ts +605 -0
- package/src/Callgraph/utils.ts +116 -0
- package/src/GraphTooltip/index.tsx +340 -0
- package/src/IcicleGraph.tsx +28 -8
- package/src/MatchersInput/index.tsx +698 -0
- package/src/MetricsCircle/index.tsx +28 -0
- package/src/MetricsGraph/index.tsx +589 -0
- package/src/MetricsSeries/index.tsx +38 -0
- package/src/ProfileExplorer/ProfileExplorerCompare.tsx +109 -0
- package/src/ProfileExplorer/ProfileExplorerSingle.tsx +72 -0
- package/src/ProfileExplorer/index.tsx +377 -0
- package/src/ProfileMetricsGraph/index.tsx +143 -0
- package/src/ProfileSelector/CompareButton.tsx +72 -0
- package/src/ProfileSelector/MergeButton.tsx +72 -0
- package/src/ProfileSelector/index.tsx +270 -0
- package/src/ProfileTypeSelector/index.tsx +180 -0
- package/src/ProfileView.tsx +2 -7
- package/src/index.tsx +11 -0
- package/src/useQuery.tsx +1 -0
- package/tailwind.config.js +8 -0
- package/tsconfig.json +7 -3
- package/typings.d.ts +14 -0
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
var __assign = (this && this.__assign) || function () {
|
|
2
|
+
__assign = Object.assign || function(t) {
|
|
3
|
+
for (var s, i = 1, n = arguments.length; i < n; i++) {
|
|
4
|
+
s = arguments[i];
|
|
5
|
+
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
|
|
6
|
+
t[p] = s[p];
|
|
7
|
+
}
|
|
8
|
+
return t;
|
|
9
|
+
};
|
|
10
|
+
return __assign.apply(this, arguments);
|
|
11
|
+
};
|
|
12
|
+
var __rest = (this && this.__rest) || function (s, e) {
|
|
13
|
+
var t = {};
|
|
14
|
+
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
|
|
15
|
+
t[p] = s[p];
|
|
16
|
+
if (s != null && typeof Object.getOwnPropertySymbols === "function")
|
|
17
|
+
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
|
|
18
|
+
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
|
|
19
|
+
t[p[i]] = s[p[i]];
|
|
20
|
+
}
|
|
21
|
+
return t;
|
|
22
|
+
};
|
|
23
|
+
import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
24
|
+
// Copyright 2022 The Parca Authors
|
|
25
|
+
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
26
|
+
// you may not use this file except in compliance with the License.
|
|
27
|
+
// You may obtain a copy of the License at
|
|
28
|
+
//
|
|
29
|
+
// http://www.apache.org/licenses/LICENSE-2.0
|
|
30
|
+
//
|
|
31
|
+
// Unless required by applicable law or agreed to in writing, software
|
|
32
|
+
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
33
|
+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
34
|
+
// See the License for the specific language governing permissions and
|
|
35
|
+
// limitations under the License.
|
|
36
|
+
import { CopyToClipboard } from 'react-copy-to-clipboard';
|
|
37
|
+
import { useState, useEffect } from 'react';
|
|
38
|
+
import { usePopper } from 'react-popper';
|
|
39
|
+
import { getLastItem, valueFormatter } from '@parca/functions';
|
|
40
|
+
import useIsShiftDown from '@parca/components/src/hooks/useIsShiftDown';
|
|
41
|
+
import { hexifyAddress } from '../';
|
|
42
|
+
var virtualElement = {
|
|
43
|
+
getBoundingClientRect: function () {
|
|
44
|
+
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
45
|
+
return ({
|
|
46
|
+
width: 0,
|
|
47
|
+
height: 0,
|
|
48
|
+
top: 0,
|
|
49
|
+
left: 0,
|
|
50
|
+
right: 0,
|
|
51
|
+
bottom: 0,
|
|
52
|
+
});
|
|
53
|
+
},
|
|
54
|
+
};
|
|
55
|
+
function generateGetBoundingClientRect(contextElement, x, y) {
|
|
56
|
+
if (x === void 0) { x = 0; }
|
|
57
|
+
if (y === void 0) { y = 0; }
|
|
58
|
+
var domRect = contextElement.getBoundingClientRect();
|
|
59
|
+
return function () {
|
|
60
|
+
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
61
|
+
return ({
|
|
62
|
+
width: 0,
|
|
63
|
+
height: 0,
|
|
64
|
+
top: domRect.y + y,
|
|
65
|
+
left: domRect.x + x,
|
|
66
|
+
right: domRect.x + x,
|
|
67
|
+
bottom: domRect.y + y,
|
|
68
|
+
});
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
var TooltipMetaInfo = function (_a) {
|
|
72
|
+
var _b, _c, _d, _e;
|
|
73
|
+
var hoveringNode = _a.hoveringNode, onCopy = _a.onCopy;
|
|
74
|
+
if (hoveringNode.meta === undefined)
|
|
75
|
+
return _jsx(_Fragment, {});
|
|
76
|
+
var getTextForFile = function (hoveringNode) {
|
|
77
|
+
var _a, _b, _c, _d;
|
|
78
|
+
if (hoveringNode.meta === undefined)
|
|
79
|
+
return '<unknown>';
|
|
80
|
+
// @ts-expect-error
|
|
81
|
+
return "".concat(hoveringNode.meta.function.filename, " ").concat(((_a = hoveringNode.meta.line) === null || _a === void 0 ? void 0 : _a.line) !== undefined && ((_b = hoveringNode.meta.line) === null || _b === void 0 ? void 0 : _b.line) !== '0'
|
|
82
|
+
? " +".concat(hoveringNode.meta.line.line.toString())
|
|
83
|
+
: "".concat(((_c = hoveringNode.meta.function) === null || _c === void 0 ? void 0 : _c.startLine) !== undefined &&
|
|
84
|
+
((_d = hoveringNode.meta.function) === null || _d === void 0 ? void 0 : _d.startLine) !== '0'
|
|
85
|
+
? " +".concat(hoveringNode.meta.function.startLine)
|
|
86
|
+
: ''));
|
|
87
|
+
};
|
|
88
|
+
return (_jsxs(_Fragment, { children: [((_b = hoveringNode.meta.function) === null || _b === void 0 ? void 0 : _b.filename) !== undefined &&
|
|
89
|
+
((_c = hoveringNode.meta.function) === null || _c === void 0 ? void 0 : _c.filename) !== '' && (_jsxs("tr", { children: [_jsx("td", __assign({ className: "w-1/5" }, { children: "File" })), _jsx("td", __assign({ className: "w-4/5 break-all" }, { children: _jsx(CopyToClipboard, __assign({ onCopy: onCopy, text: getTextForFile(hoveringNode) }, { children: _jsx("button", __assign({ className: "cursor-pointer text-left" }, { children: getTextForFile(hoveringNode) })) })) }))] })), ((_d = hoveringNode.meta.location) === null || _d === void 0 ? void 0 : _d.address) !== undefined &&
|
|
90
|
+
((_e = hoveringNode.meta.location) === null || _e === void 0 ? void 0 : _e.address) !== '0' && (_jsxs("tr", { children: [_jsx("td", __assign({ className: "w-1/5" }, { children: "Address" })), _jsx("td", __assign({ className: "w-4/5 break-all" }, { children: _jsx(CopyToClipboard, __assign({ onCopy: onCopy, text: ' 0x' + hoveringNode.meta.location.address.toString() }, { children: _jsx("button", __assign({ className: "cursor-pointer" }, { children: ' 0x' + hoveringNode.meta.location.address.toString() })) })) }))] })), hoveringNode.meta.mapping !== undefined && hoveringNode.meta.mapping.file !== '' && (_jsxs("tr", { children: [_jsx("td", __assign({ className: "w-1/5" }, { children: "Binary" })), _jsx("td", __assign({ className: "w-4/5 break-all" }, { children: _jsx(CopyToClipboard, __assign({ onCopy: onCopy, text: hoveringNode.meta.mapping.file }, { children: _jsx("button", __assign({ className: "cursor-pointer" }, { children: getLastItem(hoveringNode.meta.mapping.file) })) })) }))] })), hoveringNode.meta.mapping !== undefined && hoveringNode.meta.mapping.buildId !== '' && (_jsxs("tr", { children: [_jsx("td", __assign({ className: "w-1/5" }, { children: "Build Id" })), _jsx("td", __assign({ className: "w-4/5 break-all" }, { children: _jsx(CopyToClipboard, __assign({ onCopy: onCopy, text: hoveringNode.meta.mapping.buildId }, { children: _jsx("button", __assign({ className: "cursor-pointer" }, { children: getLastItem(hoveringNode.meta.mapping.buildId) })) })) }))] }))] }));
|
|
91
|
+
};
|
|
92
|
+
var timeoutHandle = null;
|
|
93
|
+
var GraphTooltipContent = function (_a) {
|
|
94
|
+
var hoveringNode = _a.hoveringNode, unit = _a.unit, total = _a.total, isFixed = _a.isFixed;
|
|
95
|
+
var _b = useState(false), isCopied = _b[0], setIsCopied = _b[1];
|
|
96
|
+
var onCopy = function () {
|
|
97
|
+
setIsCopied(true);
|
|
98
|
+
if (timeoutHandle !== null) {
|
|
99
|
+
clearTimeout(timeoutHandle);
|
|
100
|
+
}
|
|
101
|
+
timeoutHandle = setTimeout(function () { return setIsCopied(false); }, 3000);
|
|
102
|
+
};
|
|
103
|
+
var hoveringNodeCumulative = parseFloat(hoveringNode.cumulative);
|
|
104
|
+
var diff = hoveringNode.diff === undefined ? 0 : parseFloat(hoveringNode.diff);
|
|
105
|
+
var prevValue = hoveringNodeCumulative - diff;
|
|
106
|
+
var diffRatio = Math.abs(diff) > 0 ? diff / prevValue : 0;
|
|
107
|
+
var diffSign = diff > 0 ? '+' : '';
|
|
108
|
+
var diffValueText = diffSign + valueFormatter(diff, unit, 1);
|
|
109
|
+
var diffPercentageText = diffSign + (diffRatio * 100).toFixed(2) + '%';
|
|
110
|
+
var diffText = "".concat(diffValueText, " (").concat(diffPercentageText, ")");
|
|
111
|
+
var metaRows = hoveringNode.meta === undefined ? (_jsx(_Fragment, {})) : (_jsx(TooltipMetaInfo, { onCopy: onCopy, hoveringNode: hoveringNode }));
|
|
112
|
+
var getTextForCumulative = function (hoveringNodeCumulative) {
|
|
113
|
+
return "".concat(valueFormatter(hoveringNodeCumulative, unit, 2), " (\n ").concat(((hoveringNodeCumulative * 100) / total).toFixed(2), "%)");
|
|
114
|
+
};
|
|
115
|
+
return (_jsx("div", __assign({ className: "flex ".concat(isFixed ? 'w-full h-36' : '') }, { children: _jsx("div", __assign({ className: "m-auto w-full ".concat(isFixed ? 'w-full h-36' : '') }, { children: _jsx("div", __assign({ className: "border-gray-300 dark:border-gray-500 bg-gray-50 dark:bg-gray-900 rounded-lg p-3 shadow-lg opacity-90", style: { borderWidth: 1 } }, { children: _jsx("div", __assign({ className: "flex flex-row" }, { children: _jsxs("div", __assign({ className: "ml-2 mr-6" }, { children: [_jsx("span", __assign({ className: "font-semibold break-all" }, { children: hoveringNode.meta === undefined ? (_jsx("p", { children: "root" })) : (_jsx(_Fragment, { children: hoveringNode.meta.function !== undefined &&
|
|
116
|
+
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 &&
|
|
117
|
+
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
|
+
};
|
|
119
|
+
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;
|
|
121
|
+
var _d = useState(null), popperElement = _d[0], setPopperElement = _d[1];
|
|
122
|
+
var _e = usePopper(virtualContextElement ? virtualElement : contextElement, popperElement, {
|
|
123
|
+
placement: 'auto-start',
|
|
124
|
+
strategy: 'absolute',
|
|
125
|
+
modifiers: [
|
|
126
|
+
{
|
|
127
|
+
name: 'preventOverflow',
|
|
128
|
+
options: {
|
|
129
|
+
tether: false,
|
|
130
|
+
altAxis: true,
|
|
131
|
+
},
|
|
132
|
+
},
|
|
133
|
+
{
|
|
134
|
+
name: 'offset',
|
|
135
|
+
options: {
|
|
136
|
+
offset: [30, 30],
|
|
137
|
+
},
|
|
138
|
+
},
|
|
139
|
+
],
|
|
140
|
+
}), styles = _e.styles, attributes = _e.attributes, popperProps = __rest(_e, ["styles", "attributes"]);
|
|
141
|
+
var update = popperProps.update;
|
|
142
|
+
var isShiftDown = useIsShiftDown();
|
|
143
|
+
useEffect(function () {
|
|
144
|
+
if (contextElement != null) {
|
|
145
|
+
if (isShiftDown)
|
|
146
|
+
return;
|
|
147
|
+
virtualElement.getBoundingClientRect = generateGetBoundingClientRect(contextElement, x, y);
|
|
148
|
+
void (update === null || update === void 0 ? void 0 : update());
|
|
149
|
+
}
|
|
150
|
+
}, [x, y, contextElement, update, isShiftDown]);
|
|
151
|
+
if (hoveringNode === undefined || hoveringNode == null)
|
|
152
|
+
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 }) })));
|
|
154
|
+
};
|
|
155
|
+
export default GraphTooltip;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/// <reference types="react" />
|
|
2
|
+
import { Flamegraph, FlamegraphNode, FlamegraphRootNode } from '@parca/client';
|
|
3
|
+
interface IcicleGraphProps {
|
|
4
|
+
graph: Flamegraph;
|
|
5
|
+
sampleUnit: string;
|
|
6
|
+
width?: number;
|
|
7
|
+
curPath: string[];
|
|
8
|
+
setCurPath: (path: string[]) => void;
|
|
9
|
+
}
|
|
10
|
+
interface IcicleGraphNodesProps {
|
|
11
|
+
data: FlamegraphNode[];
|
|
12
|
+
x: number;
|
|
13
|
+
y: number;
|
|
14
|
+
total: number;
|
|
15
|
+
totalWidth: number;
|
|
16
|
+
level: number;
|
|
17
|
+
curPath: string[];
|
|
18
|
+
setCurPath: (path: string[]) => void;
|
|
19
|
+
setHoveringNode: (node: FlamegraphNode | FlamegraphRootNode | undefined) => void;
|
|
20
|
+
path: string[];
|
|
21
|
+
xScale: (value: number) => number;
|
|
22
|
+
}
|
|
23
|
+
interface IcicleGraphRootNodeProps {
|
|
24
|
+
node: FlamegraphRootNode;
|
|
25
|
+
xScale: (value: number) => number;
|
|
26
|
+
total: number;
|
|
27
|
+
totalWidth: number;
|
|
28
|
+
curPath: string[];
|
|
29
|
+
setCurPath: (path: string[]) => void;
|
|
30
|
+
setHoveringNode: (node: FlamegraphNode | FlamegraphRootNode | undefined) => void;
|
|
31
|
+
}
|
|
32
|
+
export declare function nodeLabel(node: FlamegraphNode): string;
|
|
33
|
+
export declare function IcicleGraphNodes({ data, x, y, xScale, total, totalWidth, level, setHoveringNode, path, setCurPath, curPath, }: IcicleGraphNodesProps): JSX.Element;
|
|
34
|
+
export declare function IcicleGraphRootNode({ node, xScale, total, totalWidth, setHoveringNode, setCurPath, curPath, }: IcicleGraphRootNodeProps): JSX.Element;
|
|
35
|
+
export default function IcicleGraph({ graph, width, setCurPath, curPath, sampleUnit, }: IcicleGraphProps): JSX.Element;
|
|
36
|
+
export {};
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
var __assign = (this && this.__assign) || function () {
|
|
2
|
+
__assign = Object.assign || function(t) {
|
|
3
|
+
for (var s, i = 1, n = arguments.length; i < n; i++) {
|
|
4
|
+
s = arguments[i];
|
|
5
|
+
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
|
|
6
|
+
t[p] = s[p];
|
|
7
|
+
}
|
|
8
|
+
return t;
|
|
9
|
+
};
|
|
10
|
+
return __assign.apply(this, arguments);
|
|
11
|
+
};
|
|
12
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
13
|
+
// Copyright 2022 The Parca Authors
|
|
14
|
+
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
15
|
+
// you may not use this file except in compliance with the License.
|
|
16
|
+
// You may obtain a copy of the License at
|
|
17
|
+
//
|
|
18
|
+
// http://www.apache.org/licenses/LICENSE-2.0
|
|
19
|
+
//
|
|
20
|
+
// Unless required by applicable law or agreed to in writing, software
|
|
21
|
+
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
22
|
+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
23
|
+
// See the License for the specific language governing permissions and
|
|
24
|
+
// limitations under the License.
|
|
25
|
+
import React, { useEffect, useRef, useState } from 'react';
|
|
26
|
+
import { throttle } from 'lodash';
|
|
27
|
+
import { pointer } from 'd3-selection';
|
|
28
|
+
import { scaleLinear } from 'd3-scale';
|
|
29
|
+
import GraphTooltip from './GraphTooltip';
|
|
30
|
+
import { getLastItem, diffColor, isSearchMatch } from '@parca/functions';
|
|
31
|
+
import { useAppSelector, selectDarkMode, selectSearchNodeString } from '@parca/store';
|
|
32
|
+
import useIsShiftDown from '@parca/components/src/hooks/useIsShiftDown';
|
|
33
|
+
import { hexifyAddress } from './utils';
|
|
34
|
+
var RowHeight = 26;
|
|
35
|
+
var icicleRectStyles = {
|
|
36
|
+
cursor: 'pointer',
|
|
37
|
+
transition: 'opacity .15s linear',
|
|
38
|
+
};
|
|
39
|
+
var fadedIcicleRectStyles = {
|
|
40
|
+
cursor: 'pointer',
|
|
41
|
+
transition: 'opacity .15s linear',
|
|
42
|
+
opacity: '0.5',
|
|
43
|
+
};
|
|
44
|
+
function IcicleRect(_a) {
|
|
45
|
+
var x = _a.x, y = _a.y, width = _a.width, height = _a.height, color = _a.color, name = _a.name, onMouseEnter = _a.onMouseEnter, onMouseLeave = _a.onMouseLeave, onClick = _a.onClick, curPath = _a.curPath;
|
|
46
|
+
var currentSearchString = useAppSelector(selectSearchNodeString);
|
|
47
|
+
var isFaded = curPath.length > 0 && name !== curPath[curPath.length - 1];
|
|
48
|
+
var styles = isFaded ? fadedIcicleRectStyles : icicleRectStyles;
|
|
49
|
+
return (_jsxs("g", __assign({ transform: "translate(".concat(x + 1, ", ").concat(y + 1, ")"), style: styles, onMouseEnter: onMouseEnter, onMouseLeave: onMouseLeave, onClick: onClick }, { children: [_jsx("rect", { x: 0, y: 0, width: width - 1, height: height - 1, style: {
|
|
50
|
+
opacity: currentSearchString !== undefined &&
|
|
51
|
+
currentSearchString !== '' &&
|
|
52
|
+
!isSearchMatch(currentSearchString, name)
|
|
53
|
+
? 0.5
|
|
54
|
+
: 1,
|
|
55
|
+
fill: color,
|
|
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
|
+
}
|
|
58
|
+
export function nodeLabel(node) {
|
|
59
|
+
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
60
|
+
if (node.meta === undefined)
|
|
61
|
+
return '<unknown>';
|
|
62
|
+
var mapping = "".concat(((_b = (_a = node.meta) === null || _a === void 0 ? void 0 : _a.mapping) === null || _b === void 0 ? void 0 : _b.file) !== undefined && ((_d = (_c = node.meta) === null || _c === void 0 ? void 0 : _c.mapping) === null || _d === void 0 ? void 0 : _d.file) !== ''
|
|
63
|
+
? '[' + ((_e = getLastItem(node.meta.mapping.file)) !== null && _e !== void 0 ? _e : '') + '] '
|
|
64
|
+
: '');
|
|
65
|
+
if (((_f = node.meta.function) === null || _f === void 0 ? void 0 : _f.name) !== undefined && ((_g = node.meta.function) === null || _g === void 0 ? void 0 : _g.name) !== '')
|
|
66
|
+
return mapping + node.meta.function.name;
|
|
67
|
+
var address = hexifyAddress((_h = node.meta.location) === null || _h === void 0 ? void 0 : _h.address);
|
|
68
|
+
var fallback = "".concat(mapping).concat(address);
|
|
69
|
+
return fallback === '' ? '<unknown>' : fallback;
|
|
70
|
+
}
|
|
71
|
+
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;
|
|
73
|
+
var isDarkMode = useAppSelector(selectDarkMode);
|
|
74
|
+
var isShiftDown = useIsShiftDown();
|
|
75
|
+
var nodes = curPath.length === 0 ? data : data.filter(function (d) { return d != null && curPath[0] === nodeLabel(d); });
|
|
76
|
+
var nextLevel = level + 1;
|
|
77
|
+
return (_jsx("g", __assign({ transform: "translate(".concat(x, ", ").concat(y, ")") }, { children: nodes.map(function (d, i) {
|
|
78
|
+
var cumulative = parseFloat(d.cumulative);
|
|
79
|
+
var diff = parseFloat(d.diff);
|
|
80
|
+
var start = nodes.slice(0, i).reduce(function (sum, d) { return sum + parseFloat(d.cumulative); }, 0);
|
|
81
|
+
var nextCurPath = curPath.length === 0 ? [] : curPath.slice(1);
|
|
82
|
+
var width = nextCurPath.length > 0 || (nextCurPath.length === 0 && curPath.length === 1)
|
|
83
|
+
? totalWidth
|
|
84
|
+
: xScale(cumulative);
|
|
85
|
+
if (width <= 1) {
|
|
86
|
+
return null;
|
|
87
|
+
}
|
|
88
|
+
var name = nodeLabel(d);
|
|
89
|
+
var key = "".concat(level, "-").concat(i);
|
|
90
|
+
var nextPath = path.concat([name]);
|
|
91
|
+
var color = diffColor(diff, cumulative, isDarkMode);
|
|
92
|
+
var onClick = function () {
|
|
93
|
+
setCurPath(nextPath);
|
|
94
|
+
};
|
|
95
|
+
var xStart = xScale(start);
|
|
96
|
+
var newXScale = nextCurPath.length === 0 && curPath.length === 1
|
|
97
|
+
? scaleLinear().domain([0, cumulative]).range([0, totalWidth])
|
|
98
|
+
: xScale;
|
|
99
|
+
var onMouseEnter = function () {
|
|
100
|
+
if (isShiftDown)
|
|
101
|
+
return;
|
|
102
|
+
setHoveringNode(d);
|
|
103
|
+
};
|
|
104
|
+
var onMouseLeave = function () {
|
|
105
|
+
if (isShiftDown)
|
|
106
|
+
return;
|
|
107
|
+
setHoveringNode(undefined);
|
|
108
|
+
};
|
|
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)));
|
|
110
|
+
}) })));
|
|
111
|
+
}
|
|
112
|
+
var MemoizedIcicleGraphNodes = React.memo(IcicleGraphNodes);
|
|
113
|
+
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;
|
|
115
|
+
var isDarkMode = useAppSelector(selectDarkMode);
|
|
116
|
+
var isShiftDown = useIsShiftDown();
|
|
117
|
+
var cumulative = parseFloat(node.cumulative);
|
|
118
|
+
var diff = parseFloat(node.diff);
|
|
119
|
+
var color = diffColor(diff, cumulative, isDarkMode);
|
|
120
|
+
var onClick = function () { return setCurPath([]); };
|
|
121
|
+
var onMouseEnter = function () {
|
|
122
|
+
if (isShiftDown)
|
|
123
|
+
return;
|
|
124
|
+
setHoveringNode(node);
|
|
125
|
+
};
|
|
126
|
+
var onMouseLeave = function () {
|
|
127
|
+
if (isShiftDown)
|
|
128
|
+
return;
|
|
129
|
+
setHoveringNode(undefined);
|
|
130
|
+
};
|
|
131
|
+
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 })] })));
|
|
133
|
+
}
|
|
134
|
+
var MemoizedIcicleGraphRootNode = React.memo(IcicleGraphRootNode);
|
|
135
|
+
export default function IcicleGraph(_a) {
|
|
136
|
+
var graph = _a.graph, width = _a.width, setCurPath = _a.setCurPath, curPath = _a.curPath, sampleUnit = _a.sampleUnit;
|
|
137
|
+
var _b = useState(), hoveringNode = _b[0], setHoveringNode = _b[1];
|
|
138
|
+
var _c = useState([0, 0]), pos = _c[0], setPos = _c[1];
|
|
139
|
+
var _d = useState(0), height = _d[0], setHeight = _d[1];
|
|
140
|
+
var svg = useRef(null);
|
|
141
|
+
var ref = useRef(null);
|
|
142
|
+
useEffect(function () {
|
|
143
|
+
if (ref.current != null) {
|
|
144
|
+
setHeight(ref === null || ref === void 0 ? void 0 : ref.current.getBoundingClientRect().height);
|
|
145
|
+
}
|
|
146
|
+
}, [width]);
|
|
147
|
+
if (graph.root === undefined || width === undefined)
|
|
148
|
+
return _jsx(_Fragment, {});
|
|
149
|
+
var throttledSetPos = throttle(setPos, 20);
|
|
150
|
+
var onMouseMove = function (e) {
|
|
151
|
+
// X/Y coordinate array relative to svg
|
|
152
|
+
var rel = pointer(e);
|
|
153
|
+
throttledSetPos([rel[0], rel[1]]);
|
|
154
|
+
};
|
|
155
|
+
var total = parseFloat(graph.total);
|
|
156
|
+
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 }) })) }))] })));
|
|
158
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/// <reference types="react" />
|
|
2
|
+
import { Query } from '@parca/parser';
|
|
3
|
+
import { LabelsResponse, QueryServiceClient, ValuesResponse } from '@parca/client';
|
|
4
|
+
interface MatchersInputProps {
|
|
5
|
+
queryClient: QueryServiceClient;
|
|
6
|
+
setMatchersString: (arg: string) => void;
|
|
7
|
+
runQuery: () => void;
|
|
8
|
+
currentQuery: Query;
|
|
9
|
+
}
|
|
10
|
+
export interface ILabelNamesResult {
|
|
11
|
+
response?: LabelsResponse;
|
|
12
|
+
error?: Error;
|
|
13
|
+
}
|
|
14
|
+
export interface ILabelValuesResult {
|
|
15
|
+
response?: ValuesResponse;
|
|
16
|
+
error?: Error;
|
|
17
|
+
}
|
|
18
|
+
interface UseLabelNames {
|
|
19
|
+
result: ILabelNamesResult;
|
|
20
|
+
loading: boolean;
|
|
21
|
+
}
|
|
22
|
+
export declare const useLabelNames: (client: QueryServiceClient) => UseLabelNames;
|
|
23
|
+
declare const MatchersInput: ({ queryClient, setMatchersString, runQuery, currentQuery, }: MatchersInputProps) => JSX.Element;
|
|
24
|
+
export default MatchersInput;
|