@parca/profile 0.16.360 → 0.16.362
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.d.ts +3 -2
- package/dist/Callgraph/index.js +2 -2
- package/dist/GraphTooltipArrow/Content.d.ts +3 -2
- package/dist/GraphTooltipArrow/Content.js +4 -4
- package/dist/GraphTooltipArrow/DockedGraphTooltip/index.d.ts +3 -2
- package/dist/GraphTooltipArrow/DockedGraphTooltip/index.js +2 -2
- package/dist/GraphTooltipArrow/useGraphTooltip/index.d.ts +4 -2
- package/dist/GraphTooltipArrow/useGraphTooltip/index.js +29 -11
- package/dist/ProfileIcicleGraph/IcicleGraph/index.d.ts +2 -1
- package/dist/ProfileIcicleGraph/IcicleGraph/index.js +2 -2
- package/dist/ProfileIcicleGraph/IcicleGraphArrow/ContextMenu.d.ts +3 -2
- package/dist/ProfileIcicleGraph/IcicleGraphArrow/ContextMenu.js +2 -2
- package/dist/ProfileIcicleGraph/IcicleGraphArrow/IcicleGraphNodes.d.ts +3 -0
- package/dist/ProfileIcicleGraph/IcicleGraphArrow/IcicleGraphNodes.js +62 -9
- package/dist/ProfileIcicleGraph/IcicleGraphArrow/index.d.ts +4 -1
- package/dist/ProfileIcicleGraph/IcicleGraphArrow/index.js +6 -3
- package/dist/ProfileIcicleGraph/IcicleGraphArrow/useNodeColor.d.ts +3 -1
- package/dist/ProfileIcicleGraph/IcicleGraphArrow/useNodeColor.js +5 -2
- package/dist/ProfileIcicleGraph/IcicleGraphArrow/utils.d.ts +1 -0
- package/dist/ProfileIcicleGraph/IcicleGraphArrow/utils.js +3 -0
- package/dist/ProfileIcicleGraph/index.d.ts +3 -2
- package/dist/ProfileIcicleGraph/index.js +2 -2
- package/dist/ProfileView/ProfileViewContext.d.ts +0 -1
- package/dist/ProfileView/ProfileViewContext.js +0 -1
- package/dist/ProfileView/index.d.ts +1 -2
- package/dist/ProfileView/index.js +5 -5
- package/dist/ProfileViewWithData.js +1 -13
- package/dist/SourceView/Highlighter.js +2 -2
- package/dist/Table/index.d.ts +2 -1
- package/dist/Table/index.js +6 -6
- package/package.json +6 -6
- package/src/Callgraph/index.tsx +4 -3
- package/src/GraphTooltipArrow/Content.tsx +23 -4
- package/src/GraphTooltipArrow/DockedGraphTooltip/index.tsx +4 -3
- package/src/GraphTooltipArrow/useGraphTooltip/index.ts +46 -11
- package/src/ProfileIcicleGraph/IcicleGraph/index.tsx +4 -3
- package/src/ProfileIcicleGraph/IcicleGraphArrow/ContextMenu.tsx +4 -3
- package/src/ProfileIcicleGraph/IcicleGraphArrow/IcicleGraphNodes.tsx +75 -4
- package/src/ProfileIcicleGraph/IcicleGraphArrow/index.tsx +10 -5
- package/src/ProfileIcicleGraph/IcicleGraphArrow/useNodeColor.ts +9 -1
- package/src/ProfileIcicleGraph/IcicleGraphArrow/utils.ts +11 -0
- package/src/ProfileIcicleGraph/index.tsx +5 -4
- package/src/ProfileView/ProfileViewContext.tsx +0 -2
- package/src/ProfileView/index.tsx +4 -6
- package/src/ProfileViewWithData.tsx +0 -14
- package/src/SourceView/Highlighter.tsx +7 -2
- package/src/Table/index.tsx +10 -7
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.362](https://github.com/parca-dev/parca/compare/@parca/profile@0.16.361...@parca/profile@0.16.362) (2024-04-29)
|
|
7
|
+
|
|
8
|
+
**Note:** Version bump only for package @parca/profile
|
|
9
|
+
|
|
10
|
+
## [0.16.361](https://github.com/parca-dev/parca/compare/@parca/profile@0.16.360...@parca/profile@0.16.361) (2024-04-26)
|
|
11
|
+
|
|
12
|
+
**Note:** Version bump only for package @parca/profile
|
|
13
|
+
|
|
6
14
|
## 0.16.360 (2024-04-25)
|
|
7
15
|
|
|
8
16
|
**Note:** Version bump only for package @parca/profile
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
/// <reference types="react" />
|
|
2
2
|
import { Callgraph as CallgraphType } from '@parca/client';
|
|
3
|
+
import { ProfileType } from '@parca/parser';
|
|
3
4
|
export interface Props {
|
|
4
5
|
data: CallgraphType;
|
|
5
6
|
svgString: string;
|
|
6
|
-
|
|
7
|
+
profileType: ProfileType | undefined;
|
|
7
8
|
width: number;
|
|
8
9
|
}
|
|
9
|
-
declare const Callgraph: ({ data, svgString,
|
|
10
|
+
declare const Callgraph: ({ data, svgString, profileType, width }: Props) => JSX.Element;
|
|
10
11
|
export default Callgraph;
|
package/dist/Callgraph/index.js
CHANGED
|
@@ -20,7 +20,7 @@ import { Button, useKeyDown, useURLState } from '@parca/components';
|
|
|
20
20
|
import { selectDarkMode, setHoveringNode, useAppDispatch, useAppSelector } from '@parca/store';
|
|
21
21
|
import { getNewSpanColor } from '@parca/utilities';
|
|
22
22
|
import GraphTooltip from '../GraphTooltip';
|
|
23
|
-
const Callgraph = ({ data, svgString,
|
|
23
|
+
const Callgraph = ({ data, svgString, profileType, width }) => {
|
|
24
24
|
const originalView = {
|
|
25
25
|
scale: 1,
|
|
26
26
|
translation: { x: 0, y: 0 },
|
|
@@ -98,6 +98,6 @@ const Callgraph = ({ data, svgString, sampleUnit, width }) => {
|
|
|
98
98
|
const isResetViewButtonEnabled = view.scale !== originalView.scale ||
|
|
99
99
|
view.translation.x !== originalView.translation.x ||
|
|
100
100
|
view.translation.y !== originalView.translation.y;
|
|
101
|
-
return (_jsxs("div", { className: "relative w-full", children: [_jsxs("div", { ref: containerRef, className: "w-full overflow-hidden", children: [_jsx(MapInteractionCSS, { showControls: true, minScale: 1, maxScale: 5, value: view, onChange: (value) => 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: data.cumulative, totalUnfiltered: data.cumulative, contextElement: containerRef.current }))] }), _jsx("div", { className: cx(dashboardItems.length > 1 ? 'left-[25px]' : 'left-0', 'absolute top-[-46px] w-auto'), children: _jsx(Button, { variant: "neutral", onClick: resetView, className: "z-50", disabled: !isResetViewButtonEnabled, children: "Reset View" }) })] }));
|
|
101
|
+
return (_jsxs("div", { className: "relative w-full", children: [_jsxs("div", { ref: containerRef, className: "w-full overflow-hidden", children: [_jsx(MapInteractionCSS, { showControls: true, minScale: 1, maxScale: 5, value: view, onChange: (value) => 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: profileType?.sampleUnit ?? '', total: data.cumulative, totalUnfiltered: data.cumulative, contextElement: containerRef.current }))] }), _jsx("div", { className: cx(dashboardItems.length > 1 ? 'left-[25px]' : 'left-0', 'absolute top-[-46px] w-auto'), children: _jsx(Button, { variant: "neutral", onClick: resetView, className: "z-50", disabled: !isResetViewButtonEnabled, children: "Reset View" }) })] }));
|
|
102
102
|
};
|
|
103
103
|
export default Callgraph;
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import { Table } from 'apache-arrow';
|
|
3
|
+
import { ProfileType } from '@parca/parser';
|
|
3
4
|
import { type NavigateFunction } from '@parca/utilities';
|
|
4
5
|
interface GraphTooltipArrowContentProps {
|
|
5
6
|
table: Table<any>;
|
|
6
|
-
|
|
7
|
+
profileType?: ProfileType;
|
|
7
8
|
total: bigint;
|
|
8
9
|
totalUnfiltered: bigint;
|
|
9
10
|
row: number | null;
|
|
@@ -11,5 +12,5 @@ interface GraphTooltipArrowContentProps {
|
|
|
11
12
|
isFixed: boolean;
|
|
12
13
|
navigateTo: NavigateFunction;
|
|
13
14
|
}
|
|
14
|
-
declare const GraphTooltipArrowContent: ({ table,
|
|
15
|
+
declare const GraphTooltipArrowContent: ({ table, profileType, total, totalUnfiltered, row, level, isFixed, navigateTo, }: GraphTooltipArrowContentProps) => React.JSX.Element;
|
|
15
16
|
export default GraphTooltipArrowContent;
|
|
@@ -8,10 +8,10 @@ import { useGraphTooltipMetaInfo } from './useGraphTooltipMetaInfo';
|
|
|
8
8
|
const NoData = () => {
|
|
9
9
|
return _jsx("span", { className: "rounded bg-gray-200 px-2 dark:bg-gray-800", children: "Not available" });
|
|
10
10
|
};
|
|
11
|
-
const GraphTooltipArrowContent = ({ table,
|
|
11
|
+
const GraphTooltipArrowContent = ({ table, profileType, total, totalUnfiltered, row, level, isFixed, navigateTo, }) => {
|
|
12
12
|
const graphTooltipData = useGraphTooltip({
|
|
13
13
|
table,
|
|
14
|
-
|
|
14
|
+
profileType,
|
|
15
15
|
total,
|
|
16
16
|
totalUnfiltered,
|
|
17
17
|
row,
|
|
@@ -20,12 +20,12 @@ const GraphTooltipArrowContent = ({ table, unit, total, totalUnfiltered, row, le
|
|
|
20
20
|
if (graphTooltipData === null) {
|
|
21
21
|
return _jsx(_Fragment, {});
|
|
22
22
|
}
|
|
23
|
-
const { name, locationAddress, cumulativeText, diffText, diff, row: rowNumber } = graphTooltipData;
|
|
23
|
+
const { name, locationAddress, cumulativeText, cumulativePerSecondText, diffText, diff, row: rowNumber, } = graphTooltipData;
|
|
24
24
|
return (_jsx("div", { className: `flex text-sm ${isFixed ? 'w-full' : ''}`, children: _jsx("div", { className: `m-auto w-full ${isFixed ? 'w-full' : ''}`, children: _jsxs("div", { className: "min-h-52 flex w-[500px] flex-col justify-between rounded-lg border border-gray-300 bg-gray-50 p-3 shadow-lg dark:border-gray-500 dark:bg-gray-900", children: [_jsx("div", { className: "flex flex-row", children: _jsxs("div", { className: "mx-2", children: [_jsx("div", { className: "flex h-10 items-start justify-between gap-4 break-all font-semibold", children: row === 0 ? (_jsx("p", { children: "root" })) : (_jsx("p", { children: name !== ''
|
|
25
25
|
? name
|
|
26
26
|
: locationAddress !== 0n
|
|
27
27
|
? hexifyAddress(locationAddress)
|
|
28
|
-
: 'unknown' })) }), _jsx("table", { className: "my-2 w-full table-fixed pr-0 text-gray-700 dark:text-gray-300", children: _jsxs("tbody", { children: [_jsxs("tr", { children: [_jsx("td", { className: "w-1/4", children: "Cumulative" }), _jsx("td", { className: "w-3/4", children: _jsx("div", { children: cumulativeText }) })] }), diff !== 0n && (_jsxs("tr", { children: [_jsx("td", { className: "w-1/4", children: "Diff" }), _jsx("td", { className: "w-3/4", children: _jsx("div", { children: diffText }) })] })), _jsx(TooltipMetaInfo, { table: table, row: rowNumber, navigateTo: navigateTo })] }) })] }) }), _jsxs("div", { className: "flex w-full items-center gap-1 text-xs text-gray-500", children: [_jsx(Icon, { icon: "iconoir:mouse-button-right" }), _jsx("div", { children: "Right click to show context menu" })] })] }) }) }));
|
|
28
|
+
: 'unknown' })) }), _jsx("table", { className: "my-2 w-full table-fixed pr-0 text-gray-700 dark:text-gray-300", children: _jsxs("tbody", { children: [(profileType?.delta ?? false) ? (_jsxs("tr", { children: [_jsx("td", { className: "w-1/4", children: "Per Second" }), _jsx("td", { className: "w-3/4", children: _jsx("div", { children: cumulativePerSecondText }) })] })) : (_jsx(_Fragment, {})), _jsxs("tr", { children: [_jsx("td", { className: "w-1/4", children: "Cumulative" }), _jsx("td", { className: "w-3/4", children: _jsx("div", { children: cumulativeText }) })] }), diff !== 0n && (_jsxs("tr", { children: [_jsx("td", { className: "w-1/4", children: "Diff" }), _jsx("td", { className: "w-3/4", children: _jsx("div", { children: diffText }) })] })), _jsx(TooltipMetaInfo, { table: table, row: rowNumber, navigateTo: navigateTo })] }) })] }) }), _jsxs("div", { className: "flex w-full items-center gap-1 text-xs text-gray-500", children: [_jsx(Icon, { icon: "iconoir:mouse-button-right" }), _jsx("div", { children: "Right click to show context menu" })] })] }) }) }));
|
|
29
29
|
};
|
|
30
30
|
const TooltipMetaInfo = ({ table, row, navigateTo, }) => {
|
|
31
31
|
const { labelPairs, functionFilename, file, locationAddress, mappingFile, mappingBuildID, inlined, } = useGraphTooltipMetaInfo({ table, row, navigateTo });
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
/// <reference types="react" />
|
|
2
2
|
import { Table } from 'apache-arrow';
|
|
3
|
+
import { ProfileType } from '@parca/parser';
|
|
3
4
|
interface Props {
|
|
4
5
|
table: Table<any>;
|
|
5
|
-
unit: string;
|
|
6
6
|
total: bigint;
|
|
7
7
|
totalUnfiltered: bigint;
|
|
8
8
|
row: number | null;
|
|
9
9
|
level: number;
|
|
10
|
+
profileType?: ProfileType;
|
|
10
11
|
}
|
|
11
|
-
export declare const DockedGraphTooltip: ({ table,
|
|
12
|
+
export declare const DockedGraphTooltip: ({ table, total, totalUnfiltered, row, level, profileType, }: Props) => JSX.Element;
|
|
12
13
|
export {};
|
|
@@ -25,14 +25,14 @@ const InfoSection = ({ title, value, minWidth = '', }) => {
|
|
|
25
25
|
const NoData = () => {
|
|
26
26
|
return _jsx("span", { className: "rounded bg-gray-200 px-2 dark:bg-gray-800", children: "Not available" });
|
|
27
27
|
};
|
|
28
|
-
export const DockedGraphTooltip = ({ table,
|
|
28
|
+
export const DockedGraphTooltip = ({ table, total, totalUnfiltered, row, level, profileType, }) => {
|
|
29
29
|
let { width } = useWindowSize();
|
|
30
30
|
const { profileExplorer, navigateTo } = useParcaContext();
|
|
31
31
|
const { PaddingX } = profileExplorer ?? { PaddingX: 0 };
|
|
32
32
|
width = width - PaddingX - 24;
|
|
33
33
|
const graphTooltipData = useGraphTooltip({
|
|
34
34
|
table,
|
|
35
|
-
|
|
35
|
+
profileType,
|
|
36
36
|
total,
|
|
37
37
|
totalUnfiltered,
|
|
38
38
|
row,
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { Table } from 'apache-arrow';
|
|
2
|
+
import { ProfileType } from '@parca/parser';
|
|
2
3
|
interface Props {
|
|
3
4
|
table: Table<any>;
|
|
4
|
-
|
|
5
|
+
profileType?: ProfileType;
|
|
5
6
|
total: bigint;
|
|
6
7
|
totalUnfiltered: bigint;
|
|
7
8
|
row: number | null;
|
|
@@ -11,9 +12,10 @@ interface GraphTooltipData {
|
|
|
11
12
|
name: string;
|
|
12
13
|
locationAddress: bigint;
|
|
13
14
|
cumulativeText: string;
|
|
15
|
+
cumulativePerSecondText: string;
|
|
14
16
|
diffText: string;
|
|
15
17
|
diff: bigint;
|
|
16
18
|
row: number;
|
|
17
19
|
}
|
|
18
|
-
export declare const useGraphTooltip: ({ table,
|
|
20
|
+
export declare const useGraphTooltip: ({ table, profileType, total, totalUnfiltered, row, level, }: Props) => GraphTooltipData | null;
|
|
19
21
|
export {};
|
|
@@ -11,30 +11,48 @@
|
|
|
11
11
|
// See the License for the specific language governing permissions and
|
|
12
12
|
// limitations under the License.
|
|
13
13
|
import { divide, valueFormatter } from '@parca/utilities';
|
|
14
|
-
import { FIELD_CUMULATIVE, FIELD_DIFF, FIELD_LOCATION_ADDRESS, } from '../../ProfileIcicleGraph/IcicleGraphArrow';
|
|
15
|
-
import { getTextForCumulative, nodeLabel } from '../../ProfileIcicleGraph/IcicleGraphArrow/utils';
|
|
16
|
-
export const useGraphTooltip = ({ table,
|
|
17
|
-
if (row === null) {
|
|
14
|
+
import { FIELD_CUMULATIVE, FIELD_CUMULATIVE_PER_SECOND, FIELD_DIFF, FIELD_DIFF_PER_SECOND, FIELD_LOCATION_ADDRESS, } from '../../ProfileIcicleGraph/IcicleGraphArrow';
|
|
15
|
+
import { getTextForCumulative, getTextForCumulativePerSecond, nodeLabel, } from '../../ProfileIcicleGraph/IcicleGraphArrow/utils';
|
|
16
|
+
export const useGraphTooltip = ({ table, profileType, total, totalUnfiltered, row, level, }) => {
|
|
17
|
+
if (row === null || profileType === undefined) {
|
|
18
18
|
return null;
|
|
19
19
|
}
|
|
20
20
|
const locationAddress = table.getChild(FIELD_LOCATION_ADDRESS)?.get(row) ?? 0n;
|
|
21
21
|
const cumulative = table.getChild(FIELD_CUMULATIVE)?.get(row) !== null
|
|
22
22
|
? BigInt(table.getChild(FIELD_CUMULATIVE)?.get(row))
|
|
23
23
|
: 0n;
|
|
24
|
+
const cumulativePerSecond = table.getChild(FIELD_CUMULATIVE_PER_SECOND)?.get(row) !== null
|
|
25
|
+
? table.getChild(FIELD_CUMULATIVE_PER_SECOND)?.get(row)
|
|
26
|
+
: 0;
|
|
24
27
|
const diff = table.getChild(FIELD_DIFF)?.get(row) !== null
|
|
25
28
|
? BigInt(table.getChild(FIELD_DIFF)?.get(row))
|
|
26
29
|
: 0n;
|
|
27
|
-
const
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
30
|
+
const diffPerSecond = table.getChild(FIELD_DIFF_PER_SECOND)?.get(row) !== null
|
|
31
|
+
? table.getChild(FIELD_DIFF_PER_SECOND)?.get(row)
|
|
32
|
+
: 0;
|
|
33
|
+
let diffText = '';
|
|
34
|
+
if (profileType?.delta ?? false) {
|
|
35
|
+
const prevValue = cumulativePerSecond - diffPerSecond;
|
|
36
|
+
const diffRatio = diffPerSecond !== 0 ? diffPerSecond / prevValue : 0;
|
|
37
|
+
const diffSign = diffPerSecond > 0 ? '+' : '';
|
|
38
|
+
const diffValueText = diffSign + valueFormatter(diffPerSecond, 'CPU Cores', 5);
|
|
39
|
+
const diffPercentageText = diffSign + (diffRatio * 100).toFixed(2) + '%';
|
|
40
|
+
diffText = `${diffValueText} (${diffPercentageText})`;
|
|
41
|
+
}
|
|
42
|
+
else {
|
|
43
|
+
const prevValue = cumulative - diff;
|
|
44
|
+
const diffRatio = diff !== 0n ? divide(diff, prevValue) : 0;
|
|
45
|
+
const diffSign = diff > 0 ? '+' : '';
|
|
46
|
+
const diffValueText = diffSign + valueFormatter(diff, profileType?.sampleUnit ?? '', 1);
|
|
47
|
+
const diffPercentageText = diffSign + (diffRatio * 100).toFixed(2) + '%';
|
|
48
|
+
diffText = `${diffValueText} (${diffPercentageText})`;
|
|
49
|
+
}
|
|
33
50
|
const name = nodeLabel(table, row, level, false);
|
|
34
51
|
return {
|
|
35
52
|
name,
|
|
36
53
|
locationAddress,
|
|
37
|
-
cumulativeText: getTextForCumulative(cumulative, totalUnfiltered, total,
|
|
54
|
+
cumulativeText: getTextForCumulative(cumulative, totalUnfiltered, total, profileType?.periodUnit ?? ''),
|
|
55
|
+
cumulativePerSecondText: getTextForCumulativePerSecond(cumulativePerSecond, profileType?.periodUnit ?? 'CPU Cores'),
|
|
38
56
|
diffText,
|
|
39
57
|
diff,
|
|
40
58
|
row,
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
/// <reference types="react" />
|
|
2
2
|
import { Flamegraph } from '@parca/client';
|
|
3
|
+
import { ProfileType } from '@parca/parser';
|
|
3
4
|
import { type NavigateFunction } from '@parca/utilities';
|
|
4
5
|
interface IcicleGraphProps {
|
|
5
6
|
graph: Flamegraph;
|
|
6
7
|
total: bigint;
|
|
7
8
|
filtered: bigint;
|
|
8
|
-
|
|
9
|
+
profileType?: ProfileType;
|
|
9
10
|
width?: number;
|
|
10
11
|
curPath: string[];
|
|
11
12
|
setCurPath: (path: string[]) => void;
|
|
@@ -19,7 +19,7 @@ import { useProfileViewContext } from '../../ProfileView/ProfileViewContext';
|
|
|
19
19
|
import ColorStackLegend from './ColorStackLegend';
|
|
20
20
|
import { IcicleNode, RowHeight } from './IcicleGraphNodes';
|
|
21
21
|
import useColoredGraph from './useColoredGraph';
|
|
22
|
-
export const IcicleGraph = memo(function IcicleGraph({ graph, total, filtered, width, setCurPath, curPath,
|
|
22
|
+
export const IcicleGraph = memo(function IcicleGraph({ graph, total, filtered, width, setCurPath, curPath, profileType, navigateTo, }) {
|
|
23
23
|
const dispatch = useAppDispatch();
|
|
24
24
|
const [height, setHeight] = useState(0);
|
|
25
25
|
const svg = useRef(null);
|
|
@@ -42,6 +42,6 @@ export const IcicleGraph = memo(function IcicleGraph({ graph, total, filtered, w
|
|
|
42
42
|
if (coloredGraph.root === undefined || width === undefined) {
|
|
43
43
|
return _jsx(_Fragment, {});
|
|
44
44
|
}
|
|
45
|
-
return (_jsxs("div", { onMouseLeave: () => dispatch(setHoveringNode(undefined)), children: [isColorStackLegendEnabled && (_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", { className: "font-robotoMono", width: width, height: height, preserveAspectRatio: "xMinYMid", ref: svg, children: _jsx("g", { ref: ref, children: _jsx("g", { 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 }) }) }) })] }));
|
|
45
|
+
return (_jsxs("div", { onMouseLeave: () => dispatch(setHoveringNode(undefined)), children: [isColorStackLegendEnabled && (_jsx(ColorStackLegend, { navigateTo: navigateTo, compareMode: compareMode })), _jsx(GraphTooltip, { unit: profileType?.sampleUnit ?? '', total: total, totalUnfiltered: total + filtered, contextElement: svg.current, strings: coloredGraph.stringTable, mappings: coloredGraph.mapping, locations: coloredGraph.locations, functions: coloredGraph.function }), _jsx("svg", { className: "font-robotoMono", width: width, height: height, preserveAspectRatio: "xMinYMid", ref: svg, children: _jsx("g", { ref: ref, children: _jsx("g", { 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 }) }) }) })] }));
|
|
46
46
|
});
|
|
47
47
|
export default IcicleGraph;
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
/// <reference types="react" />
|
|
2
2
|
import { Table } from 'apache-arrow';
|
|
3
|
+
import { ProfileType } from '@parca/parser';
|
|
3
4
|
import { type NavigateFunction } from '@parca/utilities';
|
|
4
5
|
interface ContextMenuProps {
|
|
5
6
|
menuId: string;
|
|
6
7
|
table: Table<any>;
|
|
7
|
-
|
|
8
|
+
profileType?: ProfileType;
|
|
8
9
|
total: bigint;
|
|
9
10
|
totalUnfiltered: bigint;
|
|
10
11
|
row: number;
|
|
@@ -15,5 +16,5 @@ interface ContextMenuProps {
|
|
|
15
16
|
setCurPath: (path: string[]) => void;
|
|
16
17
|
hideMenu: () => void;
|
|
17
18
|
}
|
|
18
|
-
declare const ContextMenu: ({ menuId, table,
|
|
19
|
+
declare const ContextMenu: ({ menuId, table, total, totalUnfiltered, row, level, navigateTo, trackVisibility, curPath, setCurPath, hideMenu, profileType, }: ContextMenuProps) => JSX.Element;
|
|
19
20
|
export default ContextMenu;
|
|
@@ -19,13 +19,13 @@ import { USER_PREFERENCES, useUserPreference } from '@parca/hooks';
|
|
|
19
19
|
import { useGraphTooltip } from '../../GraphTooltipArrow/useGraphTooltip';
|
|
20
20
|
import { useGraphTooltipMetaInfo } from '../../GraphTooltipArrow/useGraphTooltipMetaInfo';
|
|
21
21
|
import { hexifyAddress, truncateString } from '../../utils';
|
|
22
|
-
const ContextMenu = ({ menuId, table,
|
|
22
|
+
const ContextMenu = ({ menuId, table, total, totalUnfiltered, row, level, navigateTo, trackVisibility, curPath, setCurPath, hideMenu, profileType, }) => {
|
|
23
23
|
const { isDarkMode } = useParcaContext();
|
|
24
24
|
const { enableSourcesView } = useParcaContext();
|
|
25
25
|
const [isGraphTooltipDocked, setIsDocked] = useUserPreference(USER_PREFERENCES.GRAPH_METAINFO_DOCKED.key);
|
|
26
26
|
const contextMenuData = useGraphTooltip({
|
|
27
27
|
table,
|
|
28
|
-
|
|
28
|
+
profileType,
|
|
29
29
|
total,
|
|
30
30
|
totalUnfiltered,
|
|
31
31
|
row,
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import { Table } from 'apache-arrow';
|
|
3
3
|
import 'react-contexify/dist/ReactContexify.css';
|
|
4
|
+
import { ProfileType } from '@parca/parser';
|
|
4
5
|
export declare const RowHeight = 26;
|
|
5
6
|
interface IcicleGraphNodesProps {
|
|
6
7
|
table: Table<any>;
|
|
@@ -22,6 +23,7 @@ interface IcicleGraphNodesProps {
|
|
|
22
23
|
sortBy: string;
|
|
23
24
|
darkMode: boolean;
|
|
24
25
|
compareMode: boolean;
|
|
26
|
+
profileType?: ProfileType;
|
|
25
27
|
isContextMenuOpen: boolean;
|
|
26
28
|
hoveringName: string | null;
|
|
27
29
|
setHoveringName: (name: string | null) => void;
|
|
@@ -54,6 +56,7 @@ interface IcicleNodeProps {
|
|
|
54
56
|
sortBy: string;
|
|
55
57
|
darkMode: boolean;
|
|
56
58
|
compareMode: boolean;
|
|
59
|
+
profileType?: ProfileType;
|
|
57
60
|
isContextMenuOpen: boolean;
|
|
58
61
|
hoveringName: string | null;
|
|
59
62
|
setHoveringName: (name: string | null) => void;
|
|
@@ -16,11 +16,11 @@ import cx from 'classnames';
|
|
|
16
16
|
import { selectBinaries, useAppSelector } from '@parca/store';
|
|
17
17
|
import { isSearchMatch, scaleLinear } from '@parca/utilities';
|
|
18
18
|
import 'react-contexify/dist/ReactContexify.css';
|
|
19
|
-
import { FIELD_CHILDREN, FIELD_CUMULATIVE, FIELD_DIFF, FIELD_FUNCTION_NAME, FIELD_MAPPING_FILE, } from './index';
|
|
19
|
+
import { FIELD_CHILDREN, FIELD_CUMULATIVE, FIELD_CUMULATIVE_PER_SECOND, FIELD_DIFF, FIELD_DIFF_PER_SECOND, FIELD_FUNCTION_NAME, FIELD_MAPPING_FILE, } from './index';
|
|
20
20
|
import useNodeColor from './useNodeColor';
|
|
21
21
|
import { arrowToString, nodeLabel } from './utils';
|
|
22
22
|
export const RowHeight = 26;
|
|
23
|
-
export const IcicleGraphNodes = React.memo(function IcicleGraphNodesNoMemo({ table, childRows, mappingColors, x, y, xScale, total, totalWidth, level, path, setCurPath, setHoveringRow, setHoveringLevel, curPath, sortBy, searchString, darkMode, compareMode, isContextMenuOpen, hoveringName, setHoveringName, hoveringRow, colorForSimilarNodes, highlightSimilarStacksPreference, }) {
|
|
23
|
+
export const IcicleGraphNodes = React.memo(function IcicleGraphNodesNoMemo({ table, childRows, mappingColors, x, y, xScale, total, totalWidth, level, path, setCurPath, setHoveringRow, setHoveringLevel, curPath, sortBy, searchString, darkMode, compareMode, profileType, isContextMenuOpen, hoveringName, setHoveringName, hoveringRow, colorForSimilarNodes, highlightSimilarStacksPreference, }) {
|
|
24
24
|
const cumulatives = table.getChild(FIELD_CUMULATIVE);
|
|
25
25
|
if (childRows === undefined || childRows.length === 0) {
|
|
26
26
|
return _jsx(_Fragment, {});
|
|
@@ -35,7 +35,7 @@ export const IcicleGraphNodes = React.memo(function IcicleGraphNodesNoMemo({ tab
|
|
|
35
35
|
const xStart = Math.floor(xScale(BigInt(childrenCumulative)));
|
|
36
36
|
const c = BigInt(cumulatives?.get(child));
|
|
37
37
|
childrenCumulative += c;
|
|
38
|
-
childrenElements.push(_jsx(IcicleNode, { table: table, row: child, mappingColors: mappingColors, x: xStart, y: 0, totalWidth: totalWidth, height: RowHeight, path: path, setCurPath: setCurPath, setHoveringRow: setHoveringRow, setHoveringLevel: setHoveringLevel, level: level, curPath: curPath, total: total, xScale: xScale, sortBy: sortBy, searchString: searchString, darkMode: darkMode, compareMode: compareMode, isContextMenuOpen: isContextMenuOpen, hoveringName: hoveringName, setHoveringName: setHoveringName, hoveringRow: hoveringRow, colorForSimilarNodes: colorForSimilarNodes, highlightSimilarStacksPreference: highlightSimilarStacksPreference }, `node-${level}-${i}`));
|
|
38
|
+
childrenElements.push(_jsx(IcicleNode, { table: table, row: child, mappingColors: mappingColors, x: xStart, y: 0, totalWidth: totalWidth, height: RowHeight, path: path, setCurPath: setCurPath, setHoveringRow: setHoveringRow, setHoveringLevel: setHoveringLevel, level: level, curPath: curPath, total: total, xScale: xScale, sortBy: sortBy, searchString: searchString, darkMode: darkMode, compareMode: compareMode, profileType: profileType, isContextMenuOpen: isContextMenuOpen, hoveringName: hoveringName, setHoveringName: setHoveringName, hoveringRow: hoveringRow, colorForSimilarNodes: colorForSimilarNodes, highlightSimilarStacksPreference: highlightSimilarStacksPreference }, `node-${level}-${i}`));
|
|
39
39
|
});
|
|
40
40
|
return _jsx("g", { transform: `translate(${x}, ${y})`, children: childrenElements });
|
|
41
41
|
});
|
|
@@ -48,17 +48,21 @@ const fadedIcicleRectStyles = {
|
|
|
48
48
|
transition: 'opacity .15s linear',
|
|
49
49
|
opacity: '0.5',
|
|
50
50
|
};
|
|
51
|
-
export const IcicleNode = React.memo(function IcicleNodeNoMemo({ table, row, mappingColors, x, y, height, setCurPath, curPath, level, path, total, totalWidth, xScale, isRoot = false, searchString, setHoveringRow, setHoveringLevel, sortBy, darkMode, compareMode, isContextMenuOpen, hoveringName, setHoveringName, hoveringRow, colorForSimilarNodes, highlightSimilarStacksPreference, }) {
|
|
51
|
+
export const IcicleNode = React.memo(function IcicleNodeNoMemo({ table, row, mappingColors, x, y, height, setCurPath, curPath, level, path, total, totalWidth, xScale, isRoot = false, searchString, setHoveringRow, setHoveringLevel, sortBy, darkMode, compareMode, profileType, isContextMenuOpen, hoveringName, setHoveringName, hoveringRow, colorForSimilarNodes, highlightSimilarStacksPreference, }) {
|
|
52
52
|
// get the columns to read from
|
|
53
53
|
const mappingColumn = table.getChild(FIELD_MAPPING_FILE);
|
|
54
54
|
const functionNameColumn = table.getChild(FIELD_FUNCTION_NAME);
|
|
55
55
|
const cumulativeColumn = table.getChild(FIELD_CUMULATIVE);
|
|
56
|
+
const cumulativePerSecondColumn = table.getChild(FIELD_CUMULATIVE_PER_SECOND);
|
|
56
57
|
const diffColumn = table.getChild(FIELD_DIFF);
|
|
58
|
+
const diffPerSecondColumn = table.getChild(FIELD_DIFF_PER_SECOND);
|
|
57
59
|
// get the actual values from the columns
|
|
58
60
|
const mappingFile = arrowToString(mappingColumn?.get(row));
|
|
59
61
|
const functionName = arrowToString(functionNameColumn?.get(row));
|
|
60
62
|
const cumulative = cumulativeColumn?.get(row) !== null ? BigInt(cumulativeColumn?.get(row)) : 0n;
|
|
63
|
+
const cumulativePerSecond = cumulativePerSecondColumn?.get(row) != null ? cumulativePerSecondColumn.get(row) : 0;
|
|
61
64
|
const diff = diffColumn?.get(row) !== null ? BigInt(diffColumn?.get(row)) : null;
|
|
65
|
+
const diffPerSecond = diffPerSecondColumn?.get(row) != null ? diffPerSecondColumn.get(row) : null;
|
|
62
66
|
const childRows = Array.from(table.getChild(FIELD_CHILDREN)?.get(row) ?? []);
|
|
63
67
|
const highlightedNodes = useMemo(() => {
|
|
64
68
|
if (!highlightSimilarStacksPreference) {
|
|
@@ -93,6 +97,14 @@ export const IcicleNode = React.memo(function IcicleNodeNoMemo({ table, row, map
|
|
|
93
97
|
});
|
|
94
98
|
break;
|
|
95
99
|
case FIELD_CUMULATIVE:
|
|
100
|
+
if (profileType?.delta ?? false) {
|
|
101
|
+
childRows.sort((a, b) => {
|
|
102
|
+
const aCumulativePerSecond = cumulativePerSecondColumn?.get(a);
|
|
103
|
+
const bCumulativePerSecond = cumulativePerSecondColumn?.get(b);
|
|
104
|
+
return bCumulativePerSecond - aCumulativePerSecond;
|
|
105
|
+
});
|
|
106
|
+
break;
|
|
107
|
+
}
|
|
96
108
|
childRows.sort((a, b) => {
|
|
97
109
|
const aCumulative = cumulativeColumn?.get(a);
|
|
98
110
|
const bCumulative = cumulativeColumn?.get(b);
|
|
@@ -101,15 +113,54 @@ export const IcicleNode = React.memo(function IcicleNodeNoMemo({ table, row, map
|
|
|
101
113
|
break;
|
|
102
114
|
case FIELD_DIFF:
|
|
103
115
|
childRows.sort((a, b) => {
|
|
116
|
+
if (profileType?.delta ?? false) {
|
|
117
|
+
let aRatio = null;
|
|
118
|
+
let bRatio = null;
|
|
119
|
+
const aDiff = diffPerSecondColumn?.get(a);
|
|
120
|
+
if (aDiff !== null) {
|
|
121
|
+
const cumulative = cumulativePerSecondColumn?.get(a);
|
|
122
|
+
const prev = cumulative - aDiff;
|
|
123
|
+
aRatio = aDiff / prev;
|
|
124
|
+
}
|
|
125
|
+
const bDiff = diffPerSecondColumn?.get(b);
|
|
126
|
+
if (bDiff !== null) {
|
|
127
|
+
const cumulative = cumulativePerSecondColumn?.get(b);
|
|
128
|
+
const prev = cumulative - bDiff;
|
|
129
|
+
bRatio = bDiff / prev;
|
|
130
|
+
}
|
|
131
|
+
if (aRatio !== null && bRatio !== null) {
|
|
132
|
+
return bRatio - aRatio;
|
|
133
|
+
}
|
|
134
|
+
if (aRatio === null && bRatio !== null) {
|
|
135
|
+
return -1;
|
|
136
|
+
}
|
|
137
|
+
if (aRatio !== null && bRatio === null) {
|
|
138
|
+
return 1;
|
|
139
|
+
}
|
|
140
|
+
// both are null
|
|
141
|
+
return 0;
|
|
142
|
+
}
|
|
143
|
+
let aRatio = null;
|
|
104
144
|
const aDiff = diffColumn?.get(a);
|
|
145
|
+
if (aDiff !== null) {
|
|
146
|
+
const cumulative = cumulativeColumn?.get(a) ?? 0n;
|
|
147
|
+
const prev = cumulative - aDiff;
|
|
148
|
+
aRatio = Number(aDiff) / Number(prev);
|
|
149
|
+
}
|
|
150
|
+
let bRatio = null;
|
|
105
151
|
const bDiff = diffColumn?.get(b);
|
|
106
|
-
if (
|
|
107
|
-
|
|
152
|
+
if (bDiff !== null) {
|
|
153
|
+
const cumulative = cumulativeColumn?.get(b) ?? 0n;
|
|
154
|
+
const prev = cumulative - bDiff;
|
|
155
|
+
bRatio = Number(bDiff) / Number(prev);
|
|
156
|
+
}
|
|
157
|
+
if (aRatio !== null && bRatio !== null) {
|
|
158
|
+
return bRatio - aRatio;
|
|
108
159
|
}
|
|
109
|
-
if (
|
|
160
|
+
if (aRatio === null && bRatio !== null) {
|
|
110
161
|
return -1;
|
|
111
162
|
}
|
|
112
|
-
if (
|
|
163
|
+
if (aRatio !== null && bRatio === null) {
|
|
113
164
|
return 1;
|
|
114
165
|
}
|
|
115
166
|
// both are null
|
|
@@ -122,7 +173,9 @@ export const IcicleNode = React.memo(function IcicleNodeNoMemo({ table, row, map
|
|
|
122
173
|
isDarkMode: darkMode,
|
|
123
174
|
compareMode,
|
|
124
175
|
cumulative,
|
|
176
|
+
cumulativePerSecond,
|
|
125
177
|
diff,
|
|
178
|
+
diffPerSecond,
|
|
126
179
|
mappingColors,
|
|
127
180
|
mappingFile,
|
|
128
181
|
functionName,
|
|
@@ -172,5 +225,5 @@ export const IcicleNode = React.memo(function IcicleNodeNoMemo({ table, row, map
|
|
|
172
225
|
? `${colorForSimilarNodes} stroke-[3] [stroke-dasharray:6,4] [stroke-linecap:round] [stroke-linejoin:round] h-6`
|
|
173
226
|
: 'stroke-white dark:stroke-gray-700', {
|
|
174
227
|
'opacity-50': isHighlightEnabled && !isHighlighted,
|
|
175
|
-
}) }), width > 5 && (_jsx("svg", { width: width - 5, height: height, children: _jsx("text", { x: 5, y: 15, style: { fontSize: '12px' }, children: name }) }))] }), childRows.length > 0 && (_jsx(IcicleGraphNodes, { table: table, row: row, mappingColors: mappingColors, childRows: childRows, x: x, y: RowHeight, xScale: newXScale, total: total, totalWidth: totalWidth, level: nextLevel, path: nextPath, curPath: nextCurPath, setCurPath: setCurPath, setHoveringRow: setHoveringRow, setHoveringLevel: setHoveringLevel, searchString: searchString, sortBy: sortBy, darkMode: darkMode, compareMode: compareMode, isContextMenuOpen: isContextMenuOpen, hoveringName: hoveringName, setHoveringName: setHoveringName, hoveringRow: hoveringRow, colorForSimilarNodes: colorForSimilarNodes, highlightSimilarStacksPreference: highlightSimilarStacksPreference }))] }));
|
|
228
|
+
}) }), width > 5 && (_jsx("svg", { width: width - 5, height: height, children: _jsx("text", { x: 5, y: 15, style: { fontSize: '12px' }, children: name }) }))] }), childRows.length > 0 && (_jsx(IcicleGraphNodes, { table: table, row: row, mappingColors: mappingColors, childRows: childRows, x: x, y: RowHeight, xScale: newXScale, total: total, totalWidth: totalWidth, level: nextLevel, path: nextPath, curPath: nextCurPath, setCurPath: setCurPath, setHoveringRow: setHoveringRow, setHoveringLevel: setHoveringLevel, searchString: searchString, sortBy: sortBy, darkMode: darkMode, profileType: profileType, compareMode: compareMode, isContextMenuOpen: isContextMenuOpen, hoveringName: hoveringName, setHoveringName: setHoveringName, hoveringRow: hoveringRow, colorForSimilarNodes: colorForSimilarNodes, highlightSimilarStacksPreference: highlightSimilarStacksPreference }))] }));
|
|
176
229
|
});
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import { FlamegraphArrow } from '@parca/client';
|
|
3
|
+
import { ProfileType } from '@parca/parser';
|
|
3
4
|
import { type NavigateFunction } from '@parca/utilities';
|
|
4
5
|
export declare const FIELD_LABELS_ONLY = "labels_only";
|
|
5
6
|
export declare const FIELD_MAPPING_FILE = "mapping_file";
|
|
@@ -14,12 +15,14 @@ export declare const FIELD_FUNCTION_START_LINE = "function_startline";
|
|
|
14
15
|
export declare const FIELD_CHILDREN = "children";
|
|
15
16
|
export declare const FIELD_LABELS = "labels";
|
|
16
17
|
export declare const FIELD_CUMULATIVE = "cumulative";
|
|
18
|
+
export declare const FIELD_CUMULATIVE_PER_SECOND = "cumulative_per_second";
|
|
17
19
|
export declare const FIELD_DIFF = "diff";
|
|
20
|
+
export declare const FIELD_DIFF_PER_SECOND = "diff_per_second";
|
|
18
21
|
interface IcicleGraphArrowProps {
|
|
19
22
|
arrow: FlamegraphArrow;
|
|
20
23
|
total: bigint;
|
|
21
24
|
filtered: bigint;
|
|
22
|
-
|
|
25
|
+
profileType?: ProfileType;
|
|
23
26
|
width?: number;
|
|
24
27
|
curPath: string[];
|
|
25
28
|
setCurPath: (path: string[]) => void;
|
|
@@ -38,8 +38,10 @@ export const FIELD_FUNCTION_START_LINE = 'function_startline';
|
|
|
38
38
|
export const FIELD_CHILDREN = 'children';
|
|
39
39
|
export const FIELD_LABELS = 'labels';
|
|
40
40
|
export const FIELD_CUMULATIVE = 'cumulative';
|
|
41
|
+
export const FIELD_CUMULATIVE_PER_SECOND = 'cumulative_per_second';
|
|
41
42
|
export const FIELD_DIFF = 'diff';
|
|
42
|
-
export const
|
|
43
|
+
export const FIELD_DIFF_PER_SECOND = 'diff_per_second';
|
|
44
|
+
export const IcicleGraphArrow = memo(function IcicleGraphArrow({ arrow, total, filtered, width, setCurPath, curPath, profileType, navigateTo, sortBy, }) {
|
|
43
45
|
const [isContextMenuOpen, setIsContextMenuOpen] = useState(false);
|
|
44
46
|
const dispatch = useAppDispatch();
|
|
45
47
|
const [highlightSimilarStacksPreference] = useUserPreference(USER_PREFERENCES.HIGHLIGHT_SIMILAR_STACKS.key);
|
|
@@ -139,13 +141,14 @@ export const IcicleGraphArrow = memo(function IcicleGraphArrow({ arrow, total, f
|
|
|
139
141
|
};
|
|
140
142
|
// useMemo for the root graph as it otherwise renders the whole graph if the hoveringRow changes.
|
|
141
143
|
const root = useMemo(() => {
|
|
142
|
-
return (_jsx("svg", { className: "font-robotoMono", width: width, height: height, preserveAspectRatio: "xMinYMid", ref: svg, onContextMenu: displayMenu, children: _jsx("g", { ref: ref, children: _jsx("g", { transform: 'translate(0, 0)', children: _jsx(IcicleNode, { table: table, row: 0, mappingColors: mappingColors, x: 0, y: 0, totalWidth: width ?? 1, height: RowHeight, setCurPath: setCurPath, curPath: curPath, total: total, xScale: xScale, path: [], level: 0, isRoot: true, searchString: currentSearchString, setHoveringRow: setHoveringRow, setHoveringLevel: setHoveringLevel, sortBy: sortBy, darkMode: isDarkMode, compareMode: compareMode, isContextMenuOpen: isContextMenuOpen, hoveringName: hoveringName, setHoveringName: setHoveringName, hoveringRow: hoveringRow, colorForSimilarNodes: colorForSimilarNodes, highlightSimilarStacksPreference: highlightSimilarStacksPreference }) }) }) }));
|
|
144
|
+
return (_jsx("svg", { className: "font-robotoMono", width: width, height: height, preserveAspectRatio: "xMinYMid", ref: svg, onContextMenu: displayMenu, children: _jsx("g", { ref: ref, children: _jsx("g", { transform: 'translate(0, 0)', children: _jsx(IcicleNode, { table: table, row: 0, mappingColors: mappingColors, x: 0, y: 0, totalWidth: width ?? 1, height: RowHeight, setCurPath: setCurPath, curPath: curPath, total: total, xScale: xScale, path: [], level: 0, isRoot: true, searchString: currentSearchString, setHoveringRow: setHoveringRow, setHoveringLevel: setHoveringLevel, sortBy: sortBy, darkMode: isDarkMode, compareMode: compareMode, profileType: profileType, isContextMenuOpen: isContextMenuOpen, hoveringName: hoveringName, setHoveringName: setHoveringName, hoveringRow: hoveringRow, colorForSimilarNodes: colorForSimilarNodes, highlightSimilarStacksPreference: highlightSimilarStacksPreference }) }) }) }));
|
|
143
145
|
}, [
|
|
144
146
|
compareMode,
|
|
145
147
|
curPath,
|
|
146
148
|
currentSearchString,
|
|
147
149
|
height,
|
|
148
150
|
isDarkMode,
|
|
151
|
+
profileType,
|
|
149
152
|
mappingColors,
|
|
150
153
|
setCurPath,
|
|
151
154
|
sortBy,
|
|
@@ -163,6 +166,6 @@ export const IcicleGraphArrow = memo(function IcicleGraphArrow({ arrow, total, f
|
|
|
163
166
|
if (table.numRows === 0 || width === undefined) {
|
|
164
167
|
return _jsx(_Fragment, {});
|
|
165
168
|
}
|
|
166
|
-
return (_jsx(_Fragment, { children: _jsxs("div", { onMouseLeave: () => dispatch(setHoveringNode(undefined)), children: [_jsx(ContextMenu, { menuId: MENU_ID, table: table, row: hoveringRow ?? 0, level: hoveringLevel ?? 0, total: total, totalUnfiltered: total + filtered,
|
|
169
|
+
return (_jsx(_Fragment, { children: _jsxs("div", { onMouseLeave: () => dispatch(setHoveringNode(undefined)), children: [_jsx(ContextMenu, { menuId: MENU_ID, table: table, row: hoveringRow ?? 0, level: hoveringLevel ?? 0, total: total, totalUnfiltered: total + filtered, profileType: profileType, navigateTo: navigateTo, trackVisibility: trackVisibility, curPath: curPath, setCurPath: setCurPath, hideMenu: hideAll }), isColorStackLegendEnabled && (_jsx(ColorStackLegend, { mappingColors: mappingColors, navigateTo: navigateTo, compareMode: compareMode })), dockedMetainfo ? (_jsx(DockedGraphTooltip, { table: table, row: hoveringRow, level: hoveringLevel ?? 0, total: total, totalUnfiltered: total + filtered, profileType: profileType })) : (!isContextMenuOpen && (_jsx(GraphTooltipArrow, { contextElement: svg.current, isContextMenuOpen: isContextMenuOpen, children: _jsx(GraphTooltipArrowContent, { table: table, row: hoveringRow, level: hoveringLevel ?? 0, isFixed: false, total: total, totalUnfiltered: total + filtered, profileType: profileType, navigateTo: navigateTo }) }))), root] }) }));
|
|
167
170
|
});
|
|
168
171
|
export default IcicleGraphArrow;
|
|
@@ -5,10 +5,12 @@ interface Props {
|
|
|
5
5
|
isDarkMode: boolean;
|
|
6
6
|
compareMode: boolean;
|
|
7
7
|
cumulative: bigint;
|
|
8
|
+
cumulativePerSecond: number | null;
|
|
8
9
|
diff: bigint | null;
|
|
10
|
+
diffPerSecond: number | null;
|
|
9
11
|
mappingColors: mappingColors;
|
|
10
12
|
functionName: string | null;
|
|
11
13
|
mappingFile: string | null;
|
|
12
14
|
}
|
|
13
|
-
declare const useNodeColor: ({ isDarkMode, compareMode, cumulative, diff, mappingColors, functionName, mappingFile, }: Props) => string;
|
|
15
|
+
declare const useNodeColor: ({ isDarkMode, compareMode, cumulative, cumulativePerSecond, diff, diffPerSecond, mappingColors, functionName, mappingFile, }: Props) => string;
|
|
14
16
|
export default useNodeColor;
|
|
@@ -11,9 +11,12 @@
|
|
|
11
11
|
// See the License for the specific language governing permissions and
|
|
12
12
|
// limitations under the License.
|
|
13
13
|
import { EVERYTHING_ELSE } from '@parca/store';
|
|
14
|
-
import { diffColor, getLastItem } from '@parca/utilities';
|
|
15
|
-
const useNodeColor = ({ isDarkMode, compareMode, cumulative, diff, mappingColors, functionName, mappingFile, }) => {
|
|
14
|
+
import { diffColor, diffColorPerSecond, getLastItem } from '@parca/utilities';
|
|
15
|
+
const useNodeColor = ({ isDarkMode, compareMode, cumulative, cumulativePerSecond, diff, diffPerSecond, mappingColors, functionName, mappingFile, }) => {
|
|
16
16
|
if (compareMode) {
|
|
17
|
+
if (cumulativePerSecond !== null && diffPerSecond !== null) {
|
|
18
|
+
return diffColorPerSecond(diffPerSecond, cumulativePerSecond, isDarkMode);
|
|
19
|
+
}
|
|
17
20
|
return diffColor(diff ?? 0n, cumulative, isDarkMode);
|
|
18
21
|
}
|
|
19
22
|
// To get the color we first check if the function name starts with 'runtime'.
|
|
@@ -3,4 +3,5 @@ import { type Feature } from '@parca/store';
|
|
|
3
3
|
export declare function nodeLabel(table: Table<any>, row: number, level: number, showBinaryName: boolean): string;
|
|
4
4
|
export declare const extractFeature: (mapping: string) => Feature;
|
|
5
5
|
export declare const getTextForCumulative: (hoveringNodeCumulative: bigint, totalUnfiltered: bigint, total: bigint, unit: string) => string;
|
|
6
|
+
export declare const getTextForCumulativePerSecond: (hoveringNodeCumulative: number, unit: string) => string;
|
|
6
7
|
export declare const arrowToString: (buffer: any) => string | null;
|
|
@@ -60,6 +60,9 @@ export const getTextForCumulative = (hoveringNodeCumulative, totalUnfiltered, to
|
|
|
60
60
|
return `${valueFormatter(hoveringNodeCumulative, unit, 2)}
|
|
61
61
|
(${(100 * divide(hoveringNodeCumulative, totalUnfiltered)).toFixed(2)}%${filtered})`;
|
|
62
62
|
};
|
|
63
|
+
export const getTextForCumulativePerSecond = (hoveringNodeCumulative, unit) => {
|
|
64
|
+
return `${valueFormatter(hoveringNodeCumulative, unit === 'nanoseconds' ? 'CPU Cores' : unit, 5)}`;
|
|
65
|
+
};
|
|
63
66
|
export const arrowToString = (buffer) => {
|
|
64
67
|
if (buffer == null || typeof buffer === 'string') {
|
|
65
68
|
return buffer;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import { Flamegraph, FlamegraphArrow } from '@parca/client';
|
|
3
|
+
import { ProfileType } from '@parca/parser';
|
|
3
4
|
import { type NavigateFunction } from '@parca/utilities';
|
|
4
5
|
export type ResizeHandler = (width: number, height: number) => void;
|
|
5
6
|
interface ProfileIcicleGraphProps {
|
|
@@ -8,7 +9,7 @@ interface ProfileIcicleGraphProps {
|
|
|
8
9
|
arrow?: FlamegraphArrow;
|
|
9
10
|
total: bigint;
|
|
10
11
|
filtered: bigint;
|
|
11
|
-
|
|
12
|
+
profileType?: ProfileType;
|
|
12
13
|
curPath: string[] | [];
|
|
13
14
|
setNewCurPath: (path: string[]) => void;
|
|
14
15
|
navigateTo?: NavigateFunction;
|
|
@@ -17,5 +18,5 @@ interface ProfileIcicleGraphProps {
|
|
|
17
18
|
error?: any;
|
|
18
19
|
isHalfScreen: boolean;
|
|
19
20
|
}
|
|
20
|
-
declare const ProfileIcicleGraph: ({ graph, arrow, total, filtered, curPath, setNewCurPath,
|
|
21
|
+
declare const ProfileIcicleGraph: ({ graph, arrow, total, filtered, curPath, setNewCurPath, profileType, navigateTo, loading, setActionButtons, error, width, isHalfScreen, }: ProfileIcicleGraphProps) => JSX.Element;
|
|
21
22
|
export default ProfileIcicleGraph;
|
|
@@ -82,7 +82,7 @@ const GroupAndSortActionButtons = ({ navigateTo }) => {
|
|
|
82
82
|
});
|
|
83
83
|
return (_jsxs(_Fragment, { children: [_jsx(GroupByDropdown, { groupBy: groupBy, toggleGroupBy: toggleGroupBy }), _jsx(SortBySelect, { compareMode: compareMode, sortBy: storeSortBy, setSortBy: setStoreSortBy }), _jsx(RuntimeFilterDropdown, { showRuntimeRuby: showRuntimeRubyStr === 'true', toggleShowRuntimeRuby: () => setShowRuntimeRuby(showRuntimeRubyStr === 'true' ? 'false' : 'true'), showRuntimePython: showRuntimePythonStr === 'true', toggleShowRuntimePython: () => setShowRuntimePython(showRuntimePythonStr === 'true' ? 'false' : 'true'), showInterpretedOnly: showInterpretedOnlyStr === 'true', toggleShowInterpretedOnly: () => setShowInterpretedOnly(showInterpretedOnlyStr === 'true' ? 'false' : 'true') })] }));
|
|
84
84
|
};
|
|
85
|
-
const ProfileIcicleGraph = function ProfileIcicleGraphNonMemo({ graph, arrow, total, filtered, curPath, setNewCurPath,
|
|
85
|
+
const ProfileIcicleGraph = function ProfileIcicleGraphNonMemo({ graph, arrow, total, filtered, curPath, setNewCurPath, profileType, navigateTo, loading, setActionButtons, error, width, isHalfScreen, }) {
|
|
86
86
|
const { onError, authenticationErrorMessage, isDarkMode } = useParcaContext();
|
|
87
87
|
const { compareMode } = useProfileViewContext();
|
|
88
88
|
const [storeSortBy = FIELD_FUNCTION_NAME] = useURLState({
|
|
@@ -134,6 +134,6 @@ const ProfileIcicleGraph = function ProfileIcicleGraphNonMemo({ graph, arrow, to
|
|
|
134
134
|
if (isTrimmed) {
|
|
135
135
|
console.info(`Trimmed ${trimmedFormatted} (${trimmedPercentage}%) too small values.`);
|
|
136
136
|
}
|
|
137
|
-
return (_jsx(AnimatePresence, { children: _jsxs(motion.div, { className: "relative h-full w-full", initial: { opacity: 0 }, animate: { opacity: 1 }, transition: { duration: 0.5 }, children: [compareMode ? _jsx(DiffLegend, {}) : null, _jsxs("div", { className: "min-h-48", id: "h-icicle-graph", children: [graph !== undefined && (_jsx(IcicleGraph, { width: width, graph: graph, total: total, filtered: filtered, curPath: curPath, setCurPath: setNewCurPath,
|
|
137
|
+
return (_jsx(AnimatePresence, { children: _jsxs(motion.div, { className: "relative h-full w-full", initial: { opacity: 0 }, animate: { opacity: 1 }, transition: { duration: 0.5 }, children: [compareMode ? _jsx(DiffLegend, {}) : null, _jsxs("div", { className: "min-h-48", id: "h-icicle-graph", children: [graph !== undefined && (_jsx(IcicleGraph, { width: width, graph: graph, total: total, filtered: filtered, curPath: curPath, setCurPath: setNewCurPath, profileType: profileType, navigateTo: navigateTo })), arrow !== undefined && (_jsx(IcicleGraphArrow, { width: width, arrow: arrow, total: total, filtered: filtered, curPath: curPath, setCurPath: setNewCurPath, profileType: profileType, navigateTo: navigateTo, sortBy: storeSortBy }))] }), _jsxs("p", { className: "my-2 text-xs", children: ["Showing ", totalFormatted, ' ', isFiltered ? (_jsxs("span", { children: ["(", filteredPercentage, "%) filtered of ", totalUnfilteredFormatted, ' '] })) : (_jsx(_Fragment, {})), "values.", ' '] })] }, "icicle-graph-loaded") }));
|
|
138
138
|
};
|
|
139
139
|
export default ProfileIcicleGraph;
|