@parca/profile 0.16.400 → 0.16.402
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/GraphTooltipArrow/DockedGraphTooltip/index.js +4 -2
- package/dist/ProfileExplorer/ProfileExplorerCompare.js +3 -2
- package/dist/ProfileIcicleGraph/index.js +13 -1
- package/dist/ProfileSource.d.ts +2 -1
- package/dist/ProfileSource.js +5 -3
- package/package.json +7 -7
- package/src/GraphTooltipArrow/DockedGraphTooltip/index.tsx +14 -2
- package/src/ProfileExplorer/ProfileExplorerCompare.tsx +9 -2
- package/src/ProfileIcicleGraph/index.tsx +27 -1
- package/src/ProfileSource.tsx +6 -3
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.402](https://github.com/parca-dev/parca/compare/@parca/profile@0.16.401...@parca/profile@0.16.402) (2024-07-04)
|
|
7
|
+
|
|
8
|
+
**Note:** Version bump only for package @parca/profile
|
|
9
|
+
|
|
10
|
+
## [0.16.401](https://github.com/parca-dev/parca/compare/@parca/profile@0.16.400...@parca/profile@0.16.401) (2024-07-03)
|
|
11
|
+
|
|
12
|
+
**Note:** Version bump only for package @parca/profile
|
|
13
|
+
|
|
6
14
|
## [0.16.400](https://github.com/parca-dev/parca/compare/@parca/profile@0.16.399...@parca/profile@0.16.400) (2024-07-02)
|
|
7
15
|
|
|
8
16
|
**Note:** Version bump only for package @parca/profile
|
|
@@ -43,14 +43,16 @@ export const DockedGraphTooltip = ({ table, total, totalUnfiltered, row, level,
|
|
|
43
43
|
if (graphTooltipData === null) {
|
|
44
44
|
return _jsx(_Fragment, {});
|
|
45
45
|
}
|
|
46
|
-
const { name, cumulativeText, diffText, diff } = graphTooltipData;
|
|
46
|
+
const { name, cumulativeText, cumulativePerSecondText, flatText, flatPerSecondText, diffText, diff, } = graphTooltipData;
|
|
47
47
|
const labels = labelPairs.map((l) => (_jsx("span", { className: "mr-3 inline-block rounded-lg bg-gray-200 px-2 py-1 text-xs font-bold text-gray-700 dark:bg-gray-700 dark:text-gray-400", children: `${l[0]}="${l[1]}"` }, l[0])));
|
|
48
48
|
const isMappingBuildIDAvailable = mappingBuildID !== null && mappingBuildID !== '';
|
|
49
49
|
const inlinedText = inlined === null ? 'merged' : inlined ? 'yes' : 'no';
|
|
50
50
|
const addressText = locationAddress !== 0n ? hexifyAddress(locationAddress) : _jsx(NoData, {});
|
|
51
|
+
const cumulativeTextBoth = `${cumulativeText}\n${cumulativePerSecondText}`;
|
|
52
|
+
const flatTextBoth = `${flatText}\n${flatPerSecondText}`;
|
|
51
53
|
return (_jsxs("div", { className: "fixed bottom-0 z-20 overflow-hidden rounded-t-lg border-l border-r border-t border-gray-400 bg-white bg-opacity-90 px-8 py-3 dark:border-gray-600 dark:bg-black dark:bg-opacity-80", style: { width }, children: [_jsxs("div", { className: "flex flex-col gap-4", children: [_jsx("div", { className: "flex justify-between gap-4", children: row === 0 ? (_jsx("p", { children: "root" })) : (_jsx("p", { children: name !== ''
|
|
52
54
|
? name
|
|
53
55
|
: locationAddress !== 0n
|
|
54
56
|
? hexifyAddress(locationAddress)
|
|
55
|
-
: 'unknown' })) }), _jsxs("div", { className: "flex justify-between gap-3", children: [_jsx(InfoSection, { title: "Cumulative", value:
|
|
57
|
+
: 'unknown' })) }), _jsxs("div", { className: "flex justify-between gap-3", children: [_jsx(InfoSection, { title: "Cumulative", value: cumulativeTextBoth, minWidth: "w-44" }), _jsx(InfoSection, { title: "Flat", value: flatTextBoth, minWidth: "w-44" }), diff !== 0n ? _jsx(InfoSection, { title: "Diff", value: diffText, minWidth: "w-44" }) : null, _jsx(InfoSection, { title: "File", value: functionFilename !== '' ? truncateStringReverse(file, 45) : _jsx(NoData, {}), minWidth: 'w-[460px]' }), _jsx(InfoSection, { title: "Address", value: addressText, minWidth: "w-44" }), _jsx(InfoSection, { title: "Inlined", value: inlinedText, minWidth: "w-44" }), _jsx(InfoSection, { title: "Binary", value: (mappingFile != null ? getLastItem(mappingFile) : null) ?? _jsx(NoData, {}), minWidth: "w-44" }), _jsx(InfoSection, { title: "Build ID", value: isMappingBuildIDAvailable ? (_jsx("div", { children: truncateString(mappingBuildID, 28) })) : (_jsx(NoData, {})) })] }), _jsx("div", { children: _jsx("div", { className: "flex h-5 gap-1", children: labels }) })] }), _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" })] })] }));
|
|
56
58
|
};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
-
import { Card } from '@parca/components';
|
|
2
|
+
import { Card, useURLState } from '@parca/components';
|
|
3
3
|
import { Query } from '@parca/parser';
|
|
4
4
|
import { ProfileDiffSource, ProfileViewWithData } from '..';
|
|
5
5
|
import ProfileSelector from '../ProfileSelector';
|
|
@@ -10,6 +10,7 @@ const ProfileExplorerCompare = ({ queryClient, queryA, queryB, profileA, profile
|
|
|
10
10
|
const closeProfileB = () => {
|
|
11
11
|
closeProfile('B');
|
|
12
12
|
};
|
|
13
|
-
|
|
13
|
+
const [compareAbsolute] = useURLState({ param: 'compare_absolute', navigateTo });
|
|
14
|
+
return (_jsxs(_Fragment, { children: [_jsxs("div", { className: "flex justify-between gap-2", children: [_jsx(Card, { className: "mt-2 p-2", children: _jsx(ProfileSelector, { queryClient: queryClient, querySelection: queryA, profileSelection: profileA, selectProfile: selectProfileA, selectQuery: selectQueryA, closeProfile: closeProfileA, enforcedProfileName: '', comparing: true, navigateTo: navigateTo }) }), _jsx(Card, { className: "mt-2 p-2", children: _jsx(ProfileSelector, { queryClient: queryClient, querySelection: queryB, profileSelection: profileB, selectProfile: selectProfileB, selectQuery: selectQueryB, closeProfile: closeProfileB, enforcedProfileName: Query.parse(queryA.expression).profileName(), comparing: true, navigateTo: navigateTo }) })] }), _jsx("div", { className: "grid grid-cols-1", children: profileA != null && profileB != null ? (_jsx("div", { children: _jsx(Card, { className: "mt-2 px-6 py-4", children: _jsx(ProfileViewWithData, { navigateTo: navigateTo, queryClient: queryClient, profileSource: new ProfileDiffSource(profileA.ProfileSource(), profileB.ProfileSource(), '', compareAbsolute === 'true') }) }) })) : (_jsx("div", { children: _jsx("div", { className: "my-20 text-center", children: _jsx("p", { children: "Select a profile on both sides." }) }) })) })] }));
|
|
14
15
|
};
|
|
15
16
|
export default ProfileExplorerCompare;
|
|
@@ -93,6 +93,15 @@ const ProfileIcicleGraph = function ProfileIcicleGraphNonMemo({ graph, arrow, to
|
|
|
93
93
|
navigateTo,
|
|
94
94
|
});
|
|
95
95
|
const isInvert = invertStack === 'true';
|
|
96
|
+
// By default, we want delta profiles (CPU) to be relatively compared.
|
|
97
|
+
// For non-delta profiles, like goroutines or memory, we want the profiles to be compared absolutely.
|
|
98
|
+
const compareAbsoluteDefault = profileType?.delta === false ? 'true' : 'false';
|
|
99
|
+
const [compareAbsolute = compareAbsoluteDefault, setCompareAbsolute] = useURLState({
|
|
100
|
+
param: 'compare_absolute',
|
|
101
|
+
navigateTo,
|
|
102
|
+
withURLUpdate: true,
|
|
103
|
+
});
|
|
104
|
+
const isCompareAbsolute = compareAbsolute === 'true';
|
|
96
105
|
const [totalFormatted, totalUnfilteredFormatted, isTrimmed, trimmedFormatted, trimmedPercentage, isFiltered, filteredPercentage,] = useMemo(() => {
|
|
97
106
|
if (graph === undefined && arrow === undefined) {
|
|
98
107
|
return ['0', '0', false, '0', '0', false, '0', '0'];
|
|
@@ -112,7 +121,7 @@ const ProfileIcicleGraph = function ProfileIcicleGraphNonMemo({ graph, arrow, to
|
|
|
112
121
|
];
|
|
113
122
|
}, [graph, arrow, filtered, total]);
|
|
114
123
|
useEffect(() => {
|
|
115
|
-
setActionButtons?.(_jsx("div", { className: "flex w-full justify-end gap-2 pb-2", children: _jsxs("div", { className: "ml-2 flex w-full flex-col items-start justify-between gap-2 md:flex-row md:items-end", children: [_jsx(GroupAndSortActionButtons, { navigateTo: navigateTo }), isHalfScreen ? (_jsx(IconButton, { icon: isInvert ? 'ph:sort-ascending' : 'ph:sort-descending', toolTipText: isInvert ? 'Original Call Stack' : 'Invert Call Stack', onClick: () => setInvertStack(isInvert ? '' : 'true'), className: "rounded-md focus:outline-none focus:ring-2 focus:ring-offset-2 items-center flex border border-gray-200 dark:border-gray-600 dark:text-white justify-center py-2 px-3 cursor-pointer min-h-[38px]" })) : (_jsxs(Button, { variant: "neutral", className: "gap-2 w-max", onClick: () => setInvertStack(isInvert ? '' : 'true'), children: [isInvert ? 'Original Call Stack' : 'Invert Call Stack', _jsx(Icon, { icon: isInvert ? 'ph:sort-ascending' : 'ph:sort-descending', width: 20 })] })), _jsx(ShowHideLegendButton, { isHalfScreen: isHalfScreen, navigateTo: navigateTo }), isHalfScreen ? (_jsx(IconButton, { icon: "system-uicons:reset", disabled: curPath.length === 0, toolTipText: "Reset View", onClick: () => setNewCurPath([]), className: "rounded-md focus:outline-none focus:ring-2 focus:ring-offset-2 items-center flex border border-gray-200 dark:border-gray-600 dark:text-white justify-center py-2 px-3 cursor-pointer min-h-[38px]" })) : (_jsxs(Button, { variant: "neutral", className: "gap-2 w-max", onClick: () => setNewCurPath([]), disabled: curPath.length === 0, children: ["Reset View", _jsx(Icon, { icon: "system-uicons:reset", width: 20 })] }))] }) }));
|
|
124
|
+
setActionButtons?.(_jsx("div", { className: "flex w-full justify-end gap-2 pb-2", children: _jsxs("div", { className: "ml-2 flex w-full flex-col items-start justify-between gap-2 md:flex-row md:items-end", children: [_jsx(GroupAndSortActionButtons, { navigateTo: navigateTo }), isHalfScreen ? (_jsx(IconButton, { icon: isInvert ? 'ph:sort-ascending' : 'ph:sort-descending', toolTipText: isInvert ? 'Original Call Stack' : 'Invert Call Stack', onClick: () => setInvertStack(isInvert ? '' : 'true'), className: "rounded-md focus:outline-none focus:ring-2 focus:ring-offset-2 items-center flex border border-gray-200 dark:border-gray-600 dark:text-white justify-center py-2 px-3 cursor-pointer min-h-[38px]" })) : (_jsxs(Button, { variant: "neutral", className: "gap-2 w-max", onClick: () => setInvertStack(isInvert ? '' : 'true'), children: [isInvert ? 'Original Call Stack' : 'Invert Call Stack', _jsx(Icon, { icon: isInvert ? 'ph:sort-ascending' : 'ph:sort-descending', width: 20 })] })), _jsx(ShowHideLegendButton, { isHalfScreen: isHalfScreen, navigateTo: navigateTo }), compareMode && (_jsxs(Button, { variant: "neutral", className: "gap-2 w-max", onClick: () => setCompareAbsolute(isCompareAbsolute ? '' : 'true'), children: [isCompareAbsolute ? 'Compare Relative' : 'Compare Absolute', _jsx(Icon, { icon: isCompareAbsolute ? 'fluent-mdl2:compare' : 'fluent-mdl2:compare-uneven', width: 20 })] })), isHalfScreen ? (_jsx(IconButton, { icon: "system-uicons:reset", disabled: curPath.length === 0, toolTipText: "Reset View", onClick: () => setNewCurPath([]), className: "rounded-md focus:outline-none focus:ring-2 focus:ring-offset-2 items-center flex border border-gray-200 dark:border-gray-600 dark:text-white justify-center py-2 px-3 cursor-pointer min-h-[38px]" })) : (_jsxs(Button, { variant: "neutral", className: "gap-2 w-max", onClick: () => setNewCurPath([]), disabled: curPath.length === 0, children: ["Reset View", _jsx(Icon, { icon: "system-uicons:reset", width: 20 })] }))] }) }));
|
|
116
125
|
}, [
|
|
117
126
|
navigateTo,
|
|
118
127
|
isInvert,
|
|
@@ -124,6 +133,9 @@ const ProfileIcicleGraph = function ProfileIcicleGraphNonMemo({ graph, arrow, to
|
|
|
124
133
|
loading,
|
|
125
134
|
isHalfScreen,
|
|
126
135
|
isLoading,
|
|
136
|
+
compareMode,
|
|
137
|
+
isCompareAbsolute,
|
|
138
|
+
setCompareAbsolute,
|
|
127
139
|
]);
|
|
128
140
|
const loadingState = !loading && (arrow !== undefined || graph !== undefined) && mappings !== undefined;
|
|
129
141
|
useEffect(() => {
|
package/dist/ProfileSource.d.ts
CHANGED
|
@@ -42,7 +42,8 @@ export declare class ProfileDiffSource implements ProfileSource {
|
|
|
42
42
|
b: ProfileSource;
|
|
43
43
|
filterQuery: string | undefined;
|
|
44
44
|
profileType: ProfileType;
|
|
45
|
-
|
|
45
|
+
absolute?: boolean;
|
|
46
|
+
constructor(a: ProfileSource, b: ProfileSource, filterQuery?: string, absolute?: boolean);
|
|
46
47
|
DiffSelection(): ProfileDiffSelection;
|
|
47
48
|
QueryRequest(): QueryRequest;
|
|
48
49
|
ProfileType(): ProfileType;
|
package/dist/ProfileSource.js
CHANGED
|
@@ -73,11 +73,12 @@ export class MergedProfileSelection {
|
|
|
73
73
|
}
|
|
74
74
|
}
|
|
75
75
|
export class ProfileDiffSource {
|
|
76
|
-
constructor(a, b, filterQuery) {
|
|
76
|
+
constructor(a, b, filterQuery, absolute) {
|
|
77
77
|
this.a = a;
|
|
78
78
|
this.b = b;
|
|
79
79
|
this.filterQuery = filterQuery;
|
|
80
80
|
this.profileType = a.ProfileType();
|
|
81
|
+
this.absolute = absolute;
|
|
81
82
|
}
|
|
82
83
|
DiffSelection() {
|
|
83
84
|
throw new Error('Method not implemented.');
|
|
@@ -89,9 +90,10 @@ export class ProfileDiffSource {
|
|
|
89
90
|
diff: {
|
|
90
91
|
a: this.a.DiffSelection(),
|
|
91
92
|
b: this.b.DiffSelection(),
|
|
93
|
+
absolute: this.absolute,
|
|
92
94
|
},
|
|
93
95
|
},
|
|
94
|
-
reportType: QueryRequest_ReportType.
|
|
96
|
+
reportType: QueryRequest_ReportType.FLAMEGRAPH_ARROW,
|
|
95
97
|
mode: QueryRequest_Mode.DIFF,
|
|
96
98
|
filterQuery: this.filterQuery,
|
|
97
99
|
filter: [],
|
|
@@ -143,7 +145,7 @@ export class MergedProfileSource {
|
|
|
143
145
|
query: this.query.toString(),
|
|
144
146
|
},
|
|
145
147
|
},
|
|
146
|
-
reportType: QueryRequest_ReportType.
|
|
148
|
+
reportType: QueryRequest_ReportType.FLAMEGRAPH_ARROW,
|
|
147
149
|
mode: QueryRequest_Mode.MERGE,
|
|
148
150
|
filterQuery: this.filterQuery,
|
|
149
151
|
filter: [],
|
package/package.json
CHANGED
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@parca/profile",
|
|
3
|
-
"version": "0.16.
|
|
3
|
+
"version": "0.16.402",
|
|
4
4
|
"description": "Profile viewing libraries",
|
|
5
5
|
"dependencies": {
|
|
6
6
|
"@headlessui/react": "^1.7.19",
|
|
7
7
|
"@iconify/react": "^4.0.0",
|
|
8
|
-
"@parca/client": "0.16.
|
|
9
|
-
"@parca/components": "0.16.
|
|
8
|
+
"@parca/client": "0.16.120",
|
|
9
|
+
"@parca/components": "0.16.290",
|
|
10
10
|
"@parca/dynamicsize": "0.16.65",
|
|
11
|
-
"@parca/hooks": "0.0.
|
|
11
|
+
"@parca/hooks": "0.0.65",
|
|
12
12
|
"@parca/icons": "0.16.70",
|
|
13
13
|
"@parca/parser": "0.16.77",
|
|
14
|
-
"@parca/store": "0.16.
|
|
15
|
-
"@parca/utilities": "0.0.
|
|
14
|
+
"@parca/store": "0.16.154",
|
|
15
|
+
"@parca/utilities": "0.0.81",
|
|
16
16
|
"@popperjs/core": "^2.11.8",
|
|
17
17
|
"@protobuf-ts/runtime-rpc": "^2.5.0",
|
|
18
18
|
"@tanstack/react-query": "^4.0.5",
|
|
@@ -73,5 +73,5 @@
|
|
|
73
73
|
"access": "public",
|
|
74
74
|
"registry": "https://registry.npmjs.org/"
|
|
75
75
|
},
|
|
76
|
-
"gitHead": "
|
|
76
|
+
"gitHead": "25851d40d2630dbb542747d3a09718363212ad0e"
|
|
77
77
|
}
|
|
@@ -93,7 +93,15 @@ export const DockedGraphTooltip = ({
|
|
|
93
93
|
return <></>;
|
|
94
94
|
}
|
|
95
95
|
|
|
96
|
-
const {
|
|
96
|
+
const {
|
|
97
|
+
name,
|
|
98
|
+
cumulativeText,
|
|
99
|
+
cumulativePerSecondText,
|
|
100
|
+
flatText,
|
|
101
|
+
flatPerSecondText,
|
|
102
|
+
diffText,
|
|
103
|
+
diff,
|
|
104
|
+
} = graphTooltipData;
|
|
97
105
|
|
|
98
106
|
const labels = labelPairs.map(
|
|
99
107
|
(l): React.JSX.Element => (
|
|
@@ -110,6 +118,9 @@ export const DockedGraphTooltip = ({
|
|
|
110
118
|
const inlinedText = inlined === null ? 'merged' : inlined ? 'yes' : 'no';
|
|
111
119
|
const addressText = locationAddress !== 0n ? hexifyAddress(locationAddress) : <NoData />;
|
|
112
120
|
|
|
121
|
+
const cumulativeTextBoth = `${cumulativeText}\n${cumulativePerSecondText}`;
|
|
122
|
+
const flatTextBoth = `${flatText}\n${flatPerSecondText}`;
|
|
123
|
+
|
|
113
124
|
return (
|
|
114
125
|
<div
|
|
115
126
|
className="fixed bottom-0 z-20 overflow-hidden rounded-t-lg border-l border-r border-t border-gray-400 bg-white bg-opacity-90 px-8 py-3 dark:border-gray-600 dark:bg-black dark:bg-opacity-80"
|
|
@@ -130,7 +141,8 @@ export const DockedGraphTooltip = ({
|
|
|
130
141
|
)}
|
|
131
142
|
</div>
|
|
132
143
|
<div className="flex justify-between gap-3">
|
|
133
|
-
<InfoSection title="Cumulative" value={
|
|
144
|
+
<InfoSection title="Cumulative" value={cumulativeTextBoth} minWidth="w-44" />
|
|
145
|
+
<InfoSection title="Flat" value={flatTextBoth} minWidth="w-44" />
|
|
134
146
|
{diff !== 0n ? <InfoSection title="Diff" value={diffText} minWidth="w-44" /> : null}
|
|
135
147
|
<InfoSection
|
|
136
148
|
title="File"
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
// limitations under the License.
|
|
13
13
|
|
|
14
14
|
import {QueryServiceClient} from '@parca/client';
|
|
15
|
-
import {Card} from '@parca/components';
|
|
15
|
+
import {Card, useURLState} from '@parca/components';
|
|
16
16
|
import {Query} from '@parca/parser';
|
|
17
17
|
import type {NavigateFunction} from '@parca/utilities';
|
|
18
18
|
|
|
@@ -56,6 +56,8 @@ const ProfileExplorerCompare = ({
|
|
|
56
56
|
closeProfile('B');
|
|
57
57
|
};
|
|
58
58
|
|
|
59
|
+
const [compareAbsolute] = useURLState({param: 'compare_absolute', navigateTo});
|
|
60
|
+
|
|
59
61
|
return (
|
|
60
62
|
<>
|
|
61
63
|
<div className="flex justify-between gap-2">
|
|
@@ -94,7 +96,12 @@ const ProfileExplorerCompare = ({
|
|
|
94
96
|
navigateTo={navigateTo}
|
|
95
97
|
queryClient={queryClient}
|
|
96
98
|
profileSource={
|
|
97
|
-
new ProfileDiffSource(
|
|
99
|
+
new ProfileDiffSource(
|
|
100
|
+
profileA.ProfileSource(),
|
|
101
|
+
profileB.ProfileSource(),
|
|
102
|
+
'',
|
|
103
|
+
compareAbsolute === 'true'
|
|
104
|
+
)
|
|
98
105
|
}
|
|
99
106
|
/>
|
|
100
107
|
</Card>
|
|
@@ -238,9 +238,19 @@ const ProfileIcicleGraph = function ProfileIcicleGraphNonMemo({
|
|
|
238
238
|
param: 'invert_call_stack',
|
|
239
239
|
navigateTo,
|
|
240
240
|
});
|
|
241
|
-
|
|
242
241
|
const isInvert = invertStack === 'true';
|
|
243
242
|
|
|
243
|
+
// By default, we want delta profiles (CPU) to be relatively compared.
|
|
244
|
+
// For non-delta profiles, like goroutines or memory, we want the profiles to be compared absolutely.
|
|
245
|
+
const compareAbsoluteDefault = profileType?.delta === false ? 'true' : 'false';
|
|
246
|
+
|
|
247
|
+
const [compareAbsolute = compareAbsoluteDefault, setCompareAbsolute] = useURLState({
|
|
248
|
+
param: 'compare_absolute',
|
|
249
|
+
navigateTo,
|
|
250
|
+
withURLUpdate: true,
|
|
251
|
+
});
|
|
252
|
+
const isCompareAbsolute = compareAbsolute === 'true';
|
|
253
|
+
|
|
244
254
|
const [
|
|
245
255
|
totalFormatted,
|
|
246
256
|
totalUnfilteredFormatted,
|
|
@@ -294,6 +304,19 @@ const ProfileIcicleGraph = function ProfileIcicleGraphNonMemo({
|
|
|
294
304
|
</Button>
|
|
295
305
|
)}
|
|
296
306
|
<ShowHideLegendButton isHalfScreen={isHalfScreen} navigateTo={navigateTo} />
|
|
307
|
+
{compareMode && (
|
|
308
|
+
<Button
|
|
309
|
+
variant="neutral"
|
|
310
|
+
className="gap-2 w-max"
|
|
311
|
+
onClick={() => setCompareAbsolute(isCompareAbsolute ? '' : 'true')}
|
|
312
|
+
>
|
|
313
|
+
{isCompareAbsolute ? 'Compare Relative' : 'Compare Absolute'}
|
|
314
|
+
<Icon
|
|
315
|
+
icon={isCompareAbsolute ? 'fluent-mdl2:compare' : 'fluent-mdl2:compare-uneven'}
|
|
316
|
+
width={20}
|
|
317
|
+
/>
|
|
318
|
+
</Button>
|
|
319
|
+
)}
|
|
297
320
|
{isHalfScreen ? (
|
|
298
321
|
<IconButton
|
|
299
322
|
icon="system-uicons:reset"
|
|
@@ -327,6 +350,9 @@ const ProfileIcicleGraph = function ProfileIcicleGraphNonMemo({
|
|
|
327
350
|
loading,
|
|
328
351
|
isHalfScreen,
|
|
329
352
|
isLoading,
|
|
353
|
+
compareMode,
|
|
354
|
+
isCompareAbsolute,
|
|
355
|
+
setCompareAbsolute,
|
|
330
356
|
]);
|
|
331
357
|
|
|
332
358
|
const loadingState =
|
package/src/ProfileSource.tsx
CHANGED
|
@@ -136,12 +136,14 @@ export class ProfileDiffSource implements ProfileSource {
|
|
|
136
136
|
b: ProfileSource;
|
|
137
137
|
filterQuery: string | undefined;
|
|
138
138
|
profileType: ProfileType;
|
|
139
|
+
absolute?: boolean;
|
|
139
140
|
|
|
140
|
-
constructor(a: ProfileSource, b: ProfileSource, filterQuery?: string) {
|
|
141
|
+
constructor(a: ProfileSource, b: ProfileSource, filterQuery?: string, absolute?: boolean) {
|
|
141
142
|
this.a = a;
|
|
142
143
|
this.b = b;
|
|
143
144
|
this.filterQuery = filterQuery;
|
|
144
145
|
this.profileType = a.ProfileType();
|
|
146
|
+
this.absolute = absolute;
|
|
145
147
|
}
|
|
146
148
|
|
|
147
149
|
DiffSelection(): ProfileDiffSelection {
|
|
@@ -155,9 +157,10 @@ export class ProfileDiffSource implements ProfileSource {
|
|
|
155
157
|
diff: {
|
|
156
158
|
a: this.a.DiffSelection(),
|
|
157
159
|
b: this.b.DiffSelection(),
|
|
160
|
+
absolute: this.absolute,
|
|
158
161
|
},
|
|
159
162
|
},
|
|
160
|
-
reportType: QueryRequest_ReportType.
|
|
163
|
+
reportType: QueryRequest_ReportType.FLAMEGRAPH_ARROW,
|
|
161
164
|
mode: QueryRequest_Mode.DIFF,
|
|
162
165
|
filterQuery: this.filterQuery,
|
|
163
166
|
filter: [],
|
|
@@ -227,7 +230,7 @@ export class MergedProfileSource implements ProfileSource {
|
|
|
227
230
|
query: this.query.toString(),
|
|
228
231
|
},
|
|
229
232
|
},
|
|
230
|
-
reportType: QueryRequest_ReportType.
|
|
233
|
+
reportType: QueryRequest_ReportType.FLAMEGRAPH_ARROW,
|
|
231
234
|
mode: QueryRequest_Mode.MERGE,
|
|
232
235
|
filterQuery: this.filterQuery,
|
|
233
236
|
filter: [],
|