@parca/profile 0.19.50 → 0.19.52
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 +12 -0
- package/dist/ProfileFlameGraph/FlameGraphArrow/FlameGraphNodes.js +4 -3
- package/dist/ProfileFlameGraph/FlameGraphArrow/index.d.ts +2 -0
- package/dist/ProfileFlameGraph/FlameGraphArrow/index.d.ts.map +1 -1
- package/dist/ProfileFlameGraph/FlameGraphArrow/index.js +7 -36
- package/dist/ProfileFlameGraph/index.d.ts +1 -1
- package/dist/ProfileFlameGraph/index.d.ts.map +1 -1
- package/dist/ProfileFlameGraph/index.js +14 -6
- package/package.json +11 -11
- package/src/ProfileFlameGraph/FlameGraphArrow/FlameGraphNodes.tsx +4 -4
- package/src/ProfileFlameGraph/FlameGraphArrow/index.tsx +13 -42
- package/src/ProfileFlameGraph/index.tsx +15 -5
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,18 @@
|
|
|
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.19.52 (2025-09-15)
|
|
7
|
+
|
|
8
|
+
## 0.24.2 (2025-09-10)
|
|
9
|
+
|
|
10
|
+
**Note:** Version bump only for package @parca/profile
|
|
11
|
+
|
|
12
|
+
## 0.19.51 (2025-09-10)
|
|
13
|
+
|
|
14
|
+
## 0.24.1 (2025-09-09)
|
|
15
|
+
|
|
16
|
+
**Note:** Version bump only for package @parca/profile
|
|
17
|
+
|
|
6
18
|
## [0.19.50](https://github.com/parca-dev/parca/compare/@parca/profile@0.19.49...@parca/profile@0.19.50) (2025-09-08)
|
|
7
19
|
|
|
8
20
|
**Note:** Version bump only for package @parca/profile
|
|
@@ -51,7 +51,6 @@ export const FlameNode = React.memo(function FlameNodeNoMemo({ table, row, color
|
|
|
51
51
|
? BigInt(valueOffsetColumn?.get(row))
|
|
52
52
|
: 0n;
|
|
53
53
|
const colorAttribute = colorBy === 'filename' ? filename : colorBy === 'binary' ? mappingFile : null;
|
|
54
|
-
const colorsMap = colors;
|
|
55
54
|
const hoveringName = hoveringRow !== undefined ? arrowToString(functionNameColumn?.get(hoveringRow)) : '';
|
|
56
55
|
const shouldBeHighlighted = functionName != null && hoveringName != null && functionName === hoveringName;
|
|
57
56
|
const colorResult = useNodeColor({
|
|
@@ -59,7 +58,7 @@ export const FlameNode = React.memo(function FlameNodeNoMemo({ table, row, color
|
|
|
59
58
|
compareMode,
|
|
60
59
|
cumulative,
|
|
61
60
|
diff,
|
|
62
|
-
colorsMap,
|
|
61
|
+
colorsMap: colors,
|
|
63
62
|
colorAttribute,
|
|
64
63
|
});
|
|
65
64
|
const name = useMemo(() => {
|
|
@@ -138,5 +137,7 @@ export const FlameNode = React.memo(function FlameNodeNoMemo({ table, row, color
|
|
|
138
137
|
prevProps.hoveringRow === nextProps.hoveringRow &&
|
|
139
138
|
prevProps.totalWidth === nextProps.totalWidth &&
|
|
140
139
|
prevProps.height === nextProps.height &&
|
|
141
|
-
prevProps.effectiveDepth === nextProps.effectiveDepth
|
|
140
|
+
prevProps.effectiveDepth === nextProps.effectiveDepth &&
|
|
141
|
+
prevProps.colorBy === nextProps.colorBy &&
|
|
142
|
+
prevProps.colors === nextProps.colors);
|
|
142
143
|
});
|
|
@@ -37,6 +37,8 @@ interface FlameGraphArrowProps {
|
|
|
37
37
|
setCurPath: (path: CurrentPathFrame[]) => void;
|
|
38
38
|
isHalfScreen: boolean;
|
|
39
39
|
mappingsListFromMetadata: string[];
|
|
40
|
+
filenamesListFromMetadata: string[];
|
|
41
|
+
colorBy: string;
|
|
40
42
|
compareAbsolute: boolean;
|
|
41
43
|
isFlameChart?: boolean;
|
|
42
44
|
isRenderedAsFlamegraph?: boolean;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/ProfileFlameGraph/FlameGraphArrow/index.tsx"],"names":[],"mappings":"AAaA,OAAO,KAQN,MAAM,OAAO,CAAC;AAKf,OAAO,EAAC,eAAe,EAAC,MAAM,eAAe,CAAC;AAG9C,OAAO,EAAC,WAAW,EAAC,MAAM,eAAe,CAAC;AAE1C,OAAO,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/ProfileFlameGraph/FlameGraphArrow/index.tsx"],"names":[],"mappings":"AAaA,OAAO,KAQN,MAAM,OAAO,CAAC;AAKf,OAAO,EAAC,eAAe,EAAC,MAAM,eAAe,CAAC;AAG9C,OAAO,EAAC,WAAW,EAAC,MAAM,eAAe,CAAC;AAE1C,OAAO,EAAC,KAAK,WAAW,EAAC,MAAM,kBAAkB,CAAC;AAElD,OAAO,EAAC,aAAa,EAAC,MAAM,qBAAqB,CAAC;AAIlD,OAAO,EAAuB,aAAa,EAAC,MAAM,mBAAmB,CAAC;AAKtE,OAAO,EACL,gBAAgB,EAMjB,MAAM,SAAS,CAAC;AAEjB,eAAO,MAAM,iBAAiB,gBAAgB,CAAC;AAC/C,eAAO,MAAM,kBAAkB,iBAAiB,CAAC;AACjD,eAAO,MAAM,sBAAsB,qBAAqB,CAAC;AACzD,eAAO,MAAM,sBAAsB,qBAAqB,CAAC;AACzD,eAAO,MAAM,mBAAmB,kBAAkB,CAAC;AACnD,eAAO,MAAM,aAAa,YAAY,CAAC;AACvC,eAAO,MAAM,eAAe,cAAc,CAAC;AAC3C,eAAO,MAAM,cAAc,aAAa,CAAC;AACzC,eAAO,MAAM,sBAAsB,qBAAqB,CAAC;AACzD,eAAO,MAAM,mBAAmB,kBAAkB,CAAC;AACnD,eAAO,MAAM,0BAA0B,yBAAyB,CAAC;AACjE,eAAO,MAAM,wBAAwB,uBAAuB,CAAC;AAC7D,eAAO,MAAM,yBAAyB,uBAAuB,CAAC;AAC9D,eAAO,MAAM,cAAc,aAAa,CAAC;AACzC,eAAO,MAAM,YAAY,WAAW,CAAC;AACrC,eAAO,MAAM,gBAAgB,eAAe,CAAC;AAC7C,eAAO,MAAM,UAAU,SAAS,CAAC;AACjC,eAAO,MAAM,UAAU,SAAS,CAAC;AACjC,eAAO,MAAM,YAAY,WAAW,CAAC;AACrC,eAAO,MAAM,WAAW,UAAU,CAAC;AACnC,eAAO,MAAM,kBAAkB,iBAAiB,CAAC;AAEjD,UAAU,oBAAoB;IAC5B,KAAK,EAAE,eAAe,CAAC;IACvB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,aAAa,EAAE,aAAa,CAAC;IAC7B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,gBAAgB,EAAE,CAAC;IAC5B,UAAU,EAAE,CAAC,IAAI,EAAE,gBAAgB,EAAE,KAAK,IAAI,CAAC;IAC/C,YAAY,EAAE,OAAO,CAAC;IACtB,wBAAwB,EAAE,MAAM,EAAE,CAAC;IACnC,yBAAyB,EAAE,MAAM,EAAE,CAAC;IACpC,OAAO,EAAE,MAAM,CAAC;IAChB,eAAe,EAAE,OAAO,CAAC;IACzB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,sBAAsB,CAAC,EAAE,OAAO,CAAC;IACjC,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AAED,eAAO,MAAM,gBAAgB,GAC3B,cAAc,MAAM,EAAE,EACtB,YAAY,OAAO,EACnB,qBAAqB,WAAW,KAC/B,aAQF,CAAC;AAEF,eAAO,MAAM,iBAAiB,GAC5B,eAAe,MAAM,EAAE,EACvB,YAAY,OAAO,EACnB,qBAAqB,WAAW,KAC/B,aAQF,CAAC;AAIF,eAAO,MAAM,eAAe,kDA0P1B,CAAC;AAEH,eAAe,eAAe,CAAC"}
|
|
@@ -14,20 +14,18 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
14
14
|
import { memo, useCallback, useDeferredValue, useEffect, useMemo, useRef, useState, } from 'react';
|
|
15
15
|
import { tableFromIPC } from 'apache-arrow';
|
|
16
16
|
import { useContextMenu } from 'react-contexify';
|
|
17
|
-
import { useParcaContext
|
|
17
|
+
import { useParcaContext } from '@parca/components';
|
|
18
18
|
import { USER_PREFERENCES, useCurrentColorProfile, useUserPreference } from '@parca/hooks';
|
|
19
19
|
import { getColorForFeature, selectDarkMode, useAppSelector } from '@parca/store';
|
|
20
|
-
import { getLastItem } from '@parca/utilities';
|
|
21
20
|
import { useProfileFilters } from '../../ProfileView/components/ProfileFilters/useProfileFilters';
|
|
22
21
|
import { useProfileViewContext } from '../../ProfileView/context/ProfileViewContext';
|
|
23
22
|
import ContextMenuWrapper from './ContextMenuWrapper';
|
|
24
23
|
import { FlameNode, RowHeight } from './FlameGraphNodes';
|
|
25
24
|
import { MemoizedTooltip } from './MemoizedTooltip';
|
|
26
25
|
import { TooltipProvider } from './TooltipContext';
|
|
27
|
-
import { useFilenamesList } from './useMappingList';
|
|
28
26
|
import { useScrollViewport } from './useScrollViewport';
|
|
29
27
|
import { useVisibleNodes } from './useVisibleNodes';
|
|
30
|
-
import {
|
|
28
|
+
import { extractFeature, extractFilenameFeature, getCurrentPathFrameData, getMaxDepth, isCurrentPathFrameMatch, } from './utils';
|
|
31
29
|
export const FIELD_LABELS_ONLY = 'labels_only';
|
|
32
30
|
export const FIELD_MAPPING_FILE = 'mapping_file';
|
|
33
31
|
export const FIELD_MAPPING_BUILD_ID = 'mapping_build_id';
|
|
@@ -66,7 +64,7 @@ export const getFilenameColors = (filenamesList, isDarkMode, currentColorProfile
|
|
|
66
64
|
return colors;
|
|
67
65
|
};
|
|
68
66
|
const noop = () => { };
|
|
69
|
-
export const FlameGraphArrow = memo(function FlameGraphArrow({ arrow, total, filtered, width, setCurPath, curPath, profileType, profileSource, compareAbsolute, isFlameChart = false, isRenderedAsFlamegraph = false, isInSandwichView = false, tooltipId = 'default', maxFrameCount, isExpanded = false, }) {
|
|
67
|
+
export const FlameGraphArrow = memo(function FlameGraphArrow({ arrow, total, filtered, width, setCurPath, curPath, profileType, profileSource, compareAbsolute, isFlameChart = false, isRenderedAsFlamegraph = false, isInSandwichView = false, tooltipId = 'default', maxFrameCount, isExpanded = false, mappingsListFromMetadata, filenamesListFromMetadata, colorBy, }) {
|
|
70
68
|
const [highlightSimilarStacksPreference] = useUserPreference(USER_PREFERENCES.HIGHLIGHT_SIMILAR_STACKS.key);
|
|
71
69
|
const [hoveringRow, setHoveringRow] = useState(undefined);
|
|
72
70
|
const [dockedMetainfo] = useUserPreference(USER_PREFERENCES.GRAPH_METAINFO_DOCKED.key);
|
|
@@ -87,42 +85,15 @@ export const FlameGraphArrow = memo(function FlameGraphArrow({ arrow, total, fil
|
|
|
87
85
|
const { compareMode } = useProfileViewContext();
|
|
88
86
|
const currentColorProfile = useCurrentColorProfile();
|
|
89
87
|
const colorForSimilarNodes = currentColorProfile.colorForSimilarNodes;
|
|
90
|
-
const [colorBy, _] = useURLState('color_by');
|
|
91
88
|
const colorByValue = colorBy === undefined || colorBy === '' ? 'binary' : colorBy;
|
|
92
|
-
const filenamesList = useFilenamesList(table);
|
|
93
|
-
const mappingsList = useMemo(() => {
|
|
94
|
-
// Read the mappings from the dictionary that contains all mapping strings.
|
|
95
|
-
// This is great, as might only have a dozen or so mappings,
|
|
96
|
-
// and don't need to read through all the rows (potentially thousands).
|
|
97
|
-
const mappingsDict = table.getChild(FIELD_MAPPING_FILE);
|
|
98
|
-
const mappings = mappingsDict?.data
|
|
99
|
-
.map(mapping => {
|
|
100
|
-
if (mapping.dictionary == null) {
|
|
101
|
-
return [];
|
|
102
|
-
}
|
|
103
|
-
const len = mapping.dictionary.length;
|
|
104
|
-
const entries = [];
|
|
105
|
-
for (let i = 0; i < len; i++) {
|
|
106
|
-
const fn = arrowToString(mapping.dictionary.get(i));
|
|
107
|
-
entries.push(getLastItem(fn) ?? '');
|
|
108
|
-
}
|
|
109
|
-
return entries;
|
|
110
|
-
})
|
|
111
|
-
.flat() ?? [];
|
|
112
|
-
// We add a EVERYTHING ELSE mapping to the list.
|
|
113
|
-
mappings.push('');
|
|
114
|
-
// We sort the mappings alphabetically to make sure that the order is always the same.
|
|
115
|
-
mappings.sort((a, b) => a.localeCompare(b));
|
|
116
|
-
return mappings;
|
|
117
|
-
}, [table]);
|
|
118
89
|
const filenameColors = useMemo(() => {
|
|
119
|
-
const colors = getFilenameColors(
|
|
90
|
+
const colors = getFilenameColors(filenamesListFromMetadata, isDarkMode, currentColorProfile);
|
|
120
91
|
return colors;
|
|
121
|
-
}, [isDarkMode,
|
|
92
|
+
}, [isDarkMode, filenamesListFromMetadata, currentColorProfile]);
|
|
122
93
|
const mappingColors = useMemo(() => {
|
|
123
|
-
const colors = getMappingColors(
|
|
94
|
+
const colors = getMappingColors(mappingsListFromMetadata, isDarkMode, currentColorProfile);
|
|
124
95
|
return colors;
|
|
125
|
-
}, [isDarkMode,
|
|
96
|
+
}, [isDarkMode, mappingsListFromMetadata, currentColorProfile]);
|
|
126
97
|
const colorByList = {
|
|
127
98
|
filename: filenameColors,
|
|
128
99
|
binary: mappingColors,
|
|
@@ -31,6 +31,6 @@ export declare const validateFlameChartQuery: (profileSource: MergedProfileSourc
|
|
|
31
31
|
isNonDelta: boolean;
|
|
32
32
|
isDurationTooLong: boolean;
|
|
33
33
|
};
|
|
34
|
-
declare const ProfileFlameGraph: ({ arrow, total, filtered, curPathArrow, setNewCurPathArrow, profileType, loading, error, width, isHalfScreen, metadataMappingFiles, isFlameChart, profileSource, isInSandwichView, isRenderedAsFlamegraph, tooltipId, maxFrameCount, isExpanded, }: ProfileFlameGraphProps) => JSX.Element;
|
|
34
|
+
declare const ProfileFlameGraph: ({ arrow, total, filtered, curPathArrow, setNewCurPathArrow, profileType, loading, error, width, isHalfScreen, metadataMappingFiles, isFlameChart, profileSource, isInSandwichView, isRenderedAsFlamegraph, tooltipId, maxFrameCount, isExpanded, metadataLoading, }: ProfileFlameGraphProps) => JSX.Element;
|
|
35
35
|
export default ProfileFlameGraph;
|
|
36
36
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/ProfileFlameGraph/index.tsx"],"names":[],"mappings":"AAaA,OAAO,KAAwE,MAAM,OAAO,CAAC;AAM7F,OAAO,EAAC,eAAe,EAAC,MAAM,eAAe,CAAC;AAO9C,OAAO,EAAC,WAAW,EAAC,MAAM,eAAe,CAAC;AAI1C,OAAO,EAAC,mBAAmB,EAAE,aAAa,EAAC,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/ProfileFlameGraph/index.tsx"],"names":[],"mappings":"AAaA,OAAO,KAAwE,MAAM,OAAO,CAAC;AAM7F,OAAO,EAAC,eAAe,EAAC,MAAM,eAAe,CAAC;AAO9C,OAAO,EAAC,WAAW,EAAC,MAAM,eAAe,CAAC;AAI1C,OAAO,EAAC,mBAAmB,EAAE,aAAa,EAAC,MAAM,kBAAkB,CAAC;AAOpE,OAAO,EAAC,gBAAgB,EAA0B,MAAM,yBAAyB,CAAC;AAIlF,MAAM,MAAM,aAAa,GAAG,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;AAEpE,UAAU,sBAAsB;IAC9B,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,eAAe,CAAC;IACxB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,aAAa,EAAE,aAAa,CAAC;IAC7B,YAAY,EAAE,gBAAgB,EAAE,GAAG,EAAE,CAAC;IACtC,kBAAkB,EAAE,CAAC,IAAI,EAAE,gBAAgB,EAAE,KAAK,IAAI,CAAC;IACvD,OAAO,EAAE,OAAO,CAAC;IACjB,gBAAgB,CAAC,EAAE,CAAC,OAAO,EAAE,KAAK,CAAC,GAAG,CAAC,OAAO,KAAK,IAAI,CAAC;IACxD,KAAK,CAAC,EAAE,GAAG,CAAC;IACZ,YAAY,EAAE,OAAO,CAAC;IACtB,oBAAoB,CAAC,EAAE,MAAM,EAAE,CAAC;IAChC,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,sBAAsB,CAAC,EAAE,OAAO,CAAC;IACjC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AAUD,eAAO,MAAM,uBAAuB,GAClC,eAAe,mBAAmB,KACjC;IAAC,OAAO,EAAE,OAAO,CAAC;IAAC,UAAU,EAAE,OAAO,CAAC;IAAC,iBAAiB,EAAE,OAAO,CAAA;CAMpE,CAAC;AAEF,QAAA,MAAM,iBAAiB,GAAqC,qQAoBzD,sBAAsB,KAAG,GAAG,CAAC,OA0T/B,CAAC;AAEF,eAAe,iBAAiB,CAAC"}
|
|
@@ -20,9 +20,10 @@ import { testId } from '@parca/test-utils';
|
|
|
20
20
|
import { capitalizeOnlyFirstLetter, divide } from '@parca/utilities';
|
|
21
21
|
import DiffLegend from '../ProfileView/components/DiffLegend';
|
|
22
22
|
import { useProfileViewContext } from '../ProfileView/context/ProfileViewContext';
|
|
23
|
+
import { useProfileMetadata } from '../ProfileView/hooks/useProfileMetadata';
|
|
24
|
+
import { useVisualizationState } from '../ProfileView/hooks/useVisualizationState';
|
|
23
25
|
import { TimelineGuide } from '../TimelineGuide';
|
|
24
26
|
import { FlameGraphArrow } from './FlameGraphArrow';
|
|
25
|
-
import useMappingList from './FlameGraphArrow/useMappingList';
|
|
26
27
|
import { boundsFromProfileSource } from './FlameGraphArrow/utils';
|
|
27
28
|
const numberFormatter = new Intl.NumberFormat('en-US');
|
|
28
29
|
const ErrorContent = ({ errorMessage }) => {
|
|
@@ -35,11 +36,12 @@ export const validateFlameChartQuery = (profileSource) => {
|
|
|
35
36
|
const isDurationTooLong = duration > 60000000000n; // 60 seconds in nanoseconds
|
|
36
37
|
return { isValid: !isNonDelta && !isDurationTooLong, isNonDelta, isDurationTooLong };
|
|
37
38
|
};
|
|
38
|
-
const ProfileFlameGraph = function ProfileFlameGraphNonMemo({ arrow, total, filtered, curPathArrow, setNewCurPathArrow, profileType, loading, error, width, isHalfScreen, metadataMappingFiles, isFlameChart = false, profileSource, isInSandwichView = false, isRenderedAsFlamegraph = false, tooltipId, maxFrameCount, isExpanded = false, }) {
|
|
39
|
+
const ProfileFlameGraph = function ProfileFlameGraphNonMemo({ arrow, total, filtered, curPathArrow, setNewCurPathArrow, profileType, loading, error, width, isHalfScreen, metadataMappingFiles, isFlameChart = false, profileSource, isInSandwichView = false, isRenderedAsFlamegraph = false, tooltipId, maxFrameCount, isExpanded = false, metadataLoading = false, }) {
|
|
39
40
|
const { onError, authenticationErrorMessage, isDarkMode, flamechartHelpText } = useParcaContext();
|
|
40
41
|
const { compareMode } = useProfileViewContext();
|
|
41
42
|
const [isLoading, setIsLoading] = useState(true);
|
|
42
43
|
const [flameChartRef, { height: flameChartHeight }] = useMeasure();
|
|
44
|
+
const { colorBy, setColorBy } = useVisualizationState();
|
|
43
45
|
// Create local state for paths when in sandwich view to avoid URL updates
|
|
44
46
|
const [localCurPathArrow, setLocalCurPathArrow] = useState([]);
|
|
45
47
|
const setCurPathArrowWrapper = useCallback((path) => {
|
|
@@ -52,8 +54,12 @@ const ProfileFlameGraph = function ProfileFlameGraphNonMemo({ arrow, total, filt
|
|
|
52
54
|
}, [isInSandwichView, setNewCurPathArrow]);
|
|
53
55
|
// Determine which paths to use based on isInSandwichView flag
|
|
54
56
|
const effectiveCurPathArrow = isInSandwichView ? localCurPathArrow : curPathArrow;
|
|
55
|
-
const mappingsList =
|
|
56
|
-
|
|
57
|
+
const { mappingsList, filenamesList } = useProfileMetadata({
|
|
58
|
+
flamegraphArrow: arrow,
|
|
59
|
+
metadataMappingFiles,
|
|
60
|
+
metadataLoading,
|
|
61
|
+
colorBy,
|
|
62
|
+
});
|
|
57
63
|
// By default, we want delta profiles (CPU) to be relatively compared.
|
|
58
64
|
// For non-delta profiles, like goroutines or memory, we want the profiles to be compared absolutely.
|
|
59
65
|
const compareAbsoluteDefault = profileType?.delta === false ? 'true' : 'false';
|
|
@@ -119,7 +125,7 @@ const ProfileFlameGraph = function ProfileFlameGraphNonMemo({ arrow, total, filt
|
|
|
119
125
|
if (total === 0n && !loading)
|
|
120
126
|
return _jsx("div", { className: "mx-auto text-center", children: "Profile has no samples" });
|
|
121
127
|
if (arrow !== undefined) {
|
|
122
|
-
return (_jsxs("div", { className: "relative", children: [isFlameChart ? (_jsx(TimelineGuide, { bounds: boundsFromProfileSource(profileSource), width: width, height: flameChartHeight ?? 420, margin: 0, ticks: 12, timeUnit: "nanoseconds" })) : null, _jsx("div", { ref: flameChartRef, children: _jsx(FlameGraphArrow, { width: width, arrow: arrow, total: total, filtered: filtered, curPath: effectiveCurPathArrow, setCurPath: setCurPathArrowWrapper, profileType: profileType, isHalfScreen: isHalfScreen, mappingsListFromMetadata: mappingsList, compareAbsolute: isCompareAbsolute, isFlameChart: isFlameChart, profileSource: profileSource, isRenderedAsFlamegraph: isRenderedAsFlamegraph, isInSandwichView: isInSandwichView, tooltipId: tooltipId, maxFrameCount: maxFrameCount, isExpanded: isExpanded }) })] }));
|
|
128
|
+
return (_jsxs("div", { className: "relative", children: [isFlameChart ? (_jsx(TimelineGuide, { bounds: boundsFromProfileSource(profileSource), width: width, height: flameChartHeight ?? 420, margin: 0, ticks: 12, timeUnit: "nanoseconds" })) : null, _jsx("div", { ref: flameChartRef, children: _jsx(FlameGraphArrow, { width: width, arrow: arrow, total: total, filtered: filtered, curPath: effectiveCurPathArrow, setCurPath: setCurPathArrowWrapper, profileType: profileType, isHalfScreen: isHalfScreen, mappingsListFromMetadata: mappingsList, filenamesListFromMetadata: filenamesList, compareAbsolute: isCompareAbsolute, isFlameChart: isFlameChart, profileSource: profileSource, isRenderedAsFlamegraph: isRenderedAsFlamegraph, isInSandwichView: isInSandwichView, tooltipId: tooltipId, maxFrameCount: maxFrameCount, isExpanded: isExpanded, colorBy: colorBy }) })] }));
|
|
123
129
|
}
|
|
124
130
|
}, [
|
|
125
131
|
isLoading,
|
|
@@ -131,7 +137,6 @@ const ProfileFlameGraph = function ProfileFlameGraphNonMemo({ arrow, total, filt
|
|
|
131
137
|
profileType,
|
|
132
138
|
isHalfScreen,
|
|
133
139
|
isDarkMode,
|
|
134
|
-
mappingsList,
|
|
135
140
|
isCompareAbsolute,
|
|
136
141
|
isFlameChart,
|
|
137
142
|
profileSource,
|
|
@@ -145,6 +150,9 @@ const ProfileFlameGraph = function ProfileFlameGraphNonMemo({ arrow, total, filt
|
|
|
145
150
|
tooltipId,
|
|
146
151
|
maxFrameCount,
|
|
147
152
|
isExpanded,
|
|
153
|
+
mappingsList,
|
|
154
|
+
filenamesList,
|
|
155
|
+
colorBy,
|
|
148
156
|
]);
|
|
149
157
|
useEffect(() => {
|
|
150
158
|
if (isTrimmed) {
|
package/package.json
CHANGED
|
@@ -1,20 +1,20 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@parca/profile",
|
|
3
|
-
"version": "0.19.
|
|
3
|
+
"version": "0.19.52",
|
|
4
4
|
"description": "Profile viewing libraries",
|
|
5
5
|
"dependencies": {
|
|
6
6
|
"@floating-ui/react": "^0.27.12",
|
|
7
7
|
"@headlessui/react": "^1.7.19",
|
|
8
8
|
"@iconify/react": "^4.0.0",
|
|
9
|
-
"@parca/client": "0.17.
|
|
10
|
-
"@parca/components": "0.16.
|
|
11
|
-
"@parca/dynamicsize": "0.16.
|
|
12
|
-
"@parca/hooks": "0.0.
|
|
13
|
-
"@parca/icons": "0.16.
|
|
14
|
-
"@parca/parser": "0.16.
|
|
15
|
-
"@parca/store": "0.16.
|
|
16
|
-
"@parca/test-utils": "0.0.
|
|
17
|
-
"@parca/utilities": "0.0.
|
|
9
|
+
"@parca/client": "0.17.5",
|
|
10
|
+
"@parca/components": "0.16.370",
|
|
11
|
+
"@parca/dynamicsize": "0.16.67",
|
|
12
|
+
"@parca/hooks": "0.0.102",
|
|
13
|
+
"@parca/icons": "0.16.74",
|
|
14
|
+
"@parca/parser": "0.16.81",
|
|
15
|
+
"@parca/store": "0.16.186",
|
|
16
|
+
"@parca/test-utils": "0.0.12",
|
|
17
|
+
"@parca/utilities": "0.0.109",
|
|
18
18
|
"@popperjs/core": "^2.11.8",
|
|
19
19
|
"@protobuf-ts/runtime-rpc": "^2.5.0",
|
|
20
20
|
"@storybook/preview-api": "^8.4.3",
|
|
@@ -79,5 +79,5 @@
|
|
|
79
79
|
"access": "public",
|
|
80
80
|
"registry": "https://registry.npmjs.org/"
|
|
81
81
|
},
|
|
82
|
-
"gitHead": "
|
|
82
|
+
"gitHead": "df1f4ce1710f808dfc6af0a631b140cd346dfaab"
|
|
83
83
|
}
|
|
@@ -130,8 +130,6 @@ export const FlameNode = React.memo(
|
|
|
130
130
|
const colorAttribute =
|
|
131
131
|
colorBy === 'filename' ? filename : colorBy === 'binary' ? mappingFile : null;
|
|
132
132
|
|
|
133
|
-
const colorsMap = colors;
|
|
134
|
-
|
|
135
133
|
const hoveringName =
|
|
136
134
|
hoveringRow !== undefined ? arrowToString(functionNameColumn?.get(hoveringRow)) : '';
|
|
137
135
|
const shouldBeHighlighted =
|
|
@@ -142,7 +140,7 @@ export const FlameNode = React.memo(
|
|
|
142
140
|
compareMode,
|
|
143
141
|
cumulative,
|
|
144
142
|
diff,
|
|
145
|
-
colorsMap,
|
|
143
|
+
colorsMap: colors,
|
|
146
144
|
colorAttribute,
|
|
147
145
|
});
|
|
148
146
|
|
|
@@ -296,7 +294,9 @@ export const FlameNode = React.memo(
|
|
|
296
294
|
prevProps.hoveringRow === nextProps.hoveringRow &&
|
|
297
295
|
prevProps.totalWidth === nextProps.totalWidth &&
|
|
298
296
|
prevProps.height === nextProps.height &&
|
|
299
|
-
prevProps.effectiveDepth === nextProps.effectiveDepth
|
|
297
|
+
prevProps.effectiveDepth === nextProps.effectiveDepth &&
|
|
298
|
+
prevProps.colorBy === nextProps.colorBy &&
|
|
299
|
+
prevProps.colors === nextProps.colors
|
|
300
300
|
);
|
|
301
301
|
}
|
|
302
302
|
);
|
|
@@ -21,15 +21,15 @@ import React, {
|
|
|
21
21
|
useState,
|
|
22
22
|
} from 'react';
|
|
23
23
|
|
|
24
|
-
import {
|
|
24
|
+
import {Table, tableFromIPC} from 'apache-arrow';
|
|
25
25
|
import {useContextMenu} from 'react-contexify';
|
|
26
26
|
|
|
27
27
|
import {FlamegraphArrow} from '@parca/client';
|
|
28
|
-
import {useParcaContext
|
|
28
|
+
import {useParcaContext} from '@parca/components';
|
|
29
29
|
import {USER_PREFERENCES, useCurrentColorProfile, useUserPreference} from '@parca/hooks';
|
|
30
30
|
import {ProfileType} from '@parca/parser';
|
|
31
31
|
import {getColorForFeature, selectDarkMode, useAppSelector} from '@parca/store';
|
|
32
|
-
import {
|
|
32
|
+
import {type ColorConfig} from '@parca/utilities';
|
|
33
33
|
|
|
34
34
|
import {ProfileSource} from '../../ProfileSource';
|
|
35
35
|
import {useProfileFilters} from '../../ProfileView/components/ProfileFilters/useProfileFilters';
|
|
@@ -38,12 +38,10 @@ import ContextMenuWrapper, {ContextMenuWrapperRef} from './ContextMenuWrapper';
|
|
|
38
38
|
import {FlameNode, RowHeight, colorByColors} from './FlameGraphNodes';
|
|
39
39
|
import {MemoizedTooltip} from './MemoizedTooltip';
|
|
40
40
|
import {TooltipProvider} from './TooltipContext';
|
|
41
|
-
import {useFilenamesList} from './useMappingList';
|
|
42
41
|
import {useScrollViewport} from './useScrollViewport';
|
|
43
42
|
import {useVisibleNodes} from './useVisibleNodes';
|
|
44
43
|
import {
|
|
45
44
|
CurrentPathFrame,
|
|
46
|
-
arrowToString,
|
|
47
45
|
extractFeature,
|
|
48
46
|
extractFilenameFeature,
|
|
49
47
|
getCurrentPathFrameData,
|
|
@@ -84,6 +82,8 @@ interface FlameGraphArrowProps {
|
|
|
84
82
|
setCurPath: (path: CurrentPathFrame[]) => void;
|
|
85
83
|
isHalfScreen: boolean;
|
|
86
84
|
mappingsListFromMetadata: string[];
|
|
85
|
+
filenamesListFromMetadata: string[];
|
|
86
|
+
colorBy: string;
|
|
87
87
|
compareAbsolute: boolean;
|
|
88
88
|
isFlameChart?: boolean;
|
|
89
89
|
isRenderedAsFlamegraph?: boolean;
|
|
@@ -139,6 +139,9 @@ export const FlameGraphArrow = memo(function FlameGraphArrow({
|
|
|
139
139
|
tooltipId = 'default',
|
|
140
140
|
maxFrameCount,
|
|
141
141
|
isExpanded = false,
|
|
142
|
+
mappingsListFromMetadata,
|
|
143
|
+
filenamesListFromMetadata,
|
|
144
|
+
colorBy,
|
|
142
145
|
}: FlameGraphArrowProps): React.JSX.Element {
|
|
143
146
|
const [highlightSimilarStacksPreference] = useUserPreference<boolean>(
|
|
144
147
|
USER_PREFERENCES.HIGHLIGHT_SIMILAR_STACKS.key
|
|
@@ -169,49 +172,17 @@ export const FlameGraphArrow = memo(function FlameGraphArrow({
|
|
|
169
172
|
const currentColorProfile = useCurrentColorProfile();
|
|
170
173
|
const colorForSimilarNodes = currentColorProfile.colorForSimilarNodes;
|
|
171
174
|
|
|
172
|
-
const
|
|
173
|
-
const colorByValue = colorBy === undefined || colorBy === '' ? 'binary' : (colorBy as string);
|
|
174
|
-
|
|
175
|
-
const filenamesList = useFilenamesList(table);
|
|
176
|
-
|
|
177
|
-
const mappingsList = useMemo(() => {
|
|
178
|
-
// Read the mappings from the dictionary that contains all mapping strings.
|
|
179
|
-
// This is great, as might only have a dozen or so mappings,
|
|
180
|
-
// and don't need to read through all the rows (potentially thousands).
|
|
181
|
-
const mappingsDict: Vector<Dictionary> | null = table.getChild(FIELD_MAPPING_FILE);
|
|
182
|
-
const mappings =
|
|
183
|
-
mappingsDict?.data
|
|
184
|
-
.map(mapping => {
|
|
185
|
-
if (mapping.dictionary == null) {
|
|
186
|
-
return [];
|
|
187
|
-
}
|
|
188
|
-
const len = mapping.dictionary.length;
|
|
189
|
-
const entries: string[] = [];
|
|
190
|
-
for (let i = 0; i < len; i++) {
|
|
191
|
-
const fn = arrowToString(mapping.dictionary.get(i));
|
|
192
|
-
entries.push(getLastItem(fn) ?? '');
|
|
193
|
-
}
|
|
194
|
-
return entries;
|
|
195
|
-
})
|
|
196
|
-
.flat() ?? [];
|
|
197
|
-
|
|
198
|
-
// We add a EVERYTHING ELSE mapping to the list.
|
|
199
|
-
mappings.push('');
|
|
200
|
-
|
|
201
|
-
// We sort the mappings alphabetically to make sure that the order is always the same.
|
|
202
|
-
mappings.sort((a, b) => a.localeCompare(b));
|
|
203
|
-
return mappings;
|
|
204
|
-
}, [table]);
|
|
175
|
+
const colorByValue = colorBy === undefined || colorBy === '' ? 'binary' : colorBy;
|
|
205
176
|
|
|
206
177
|
const filenameColors = useMemo(() => {
|
|
207
|
-
const colors = getFilenameColors(
|
|
178
|
+
const colors = getFilenameColors(filenamesListFromMetadata, isDarkMode, currentColorProfile);
|
|
208
179
|
return colors;
|
|
209
|
-
}, [isDarkMode,
|
|
180
|
+
}, [isDarkMode, filenamesListFromMetadata, currentColorProfile]);
|
|
210
181
|
|
|
211
182
|
const mappingColors = useMemo(() => {
|
|
212
|
-
const colors = getMappingColors(
|
|
183
|
+
const colors = getMappingColors(mappingsListFromMetadata, isDarkMode, currentColorProfile);
|
|
213
184
|
return colors;
|
|
214
|
-
}, [isDarkMode,
|
|
185
|
+
}, [isDarkMode, mappingsListFromMetadata, currentColorProfile]);
|
|
215
186
|
|
|
216
187
|
const colorByList = {
|
|
217
188
|
filename: filenameColors,
|
|
@@ -31,9 +31,10 @@ import {capitalizeOnlyFirstLetter, divide} from '@parca/utilities';
|
|
|
31
31
|
import {MergedProfileSource, ProfileSource} from '../ProfileSource';
|
|
32
32
|
import DiffLegend from '../ProfileView/components/DiffLegend';
|
|
33
33
|
import {useProfileViewContext} from '../ProfileView/context/ProfileViewContext';
|
|
34
|
+
import {useProfileMetadata} from '../ProfileView/hooks/useProfileMetadata';
|
|
35
|
+
import {useVisualizationState} from '../ProfileView/hooks/useVisualizationState';
|
|
34
36
|
import {TimelineGuide} from '../TimelineGuide';
|
|
35
37
|
import {FlameGraphArrow} from './FlameGraphArrow';
|
|
36
|
-
import useMappingList from './FlameGraphArrow/useMappingList';
|
|
37
38
|
import {CurrentPathFrame, boundsFromProfileSource} from './FlameGraphArrow/utils';
|
|
38
39
|
|
|
39
40
|
const numberFormatter = new Intl.NumberFormat('en-US');
|
|
@@ -100,11 +101,13 @@ const ProfileFlameGraph = function ProfileFlameGraphNonMemo({
|
|
|
100
101
|
tooltipId,
|
|
101
102
|
maxFrameCount,
|
|
102
103
|
isExpanded = false,
|
|
104
|
+
metadataLoading = false,
|
|
103
105
|
}: ProfileFlameGraphProps): JSX.Element {
|
|
104
106
|
const {onError, authenticationErrorMessage, isDarkMode, flamechartHelpText} = useParcaContext();
|
|
105
107
|
const {compareMode} = useProfileViewContext();
|
|
106
108
|
const [isLoading, setIsLoading] = useState<boolean>(true);
|
|
107
109
|
const [flameChartRef, {height: flameChartHeight}] = useMeasure();
|
|
110
|
+
const {colorBy, setColorBy} = useVisualizationState();
|
|
108
111
|
|
|
109
112
|
// Create local state for paths when in sandwich view to avoid URL updates
|
|
110
113
|
const [localCurPathArrow, setLocalCurPathArrow] = useState<CurrentPathFrame[]>([]);
|
|
@@ -123,9 +126,12 @@ const ProfileFlameGraph = function ProfileFlameGraphNonMemo({
|
|
|
123
126
|
// Determine which paths to use based on isInSandwichView flag
|
|
124
127
|
const effectiveCurPathArrow = isInSandwichView ? localCurPathArrow : curPathArrow;
|
|
125
128
|
|
|
126
|
-
const mappingsList =
|
|
127
|
-
|
|
128
|
-
|
|
129
|
+
const {mappingsList, filenamesList} = useProfileMetadata({
|
|
130
|
+
flamegraphArrow: arrow,
|
|
131
|
+
metadataMappingFiles,
|
|
132
|
+
metadataLoading,
|
|
133
|
+
colorBy,
|
|
134
|
+
});
|
|
129
135
|
|
|
130
136
|
// By default, we want delta profiles (CPU) to be relatively compared.
|
|
131
137
|
// For non-delta profiles, like goroutines or memory, we want the profiles to be compared absolutely.
|
|
@@ -279,6 +285,7 @@ const ProfileFlameGraph = function ProfileFlameGraphNonMemo({
|
|
|
279
285
|
profileType={profileType}
|
|
280
286
|
isHalfScreen={isHalfScreen}
|
|
281
287
|
mappingsListFromMetadata={mappingsList}
|
|
288
|
+
filenamesListFromMetadata={filenamesList}
|
|
282
289
|
compareAbsolute={isCompareAbsolute}
|
|
283
290
|
isFlameChart={isFlameChart}
|
|
284
291
|
profileSource={profileSource}
|
|
@@ -287,6 +294,7 @@ const ProfileFlameGraph = function ProfileFlameGraphNonMemo({
|
|
|
287
294
|
tooltipId={tooltipId}
|
|
288
295
|
maxFrameCount={maxFrameCount}
|
|
289
296
|
isExpanded={isExpanded}
|
|
297
|
+
colorBy={colorBy}
|
|
290
298
|
/>
|
|
291
299
|
</div>
|
|
292
300
|
</div>
|
|
@@ -302,7 +310,6 @@ const ProfileFlameGraph = function ProfileFlameGraphNonMemo({
|
|
|
302
310
|
profileType,
|
|
303
311
|
isHalfScreen,
|
|
304
312
|
isDarkMode,
|
|
305
|
-
mappingsList,
|
|
306
313
|
isCompareAbsolute,
|
|
307
314
|
isFlameChart,
|
|
308
315
|
profileSource,
|
|
@@ -316,6 +323,9 @@ const ProfileFlameGraph = function ProfileFlameGraphNonMemo({
|
|
|
316
323
|
tooltipId,
|
|
317
324
|
maxFrameCount,
|
|
318
325
|
isExpanded,
|
|
326
|
+
mappingsList,
|
|
327
|
+
filenamesList,
|
|
328
|
+
colorBy,
|
|
319
329
|
]);
|
|
320
330
|
|
|
321
331
|
useEffect(() => {
|