@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
|
@@ -14,7 +14,6 @@ import { jsx as _jsx } from "react/jsx-runtime";
|
|
|
14
14
|
import { createContext, useContext } from 'react';
|
|
15
15
|
export const defaultValue = {
|
|
16
16
|
profileSource: undefined,
|
|
17
|
-
sampleUnit: 'bytes',
|
|
18
17
|
compareMode: false,
|
|
19
18
|
};
|
|
20
19
|
const ProfileViewContext = createContext(defaultValue);
|
|
@@ -39,7 +39,6 @@ export interface ProfileViewProps {
|
|
|
39
39
|
topTableData?: TopTableData;
|
|
40
40
|
callgraphData?: CallgraphData;
|
|
41
41
|
sourceData?: SourceData;
|
|
42
|
-
sampleUnit: string;
|
|
43
42
|
profileSource?: ProfileSource;
|
|
44
43
|
queryClient?: QueryServiceClient;
|
|
45
44
|
navigateTo?: NavigateFunction;
|
|
@@ -47,5 +46,5 @@ export interface ProfileViewProps {
|
|
|
47
46
|
onDownloadPProf: () => void;
|
|
48
47
|
pprofDownloading?: boolean;
|
|
49
48
|
}
|
|
50
|
-
export declare const ProfileView: ({ total, filtered, flamegraphData, topTableData, callgraphData, sourceData,
|
|
49
|
+
export declare const ProfileView: ({ total, filtered, flamegraphData, topTableData, callgraphData, sourceData, profileSource, queryClient, navigateTo, onDownloadPProf, pprofDownloading, compare, }: ProfileViewProps) => JSX.Element;
|
|
51
50
|
export {};
|
|
@@ -38,7 +38,7 @@ function arrayEquals(a, b) {
|
|
|
38
38
|
a.length === b.length &&
|
|
39
39
|
a.every((val, index) => val === b[index]));
|
|
40
40
|
}
|
|
41
|
-
export const ProfileView = ({ total, filtered, flamegraphData, topTableData, callgraphData, sourceData,
|
|
41
|
+
export const ProfileView = ({ total, filtered, flamegraphData, topTableData, callgraphData, sourceData, profileSource, queryClient, navigateTo, onDownloadPProf, pprofDownloading, compare, }) => {
|
|
42
42
|
const { timezone } = useParcaContext();
|
|
43
43
|
const { ref, dimensions } = useContainerDimensions();
|
|
44
44
|
const [curPath, setCurPath] = useState([]);
|
|
@@ -107,7 +107,7 @@ export const ProfileView = ({ total, filtered, flamegraphData, topTableData, cal
|
|
|
107
107
|
return (_jsx(ConditionalWrapper, { condition: perf?.onRender != null, WrapperComponent: Profiler, wrapperProps: {
|
|
108
108
|
id: 'icicleGraph',
|
|
109
109
|
onRender: perf?.onRender,
|
|
110
|
-
}, children: _jsx(ProfileIcicleGraph, { curPath: curPath, setNewCurPath: setNewCurPath, arrow: flamegraphData?.arrow, graph: flamegraphData?.data, total: total, filtered: filtered,
|
|
110
|
+
}, children: _jsx(ProfileIcicleGraph, { curPath: curPath, setNewCurPath: setNewCurPath, arrow: flamegraphData?.arrow, graph: flamegraphData?.data, total: total, filtered: filtered, profileType: profileSource?.ProfileType(), navigateTo: navigateTo, loading: flamegraphData.loading, setActionButtons: setActionButtons, error: flamegraphData.error, isHalfScreen: isHalfScreen, width: dimensions?.width !== undefined
|
|
111
111
|
? isHalfScreen
|
|
112
112
|
? (dimensions.width - 40) / 2
|
|
113
113
|
: dimensions.width - 16
|
|
@@ -116,10 +116,10 @@ export const ProfileView = ({ total, filtered, flamegraphData, topTableData, cal
|
|
|
116
116
|
case 'callgraph': {
|
|
117
117
|
return callgraphData?.data !== undefined &&
|
|
118
118
|
callgraphSVG !== undefined &&
|
|
119
|
-
dimensions?.width !== undefined ? (_jsx(Callgraph, { data: callgraphData.data, svgString: callgraphSVG,
|
|
119
|
+
dimensions?.width !== undefined ? (_jsx(Callgraph, { data: callgraphData.data, svgString: callgraphSVG, profileType: profileSource?.ProfileType(), width: isHalfScreen ? dimensions?.width / 2 : dimensions?.width })) : (_jsx(_Fragment, {}));
|
|
120
120
|
}
|
|
121
121
|
case 'table': {
|
|
122
|
-
return topTableData != null ? (_jsx(Table, { total: total, filtered: filtered, loading: topTableData.loading, data: topTableData.arrow?.record,
|
|
122
|
+
return topTableData != null ? (_jsx(Table, { total: total, filtered: filtered, loading: topTableData.loading, data: topTableData.arrow?.record, profileType: profileSource?.ProfileType(), navigateTo: navigateTo, setActionButtons: setActionButtons, currentSearchString: currentSearchString, isHalfScreen: isHalfScreen })) : (_jsx(_Fragment, {}));
|
|
123
123
|
}
|
|
124
124
|
case 'source': {
|
|
125
125
|
return sourceData != null ? (_jsx(SourceView, { loading: sourceData.loading, data: sourceData.data, total: total, filtered: filtered, setActionButtons: setActionButtons })) : (_jsx(_Fragment, {}));
|
|
@@ -150,7 +150,7 @@ export const ProfileView = ({ total, filtered, flamegraphData, topTableData, cal
|
|
|
150
150
|
const headerParts = profileSourceString?.split('"') ?? [];
|
|
151
151
|
const compareMode = compare === true ||
|
|
152
152
|
(selectQueryParam('compare_a') === 'true' && selectQueryParam('compare_b') === 'true');
|
|
153
|
-
return (_jsx(KeyDownProvider, { children: _jsxs(ProfileViewContextProvider, { value: { profileSource,
|
|
153
|
+
return (_jsx(KeyDownProvider, { children: _jsxs(ProfileViewContextProvider, { value: { profileSource, compareMode }, children: [_jsxs("div", { className: cx('mb-4 flex w-full', hasProfileSource || profileViewExternalMainActions != null
|
|
154
154
|
? 'justify-between'
|
|
155
155
|
: 'justify-end', {
|
|
156
156
|
'items-end': !hasProfileSource && profileViewExternalMainActions != null,
|
|
@@ -87,18 +87,6 @@ export const ProfileViewWithData = ({ queryClient, profileSource, navigateTo, })
|
|
|
87
87
|
sourceResponse,
|
|
88
88
|
perf,
|
|
89
89
|
]);
|
|
90
|
-
// Default to the unit of the selected profile type. This is a heuristic, and
|
|
91
|
-
// only a fallback, the unit should be returned by the backend.
|
|
92
|
-
let sampleUnit = profileSource.ProfileType().sampleUnit;
|
|
93
|
-
if (flamegraphResponse?.report.oneofKind === 'flamegraphArrow') {
|
|
94
|
-
sampleUnit = flamegraphResponse.report.flamegraphArrow.unit;
|
|
95
|
-
}
|
|
96
|
-
if (tableResponse?.report.oneofKind === 'tableArrow') {
|
|
97
|
-
sampleUnit = tableResponse.report.tableArrow.unit;
|
|
98
|
-
}
|
|
99
|
-
if (sourceResponse?.report.oneofKind === 'source') {
|
|
100
|
-
sampleUnit = sourceResponse.report.source.unit;
|
|
101
|
-
}
|
|
102
90
|
const downloadPProfClick = async () => {
|
|
103
91
|
if (profileSource == null || queryClient == null) {
|
|
104
92
|
return;
|
|
@@ -163,6 +151,6 @@ export const ProfileViewWithData = ({ queryClient, profileSource, navigateTo, })
|
|
|
163
151
|
? sourceResponse?.report?.source
|
|
164
152
|
: undefined,
|
|
165
153
|
error: sourceError,
|
|
166
|
-
},
|
|
154
|
+
}, profileSource: profileSource, queryClient: queryClient, navigateTo: navigateTo, onDownloadPProf: () => void downloadPProfClick(), pprofDownloading: pprofDownloading }));
|
|
167
155
|
};
|
|
168
156
|
export default ProfileViewWithData;
|
|
@@ -45,13 +45,13 @@ const intensityScale = scaleLinear().domain([0, 99]).range([0.05, 0.75]);
|
|
|
45
45
|
const LineProfileMetadata = ({ value, total, filtered, }) => {
|
|
46
46
|
const commonClasses = 'w-[52px] shrink-0';
|
|
47
47
|
const id = useId();
|
|
48
|
-
const {
|
|
48
|
+
const { profileSource } = useProfileViewContext();
|
|
49
49
|
if (value === 0n) {
|
|
50
50
|
return _jsx("div", { className: cx(commonClasses) });
|
|
51
51
|
}
|
|
52
52
|
const unfilteredPercent = (Number(value) / Number(total + filtered)) * 100;
|
|
53
53
|
const filteredPercent = (Number(value) / Number(total)) * 100;
|
|
54
|
-
const valueWithUnit = valueFormatter(value, sampleUnit, 1, true);
|
|
54
|
+
const valueWithUnit = valueFormatter(value, profileSource?.ProfileType().sampleUnit ?? '', 1, true);
|
|
55
55
|
return (_jsxs(_Fragment, { children: [_jsx("p", { className: cx('w- flex justify-end overflow-hidden text-ellipsis whitespace-nowrap', commonClasses), style: { backgroundColor: `rgba(236, 151, 6, ${intensityScale(unfilteredPercent)})` }, "data-tooltip-id": id, "data-tooltip-content": `${valueWithUnit} (${unfilteredPercent.toFixed(2)}%${filtered > 0n ? ` / ${filteredPercent.toFixed(2)}%` : ''})`, children: valueWithUnit }), _jsx(Tooltip, { id: id })] }));
|
|
56
56
|
};
|
|
57
57
|
const charsToWidth = (chars) => {
|
package/dist/Table/index.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import { Vector } from 'apache-arrow';
|
|
3
|
+
import { ProfileType } from '@parca/parser';
|
|
3
4
|
import { type NavigateFunction } from '@parca/utilities';
|
|
4
5
|
export interface ColumnDef {
|
|
5
6
|
id: string;
|
|
@@ -17,7 +18,7 @@ interface TableProps {
|
|
|
17
18
|
data?: Uint8Array;
|
|
18
19
|
total: bigint;
|
|
19
20
|
filtered: bigint;
|
|
20
|
-
|
|
21
|
+
profileType?: ProfileType;
|
|
21
22
|
navigateTo?: NavigateFunction;
|
|
22
23
|
loading: boolean;
|
|
23
24
|
currentSearchString?: string;
|
package/dist/Table/index.js
CHANGED
|
@@ -28,7 +28,7 @@ const FIELD_FLAT = 'flat';
|
|
|
28
28
|
const FIELD_FLAT_DIFF = 'flat_diff';
|
|
29
29
|
const FIELD_CUMULATIVE = 'cumulative';
|
|
30
30
|
const FIELD_CUMULATIVE_DIFF = 'cumulative_diff';
|
|
31
|
-
export const Table = React.memo(function Table({ data, total, filtered,
|
|
31
|
+
export const Table = React.memo(function Table({ data, total, filtered, profileType, navigateTo, loading, currentSearchString, setActionButtons, isHalfScreen, }) {
|
|
32
32
|
const router = parseParams(window?.location.search);
|
|
33
33
|
const [rawDashboardItems] = useURLState({ param: 'dashboard_items' });
|
|
34
34
|
const [filterByFunctionInput] = useURLState({ param: 'filter_by_function' });
|
|
@@ -59,7 +59,7 @@ export const Table = React.memo(function Table({ data, total, filtered, sampleUn
|
|
|
59
59
|
id: 'flat',
|
|
60
60
|
accessorKey: 'flat',
|
|
61
61
|
header: 'Flat',
|
|
62
|
-
cell: info => valueFormatter(info.getValue(),
|
|
62
|
+
cell: info => valueFormatter(info.getValue(), profileType?.sampleUnit ?? '', 2),
|
|
63
63
|
size: 80,
|
|
64
64
|
meta: {
|
|
65
65
|
align: 'right',
|
|
@@ -81,7 +81,7 @@ export const Table = React.memo(function Table({ data, total, filtered, sampleUn
|
|
|
81
81
|
id: 'flatDiff',
|
|
82
82
|
accessorKey: 'flatDiff',
|
|
83
83
|
header: 'Flat Diff',
|
|
84
|
-
cell: info => addPlusSign(valueFormatter(info.getValue(),
|
|
84
|
+
cell: info => addPlusSign(valueFormatter(info.getValue(), profileType?.sampleUnit ?? '', 2)),
|
|
85
85
|
size: 120,
|
|
86
86
|
meta: {
|
|
87
87
|
align: 'right',
|
|
@@ -103,7 +103,7 @@ export const Table = React.memo(function Table({ data, total, filtered, sampleUn
|
|
|
103
103
|
id: 'cumulative',
|
|
104
104
|
accessorKey: 'cumulative',
|
|
105
105
|
header: 'Cumulative',
|
|
106
|
-
cell: info => valueFormatter(info.getValue(),
|
|
106
|
+
cell: info => valueFormatter(info.getValue(), profileType?.sampleUnit ?? '', 2),
|
|
107
107
|
size: 150,
|
|
108
108
|
meta: {
|
|
109
109
|
align: 'right',
|
|
@@ -125,7 +125,7 @@ export const Table = React.memo(function Table({ data, total, filtered, sampleUn
|
|
|
125
125
|
id: 'cumulativeDiff',
|
|
126
126
|
accessorKey: 'cumulativeDiff',
|
|
127
127
|
header: 'Cumulative Diff',
|
|
128
|
-
cell: info => addPlusSign(valueFormatter(info.getValue(),
|
|
128
|
+
cell: info => addPlusSign(valueFormatter(info.getValue(), profileType?.sampleUnit ?? '', 2)),
|
|
129
129
|
size: 170,
|
|
130
130
|
meta: {
|
|
131
131
|
align: 'right',
|
|
@@ -166,7 +166,7 @@ export const Table = React.memo(function Table({ data, total, filtered, sampleUn
|
|
|
166
166
|
},
|
|
167
167
|
];
|
|
168
168
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
169
|
-
}, [
|
|
169
|
+
}, [profileType]);
|
|
170
170
|
const [columnVisibility, setColumnVisibility] = useState(() => {
|
|
171
171
|
return {
|
|
172
172
|
flat: true,
|
package/package.json
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@parca/profile",
|
|
3
|
-
"version": "0.16.
|
|
3
|
+
"version": "0.16.362",
|
|
4
4
|
"description": "Profile viewing libraries",
|
|
5
5
|
"dependencies": {
|
|
6
6
|
"@parca/client": "^0.16.107",
|
|
7
|
-
"@parca/components": "^0.16.
|
|
7
|
+
"@parca/components": "^0.16.267",
|
|
8
8
|
"@parca/dynamicsize": "^0.16.61",
|
|
9
|
-
"@parca/hooks": "^0.0.
|
|
9
|
+
"@parca/hooks": "^0.0.48",
|
|
10
10
|
"@parca/parser": "^0.16.69",
|
|
11
|
-
"@parca/store": "^0.16.
|
|
12
|
-
"@parca/utilities": "^0.0.
|
|
11
|
+
"@parca/store": "^0.16.137",
|
|
12
|
+
"@parca/utilities": "^0.0.65",
|
|
13
13
|
"@tanstack/react-query": "^4.0.5",
|
|
14
14
|
"@types/react-beautiful-dnd": "^13.1.8",
|
|
15
15
|
"apache-arrow": "^12.0.0",
|
|
@@ -50,5 +50,5 @@
|
|
|
50
50
|
"access": "public",
|
|
51
51
|
"registry": "https://registry.npmjs.org/"
|
|
52
52
|
},
|
|
53
|
-
"gitHead": "
|
|
53
|
+
"gitHead": "b9faf0a1236107753bda612b90d67c7d82e9583c"
|
|
54
54
|
}
|
package/src/Callgraph/index.tsx
CHANGED
|
@@ -20,6 +20,7 @@ import {MapInteractionCSS} from 'react-map-interaction';
|
|
|
20
20
|
|
|
21
21
|
import {CallgraphEdge, Callgraph as CallgraphType} from '@parca/client';
|
|
22
22
|
import {Button, useKeyDown, useURLState} from '@parca/components';
|
|
23
|
+
import {ProfileType} from '@parca/parser';
|
|
23
24
|
import {selectDarkMode, setHoveringNode, useAppDispatch, useAppSelector} from '@parca/store';
|
|
24
25
|
import {getNewSpanColor} from '@parca/utilities';
|
|
25
26
|
|
|
@@ -28,7 +29,7 @@ import GraphTooltip from '../GraphTooltip';
|
|
|
28
29
|
export interface Props {
|
|
29
30
|
data: CallgraphType;
|
|
30
31
|
svgString: string;
|
|
31
|
-
|
|
32
|
+
profileType: ProfileType | undefined;
|
|
32
33
|
width: number;
|
|
33
34
|
}
|
|
34
35
|
|
|
@@ -37,7 +38,7 @@ interface View {
|
|
|
37
38
|
translation: {x: number; y: number};
|
|
38
39
|
}
|
|
39
40
|
|
|
40
|
-
const Callgraph = ({data, svgString,
|
|
41
|
+
const Callgraph = ({data, svgString, profileType, width}: Props): JSX.Element => {
|
|
41
42
|
const originalView = {
|
|
42
43
|
scale: 1,
|
|
43
44
|
translation: {x: 0, y: 0},
|
|
@@ -147,7 +148,7 @@ const Callgraph = ({data, svgString, sampleUnit, width}: Props): JSX.Element =>
|
|
|
147
148
|
{svgRef.current !== null && (
|
|
148
149
|
<GraphTooltip
|
|
149
150
|
type="callgraph"
|
|
150
|
-
unit={sampleUnit}
|
|
151
|
+
unit={profileType?.sampleUnit ?? ''}
|
|
151
152
|
total={data.cumulative}
|
|
152
153
|
totalUnfiltered={data.cumulative}
|
|
153
154
|
contextElement={containerRef.current}
|
|
@@ -16,6 +16,7 @@ import React from 'react';
|
|
|
16
16
|
import {Icon} from '@iconify/react';
|
|
17
17
|
import {Table} from 'apache-arrow';
|
|
18
18
|
|
|
19
|
+
import {ProfileType} from '@parca/parser';
|
|
19
20
|
import {getLastItem, type NavigateFunction} from '@parca/utilities';
|
|
20
21
|
|
|
21
22
|
import {hexifyAddress, truncateString, truncateStringReverse} from '../utils';
|
|
@@ -25,7 +26,7 @@ import {useGraphTooltipMetaInfo} from './useGraphTooltipMetaInfo';
|
|
|
25
26
|
|
|
26
27
|
interface GraphTooltipArrowContentProps {
|
|
27
28
|
table: Table<any>;
|
|
28
|
-
|
|
29
|
+
profileType?: ProfileType;
|
|
29
30
|
total: bigint;
|
|
30
31
|
totalUnfiltered: bigint;
|
|
31
32
|
row: number | null;
|
|
@@ -40,7 +41,7 @@ const NoData = (): React.JSX.Element => {
|
|
|
40
41
|
|
|
41
42
|
const GraphTooltipArrowContent = ({
|
|
42
43
|
table,
|
|
43
|
-
|
|
44
|
+
profileType,
|
|
44
45
|
total,
|
|
45
46
|
totalUnfiltered,
|
|
46
47
|
row,
|
|
@@ -50,7 +51,7 @@ const GraphTooltipArrowContent = ({
|
|
|
50
51
|
}: GraphTooltipArrowContentProps): React.JSX.Element => {
|
|
51
52
|
const graphTooltipData = useGraphTooltip({
|
|
52
53
|
table,
|
|
53
|
-
|
|
54
|
+
profileType,
|
|
54
55
|
total,
|
|
55
56
|
totalUnfiltered,
|
|
56
57
|
row,
|
|
@@ -61,7 +62,15 @@ const GraphTooltipArrowContent = ({
|
|
|
61
62
|
return <></>;
|
|
62
63
|
}
|
|
63
64
|
|
|
64
|
-
const {
|
|
65
|
+
const {
|
|
66
|
+
name,
|
|
67
|
+
locationAddress,
|
|
68
|
+
cumulativeText,
|
|
69
|
+
cumulativePerSecondText,
|
|
70
|
+
diffText,
|
|
71
|
+
diff,
|
|
72
|
+
row: rowNumber,
|
|
73
|
+
} = graphTooltipData;
|
|
65
74
|
|
|
66
75
|
return (
|
|
67
76
|
<div className={`flex text-sm ${isFixed ? 'w-full' : ''}`}>
|
|
@@ -84,6 +93,16 @@ const GraphTooltipArrowContent = ({
|
|
|
84
93
|
</div>
|
|
85
94
|
<table className="my-2 w-full table-fixed pr-0 text-gray-700 dark:text-gray-300">
|
|
86
95
|
<tbody>
|
|
96
|
+
{profileType?.delta ?? false ? (
|
|
97
|
+
<tr>
|
|
98
|
+
<td className="w-1/4">Per Second</td>
|
|
99
|
+
<td className="w-3/4">
|
|
100
|
+
<div>{cumulativePerSecondText}</div>
|
|
101
|
+
</td>
|
|
102
|
+
</tr>
|
|
103
|
+
) : (
|
|
104
|
+
<></>
|
|
105
|
+
)}
|
|
87
106
|
<tr>
|
|
88
107
|
<td className="w-1/4">Cumulative</td>
|
|
89
108
|
|
|
@@ -17,6 +17,7 @@ import cx from 'classnames';
|
|
|
17
17
|
import {useWindowSize} from 'react-use';
|
|
18
18
|
|
|
19
19
|
import {useParcaContext} from '@parca/components';
|
|
20
|
+
import {ProfileType} from '@parca/parser';
|
|
20
21
|
import {getLastItem} from '@parca/utilities';
|
|
21
22
|
|
|
22
23
|
import {hexifyAddress, truncateString, truncateStringReverse} from '../../utils';
|
|
@@ -25,11 +26,11 @@ import {useGraphTooltipMetaInfo} from '../useGraphTooltipMetaInfo';
|
|
|
25
26
|
|
|
26
27
|
interface Props {
|
|
27
28
|
table: Table<any>;
|
|
28
|
-
unit: string;
|
|
29
29
|
total: bigint;
|
|
30
30
|
totalUnfiltered: bigint;
|
|
31
31
|
row: number | null;
|
|
32
32
|
level: number;
|
|
33
|
+
profileType?: ProfileType;
|
|
33
34
|
}
|
|
34
35
|
|
|
35
36
|
const InfoSection = ({
|
|
@@ -55,11 +56,11 @@ const NoData = (): React.JSX.Element => {
|
|
|
55
56
|
|
|
56
57
|
export const DockedGraphTooltip = ({
|
|
57
58
|
table,
|
|
58
|
-
unit,
|
|
59
59
|
total,
|
|
60
60
|
totalUnfiltered,
|
|
61
61
|
row,
|
|
62
62
|
level,
|
|
63
|
+
profileType,
|
|
63
64
|
}: Props): JSX.Element => {
|
|
64
65
|
let {width} = useWindowSize();
|
|
65
66
|
const {profileExplorer, navigateTo} = useParcaContext();
|
|
@@ -68,7 +69,7 @@ export const DockedGraphTooltip = ({
|
|
|
68
69
|
|
|
69
70
|
const graphTooltipData = useGraphTooltip({
|
|
70
71
|
table,
|
|
71
|
-
|
|
72
|
+
profileType,
|
|
72
73
|
total,
|
|
73
74
|
totalUnfiltered,
|
|
74
75
|
row,
|
|
@@ -13,18 +13,25 @@
|
|
|
13
13
|
|
|
14
14
|
import {Table} from 'apache-arrow';
|
|
15
15
|
|
|
16
|
+
import {ProfileType} from '@parca/parser';
|
|
16
17
|
import {divide, valueFormatter} from '@parca/utilities';
|
|
17
18
|
|
|
18
19
|
import {
|
|
19
20
|
FIELD_CUMULATIVE,
|
|
21
|
+
FIELD_CUMULATIVE_PER_SECOND,
|
|
20
22
|
FIELD_DIFF,
|
|
23
|
+
FIELD_DIFF_PER_SECOND,
|
|
21
24
|
FIELD_LOCATION_ADDRESS,
|
|
22
25
|
} from '../../ProfileIcicleGraph/IcicleGraphArrow';
|
|
23
|
-
import {
|
|
26
|
+
import {
|
|
27
|
+
getTextForCumulative,
|
|
28
|
+
getTextForCumulativePerSecond,
|
|
29
|
+
nodeLabel,
|
|
30
|
+
} from '../../ProfileIcicleGraph/IcicleGraphArrow/utils';
|
|
24
31
|
|
|
25
32
|
interface Props {
|
|
26
33
|
table: Table<any>;
|
|
27
|
-
|
|
34
|
+
profileType?: ProfileType;
|
|
28
35
|
total: bigint;
|
|
29
36
|
totalUnfiltered: bigint;
|
|
30
37
|
row: number | null;
|
|
@@ -35,6 +42,7 @@ interface GraphTooltipData {
|
|
|
35
42
|
name: string;
|
|
36
43
|
locationAddress: bigint;
|
|
37
44
|
cumulativeText: string;
|
|
45
|
+
cumulativePerSecondText: string;
|
|
38
46
|
diffText: string;
|
|
39
47
|
diff: bigint;
|
|
40
48
|
row: number;
|
|
@@ -42,13 +50,13 @@ interface GraphTooltipData {
|
|
|
42
50
|
|
|
43
51
|
export const useGraphTooltip = ({
|
|
44
52
|
table,
|
|
45
|
-
|
|
53
|
+
profileType,
|
|
46
54
|
total,
|
|
47
55
|
totalUnfiltered,
|
|
48
56
|
row,
|
|
49
57
|
level,
|
|
50
58
|
}: Props): GraphTooltipData | null => {
|
|
51
|
-
if (row === null) {
|
|
59
|
+
if (row === null || profileType === undefined) {
|
|
52
60
|
return null;
|
|
53
61
|
}
|
|
54
62
|
|
|
@@ -58,24 +66,51 @@ export const useGraphTooltip = ({
|
|
|
58
66
|
table.getChild(FIELD_CUMULATIVE)?.get(row) !== null
|
|
59
67
|
? BigInt(table.getChild(FIELD_CUMULATIVE)?.get(row))
|
|
60
68
|
: 0n;
|
|
69
|
+
const cumulativePerSecond: number =
|
|
70
|
+
table.getChild(FIELD_CUMULATIVE_PER_SECOND)?.get(row) !== null
|
|
71
|
+
? table.getChild(FIELD_CUMULATIVE_PER_SECOND)?.get(row)
|
|
72
|
+
: 0;
|
|
61
73
|
const diff: bigint =
|
|
62
74
|
table.getChild(FIELD_DIFF)?.get(row) !== null
|
|
63
75
|
? BigInt(table.getChild(FIELD_DIFF)?.get(row))
|
|
64
76
|
: 0n;
|
|
77
|
+
const diffPerSecond: number =
|
|
78
|
+
table.getChild(FIELD_DIFF_PER_SECOND)?.get(row) !== null
|
|
79
|
+
? table.getChild(FIELD_DIFF_PER_SECOND)?.get(row)
|
|
80
|
+
: 0;
|
|
65
81
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
82
|
+
let diffText = '';
|
|
83
|
+
if (profileType?.delta ?? false) {
|
|
84
|
+
const prevValue = cumulativePerSecond - diffPerSecond;
|
|
85
|
+
const diffRatio = diffPerSecond !== 0 ? diffPerSecond / prevValue : 0;
|
|
86
|
+
const diffSign = diffPerSecond > 0 ? '+' : '';
|
|
87
|
+
const diffValueText = diffSign + valueFormatter(diffPerSecond, 'CPU Cores', 5);
|
|
88
|
+
const diffPercentageText = diffSign + (diffRatio * 100).toFixed(2) + '%';
|
|
89
|
+
diffText = `${diffValueText} (${diffPercentageText})`;
|
|
90
|
+
} else {
|
|
91
|
+
const prevValue = cumulative - diff;
|
|
92
|
+
const diffRatio = diff !== 0n ? divide(diff, prevValue) : 0;
|
|
93
|
+
const diffSign = diff > 0 ? '+' : '';
|
|
94
|
+
const diffValueText = diffSign + valueFormatter(diff, profileType?.sampleUnit ?? '', 1);
|
|
95
|
+
const diffPercentageText = diffSign + (diffRatio * 100).toFixed(2) + '%';
|
|
96
|
+
diffText = `${diffValueText} (${diffPercentageText})`;
|
|
97
|
+
}
|
|
72
98
|
|
|
73
99
|
const name = nodeLabel(table, row, level, false);
|
|
74
100
|
|
|
75
101
|
return {
|
|
76
102
|
name,
|
|
77
103
|
locationAddress,
|
|
78
|
-
cumulativeText: getTextForCumulative(
|
|
104
|
+
cumulativeText: getTextForCumulative(
|
|
105
|
+
cumulative,
|
|
106
|
+
totalUnfiltered,
|
|
107
|
+
total,
|
|
108
|
+
profileType?.periodUnit ?? ''
|
|
109
|
+
),
|
|
110
|
+
cumulativePerSecondText: getTextForCumulativePerSecond(
|
|
111
|
+
cumulativePerSecond,
|
|
112
|
+
profileType?.periodUnit ?? 'CPU Cores'
|
|
113
|
+
),
|
|
79
114
|
diffText,
|
|
80
115
|
diff,
|
|
81
116
|
row,
|
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
import {memo, useEffect, useMemo, useRef, useState} from 'react';
|
|
15
15
|
|
|
16
16
|
import {Flamegraph} from '@parca/client';
|
|
17
|
+
import {ProfileType} from '@parca/parser';
|
|
17
18
|
import {setHoveringNode, useAppDispatch} from '@parca/store';
|
|
18
19
|
import {scaleLinear, selectQueryParam, type NavigateFunction} from '@parca/utilities';
|
|
19
20
|
|
|
@@ -27,7 +28,7 @@ interface IcicleGraphProps {
|
|
|
27
28
|
graph: Flamegraph;
|
|
28
29
|
total: bigint;
|
|
29
30
|
filtered: bigint;
|
|
30
|
-
|
|
31
|
+
profileType?: ProfileType;
|
|
31
32
|
width?: number;
|
|
32
33
|
curPath: string[];
|
|
33
34
|
setCurPath: (path: string[]) => void;
|
|
@@ -41,7 +42,7 @@ export const IcicleGraph = memo(function IcicleGraph({
|
|
|
41
42
|
width,
|
|
42
43
|
setCurPath,
|
|
43
44
|
curPath,
|
|
44
|
-
|
|
45
|
+
profileType,
|
|
45
46
|
navigateTo,
|
|
46
47
|
}: IcicleGraphProps): JSX.Element {
|
|
47
48
|
const dispatch = useAppDispatch();
|
|
@@ -77,7 +78,7 @@ export const IcicleGraph = memo(function IcicleGraph({
|
|
|
77
78
|
<ColorStackLegend navigateTo={navigateTo} compareMode={compareMode} />
|
|
78
79
|
)}
|
|
79
80
|
<GraphTooltip
|
|
80
|
-
unit={sampleUnit}
|
|
81
|
+
unit={profileType?.sampleUnit ?? ''}
|
|
81
82
|
total={total}
|
|
82
83
|
totalUnfiltered={total + filtered}
|
|
83
84
|
contextElement={svg.current}
|
|
@@ -18,6 +18,7 @@ import {Tooltip} from 'react-tooltip';
|
|
|
18
18
|
|
|
19
19
|
import {useParcaContext} from '@parca/components';
|
|
20
20
|
import {USER_PREFERENCES, useUserPreference} from '@parca/hooks';
|
|
21
|
+
import {ProfileType} from '@parca/parser';
|
|
21
22
|
import {type NavigateFunction} from '@parca/utilities';
|
|
22
23
|
|
|
23
24
|
import {useGraphTooltip} from '../../GraphTooltipArrow/useGraphTooltip';
|
|
@@ -27,7 +28,7 @@ import {hexifyAddress, truncateString} from '../../utils';
|
|
|
27
28
|
interface ContextMenuProps {
|
|
28
29
|
menuId: string;
|
|
29
30
|
table: Table<any>;
|
|
30
|
-
|
|
31
|
+
profileType?: ProfileType;
|
|
31
32
|
total: bigint;
|
|
32
33
|
totalUnfiltered: bigint;
|
|
33
34
|
row: number;
|
|
@@ -42,7 +43,6 @@ interface ContextMenuProps {
|
|
|
42
43
|
const ContextMenu = ({
|
|
43
44
|
menuId,
|
|
44
45
|
table,
|
|
45
|
-
unit,
|
|
46
46
|
total,
|
|
47
47
|
totalUnfiltered,
|
|
48
48
|
row,
|
|
@@ -52,6 +52,7 @@ const ContextMenu = ({
|
|
|
52
52
|
curPath,
|
|
53
53
|
setCurPath,
|
|
54
54
|
hideMenu,
|
|
55
|
+
profileType,
|
|
55
56
|
}: ContextMenuProps): JSX.Element => {
|
|
56
57
|
const {isDarkMode} = useParcaContext();
|
|
57
58
|
const {enableSourcesView} = useParcaContext();
|
|
@@ -60,7 +61,7 @@ const ContextMenu = ({
|
|
|
60
61
|
);
|
|
61
62
|
const contextMenuData = useGraphTooltip({
|
|
62
63
|
table,
|
|
63
|
-
|
|
64
|
+
profileType,
|
|
64
65
|
total,
|
|
65
66
|
totalUnfiltered,
|
|
66
67
|
row,
|