@parca/profile 0.19.24 → 0.19.26

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 (50) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/dist/ProfileFlameGraph/FlameGraphArrow/FlameGraphNodes.d.ts.map +1 -1
  3. package/dist/ProfileFlameGraph/FlameGraphArrow/FlameGraphNodes.js +8 -0
  4. package/dist/ProfileFlameGraph/FlameGraphArrow/index.d.ts.map +1 -1
  5. package/dist/ProfileFlameGraph/FlameGraphArrow/index.js +33 -40
  6. package/dist/ProfileFlameGraph/FlameGraphArrow/useScrollViewport.d.ts +8 -0
  7. package/dist/ProfileFlameGraph/FlameGraphArrow/useScrollViewport.d.ts.map +1 -0
  8. package/dist/ProfileFlameGraph/FlameGraphArrow/useScrollViewport.js +70 -0
  9. package/dist/ProfileFlameGraph/FlameGraphArrow/useVisibleNodes.d.ts +24 -0
  10. package/dist/ProfileFlameGraph/FlameGraphArrow/useVisibleNodes.d.ts.map +1 -0
  11. package/dist/ProfileFlameGraph/FlameGraphArrow/useVisibleNodes.js +111 -0
  12. package/dist/ProfileFlameGraph/FlameGraphArrow/utils.d.ts +2 -1
  13. package/dist/ProfileFlameGraph/FlameGraphArrow/utils.d.ts.map +1 -1
  14. package/dist/ProfileFlameGraph/FlameGraphArrow/utils.js +11 -0
  15. package/dist/ProfileView/components/ColorStackLegend.d.ts.map +1 -1
  16. package/dist/ProfileView/components/ColorStackLegend.js +0 -1
  17. package/dist/ProfileView/components/DashboardItems/index.d.ts +3 -2
  18. package/dist/ProfileView/components/DashboardItems/index.d.ts.map +1 -1
  19. package/dist/ProfileView/components/DashboardItems/index.js +2 -2
  20. package/dist/ProfileView/index.d.ts +1 -1
  21. package/dist/ProfileView/index.d.ts.map +1 -1
  22. package/dist/ProfileView/index.js +2 -1
  23. package/dist/ProfileView/types/visualization.d.ts +6 -10
  24. package/dist/ProfileView/types/visualization.d.ts.map +1 -1
  25. package/dist/ProfileViewWithData.d.ts.map +1 -1
  26. package/dist/ProfileViewWithData.js +52 -22
  27. package/dist/Sandwich/components/CalleesSection.d.ts +3 -12
  28. package/dist/Sandwich/components/CalleesSection.d.ts.map +1 -1
  29. package/dist/Sandwich/components/CalleesSection.js +2 -4
  30. package/dist/Sandwich/components/CallersSection.d.ts +3 -13
  31. package/dist/Sandwich/components/CallersSection.d.ts.map +1 -1
  32. package/dist/Sandwich/components/CallersSection.js +5 -8
  33. package/dist/Sandwich/index.d.ts +2 -10
  34. package/dist/Sandwich/index.d.ts.map +1 -1
  35. package/dist/Sandwich/index.js +5 -103
  36. package/dist/styles.css +1 -1
  37. package/package.json +6 -6
  38. package/src/ProfileFlameGraph/FlameGraphArrow/FlameGraphNodes.tsx +214 -200
  39. package/src/ProfileFlameGraph/FlameGraphArrow/index.tsx +75 -76
  40. package/src/ProfileFlameGraph/FlameGraphArrow/useScrollViewport.ts +89 -0
  41. package/src/ProfileFlameGraph/FlameGraphArrow/useVisibleNodes.ts +167 -0
  42. package/src/ProfileFlameGraph/FlameGraphArrow/utils.ts +12 -1
  43. package/src/ProfileView/components/ColorStackLegend.tsx +0 -2
  44. package/src/ProfileView/components/DashboardItems/index.tsx +4 -12
  45. package/src/ProfileView/index.tsx +2 -0
  46. package/src/ProfileView/types/visualization.ts +7 -18
  47. package/src/ProfileViewWithData.tsx +65 -30
  48. package/src/Sandwich/components/CalleesSection.tsx +10 -28
  49. package/src/Sandwich/components/CallersSection.tsx +13 -34
  50. package/src/Sandwich/index.tsx +8 -170
@@ -16,12 +16,12 @@ import React, {useMemo} from 'react';
16
16
  import {Vector, tableFromIPC} from 'apache-arrow';
17
17
  import {Tooltip} from 'react-tooltip';
18
18
 
19
- import {type FlamegraphArrow} from '@parca/client';
20
19
  import {Button} from '@parca/components';
21
20
 
22
21
  import ProfileFlameGraph from '../../ProfileFlameGraph';
23
22
  import {type CurrentPathFrame} from '../../ProfileFlameGraph/FlameGraphArrow/utils';
24
23
  import {type ProfileSource} from '../../ProfileSource';
24
+ import {FlamegraphData} from '../../ProfileView/types/visualization';
25
25
 
26
26
  const FIELD_DEPTH = 'depth';
27
27
 
@@ -38,20 +38,10 @@ function getMaxDepth(depthColumn: Vector<any> | null): number {
38
38
 
39
39
  interface CallersSectionProps {
40
40
  callersRef: React.RefObject<HTMLDivElement>;
41
- callersFlamegraphResponse?: {
42
- report: {
43
- oneofKind: string;
44
- flamegraphArrow?: FlamegraphArrow;
45
- };
46
- total?: string;
47
- };
48
- callersFlamegraphLoading: boolean;
49
- callersFlamegraphError: any;
50
- filtered: bigint;
41
+ callersFlamegraphData: FlamegraphData;
51
42
  profileSource: ProfileSource;
52
43
  curPathArrow: CurrentPathFrame[];
53
44
  setCurPathArrow: (path: CurrentPathFrame[]) => void;
54
- metadataMappingFiles?: string[];
55
45
  isExpanded: boolean;
56
46
  setIsExpanded: (isExpanded: boolean) => void;
57
47
  defaultMaxFrames: number;
@@ -59,29 +49,22 @@ interface CallersSectionProps {
59
49
 
60
50
  export function CallersSection({
61
51
  callersRef,
62
- callersFlamegraphResponse,
63
- callersFlamegraphLoading,
64
- callersFlamegraphError,
65
- filtered,
52
+ callersFlamegraphData,
66
53
  profileSource,
67
54
  curPathArrow,
68
55
  setCurPathArrow,
69
- metadataMappingFiles,
70
56
  isExpanded,
71
57
  setIsExpanded,
72
58
  defaultMaxFrames,
73
59
  }: CallersSectionProps): JSX.Element {
74
60
  const maxDepth = useMemo(() => {
75
- if (
76
- callersFlamegraphResponse?.report.oneofKind === 'flamegraphArrow' &&
77
- callersFlamegraphResponse?.report?.flamegraphArrow != null
78
- ) {
79
- const table = tableFromIPC(callersFlamegraphResponse.report.flamegraphArrow.record);
61
+ if (callersFlamegraphData?.arrow != null) {
62
+ const table = tableFromIPC(callersFlamegraphData.arrow.record);
80
63
  const depthColumn = table.getChild(FIELD_DEPTH);
81
64
  return getMaxDepth(depthColumn);
82
65
  }
83
66
  return 0;
84
- }, [callersFlamegraphResponse]);
67
+ }, [callersFlamegraphData]);
85
68
 
86
69
  const shouldShowButton = maxDepth > defaultMaxFrames;
87
70
 
@@ -113,22 +96,18 @@ export function CallersSection({
113
96
  </div>
114
97
  <div className="flex-1 overflow-hidden relative">
115
98
  <ProfileFlameGraph
116
- arrow={
117
- callersFlamegraphResponse?.report.oneofKind === 'flamegraphArrow'
118
- ? callersFlamegraphResponse?.report?.flamegraphArrow
119
- : undefined
120
- }
121
- total={BigInt(callersFlamegraphResponse?.total ?? '0')}
122
- filtered={filtered}
99
+ arrow={callersFlamegraphData?.arrow}
100
+ total={callersFlamegraphData.total ?? BigInt(0)}
101
+ filtered={callersFlamegraphData.filtered ?? BigInt(0)}
123
102
  profileType={profileSource?.ProfileType()}
124
- loading={callersFlamegraphLoading}
125
- error={callersFlamegraphError}
103
+ loading={callersFlamegraphData.loading}
104
+ error={callersFlamegraphData.error}
126
105
  isHalfScreen={true}
127
106
  width={
128
107
  callersRef.current != null ? callersRef.current.getBoundingClientRect().width - 25 : 0
129
108
  }
130
- metadataMappingFiles={metadataMappingFiles}
131
- metadataLoading={false}
109
+ metadataMappingFiles={callersFlamegraphData.metadataMappingFiles}
110
+ metadataLoading={callersFlamegraphData.metadataLoading}
132
111
  isInSandwichView={true}
133
112
  curPathArrow={curPathArrow}
134
113
  setNewCurPathArrow={setCurPathArrow}
@@ -11,59 +11,31 @@
11
11
  // See the License for the specific language governing permissions and
12
12
  // limitations under the License.
13
13
 
14
- import React, {useEffect, useMemo, useRef, useState} from 'react';
14
+ import React, {useRef, useState} from 'react';
15
15
 
16
- import {type Row as TableRow} from '@tanstack/table-core';
17
- import {tableFromIPC} from 'apache-arrow';
18
16
  import {AnimatePresence, motion} from 'framer-motion';
19
17
 
20
- import {QueryRequest_ReportType, QueryServiceClient} from '@parca/client';
21
- import {useParcaContext, useURLState} from '@parca/components';
22
- import {useCurrentColorProfile} from '@parca/hooks';
23
- import {ProfileType} from '@parca/parser';
18
+ import {useURLState} from '@parca/components';
24
19
 
25
- import useMappingList, {
26
- useFilenamesList,
27
- } from '../ProfileFlameGraph/FlameGraphArrow/useMappingList';
28
20
  import {ProfileSource} from '../ProfileSource';
29
- import {useProfileFilters} from '../ProfileView/components/ProfileFilters/useProfileFilters';
30
21
  import {useDashboard} from '../ProfileView/context/DashboardContext';
31
22
  import {useVisualizationState} from '../ProfileView/hooks/useVisualizationState';
32
- import {FIELD_FUNCTION_NAME, Row} from '../Table';
33
- import {useColorManagement} from '../Table/hooks/useColorManagement';
34
- import {useQuery} from '../useQuery';
23
+ import {SandwichData} from '../ProfileView/types/visualization';
35
24
  import {CalleesSection} from './components/CalleesSection';
36
25
  import {CallersSection} from './components/CallersSection';
37
- import {processRowData} from './utils/processRowData';
38
26
 
39
27
  interface Props {
40
- data?: Uint8Array;
41
- total: bigint;
42
- filtered: bigint;
43
- profileType?: ProfileType;
44
- loading: boolean;
45
- unit?: string;
46
- metadataMappingFiles?: string[];
47
- queryClient?: QueryServiceClient;
48
28
  profileSource: ProfileSource;
29
+ sandwichData: SandwichData;
49
30
  }
50
31
 
51
32
  const Sandwich = React.memo(function Sandwich({
52
- data,
53
- filtered,
54
- profileType,
55
- loading,
56
- unit,
57
- metadataMappingFiles,
58
- queryClient,
33
+ sandwichData,
59
34
  profileSource,
60
35
  }: Props): React.JSX.Element {
61
- const currentColorProfile = useCurrentColorProfile();
62
36
  const {dashboardItems} = useDashboard();
63
37
  const [sandwichFunctionName] = useURLState<string | undefined>('sandwich_function_name');
64
38
 
65
- const {isDarkMode} = useParcaContext();
66
- const [selectedRow, setSelectedRow] = useState<TableRow<Row> | null>(null);
67
39
  const callersRef = React.useRef<HTMLDivElement | null>(null);
68
40
  const calleesRef = React.useRef<HTMLDivElement | null>(null);
69
41
  const [isExpanded, setIsExpanded] = useState(false);
@@ -71,113 +43,7 @@ const Sandwich = React.memo(function Sandwich({
71
43
 
72
44
  const callersCalleesContainerRef = useRef<HTMLDivElement | null>(null);
73
45
 
74
- const {colorBy, setColorBy, curPathArrow, setCurPathArrow} = useVisualizationState();
75
-
76
- const nodeTrimThreshold = useMemo(() => {
77
- let width =
78
- // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
79
- window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth;
80
- // subtract the padding
81
- width = width - 12 - 16 - 12;
82
- return (1 / width) * 100;
83
- }, []);
84
-
85
- const {protoFilters} = useProfileFilters();
86
-
87
- const {
88
- isLoading: callersFlamegraphLoading,
89
- response: callersFlamegraphResponse,
90
- error: callersFlamegraphError,
91
- } = useQuery(
92
- queryClient as QueryServiceClient,
93
- profileSource,
94
- QueryRequest_ReportType.FLAMEGRAPH_ARROW,
95
- {
96
- nodeTrimThreshold,
97
- groupBy: [FIELD_FUNCTION_NAME],
98
- invertCallStack: true,
99
- sandwichByFunction: sandwichFunctionName,
100
- skip: sandwichFunctionName === undefined,
101
- protoFilters,
102
- }
103
- );
104
-
105
- const {
106
- isLoading: calleesFlamegraphLoading,
107
- response: calleesFlamegraphResponse,
108
- error: calleesFlamegraphError,
109
- } = useQuery(
110
- queryClient as QueryServiceClient,
111
- profileSource,
112
- QueryRequest_ReportType.FLAMEGRAPH_ARROW,
113
- {
114
- nodeTrimThreshold,
115
- groupBy: [FIELD_FUNCTION_NAME],
116
- invertCallStack: false,
117
- sandwichByFunction: sandwichFunctionName,
118
- skip: sandwichFunctionName === undefined,
119
- protoFilters,
120
- }
121
- );
122
-
123
- const table = useMemo(() => {
124
- if (loading || data == null) {
125
- return null;
126
- }
127
-
128
- return tableFromIPC(data);
129
- }, [data, loading]);
130
-
131
- const mappingsList = useMappingList(metadataMappingFiles);
132
- const filenamesList = useFilenamesList(table);
133
-
134
- const mappingsListCount = useMemo(
135
- () => mappingsList.filter(m => m !== '').length,
136
- [mappingsList]
137
- );
138
-
139
- // If there is only one mapping file, we want to color by filename by default.
140
- useEffect(() => {
141
- if (mappingsListCount === 1 && colorBy !== 'filename') {
142
- setColorBy('filename');
143
- }
144
- // eslint-disable-next-line react-hooks/exhaustive-deps
145
- }, [mappingsListCount]);
146
-
147
- const {colorByColors, colorByValue} = useColorManagement({
148
- isDarkMode,
149
- currentColorProfile,
150
- mappingsList,
151
- filenamesList,
152
- colorBy,
153
- });
154
-
155
- unit = useMemo(() => unit ?? profileType?.sampleUnit ?? '', [unit, profileType?.sampleUnit]);
156
-
157
- const rows = useMemo(() => {
158
- if (table == null || table.numRows === 0) {
159
- return [];
160
- }
161
-
162
- return processRowData({
163
- table,
164
- colorByColors,
165
- colorBy: colorByValue,
166
- });
167
- }, [table, colorByColors, colorByValue]);
168
-
169
- useEffect(() => {
170
- if (sandwichFunctionName !== undefined && selectedRow == null) {
171
- // find the row with the sandwichFunctionName
172
- const row = rows.find(row => {
173
- return row.name.trim() === sandwichFunctionName.trim();
174
- });
175
-
176
- if (row != null) {
177
- setSelectedRow(row as unknown as TableRow<Row>);
178
- }
179
- }
180
- }, [sandwichFunctionName, rows, selectedRow]);
46
+ const {curPathArrow, setCurPathArrow} = useVisualizationState();
181
47
 
182
48
  return (
183
49
  <section className="flex flex-row h-full w-full">
@@ -194,24 +60,10 @@ const Sandwich = React.memo(function Sandwich({
194
60
  <div className="w-full flex flex-col" ref={callersCalleesContainerRef}>
195
61
  <CallersSection
196
62
  callersRef={callersRef}
197
- callersFlamegraphResponse={
198
- callersFlamegraphResponse?.report.oneofKind === 'flamegraphArrow'
199
- ? {
200
- report: {
201
- oneofKind: 'flamegraphArrow',
202
- flamegraphArrow: callersFlamegraphResponse.report.flamegraphArrow,
203
- },
204
- total: callersFlamegraphResponse.total?.toString() ?? '0',
205
- }
206
- : undefined
207
- }
208
- callersFlamegraphLoading={callersFlamegraphLoading}
209
- callersFlamegraphError={callersFlamegraphError}
210
- filtered={filtered}
63
+ callersFlamegraphData={sandwichData.callers}
211
64
  profileSource={profileSource}
212
65
  curPathArrow={curPathArrow}
213
66
  setCurPathArrow={setCurPathArrow}
214
- metadataMappingFiles={metadataMappingFiles}
215
67
  isExpanded={isExpanded}
216
68
  setIsExpanded={setIsExpanded}
217
69
  defaultMaxFrames={defaultMaxFrames}
@@ -219,24 +71,10 @@ const Sandwich = React.memo(function Sandwich({
219
71
  <div className="h-4" />
220
72
  <CalleesSection
221
73
  calleesRef={calleesRef}
222
- calleesFlamegraphResponse={
223
- calleesFlamegraphResponse?.report.oneofKind === 'flamegraphArrow'
224
- ? {
225
- report: {
226
- oneofKind: 'flamegraphArrow',
227
- flamegraphArrow: calleesFlamegraphResponse.report.flamegraphArrow,
228
- },
229
- total: calleesFlamegraphResponse.total?.toString() ?? '0',
230
- }
231
- : undefined
232
- }
233
- calleesFlamegraphLoading={calleesFlamegraphLoading}
234
- calleesFlamegraphError={calleesFlamegraphError}
235
- filtered={filtered}
74
+ calleesFlamegraphData={sandwichData.callees}
236
75
  profileSource={profileSource}
237
76
  curPathArrow={curPathArrow}
238
77
  setCurPathArrow={setCurPathArrow}
239
- metadataMappingFiles={metadataMappingFiles}
240
78
  />
241
79
  </div>
242
80
  ) : (