@parca/profile 0.16.360 → 0.16.361
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 +4 -0
- package/dist/GraphTooltipArrow/Content.js +3 -2
- package/dist/GraphTooltipArrow/useGraphTooltip/index.d.ts +1 -0
- package/dist/GraphTooltipArrow/useGraphTooltip/index.js +27 -8
- package/dist/ProfileIcicleGraph/IcicleGraphArrow/IcicleGraphNodes.d.ts +2 -0
- package/dist/ProfileIcicleGraph/IcicleGraphArrow/IcicleGraphNodes.js +62 -9
- package/dist/ProfileIcicleGraph/IcicleGraphArrow/index.d.ts +2 -0
- package/dist/ProfileIcicleGraph/IcicleGraphArrow/index.js +4 -1
- 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/package.json +6 -6
- package/src/GraphTooltipArrow/Content.tsx +21 -1
- package/src/GraphTooltipArrow/useGraphTooltip/index.ts +35 -7
- package/src/ProfileIcicleGraph/IcicleGraphArrow/IcicleGraphNodes.tsx +73 -4
- package/src/ProfileIcicleGraph/IcicleGraphArrow/index.tsx +4 -0
- package/src/ProfileIcicleGraph/IcicleGraphArrow/useNodeColor.ts +9 -1
- package/src/ProfileIcicleGraph/IcicleGraphArrow/utils.ts +11 -0
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,10 @@
|
|
|
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.361](https://github.com/parca-dev/parca/compare/@parca/profile@0.16.360...@parca/profile@0.16.361) (2024-04-26)
|
|
7
|
+
|
|
8
|
+
**Note:** Version bump only for package @parca/profile
|
|
9
|
+
|
|
6
10
|
## 0.16.360 (2024-04-25)
|
|
7
11
|
|
|
8
12
|
**Note:** Version bump only for package @parca/profile
|
|
@@ -20,12 +20,13 @@ 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
|
+
const delta = unit === 'nanoseconds';
|
|
24
25
|
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
26
|
? name
|
|
26
27
|
: locationAddress !== 0n
|
|
27
28
|
? 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" })] })] }) }) }));
|
|
29
|
+
: 'unknown' })) }), _jsx("table", { className: "my-2 w-full table-fixed pr-0 text-gray-700 dark:text-gray-300", children: _jsxs("tbody", { children: [delta ? (_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
30
|
};
|
|
30
31
|
const TooltipMetaInfo = ({ table, row, navigateTo, }) => {
|
|
31
32
|
const { labelPairs, functionFilename, file, locationAddress, mappingFile, mappingBuildID, inlined, } = useGraphTooltipMetaInfo({ table, row, navigateTo });
|
|
@@ -11,8 +11,8 @@
|
|
|
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';
|
|
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
16
|
export const useGraphTooltip = ({ table, unit, total, totalUnfiltered, row, level, }) => {
|
|
17
17
|
if (row === null) {
|
|
18
18
|
return null;
|
|
@@ -21,20 +21,39 @@ export const useGraphTooltip = ({ table, unit, total, totalUnfiltered, row, leve
|
|
|
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
|
-
const
|
|
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
|
+
const delta = unit === 'nanoseconds';
|
|
34
|
+
let diffText = '';
|
|
35
|
+
if (delta) {
|
|
36
|
+
const prevValue = cumulativePerSecond - diffPerSecond;
|
|
37
|
+
const diffRatio = diffPerSecond !== 0 ? diffPerSecond / prevValue : 0;
|
|
38
|
+
const diffSign = diffPerSecond > 0 ? '+' : '';
|
|
39
|
+
const diffValueText = diffSign + valueFormatter(diffPerSecond, 'CPU Cores', 5);
|
|
40
|
+
const diffPercentageText = diffSign + (diffRatio * 100).toFixed(2) + '%';
|
|
41
|
+
diffText = `${diffValueText} (${diffPercentageText})`;
|
|
42
|
+
}
|
|
43
|
+
else {
|
|
44
|
+
const prevValue = cumulative - diff;
|
|
45
|
+
const diffRatio = diff !== 0n ? divide(diff, prevValue) : 0;
|
|
46
|
+
const diffSign = diff > 0 ? '+' : '';
|
|
47
|
+
const diffValueText = diffSign + valueFormatter(diff, unit, 1);
|
|
48
|
+
const diffPercentageText = diffSign + (diffRatio * 100).toFixed(2) + '%';
|
|
49
|
+
diffText = `${diffValueText} (${diffPercentageText})`;
|
|
50
|
+
}
|
|
33
51
|
const name = nodeLabel(table, row, level, false);
|
|
34
52
|
return {
|
|
35
53
|
name,
|
|
36
54
|
locationAddress,
|
|
37
55
|
cumulativeText: getTextForCumulative(cumulative, totalUnfiltered, total, unit),
|
|
56
|
+
cumulativePerSecondText: getTextForCumulativePerSecond(cumulativePerSecond, unit),
|
|
38
57
|
diffText,
|
|
39
58
|
diff,
|
|
40
59
|
row,
|
|
@@ -22,6 +22,7 @@ interface IcicleGraphNodesProps {
|
|
|
22
22
|
sortBy: string;
|
|
23
23
|
darkMode: boolean;
|
|
24
24
|
compareMode: boolean;
|
|
25
|
+
delta: boolean;
|
|
25
26
|
isContextMenuOpen: boolean;
|
|
26
27
|
hoveringName: string | null;
|
|
27
28
|
setHoveringName: (name: string | null) => void;
|
|
@@ -54,6 +55,7 @@ interface IcicleNodeProps {
|
|
|
54
55
|
sortBy: string;
|
|
55
56
|
darkMode: boolean;
|
|
56
57
|
compareMode: boolean;
|
|
58
|
+
delta: boolean;
|
|
57
59
|
isContextMenuOpen: boolean;
|
|
58
60
|
hoveringName: string | null;
|
|
59
61
|
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, delta, 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, delta: delta, 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, delta, 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 (delta) {
|
|
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 (delta) {
|
|
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, delta: delta, compareMode: compareMode, isContextMenuOpen: isContextMenuOpen, hoveringName: hoveringName, setHoveringName: setHoveringName, hoveringRow: hoveringRow, colorForSimilarNodes: colorForSimilarNodes, highlightSimilarStacksPreference: highlightSimilarStacksPreference }))] }));
|
|
176
229
|
});
|
|
@@ -14,7 +14,9 @@ export declare const FIELD_FUNCTION_START_LINE = "function_startline";
|
|
|
14
14
|
export declare const FIELD_CHILDREN = "children";
|
|
15
15
|
export declare const FIELD_LABELS = "labels";
|
|
16
16
|
export declare const FIELD_CUMULATIVE = "cumulative";
|
|
17
|
+
export declare const FIELD_CUMULATIVE_PER_SECOND = "cumulative_per_second";
|
|
17
18
|
export declare const FIELD_DIFF = "diff";
|
|
19
|
+
export declare const FIELD_DIFF_PER_SECOND = "diff_per_second";
|
|
18
20
|
interface IcicleGraphArrowProps {
|
|
19
21
|
arrow: FlamegraphArrow;
|
|
20
22
|
total: bigint;
|
|
@@ -38,7 +38,9 @@ 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';
|
|
43
|
+
export const FIELD_DIFF_PER_SECOND = 'diff_per_second';
|
|
42
44
|
export const IcicleGraphArrow = memo(function IcicleGraphArrow({ arrow, total, filtered, width, setCurPath, curPath, sampleUnit, navigateTo, sortBy, }) {
|
|
43
45
|
const [isContextMenuOpen, setIsContextMenuOpen] = useState(false);
|
|
44
46
|
const dispatch = useAppDispatch();
|
|
@@ -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, delta: sampleUnit === 'nanoseconds', 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
|
+
sampleUnit,
|
|
149
152
|
mappingColors,
|
|
150
153
|
setCurPath,
|
|
151
154
|
sortBy,
|
|
@@ -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;
|
package/package.json
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@parca/profile",
|
|
3
|
-
"version": "0.16.
|
|
3
|
+
"version": "0.16.361",
|
|
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": "d900cb1de5375362e3e211809c98990a6e686140"
|
|
54
54
|
}
|
|
@@ -61,7 +61,17 @@ const GraphTooltipArrowContent = ({
|
|
|
61
61
|
return <></>;
|
|
62
62
|
}
|
|
63
63
|
|
|
64
|
-
const {
|
|
64
|
+
const {
|
|
65
|
+
name,
|
|
66
|
+
locationAddress,
|
|
67
|
+
cumulativeText,
|
|
68
|
+
cumulativePerSecondText,
|
|
69
|
+
diffText,
|
|
70
|
+
diff,
|
|
71
|
+
row: rowNumber,
|
|
72
|
+
} = graphTooltipData;
|
|
73
|
+
|
|
74
|
+
const delta = unit === 'nanoseconds';
|
|
65
75
|
|
|
66
76
|
return (
|
|
67
77
|
<div className={`flex text-sm ${isFixed ? 'w-full' : ''}`}>
|
|
@@ -84,6 +94,16 @@ const GraphTooltipArrowContent = ({
|
|
|
84
94
|
</div>
|
|
85
95
|
<table className="my-2 w-full table-fixed pr-0 text-gray-700 dark:text-gray-300">
|
|
86
96
|
<tbody>
|
|
97
|
+
{delta ? (
|
|
98
|
+
<tr>
|
|
99
|
+
<td className="w-1/4">Per Second</td>
|
|
100
|
+
<td className="w-3/4">
|
|
101
|
+
<div>{cumulativePerSecondText}</div>
|
|
102
|
+
</td>
|
|
103
|
+
</tr>
|
|
104
|
+
) : (
|
|
105
|
+
<></>
|
|
106
|
+
)}
|
|
87
107
|
<tr>
|
|
88
108
|
<td className="w-1/4">Cumulative</td>
|
|
89
109
|
|
|
@@ -17,10 +17,16 @@ import {divide, valueFormatter} from '@parca/utilities';
|
|
|
17
17
|
|
|
18
18
|
import {
|
|
19
19
|
FIELD_CUMULATIVE,
|
|
20
|
+
FIELD_CUMULATIVE_PER_SECOND,
|
|
20
21
|
FIELD_DIFF,
|
|
22
|
+
FIELD_DIFF_PER_SECOND,
|
|
21
23
|
FIELD_LOCATION_ADDRESS,
|
|
22
24
|
} from '../../ProfileIcicleGraph/IcicleGraphArrow';
|
|
23
|
-
import {
|
|
25
|
+
import {
|
|
26
|
+
getTextForCumulative,
|
|
27
|
+
getTextForCumulativePerSecond,
|
|
28
|
+
nodeLabel,
|
|
29
|
+
} from '../../ProfileIcicleGraph/IcicleGraphArrow/utils';
|
|
24
30
|
|
|
25
31
|
interface Props {
|
|
26
32
|
table: Table<any>;
|
|
@@ -35,6 +41,7 @@ interface GraphTooltipData {
|
|
|
35
41
|
name: string;
|
|
36
42
|
locationAddress: bigint;
|
|
37
43
|
cumulativeText: string;
|
|
44
|
+
cumulativePerSecondText: string;
|
|
38
45
|
diffText: string;
|
|
39
46
|
diff: bigint;
|
|
40
47
|
row: number;
|
|
@@ -58,17 +65,37 @@ export const useGraphTooltip = ({
|
|
|
58
65
|
table.getChild(FIELD_CUMULATIVE)?.get(row) !== null
|
|
59
66
|
? BigInt(table.getChild(FIELD_CUMULATIVE)?.get(row))
|
|
60
67
|
: 0n;
|
|
68
|
+
const cumulativePerSecond: number =
|
|
69
|
+
table.getChild(FIELD_CUMULATIVE_PER_SECOND)?.get(row) !== null
|
|
70
|
+
? table.getChild(FIELD_CUMULATIVE_PER_SECOND)?.get(row)
|
|
71
|
+
: 0;
|
|
61
72
|
const diff: bigint =
|
|
62
73
|
table.getChild(FIELD_DIFF)?.get(row) !== null
|
|
63
74
|
? BigInt(table.getChild(FIELD_DIFF)?.get(row))
|
|
64
75
|
: 0n;
|
|
76
|
+
const diffPerSecond: number =
|
|
77
|
+
table.getChild(FIELD_DIFF_PER_SECOND)?.get(row) !== null
|
|
78
|
+
? table.getChild(FIELD_DIFF_PER_SECOND)?.get(row)
|
|
79
|
+
: 0;
|
|
80
|
+
|
|
81
|
+
const delta = unit === 'nanoseconds';
|
|
65
82
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
83
|
+
let diffText = '';
|
|
84
|
+
if (delta) {
|
|
85
|
+
const prevValue = cumulativePerSecond - diffPerSecond;
|
|
86
|
+
const diffRatio = diffPerSecond !== 0 ? diffPerSecond / prevValue : 0;
|
|
87
|
+
const diffSign = diffPerSecond > 0 ? '+' : '';
|
|
88
|
+
const diffValueText = diffSign + valueFormatter(diffPerSecond, 'CPU Cores', 5);
|
|
89
|
+
const diffPercentageText = diffSign + (diffRatio * 100).toFixed(2) + '%';
|
|
90
|
+
diffText = `${diffValueText} (${diffPercentageText})`;
|
|
91
|
+
} else {
|
|
92
|
+
const prevValue = cumulative - diff;
|
|
93
|
+
const diffRatio = diff !== 0n ? divide(diff, prevValue) : 0;
|
|
94
|
+
const diffSign = diff > 0 ? '+' : '';
|
|
95
|
+
const diffValueText = diffSign + valueFormatter(diff, unit, 1);
|
|
96
|
+
const diffPercentageText = diffSign + (diffRatio * 100).toFixed(2) + '%';
|
|
97
|
+
diffText = `${diffValueText} (${diffPercentageText})`;
|
|
98
|
+
}
|
|
72
99
|
|
|
73
100
|
const name = nodeLabel(table, row, level, false);
|
|
74
101
|
|
|
@@ -76,6 +103,7 @@ export const useGraphTooltip = ({
|
|
|
76
103
|
name,
|
|
77
104
|
locationAddress,
|
|
78
105
|
cumulativeText: getTextForCumulative(cumulative, totalUnfiltered, total, unit),
|
|
106
|
+
cumulativePerSecondText: getTextForCumulativePerSecond(cumulativePerSecond, unit),
|
|
79
107
|
diffText,
|
|
80
108
|
diff,
|
|
81
109
|
row,
|
|
@@ -24,7 +24,9 @@ import 'react-contexify/dist/ReactContexify.css';
|
|
|
24
24
|
import {
|
|
25
25
|
FIELD_CHILDREN,
|
|
26
26
|
FIELD_CUMULATIVE,
|
|
27
|
+
FIELD_CUMULATIVE_PER_SECOND,
|
|
27
28
|
FIELD_DIFF,
|
|
29
|
+
FIELD_DIFF_PER_SECOND,
|
|
28
30
|
FIELD_FUNCTION_NAME,
|
|
29
31
|
FIELD_MAPPING_FILE,
|
|
30
32
|
} from './index';
|
|
@@ -53,6 +55,7 @@ interface IcicleGraphNodesProps {
|
|
|
53
55
|
sortBy: string;
|
|
54
56
|
darkMode: boolean;
|
|
55
57
|
compareMode: boolean;
|
|
58
|
+
delta: boolean;
|
|
56
59
|
isContextMenuOpen: boolean;
|
|
57
60
|
hoveringName: string | null;
|
|
58
61
|
setHoveringName: (name: string | null) => void;
|
|
@@ -80,6 +83,7 @@ export const IcicleGraphNodes = React.memo(function IcicleGraphNodesNoMemo({
|
|
|
80
83
|
searchString,
|
|
81
84
|
darkMode,
|
|
82
85
|
compareMode,
|
|
86
|
+
delta,
|
|
83
87
|
isContextMenuOpen,
|
|
84
88
|
hoveringName,
|
|
85
89
|
setHoveringName,
|
|
@@ -127,6 +131,7 @@ export const IcicleGraphNodes = React.memo(function IcicleGraphNodesNoMemo({
|
|
|
127
131
|
searchString={searchString}
|
|
128
132
|
darkMode={darkMode}
|
|
129
133
|
compareMode={compareMode}
|
|
134
|
+
delta={delta}
|
|
130
135
|
isContextMenuOpen={isContextMenuOpen}
|
|
131
136
|
hoveringName={hoveringName}
|
|
132
137
|
setHoveringName={setHoveringName}
|
|
@@ -165,6 +170,7 @@ interface IcicleNodeProps {
|
|
|
165
170
|
sortBy: string;
|
|
166
171
|
darkMode: boolean;
|
|
167
172
|
compareMode: boolean;
|
|
173
|
+
delta: boolean;
|
|
168
174
|
isContextMenuOpen: boolean;
|
|
169
175
|
hoveringName: string | null;
|
|
170
176
|
setHoveringName: (name: string | null) => void;
|
|
@@ -204,6 +210,7 @@ export const IcicleNode = React.memo(function IcicleNodeNoMemo({
|
|
|
204
210
|
sortBy,
|
|
205
211
|
darkMode,
|
|
206
212
|
compareMode,
|
|
213
|
+
delta,
|
|
207
214
|
isContextMenuOpen,
|
|
208
215
|
hoveringName,
|
|
209
216
|
setHoveringName,
|
|
@@ -215,12 +222,18 @@ export const IcicleNode = React.memo(function IcicleNodeNoMemo({
|
|
|
215
222
|
const mappingColumn = table.getChild(FIELD_MAPPING_FILE);
|
|
216
223
|
const functionNameColumn = table.getChild(FIELD_FUNCTION_NAME);
|
|
217
224
|
const cumulativeColumn = table.getChild(FIELD_CUMULATIVE);
|
|
225
|
+
const cumulativePerSecondColumn = table.getChild(FIELD_CUMULATIVE_PER_SECOND);
|
|
218
226
|
const diffColumn = table.getChild(FIELD_DIFF);
|
|
227
|
+
const diffPerSecondColumn = table.getChild(FIELD_DIFF_PER_SECOND);
|
|
219
228
|
// get the actual values from the columns
|
|
220
229
|
const mappingFile: string | null = arrowToString(mappingColumn?.get(row));
|
|
221
230
|
const functionName: string | null = arrowToString(functionNameColumn?.get(row));
|
|
222
231
|
const cumulative = cumulativeColumn?.get(row) !== null ? BigInt(cumulativeColumn?.get(row)) : 0n;
|
|
232
|
+
const cumulativePerSecond: number | null =
|
|
233
|
+
cumulativePerSecondColumn?.get(row) != null ? cumulativePerSecondColumn.get(row) : 0;
|
|
223
234
|
const diff: bigint | null = diffColumn?.get(row) !== null ? BigInt(diffColumn?.get(row)) : null;
|
|
235
|
+
const diffPerSecond: number | null =
|
|
236
|
+
diffPerSecondColumn?.get(row) != null ? diffPerSecondColumn.get(row) : null;
|
|
224
237
|
const childRows: number[] = Array.from(table.getChild(FIELD_CHILDREN)?.get(row) ?? []);
|
|
225
238
|
|
|
226
239
|
const highlightedNodes = useMemo(() => {
|
|
@@ -259,6 +272,15 @@ export const IcicleNode = React.memo(function IcicleNodeNoMemo({
|
|
|
259
272
|
});
|
|
260
273
|
break;
|
|
261
274
|
case FIELD_CUMULATIVE:
|
|
275
|
+
if (delta) {
|
|
276
|
+
childRows.sort((a, b) => {
|
|
277
|
+
const aCumulativePerSecond = cumulativePerSecondColumn?.get(a);
|
|
278
|
+
const bCumulativePerSecond = cumulativePerSecondColumn?.get(b);
|
|
279
|
+
return bCumulativePerSecond - aCumulativePerSecond;
|
|
280
|
+
});
|
|
281
|
+
break;
|
|
282
|
+
}
|
|
283
|
+
|
|
262
284
|
childRows.sort((a, b) => {
|
|
263
285
|
const aCumulative: bigint = cumulativeColumn?.get(a);
|
|
264
286
|
const bCumulative: bigint = cumulativeColumn?.get(b);
|
|
@@ -267,15 +289,59 @@ export const IcicleNode = React.memo(function IcicleNodeNoMemo({
|
|
|
267
289
|
break;
|
|
268
290
|
case FIELD_DIFF:
|
|
269
291
|
childRows.sort((a, b) => {
|
|
292
|
+
if (delta) {
|
|
293
|
+
let aRatio: number | null = null;
|
|
294
|
+
let bRatio: number | null = null;
|
|
295
|
+
|
|
296
|
+
const aDiff: number | null = diffPerSecondColumn?.get(a);
|
|
297
|
+
if (aDiff !== null) {
|
|
298
|
+
const cumulative: number = cumulativePerSecondColumn?.get(a);
|
|
299
|
+
const prev = cumulative - aDiff;
|
|
300
|
+
aRatio = aDiff / prev;
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
const bDiff: number | null = diffPerSecondColumn?.get(b);
|
|
304
|
+
if (bDiff !== null) {
|
|
305
|
+
const cumulative: number = cumulativePerSecondColumn?.get(b);
|
|
306
|
+
const prev = cumulative - bDiff;
|
|
307
|
+
bRatio = bDiff / prev;
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
if (aRatio !== null && bRatio !== null) {
|
|
311
|
+
return bRatio - aRatio;
|
|
312
|
+
}
|
|
313
|
+
if (aRatio === null && bRatio !== null) {
|
|
314
|
+
return -1;
|
|
315
|
+
}
|
|
316
|
+
if (aRatio !== null && bRatio === null) {
|
|
317
|
+
return 1;
|
|
318
|
+
}
|
|
319
|
+
// both are null
|
|
320
|
+
return 0;
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
let aRatio: number | null = null;
|
|
270
324
|
const aDiff: bigint | null = diffColumn?.get(a);
|
|
325
|
+
if (aDiff !== null) {
|
|
326
|
+
const cumulative: bigint = cumulativeColumn?.get(a) ?? 0n;
|
|
327
|
+
const prev: bigint = cumulative - aDiff;
|
|
328
|
+
aRatio = Number(aDiff) / Number(prev);
|
|
329
|
+
}
|
|
330
|
+
let bRatio: number | null = null;
|
|
271
331
|
const bDiff: bigint | null = diffColumn?.get(b);
|
|
272
|
-
if (
|
|
273
|
-
|
|
332
|
+
if (bDiff !== null) {
|
|
333
|
+
const cumulative: bigint = cumulativeColumn?.get(b) ?? 0n;
|
|
334
|
+
const prev: bigint = cumulative - bDiff;
|
|
335
|
+
bRatio = Number(bDiff) / Number(prev);
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
if (aRatio !== null && bRatio !== null) {
|
|
339
|
+
return bRatio - aRatio;
|
|
274
340
|
}
|
|
275
|
-
if (
|
|
341
|
+
if (aRatio === null && bRatio !== null) {
|
|
276
342
|
return -1;
|
|
277
343
|
}
|
|
278
|
-
if (
|
|
344
|
+
if (aRatio !== null && bRatio === null) {
|
|
279
345
|
return 1;
|
|
280
346
|
}
|
|
281
347
|
// both are null
|
|
@@ -289,7 +355,9 @@ export const IcicleNode = React.memo(function IcicleNodeNoMemo({
|
|
|
289
355
|
isDarkMode: darkMode,
|
|
290
356
|
compareMode,
|
|
291
357
|
cumulative,
|
|
358
|
+
cumulativePerSecond,
|
|
292
359
|
diff,
|
|
360
|
+
diffPerSecond,
|
|
293
361
|
mappingColors,
|
|
294
362
|
mappingFile,
|
|
295
363
|
functionName,
|
|
@@ -393,6 +461,7 @@ export const IcicleNode = React.memo(function IcicleNodeNoMemo({
|
|
|
393
461
|
searchString={searchString}
|
|
394
462
|
sortBy={sortBy}
|
|
395
463
|
darkMode={darkMode}
|
|
464
|
+
delta={delta}
|
|
396
465
|
compareMode={compareMode}
|
|
397
466
|
isContextMenuOpen={isContextMenuOpen}
|
|
398
467
|
hoveringName={hoveringName}
|
|
@@ -49,7 +49,9 @@ export const FIELD_FUNCTION_START_LINE = 'function_startline';
|
|
|
49
49
|
export const FIELD_CHILDREN = 'children';
|
|
50
50
|
export const FIELD_LABELS = 'labels';
|
|
51
51
|
export const FIELD_CUMULATIVE = 'cumulative';
|
|
52
|
+
export const FIELD_CUMULATIVE_PER_SECOND = 'cumulative_per_second';
|
|
52
53
|
export const FIELD_DIFF = 'diff';
|
|
54
|
+
export const FIELD_DIFF_PER_SECOND = 'diff_per_second';
|
|
53
55
|
|
|
54
56
|
interface IcicleGraphArrowProps {
|
|
55
57
|
arrow: FlamegraphArrow;
|
|
@@ -229,6 +231,7 @@ export const IcicleGraphArrow = memo(function IcicleGraphArrow({
|
|
|
229
231
|
sortBy={sortBy}
|
|
230
232
|
darkMode={isDarkMode}
|
|
231
233
|
compareMode={compareMode}
|
|
234
|
+
delta={sampleUnit === 'nanoseconds'}
|
|
232
235
|
isContextMenuOpen={isContextMenuOpen}
|
|
233
236
|
hoveringName={hoveringName}
|
|
234
237
|
setHoveringName={setHoveringName}
|
|
@@ -246,6 +249,7 @@ export const IcicleGraphArrow = memo(function IcicleGraphArrow({
|
|
|
246
249
|
currentSearchString,
|
|
247
250
|
height,
|
|
248
251
|
isDarkMode,
|
|
252
|
+
sampleUnit,
|
|
249
253
|
mappingColors,
|
|
250
254
|
setCurPath,
|
|
251
255
|
sortBy,
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
// limitations under the License.
|
|
13
13
|
|
|
14
14
|
import {EVERYTHING_ELSE} from '@parca/store';
|
|
15
|
-
import {diffColor, getLastItem} from '@parca/utilities';
|
|
15
|
+
import {diffColor, diffColorPerSecond, getLastItem} from '@parca/utilities';
|
|
16
16
|
|
|
17
17
|
interface mappingColors {
|
|
18
18
|
[key: string]: string;
|
|
@@ -22,7 +22,9 @@ interface Props {
|
|
|
22
22
|
isDarkMode: boolean;
|
|
23
23
|
compareMode: boolean;
|
|
24
24
|
cumulative: bigint;
|
|
25
|
+
cumulativePerSecond: number | null;
|
|
25
26
|
diff: bigint | null;
|
|
27
|
+
diffPerSecond: number | null;
|
|
26
28
|
mappingColors: mappingColors;
|
|
27
29
|
functionName: string | null;
|
|
28
30
|
mappingFile: string | null;
|
|
@@ -32,12 +34,18 @@ const useNodeColor = ({
|
|
|
32
34
|
isDarkMode,
|
|
33
35
|
compareMode,
|
|
34
36
|
cumulative,
|
|
37
|
+
cumulativePerSecond,
|
|
35
38
|
diff,
|
|
39
|
+
diffPerSecond,
|
|
36
40
|
mappingColors,
|
|
37
41
|
functionName,
|
|
38
42
|
mappingFile,
|
|
39
43
|
}: Props): string => {
|
|
40
44
|
if (compareMode) {
|
|
45
|
+
if (cumulativePerSecond !== null && diffPerSecond !== null) {
|
|
46
|
+
return diffColorPerSecond(diffPerSecond, cumulativePerSecond, isDarkMode);
|
|
47
|
+
}
|
|
48
|
+
|
|
41
49
|
return diffColor(diff ?? 0n, cumulative, isDarkMode);
|
|
42
50
|
}
|
|
43
51
|
|
|
@@ -91,6 +91,17 @@ export const getTextForCumulative = (
|
|
|
91
91
|
(${(100 * divide(hoveringNodeCumulative, totalUnfiltered)).toFixed(2)}%${filtered})`;
|
|
92
92
|
};
|
|
93
93
|
|
|
94
|
+
export const getTextForCumulativePerSecond = (
|
|
95
|
+
hoveringNodeCumulative: number,
|
|
96
|
+
unit: string
|
|
97
|
+
): string => {
|
|
98
|
+
return `${valueFormatter(
|
|
99
|
+
hoveringNodeCumulative,
|
|
100
|
+
unit === 'nanoseconds' ? 'CPU Cores' : unit,
|
|
101
|
+
5
|
|
102
|
+
)}`;
|
|
103
|
+
};
|
|
104
|
+
|
|
94
105
|
export const arrowToString = (buffer: any): string | null => {
|
|
95
106
|
if (buffer == null || typeof buffer === 'string') {
|
|
96
107
|
return buffer;
|