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