@parca/profile 0.16.376 → 0.16.378

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 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.378](https://github.com/parca-dev/parca/compare/@parca/profile@0.16.377...@parca/profile@0.16.378) (2024-05-31)
7
+
8
+ **Note:** Version bump only for package @parca/profile
9
+
10
+ ## [0.16.377](https://github.com/parca-dev/parca/compare/@parca/profile@0.16.376...@parca/profile@0.16.377) (2024-05-30)
11
+
12
+ **Note:** Version bump only for package @parca/profile
13
+
6
14
  ## 0.16.376 (2024-05-30)
7
15
 
8
16
  **Note:** Version bump only for package @parca/profile
@@ -2,9 +2,9 @@ import React from 'react';
2
2
  import { type NavigateFunction } from '@parca/utilities';
3
3
  interface Props {
4
4
  mappings?: string[];
5
- mappingsLoading?: boolean;
5
+ loading?: boolean;
6
6
  navigateTo?: NavigateFunction;
7
7
  compareMode?: boolean;
8
8
  }
9
- declare const ColorStackLegend: ({ mappings, navigateTo, compareMode, mappingsLoading, }: Props) => React.JSX.Element;
9
+ declare const ColorStackLegend: ({ mappings, navigateTo, compareMode, loading, }: Props) => React.JSX.Element;
10
10
  export default ColorStackLegend;
@@ -17,9 +17,9 @@ import cx from 'classnames';
17
17
  import { useURLState } from '@parca/components';
18
18
  import { USER_PREFERENCES, useCurrentColorProfile, useUserPreference } from '@parca/hooks';
19
19
  import { EVERYTHING_ELSE, selectDarkMode, useAppSelector } from '@parca/store';
20
- import { getLastItem } from '@parca/utilities';
21
20
  import { getMappingColors } from '.';
22
- const ColorStackLegend = ({ mappings, navigateTo, compareMode = false, mappingsLoading, }) => {
21
+ import useMappingList from './useMappingList';
22
+ const ColorStackLegend = ({ mappings, navigateTo, compareMode = false, loading, }) => {
23
23
  const isDarkMode = useAppSelector(selectDarkMode);
24
24
  const currentColorProfile = useCurrentColorProfile();
25
25
  const [colorProfileName] = useUserPreference(USER_PREFERENCES.FLAMEGRAPH_COLOR_PROFILE.key);
@@ -27,21 +27,7 @@ const ColorStackLegend = ({ mappings, navigateTo, compareMode = false, mappingsL
27
27
  param: 'binary_frame_filter',
28
28
  navigateTo,
29
29
  });
30
- const mappingsList = useMemo(() => {
31
- if (mappings === undefined) {
32
- return [];
33
- }
34
- const list = mappings
35
- ?.map(mapping => {
36
- return getLastItem(mapping);
37
- })
38
- .flat() ?? [];
39
- // We add a EVERYTHING ELSE mapping to the list.
40
- list.push('');
41
- // We sort the mappings alphabetically to make sure that the order is always the same.
42
- list.sort((a, b) => a.localeCompare(b));
43
- return list;
44
- }, [mappings]);
30
+ const mappingsList = useMappingList(mappings);
45
31
  const mappingColors = useMemo(() => {
46
32
  const colors = getMappingColors(mappingsList, isDarkMode, currentColorProfile);
47
33
  return colors;
@@ -57,7 +43,7 @@ const ColorStackLegend = ({ mappings, navigateTo, compareMode = false, mappingsL
57
43
  return featureA?.localeCompare(featureB ?? '') ?? 0;
58
44
  });
59
45
  }, [mappingColors]);
60
- if (mappingColors === undefined && mappingsLoading === false) {
46
+ if (stackColorArray.length === 0 && loading === false) {
61
47
  return _jsx(_Fragment, {});
62
48
  }
63
49
  if (Object.entries(mappingColors).length === 0) {
@@ -31,6 +31,7 @@ interface IcicleGraphArrowProps {
31
31
  sortBy: string;
32
32
  flamegraphLoading: boolean;
33
33
  isHalfScreen: boolean;
34
+ mappingsListFromMetadata: string[];
34
35
  }
35
36
  export declare const getMappingColors: (mappingsList: string[], isDarkMode: boolean, currentColorProfile: ColorConfig) => mappingColors;
36
37
  export declare const IcicleGraphArrow: React.NamedExoticComponent<IcicleGraphArrowProps>;
@@ -49,7 +49,8 @@ export const getMappingColors = (mappingsList, isDarkMode, currentColorProfile)
49
49
  });
50
50
  return colors;
51
51
  };
52
- export const IcicleGraphArrow = memo(function IcicleGraphArrow({ arrow, total, filtered, width, setCurPath, curPath, profileType, navigateTo, sortBy, flamegraphLoading, }) {
52
+ const noop = () => { };
53
+ export const IcicleGraphArrow = memo(function IcicleGraphArrow({ arrow, total, filtered, width, setCurPath, curPath, profileType, navigateTo, sortBy, flamegraphLoading, mappingsListFromMetadata, }) {
53
54
  const [isContextMenuOpen, setIsContextMenuOpen] = useState(false);
54
55
  const dispatch = useAppDispatch();
55
56
  const [highlightSimilarStacksPreference] = useUserPreference(USER_PREFERENCES.HIGHLIGHT_SIMILAR_STACKS.key);
@@ -70,7 +71,6 @@ export const IcicleGraphArrow = memo(function IcicleGraphArrow({ arrow, total, f
70
71
  });
71
72
  const currentSearchString = selectQueryParam('search_string') ?? '';
72
73
  const { compareMode } = useProfileViewContext();
73
- // const isColorStackLegendEnabled = selectQueryParam('color_stack_legend') === 'true';
74
74
  const currentColorProfile = useCurrentColorProfile();
75
75
  const colorForSimilarNodes = currentColorProfile.colorForSimilarNodes;
76
76
  const mappingsList = useMemo(() => {
@@ -137,12 +137,23 @@ export const IcicleGraphArrow = memo(function IcicleGraphArrow({ arrow, total, f
137
137
  return;
138
138
  }
139
139
  // first time hiding a binary
140
- const newMappingsList = mappingsList.filter(mapping => mapping !== binaryToRemove);
140
+ const newMappingsList = mappingsListFromMetadata.filter(mapping => mapping !== binaryToRemove);
141
141
  setBinaryFrameFilter(newMappingsList);
142
142
  };
143
+ const highlightSimilarStacksName = highlightSimilarStacksPreference ? hoveringName : null;
144
+ const highlightSimilarStacksSetName = useMemo(() => {
145
+ return highlightSimilarStacksPreference ? setHoveringName : noop;
146
+ }, [highlightSimilarStacksPreference]);
147
+ const highlightSimilarStacksSetLevel = useMemo(() => {
148
+ return highlightSimilarStacksPreference ? setHoveringLevel : noop;
149
+ }, [highlightSimilarStacksPreference]);
150
+ const highlightSimilarStacksRow = highlightSimilarStacksPreference ? hoveringRow : null;
151
+ const path = useMemo(() => {
152
+ return [];
153
+ }, []);
143
154
  // useMemo for the root graph as it otherwise renders the whole graph if the hoveringRow changes.
144
155
  const root = useMemo(() => {
145
- 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 }) }) }) }));
156
+ 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: path, level: 0, isRoot: true, searchString: currentSearchString, setHoveringRow: setHoveringRow, setHoveringLevel: highlightSimilarStacksSetLevel, sortBy: sortBy, darkMode: isDarkMode, compareMode: compareMode, profileType: profileType, isContextMenuOpen: isContextMenuOpen, hoveringName: highlightSimilarStacksName, setHoveringName: highlightSimilarStacksSetName, hoveringRow: highlightSimilarStacksRow, colorForSimilarNodes: colorForSimilarNodes, highlightSimilarStacksPreference: highlightSimilarStacksPreference }) }) }) }));
146
157
  }, [
147
158
  width,
148
159
  height,
@@ -159,10 +170,13 @@ export const IcicleGraphArrow = memo(function IcicleGraphArrow({ arrow, total, f
159
170
  compareMode,
160
171
  profileType,
161
172
  isContextMenuOpen,
162
- hoveringName,
163
- hoveringRow,
173
+ highlightSimilarStacksName,
174
+ highlightSimilarStacksRow,
164
175
  colorForSimilarNodes,
165
176
  highlightSimilarStacksPreference,
177
+ path,
178
+ highlightSimilarStacksSetLevel,
179
+ highlightSimilarStacksSetName,
166
180
  ]);
167
181
  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, hideBinary: hideBinary }), 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] }) }));
168
182
  });
@@ -0,0 +1,2 @@
1
+ declare const useMappingList: (mappings: string[] | undefined) => string[];
2
+ export default useMappingList;
@@ -0,0 +1,33 @@
1
+ // Copyright 2022 The Parca Authors
2
+ // Licensed under the Apache License, Version 2.0 (the "License");
3
+ // you may not use this file except in compliance with the License.
4
+ // You may obtain a copy of the License at
5
+ //
6
+ // http://www.apache.org/licenses/LICENSE-2.0
7
+ //
8
+ // Unless required by applicable law or agreed to in writing, software
9
+ // distributed under the License is distributed on an "AS IS" BASIS,
10
+ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11
+ // See the License for the specific language governing permissions and
12
+ // limitations under the License.
13
+ import { useMemo } from 'react';
14
+ import { getLastItem } from '@parca/utilities';
15
+ const useMappingList = (mappings) => {
16
+ const mappingsList = useMemo(() => {
17
+ if (mappings === undefined) {
18
+ return [];
19
+ }
20
+ const list = mappings
21
+ ?.map(mapping => {
22
+ return getLastItem(mapping);
23
+ })
24
+ .flat() ?? [];
25
+ // We add a EVERYTHING ELSE mapping to the list.
26
+ list.push('');
27
+ // We sort the mappings alphabetically to make sure that the order is always the same.
28
+ list.sort((a, b) => a.localeCompare(b));
29
+ return list;
30
+ }, [mappings]);
31
+ return mappingsList;
32
+ };
33
+ export default useMappingList;
@@ -20,5 +20,5 @@ interface ProfileIcicleGraphProps {
20
20
  mappings?: string[];
21
21
  mappingsLoading?: boolean;
22
22
  }
23
- declare const ProfileIcicleGraph: ({ graph, arrow, total, filtered, curPath, setNewCurPath, profileType, navigateTo, loading, setActionButtons, error, width, isHalfScreen, mappings, mappingsLoading, }: ProfileIcicleGraphProps) => JSX.Element;
23
+ declare const ProfileIcicleGraph: ({ graph, arrow, total, filtered, curPath, setNewCurPath, profileType, navigateTo, loading, setActionButtons, error, width, isHalfScreen, mappings, }: ProfileIcicleGraphProps) => JSX.Element;
24
24
  export default ProfileIcicleGraph;
@@ -24,6 +24,7 @@ import SortBySelect from './ActionButtons/SortBySelect';
24
24
  import IcicleGraph from './IcicleGraph';
25
25
  import IcicleGraphArrow, { FIELD_FUNCTION_NAME } from './IcicleGraphArrow';
26
26
  import ColorStackLegend from './IcicleGraphArrow/ColorStackLegend';
27
+ import useMappingList from './IcicleGraphArrow/useMappingList';
27
28
  const numberFormatter = new Intl.NumberFormat('en-US');
28
29
  const ErrorContent = ({ errorMessage }) => {
29
30
  return _jsx("div", { className: "flex justify-center p-10", children: errorMessage });
@@ -77,11 +78,12 @@ const GroupAndSortActionButtons = ({ navigateTo }) => {
77
78
  }, [groupBy, setGroupBy]);
78
79
  return (_jsxs(_Fragment, { children: [_jsx(GroupByDropdown, { groupBy: groupBy, toggleGroupBy: toggleGroupBy }), _jsx(SortBySelect, { compareMode: compareMode, sortBy: storeSortBy, setSortBy: setStoreSortBy })] }));
79
80
  };
80
- const ProfileIcicleGraph = function ProfileIcicleGraphNonMemo({ graph, arrow, total, filtered, curPath, setNewCurPath, profileType, navigateTo, loading, setActionButtons, error, width, isHalfScreen, mappings, mappingsLoading, }) {
81
+ const ProfileIcicleGraph = function ProfileIcicleGraphNonMemo({ graph, arrow, total, filtered, curPath, setNewCurPath, profileType, navigateTo, loading, setActionButtons, error, width, isHalfScreen, mappings, }) {
81
82
  const { onError, authenticationErrorMessage, isDarkMode } = useParcaContext();
82
83
  const { compareMode } = useProfileViewContext();
83
84
  const [isLoading, setIsLoading] = useState(true);
84
85
  const isColorStackLegendEnabled = selectQueryParam('color_stack_legend') === 'true';
86
+ const mappingsList = useMappingList(mappings);
85
87
  const [storeSortBy = FIELD_FUNCTION_NAME] = useURLState({
86
88
  param: 'sort_by',
87
89
  navigateTo,
@@ -123,14 +125,15 @@ const ProfileIcicleGraph = function ProfileIcicleGraphNonMemo({ graph, arrow, to
123
125
  isHalfScreen,
124
126
  isLoading,
125
127
  ]);
128
+ const loadingState = !loading && (arrow !== undefined || graph !== undefined) && mappings !== undefined;
126
129
  useEffect(() => {
127
- if (!loading && (arrow !== undefined || graph !== undefined)) {
130
+ if (loadingState) {
128
131
  setIsLoading(false);
129
132
  }
130
133
  else {
131
134
  setIsLoading(true);
132
135
  }
133
- }, [loading, arrow, graph]);
136
+ }, [loadingState]);
134
137
  if (error != null) {
135
138
  onError?.(error);
136
139
  if (authenticationErrorMessage !== undefined && error.code === 'UNAUTHENTICATED') {
@@ -150,26 +153,27 @@ const ProfileIcicleGraph = function ProfileIcicleGraphNonMemo({ graph, arrow, to
150
153
  if (graph !== undefined)
151
154
  return (_jsx(IcicleGraph, { width: width, graph: graph, total: total, filtered: filtered, curPath: curPath, setCurPath: setNewCurPath, profileType: profileType, navigateTo: navigateTo }));
152
155
  if (arrow !== undefined)
153
- return (_jsx(IcicleGraphArrow, { width: width, arrow: arrow, total: total, filtered: filtered, curPath: curPath, setCurPath: setNewCurPath, profileType: profileType, navigateTo: navigateTo, sortBy: storeSortBy, flamegraphLoading: isLoading, isHalfScreen: isHalfScreen }));
156
+ return (_jsx(IcicleGraphArrow, { width: width, arrow: arrow, total: total, filtered: filtered, curPath: curPath, setCurPath: setNewCurPath, profileType: profileType, navigateTo: navigateTo, sortBy: storeSortBy, flamegraphLoading: isLoading, isHalfScreen: isHalfScreen, mappingsListFromMetadata: mappingsList }));
154
157
  }, [
155
158
  isLoading,
156
159
  graph,
157
160
  arrow,
158
161
  total,
162
+ loading,
163
+ width,
159
164
  filtered,
160
165
  curPath,
161
166
  setNewCurPath,
162
167
  profileType,
163
168
  navigateTo,
164
- width,
165
169
  storeSortBy,
166
170
  isHalfScreen,
167
171
  isDarkMode,
168
- loading,
172
+ mappingsList,
169
173
  ]);
170
174
  if (isTrimmed) {
171
175
  console.info(`Trimmed ${trimmedFormatted} (${trimmedPercentage}%) too small values.`);
172
176
  }
173
- 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, isColorStackLegendEnabled && (_jsx(ColorStackLegend, { navigateTo: navigateTo, compareMode: compareMode, mappings: mappings, mappingsLoading: mappingsLoading })), _jsx("div", { className: "min-h-48", id: "h-icicle-graph", children: _jsx(_Fragment, { children: icicleGraph }) }), _jsxs("p", { className: "my-2 text-xs", children: ["Showing ", totalFormatted, ' ', isFiltered ? (_jsxs("span", { children: ["(", filteredPercentage, "%) filtered of ", totalUnfilteredFormatted, ' '] })) : (_jsx(_Fragment, {})), "values.", ' '] })] }, "icicle-graph-loaded") }));
177
+ 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, isColorStackLegendEnabled && (_jsx(ColorStackLegend, { navigateTo: navigateTo, compareMode: compareMode, mappings: mappings, loading: isLoading })), _jsx("div", { className: "min-h-48", id: "h-icicle-graph", children: _jsx(_Fragment, { children: icicleGraph }) }), _jsxs("p", { className: "my-2 text-xs", children: ["Showing ", totalFormatted, ' ', isFiltered ? (_jsxs("span", { children: ["(", filteredPercentage, "%) filtered of ", totalUnfilteredFormatted, ' '] })) : (_jsx(_Fragment, {})), "values.", ' '] })] }, "icicle-graph-loaded") }));
174
178
  };
175
179
  export default ProfileIcicleGraph;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@parca/profile",
3
- "version": "0.16.376",
3
+ "version": "0.16.378",
4
4
  "description": "Profile viewing libraries",
5
5
  "dependencies": {
6
6
  "@headlessui/react": "^1.7.19",
@@ -71,5 +71,5 @@
71
71
  "access": "public",
72
72
  "registry": "https://registry.npmjs.org/"
73
73
  },
74
- "gitHead": "6f30d0d2d958ea4a32f58671bfc97bf72eb232d7"
74
+ "gitHead": "fbab8208a5a08c44a96f81c90bdd69494914c11c"
75
75
  }
@@ -19,13 +19,14 @@ import cx from 'classnames';
19
19
  import {useURLState} from '@parca/components';
20
20
  import {USER_PREFERENCES, useCurrentColorProfile, useUserPreference} from '@parca/hooks';
21
21
  import {EVERYTHING_ELSE, selectDarkMode, useAppSelector} from '@parca/store';
22
- import {getLastItem, type NavigateFunction} from '@parca/utilities';
22
+ import {type NavigateFunction} from '@parca/utilities';
23
23
 
24
24
  import {getMappingColors} from '.';
25
+ import useMappingList from './useMappingList';
25
26
 
26
27
  interface Props {
27
28
  mappings?: string[];
28
- mappingsLoading?: boolean;
29
+ loading?: boolean;
29
30
  navigateTo?: NavigateFunction;
30
31
  compareMode?: boolean;
31
32
  }
@@ -34,7 +35,7 @@ const ColorStackLegend = ({
34
35
  mappings,
35
36
  navigateTo,
36
37
  compareMode = false,
37
- mappingsLoading,
38
+ loading,
38
39
  }: Props): React.JSX.Element => {
39
40
  const isDarkMode = useAppSelector(selectDarkMode);
40
41
  const currentColorProfile = useCurrentColorProfile();
@@ -46,25 +47,7 @@ const ColorStackLegend = ({
46
47
  navigateTo,
47
48
  });
48
49
 
49
- const mappingsList = useMemo(() => {
50
- if (mappings === undefined) {
51
- return [];
52
- }
53
- const list =
54
- mappings
55
- ?.map(mapping => {
56
- return getLastItem(mapping) as string;
57
- })
58
- .flat() ?? [];
59
-
60
- // We add a EVERYTHING ELSE mapping to the list.
61
- list.push('');
62
-
63
- // We sort the mappings alphabetically to make sure that the order is always the same.
64
- list.sort((a, b) => a.localeCompare(b));
65
-
66
- return list;
67
- }, [mappings]);
50
+ const mappingsList = useMappingList(mappings);
68
51
 
69
52
  const mappingColors = useMemo(() => {
70
53
  const colors = getMappingColors(mappingsList, isDarkMode, currentColorProfile);
@@ -83,7 +66,7 @@ const ColorStackLegend = ({
83
66
  });
84
67
  }, [mappingColors]);
85
68
 
86
- if (mappingColors === undefined && mappingsLoading === false) {
69
+ if (stackColorArray.length === 0 && loading === false) {
87
70
  return <></>;
88
71
  }
89
72
 
@@ -72,6 +72,7 @@ interface IcicleGraphArrowProps {
72
72
  sortBy: string;
73
73
  flamegraphLoading: boolean;
74
74
  isHalfScreen: boolean;
75
+ mappingsListFromMetadata: string[];
75
76
  }
76
77
 
77
78
  export const getMappingColors = (
@@ -88,6 +89,8 @@ export const getMappingColors = (
88
89
  return colors;
89
90
  };
90
91
 
92
+ const noop = (): void => {};
93
+
91
94
  export const IcicleGraphArrow = memo(function IcicleGraphArrow({
92
95
  arrow,
93
96
  total,
@@ -99,6 +102,7 @@ export const IcicleGraphArrow = memo(function IcicleGraphArrow({
99
102
  navigateTo,
100
103
  sortBy,
101
104
  flamegraphLoading,
105
+ mappingsListFromMetadata,
102
106
  }: IcicleGraphArrowProps): React.JSX.Element {
103
107
  const [isContextMenuOpen, setIsContextMenuOpen] = useState<boolean>(false);
104
108
  const dispatch = useAppDispatch();
@@ -126,7 +130,6 @@ export const IcicleGraphArrow = memo(function IcicleGraphArrow({
126
130
 
127
131
  const currentSearchString = (selectQueryParam('search_string') as string) ?? '';
128
132
  const {compareMode} = useProfileViewContext();
129
- // const isColorStackLegendEnabled = selectQueryParam('color_stack_legend') === 'true';
130
133
  const currentColorProfile = useCurrentColorProfile();
131
134
  const colorForSimilarNodes = currentColorProfile.colorForSimilarNodes;
132
135
 
@@ -209,10 +212,22 @@ export const IcicleGraphArrow = memo(function IcicleGraphArrow({
209
212
  }
210
213
 
211
214
  // first time hiding a binary
212
- const newMappingsList = mappingsList.filter(mapping => mapping !== binaryToRemove);
215
+ const newMappingsList = mappingsListFromMetadata.filter(mapping => mapping !== binaryToRemove);
213
216
  setBinaryFrameFilter(newMappingsList);
214
217
  };
215
218
 
219
+ const highlightSimilarStacksName = highlightSimilarStacksPreference ? hoveringName : null;
220
+ const highlightSimilarStacksSetName = useMemo(() => {
221
+ return highlightSimilarStacksPreference ? setHoveringName : noop;
222
+ }, [highlightSimilarStacksPreference]);
223
+ const highlightSimilarStacksSetLevel = useMemo(() => {
224
+ return highlightSimilarStacksPreference ? setHoveringLevel : noop;
225
+ }, [highlightSimilarStacksPreference]);
226
+ const highlightSimilarStacksRow = highlightSimilarStacksPreference ? hoveringRow : null;
227
+ const path = useMemo(() => {
228
+ return [];
229
+ }, []);
230
+
216
231
  // useMemo for the root graph as it otherwise renders the whole graph if the hoveringRow changes.
217
232
  const root = useMemo(() => {
218
233
  return (
@@ -238,20 +253,20 @@ export const IcicleGraphArrow = memo(function IcicleGraphArrow({
238
253
  curPath={curPath}
239
254
  total={total}
240
255
  xScale={xScale}
241
- path={[]}
256
+ path={path}
242
257
  level={0}
243
258
  isRoot={true}
244
259
  searchString={currentSearchString}
245
260
  setHoveringRow={setHoveringRow}
246
- setHoveringLevel={setHoveringLevel}
261
+ setHoveringLevel={highlightSimilarStacksSetLevel}
247
262
  sortBy={sortBy}
248
263
  darkMode={isDarkMode}
249
264
  compareMode={compareMode}
250
265
  profileType={profileType}
251
266
  isContextMenuOpen={isContextMenuOpen}
252
- hoveringName={hoveringName}
253
- setHoveringName={setHoveringName}
254
- hoveringRow={hoveringRow}
267
+ hoveringName={highlightSimilarStacksName}
268
+ setHoveringName={highlightSimilarStacksSetName}
269
+ hoveringRow={highlightSimilarStacksRow}
255
270
  colorForSimilarNodes={colorForSimilarNodes}
256
271
  highlightSimilarStacksPreference={highlightSimilarStacksPreference}
257
272
  />
@@ -275,10 +290,13 @@ export const IcicleGraphArrow = memo(function IcicleGraphArrow({
275
290
  compareMode,
276
291
  profileType,
277
292
  isContextMenuOpen,
278
- hoveringName,
279
- hoveringRow,
293
+ highlightSimilarStacksName,
294
+ highlightSimilarStacksRow,
280
295
  colorForSimilarNodes,
281
296
  highlightSimilarStacksPreference,
297
+ path,
298
+ highlightSimilarStacksSetLevel,
299
+ highlightSimilarStacksSetName,
282
300
  ]);
283
301
 
284
302
  return (
@@ -0,0 +1,42 @@
1
+ // Copyright 2022 The Parca Authors
2
+ // Licensed under the Apache License, Version 2.0 (the "License");
3
+ // you may not use this file except in compliance with the License.
4
+ // You may obtain a copy of the License at
5
+ //
6
+ // http://www.apache.org/licenses/LICENSE-2.0
7
+ //
8
+ // Unless required by applicable law or agreed to in writing, software
9
+ // distributed under the License is distributed on an "AS IS" BASIS,
10
+ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11
+ // See the License for the specific language governing permissions and
12
+ // limitations under the License.
13
+
14
+ import {useMemo} from 'react';
15
+
16
+ import {getLastItem} from '@parca/utilities';
17
+
18
+ const useMappingList = (mappings: string[] | undefined): string[] => {
19
+ const mappingsList = useMemo(() => {
20
+ if (mappings === undefined) {
21
+ return [];
22
+ }
23
+ const list =
24
+ mappings
25
+ ?.map(mapping => {
26
+ return getLastItem(mapping) as string;
27
+ })
28
+ .flat() ?? [];
29
+
30
+ // We add a EVERYTHING ELSE mapping to the list.
31
+ list.push('');
32
+
33
+ // We sort the mappings alphabetically to make sure that the order is always the same.
34
+ list.sort((a, b) => a.localeCompare(b));
35
+
36
+ return list;
37
+ }, [mappings]);
38
+
39
+ return mappingsList;
40
+ };
41
+
42
+ export default useMappingList;
@@ -40,6 +40,7 @@ import SortBySelect from './ActionButtons/SortBySelect';
40
40
  import IcicleGraph from './IcicleGraph';
41
41
  import IcicleGraphArrow, {FIELD_FUNCTION_NAME} from './IcicleGraphArrow';
42
42
  import ColorStackLegend from './IcicleGraphArrow/ColorStackLegend';
43
+ import useMappingList from './IcicleGraphArrow/useMappingList';
43
44
 
44
45
  const numberFormatter = new Intl.NumberFormat('en-US');
45
46
 
@@ -220,13 +221,14 @@ const ProfileIcicleGraph = function ProfileIcicleGraphNonMemo({
220
221
  width,
221
222
  isHalfScreen,
222
223
  mappings,
223
- mappingsLoading,
224
224
  }: ProfileIcicleGraphProps): JSX.Element {
225
225
  const {onError, authenticationErrorMessage, isDarkMode} = useParcaContext();
226
226
  const {compareMode} = useProfileViewContext();
227
227
  const [isLoading, setIsLoading] = useState<boolean>(true);
228
228
  const isColorStackLegendEnabled = selectQueryParam('color_stack_legend') === 'true';
229
229
 
230
+ const mappingsList = useMappingList(mappings);
231
+
230
232
  const [storeSortBy = FIELD_FUNCTION_NAME] = useURLState({
231
233
  param: 'sort_by',
232
234
  navigateTo,
@@ -327,13 +329,16 @@ const ProfileIcicleGraph = function ProfileIcicleGraphNonMemo({
327
329
  isLoading,
328
330
  ]);
329
331
 
332
+ const loadingState =
333
+ !loading && (arrow !== undefined || graph !== undefined) && mappings !== undefined;
334
+
330
335
  useEffect(() => {
331
- if (!loading && (arrow !== undefined || graph !== undefined)) {
336
+ if (loadingState) {
332
337
  setIsLoading(false);
333
338
  } else {
334
339
  setIsLoading(true);
335
340
  }
336
- }, [loading, arrow, graph]);
341
+ }, [loadingState]);
337
342
 
338
343
  if (error != null) {
339
344
  onError?.(error);
@@ -389,6 +394,7 @@ const ProfileIcicleGraph = function ProfileIcicleGraphNonMemo({
389
394
  sortBy={storeSortBy as string}
390
395
  flamegraphLoading={isLoading}
391
396
  isHalfScreen={isHalfScreen}
397
+ mappingsListFromMetadata={mappingsList}
392
398
  />
393
399
  );
394
400
  }, [
@@ -396,16 +402,17 @@ const ProfileIcicleGraph = function ProfileIcicleGraphNonMemo({
396
402
  graph,
397
403
  arrow,
398
404
  total,
405
+ loading,
406
+ width,
399
407
  filtered,
400
408
  curPath,
401
409
  setNewCurPath,
402
410
  profileType,
403
411
  navigateTo,
404
- width,
405
412
  storeSortBy,
406
413
  isHalfScreen,
407
414
  isDarkMode,
408
- loading,
415
+ mappingsList,
409
416
  ]);
410
417
 
411
418
  if (isTrimmed) {
@@ -427,7 +434,7 @@ const ProfileIcicleGraph = function ProfileIcicleGraphNonMemo({
427
434
  navigateTo={navigateTo}
428
435
  compareMode={compareMode}
429
436
  mappings={mappings}
430
- mappingsLoading={mappingsLoading}
437
+ loading={isLoading}
431
438
  />
432
439
  )}
433
440
  <div className="min-h-48" id="h-icicle-graph">