@parca/profile 0.18.3 → 0.19.0

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 (121) hide show
  1. package/CHANGELOG.md +10 -0
  2. package/dist/GraphTooltipArrow/useGraphTooltip/index.d.ts.map +1 -1
  3. package/dist/GraphTooltipArrow/useGraphTooltip/index.js +6 -3
  4. package/dist/MetricsGraph/UtilizationMetrics/index.d.ts.map +1 -1
  5. package/dist/MetricsGraph/UtilizationMetrics/index.js +6 -2
  6. package/dist/MetricsGraph/index.d.ts.map +1 -1
  7. package/dist/MetricsGraph/index.js +8 -4
  8. package/dist/MetricsSeries/index.d.ts +2 -1
  9. package/dist/MetricsSeries/index.d.ts.map +1 -1
  10. package/dist/MetricsSeries/index.js +2 -1
  11. package/dist/ProfileIcicleGraph/IcicleGraphArrow/ContextMenu.d.ts +2 -1
  12. package/dist/ProfileIcicleGraph/IcicleGraphArrow/ContextMenu.d.ts.map +1 -1
  13. package/dist/ProfileIcicleGraph/IcicleGraphArrow/ContextMenu.js +13 -3
  14. package/dist/ProfileIcicleGraph/IcicleGraphArrow/ContextMenuWrapper.d.ts +1 -0
  15. package/dist/ProfileIcicleGraph/IcicleGraphArrow/ContextMenuWrapper.d.ts.map +1 -1
  16. package/dist/ProfileIcicleGraph/IcicleGraphArrow/IcicleGraphNodes.d.ts +4 -0
  17. package/dist/ProfileIcicleGraph/IcicleGraphArrow/IcicleGraphNodes.d.ts.map +1 -1
  18. package/dist/ProfileIcicleGraph/IcicleGraphArrow/IcicleGraphNodes.js +15 -6
  19. package/dist/ProfileIcicleGraph/IcicleGraphArrow/MemoizedTooltip.d.ts.map +1 -1
  20. package/dist/ProfileIcicleGraph/IcicleGraphArrow/MemoizedTooltip.js +5 -4
  21. package/dist/ProfileIcicleGraph/IcicleGraphArrow/TooltipContext.d.ts +2 -0
  22. package/dist/ProfileIcicleGraph/IcicleGraphArrow/TooltipContext.d.ts.map +1 -1
  23. package/dist/ProfileIcicleGraph/IcicleGraphArrow/TooltipContext.js +3 -2
  24. package/dist/ProfileIcicleGraph/IcicleGraphArrow/index.d.ts +3 -0
  25. package/dist/ProfileIcicleGraph/IcicleGraphArrow/index.d.ts.map +1 -1
  26. package/dist/ProfileIcicleGraph/IcicleGraphArrow/index.js +4 -4
  27. package/dist/ProfileIcicleGraph/IcicleGraphArrow/utils.js +1 -1
  28. package/dist/ProfileIcicleGraph/index.d.ts +4 -1
  29. package/dist/ProfileIcicleGraph/index.d.ts.map +1 -1
  30. package/dist/ProfileIcicleGraph/index.js +22 -6
  31. package/dist/ProfileView/components/DashboardItems/index.d.ts +3 -1
  32. package/dist/ProfileView/components/DashboardItems/index.d.ts.map +1 -1
  33. package/dist/ProfileView/components/DashboardItems/index.js +4 -1
  34. package/dist/ProfileView/components/Toolbars/TableColumnsDropdown.d.ts.map +1 -1
  35. package/dist/ProfileView/components/Toolbars/TableColumnsDropdown.js +0 -13
  36. package/dist/ProfileView/components/Toolbars/index.d.ts +8 -0
  37. package/dist/ProfileView/components/Toolbars/index.d.ts.map +1 -1
  38. package/dist/ProfileView/components/Toolbars/index.js +6 -2
  39. package/dist/ProfileView/components/ViewSelector/Dropdown.d.ts +1 -0
  40. package/dist/ProfileView/components/ViewSelector/Dropdown.d.ts.map +1 -1
  41. package/dist/ProfileView/components/ViewSelector/Dropdown.js +1 -1
  42. package/dist/ProfileView/components/ViewSelector/index.d.ts.map +1 -1
  43. package/dist/ProfileView/components/ViewSelector/index.js +9 -0
  44. package/dist/ProfileView/hooks/useVisualizationState.d.ts +4 -0
  45. package/dist/ProfileView/hooks/useVisualizationState.d.ts.map +1 -1
  46. package/dist/ProfileView/hooks/useVisualizationState.js +9 -1
  47. package/dist/ProfileView/index.d.ts.map +1 -1
  48. package/dist/ProfileView/index.js +3 -2
  49. package/dist/ProfileView/types/visualization.d.ts +1 -1
  50. package/dist/ProfileView/types/visualization.d.ts.map +1 -1
  51. package/dist/ProfileViewWithData.js +1 -1
  52. package/dist/Sandwich/components/CalleesSection.d.ts +25 -0
  53. package/dist/Sandwich/components/CalleesSection.d.ts.map +1 -0
  54. package/dist/Sandwich/components/CalleesSection.js +11 -0
  55. package/dist/Sandwich/components/CallersSection.d.ts +25 -0
  56. package/dist/Sandwich/components/CallersSection.d.ts.map +1 -0
  57. package/dist/Sandwich/components/CallersSection.js +11 -0
  58. package/dist/Sandwich/components/TableSection.d.ts +21 -0
  59. package/dist/Sandwich/components/TableSection.d.ts.map +1 -0
  60. package/dist/Sandwich/components/TableSection.js +7 -0
  61. package/dist/Sandwich/index.d.ts +19 -0
  62. package/dist/Sandwich/index.d.ts.map +1 -0
  63. package/dist/Sandwich/index.js +182 -0
  64. package/dist/Sandwich/utils/processRowData.d.ts +11 -0
  65. package/dist/Sandwich/utils/processRowData.d.ts.map +1 -0
  66. package/dist/Sandwich/utils/processRowData.js +53 -0
  67. package/dist/Table/ColorCell.d.ts +7 -0
  68. package/dist/Table/ColorCell.d.ts.map +1 -0
  69. package/dist/Table/ColorCell.js +2 -0
  70. package/dist/Table/MoreDropdown.d.ts +5 -0
  71. package/dist/Table/MoreDropdown.d.ts.map +1 -0
  72. package/dist/Table/MoreDropdown.js +39 -0
  73. package/dist/Table/hooks/useColorManagement.d.ts +14 -0
  74. package/dist/Table/hooks/useColorManagement.d.ts.map +1 -0
  75. package/dist/Table/hooks/useColorManagement.js +32 -0
  76. package/dist/Table/hooks/useTableConfiguration.d.ts +21 -0
  77. package/dist/Table/hooks/useTableConfiguration.d.ts.map +1 -0
  78. package/dist/Table/hooks/useTableConfiguration.js +204 -0
  79. package/dist/Table/index.d.ts +14 -4
  80. package/dist/Table/index.d.ts.map +1 -1
  81. package/dist/Table/index.js +34 -332
  82. package/dist/Table/utils/functions.d.ts +1 -0
  83. package/dist/Table/utils/functions.d.ts.map +1 -1
  84. package/dist/styles.css +1 -1
  85. package/dist/useQuery.d.ts +1 -0
  86. package/dist/useQuery.d.ts.map +1 -1
  87. package/dist/useQuery.js +7 -1
  88. package/package.json +7 -7
  89. package/src/GraphTooltipArrow/useGraphTooltip/index.ts +6 -3
  90. package/src/MetricsGraph/UtilizationMetrics/index.tsx +6 -2
  91. package/src/MetricsGraph/index.tsx +12 -2
  92. package/src/MetricsSeries/index.tsx +3 -0
  93. package/src/ProfileIcicleGraph/IcicleGraphArrow/ContextMenu.tsx +23 -1
  94. package/src/ProfileIcicleGraph/IcicleGraphArrow/ContextMenuWrapper.tsx +1 -0
  95. package/src/ProfileIcicleGraph/IcicleGraphArrow/IcicleGraphNodes.tsx +34 -5
  96. package/src/ProfileIcicleGraph/IcicleGraphArrow/MemoizedTooltip.tsx +6 -4
  97. package/src/ProfileIcicleGraph/IcicleGraphArrow/TooltipContext.tsx +5 -1
  98. package/src/ProfileIcicleGraph/IcicleGraphArrow/index.tsx +13 -1
  99. package/src/ProfileIcicleGraph/IcicleGraphArrow/utils.ts +1 -1
  100. package/src/ProfileIcicleGraph/index.tsx +50 -18
  101. package/src/ProfileView/components/DashboardItems/index.tsx +21 -0
  102. package/src/ProfileView/components/Toolbars/TableColumnsDropdown.tsx +11 -25
  103. package/src/ProfileView/components/Toolbars/index.tsx +42 -1
  104. package/src/ProfileView/components/ViewSelector/Dropdown.tsx +2 -1
  105. package/src/ProfileView/components/ViewSelector/index.tsx +11 -0
  106. package/src/ProfileView/hooks/useVisualizationState.ts +16 -1
  107. package/src/ProfileView/index.tsx +7 -0
  108. package/src/ProfileView/types/visualization.ts +7 -1
  109. package/src/ProfileViewWithData.tsx +1 -1
  110. package/src/Sandwich/components/CalleesSection.tsx +87 -0
  111. package/src/Sandwich/components/CallersSection.tsx +88 -0
  112. package/src/Sandwich/components/TableSection.tsx +67 -0
  113. package/src/Sandwich/index.tsx +342 -0
  114. package/src/Sandwich/utils/processRowData.ts +78 -0
  115. package/src/Table/ColorCell.tsx +26 -0
  116. package/src/Table/MoreDropdown.tsx +75 -0
  117. package/src/Table/hooks/useColorManagement.ts +58 -0
  118. package/src/Table/hooks/useTableConfiguration.tsx +237 -0
  119. package/src/Table/index.tsx +37 -470
  120. package/src/Table/utils/functions.ts +1 -0
  121. package/src/useQuery.tsx +10 -1
@@ -0,0 +1,342 @@
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 React, {useCallback, useEffect, useMemo, useRef, useState} from 'react';
15
+
16
+ import {type Row as TableRow} from '@tanstack/table-core';
17
+ import {tableFromIPC} from 'apache-arrow';
18
+ import {AnimatePresence, motion} from 'framer-motion';
19
+
20
+ import {QueryRequest_ReportType, QueryServiceClient} from '@parca/client';
21
+ import {TableSkeleton, useParcaContext, useURLState} from '@parca/components';
22
+ import {useCurrentColorProfile} from '@parca/hooks';
23
+ import {ProfileType} from '@parca/parser';
24
+ import {isSearchMatch} from '@parca/utilities';
25
+
26
+ import useMappingList, {
27
+ useFilenamesList,
28
+ } from '../ProfileIcicleGraph/IcicleGraphArrow/useMappingList';
29
+ import {ProfileSource} from '../ProfileSource';
30
+ import {useProfileViewContext} from '../ProfileView/context/ProfileViewContext';
31
+ import {useVisualizationState} from '../ProfileView/hooks/useVisualizationState';
32
+ import {FIELD_FUNCTION_NAME, Row} from '../Table';
33
+ import {useColorManagement} from '../Table/hooks/useColorManagement';
34
+ import {useTableConfiguration} from '../Table/hooks/useTableConfiguration';
35
+ import {type DataRow} from '../Table/utils/functions';
36
+ import {useQuery} from '../useQuery';
37
+ import {CalleesSection} from './components/CalleesSection';
38
+ import {CallersSection} from './components/CallersSection';
39
+ import {TableSection} from './components/TableSection';
40
+ import {processRowData} from './utils/processRowData';
41
+
42
+ interface Props {
43
+ data?: Uint8Array;
44
+ total: bigint;
45
+ filtered: bigint;
46
+ profileType?: ProfileType;
47
+ loading: boolean;
48
+ isHalfScreen: boolean;
49
+ unit?: string;
50
+ metadataMappingFiles?: string[];
51
+ queryClient?: QueryServiceClient;
52
+ profileSource: ProfileSource;
53
+ }
54
+
55
+ const Sandwich = React.memo(function Sandwich({
56
+ data,
57
+ total,
58
+ filtered,
59
+ profileType,
60
+ loading,
61
+ isHalfScreen,
62
+ unit,
63
+ metadataMappingFiles,
64
+ queryClient,
65
+ profileSource,
66
+ }: Props): React.JSX.Element {
67
+ const currentColorProfile = useCurrentColorProfile();
68
+
69
+ const [sandwichFunctionName, setSandwichFunctionName] = useURLState<string | undefined>(
70
+ 'sandwich_function_name'
71
+ );
72
+ const {isDarkMode} = useParcaContext();
73
+ const [selectedRow, setSelectedRow] = useState<TableRow<Row> | null>(null);
74
+ const callersRef = React.useRef<HTMLDivElement | null>(null);
75
+ const calleesRef = React.useRef<HTMLDivElement | null>(null);
76
+
77
+ const callersCalleesContainerRef = useRef<HTMLDivElement | null>(null);
78
+ const [tableHeight, setTableHeight] = useState<number | undefined>(undefined);
79
+
80
+ const {compareMode} = useProfileViewContext();
81
+
82
+ const {colorBy, setColorBy, curPathArrow, setCurPathArrow} = useVisualizationState();
83
+
84
+ const nodeTrimThreshold = useMemo(() => {
85
+ let width =
86
+ // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
87
+ window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth;
88
+ // subtract the padding
89
+ width = width - 12 - 16 - 12;
90
+ return (1 / width) * 100;
91
+ }, []);
92
+
93
+ const {
94
+ isLoading: callersFlamegraphLoading,
95
+ response: callersFlamegraphResponse,
96
+ error: callersFlamegraphError,
97
+ } = useQuery(
98
+ queryClient as QueryServiceClient,
99
+ profileSource,
100
+ QueryRequest_ReportType.FLAMEGRAPH_ARROW,
101
+ {
102
+ nodeTrimThreshold,
103
+ groupBy: [FIELD_FUNCTION_NAME],
104
+ invertCallStack: true,
105
+ binaryFrameFilter: [],
106
+ sandwichByFunction: sandwichFunctionName,
107
+ skip: sandwichFunctionName === undefined,
108
+ }
109
+ );
110
+
111
+ const {
112
+ isLoading: calleesFlamegraphLoading,
113
+ response: calleesFlamegraphResponse,
114
+ error: calleesFlamegraphError,
115
+ } = useQuery(
116
+ queryClient as QueryServiceClient,
117
+ profileSource,
118
+ QueryRequest_ReportType.FLAMEGRAPH_ARROW,
119
+ {
120
+ nodeTrimThreshold,
121
+ groupBy: [FIELD_FUNCTION_NAME],
122
+ invertCallStack: false,
123
+ binaryFrameFilter: [],
124
+ sandwichByFunction: sandwichFunctionName,
125
+ skip: sandwichFunctionName === undefined,
126
+ }
127
+ );
128
+
129
+ const table = useMemo(() => {
130
+ if (loading || data == null) {
131
+ return null;
132
+ }
133
+
134
+ return tableFromIPC(data);
135
+ }, [data, loading]);
136
+
137
+ const mappingsList = useMappingList(metadataMappingFiles);
138
+ const filenamesList = useFilenamesList(table);
139
+
140
+ const mappingsListCount = useMemo(
141
+ () => mappingsList.filter(m => m !== '').length,
142
+ [mappingsList]
143
+ );
144
+
145
+ // If there is only one mapping file, we want to color by filename by default.
146
+ useEffect(() => {
147
+ if (mappingsListCount === 1 && colorBy !== 'filename') {
148
+ setColorBy('filename');
149
+ }
150
+ // eslint-disable-next-line react-hooks/exhaustive-deps
151
+ }, [mappingsListCount]);
152
+
153
+ const {colorByColors, colorByValue} = useColorManagement({
154
+ isDarkMode,
155
+ currentColorProfile,
156
+ mappingsList,
157
+ filenamesList,
158
+ colorBy,
159
+ });
160
+
161
+ unit = useMemo(() => unit ?? profileType?.sampleUnit ?? '', [unit, profileType?.sampleUnit]);
162
+
163
+ const tableConfig = useTableConfiguration({
164
+ unit,
165
+ total,
166
+ filtered,
167
+ compareMode,
168
+ });
169
+
170
+ const {columns, initialSorting, columnVisibility} = tableConfig;
171
+
172
+ const rows = useMemo(() => {
173
+ if (table == null || table.numRows === 0) {
174
+ return [];
175
+ }
176
+
177
+ return processRowData({
178
+ table,
179
+ colorByColors,
180
+ colorBy: colorByValue,
181
+ });
182
+ }, [table, colorByColors, colorByValue]);
183
+
184
+ useEffect(() => {
185
+ if (sandwichFunctionName !== undefined && selectedRow == null) {
186
+ // find the row with the sandwichFunctionName
187
+ const row = rows.find(row => {
188
+ return row.name.trim() === sandwichFunctionName.trim();
189
+ });
190
+
191
+ if (row != null) {
192
+ setSelectedRow(row as unknown as TableRow<Row>);
193
+ }
194
+ }
195
+ }, [sandwichFunctionName, rows, selectedRow]);
196
+
197
+ // Update table height based on callers/callees container height
198
+ useEffect(() => {
199
+ const updateTableHeight = (): void => {
200
+ if (callersCalleesContainerRef.current != null) {
201
+ const containerHeight = callersCalleesContainerRef.current.getBoundingClientRect().height;
202
+ setTableHeight(containerHeight);
203
+ }
204
+ };
205
+
206
+ // Initial measurement
207
+ updateTableHeight();
208
+
209
+ // Update on window resize
210
+ window.addEventListener('resize', updateTableHeight);
211
+
212
+ // Use ResizeObserver if available for more accurate updates
213
+ let resizeObserver: ResizeObserver | null = null;
214
+ if (callersCalleesContainerRef.current != null && 'ResizeObserver' in window) {
215
+ resizeObserver = new ResizeObserver(updateTableHeight);
216
+ resizeObserver.observe(callersCalleesContainerRef.current);
217
+ }
218
+
219
+ return () => {
220
+ window.removeEventListener('resize', updateTableHeight);
221
+ if (resizeObserver != null) {
222
+ resizeObserver.disconnect();
223
+ }
224
+ };
225
+ }, [sandwichFunctionName, callersFlamegraphResponse, calleesFlamegraphResponse]);
226
+
227
+ const onRowClick = useCallback(
228
+ (row: DataRow) => {
229
+ setSelectedRow(row as unknown as TableRow<Row>);
230
+ setSandwichFunctionName(row.name.trim());
231
+ },
232
+ [setSandwichFunctionName]
233
+ );
234
+
235
+ const enableHighlighting = useMemo(() => {
236
+ return sandwichFunctionName != null && sandwichFunctionName?.length > 0;
237
+ }, [sandwichFunctionName]);
238
+
239
+ const shouldHighlightRow = useCallback(
240
+ (row: Row) => {
241
+ if (!('name' in row)) {
242
+ return false;
243
+ }
244
+ const name = row.name;
245
+ return isSearchMatch(sandwichFunctionName as string, name);
246
+ },
247
+ [sandwichFunctionName]
248
+ );
249
+
250
+ if (loading) {
251
+ return (
252
+ <div className="overflow-clip h-[700px] min-h-[700px]">
253
+ <TableSkeleton isHalfScreen={isHalfScreen} isDarkMode={isDarkMode} />
254
+ </div>
255
+ );
256
+ }
257
+
258
+ if (rows.length === 0) {
259
+ return <div className="mx-auto text-center">Profile has no samples</div>;
260
+ }
261
+
262
+ return (
263
+ <section className="flex flex-row h-full w-full">
264
+ <AnimatePresence>
265
+ <motion.div
266
+ className="h-full w-full"
267
+ key="sandwich-loaded"
268
+ initial={{display: 'none', opacity: 0}}
269
+ animate={{display: 'block', opacity: 1}}
270
+ transition={{duration: 0.5}}
271
+ >
272
+ <div className="relative flex flex-row">
273
+ <TableSection
274
+ rows={rows}
275
+ columns={columns}
276
+ initialSorting={initialSorting}
277
+ columnVisibility={columnVisibility}
278
+ selectedRow={selectedRow}
279
+ onRowClick={onRowClick}
280
+ shouldHighlightRow={shouldHighlightRow}
281
+ enableHighlighting={enableHighlighting}
282
+ height={tableHeight}
283
+ sandwichFunctionName={sandwichFunctionName}
284
+ />
285
+
286
+ {sandwichFunctionName !== undefined && (
287
+ <div className="w-[50%] flex flex-col" ref={callersCalleesContainerRef}>
288
+ <CallersSection
289
+ callersRef={callersRef}
290
+ isHalfScreen={isHalfScreen}
291
+ callersFlamegraphResponse={
292
+ callersFlamegraphResponse?.report.oneofKind === 'flamegraphArrow'
293
+ ? {
294
+ report: {
295
+ oneofKind: 'flamegraphArrow',
296
+ flamegraphArrow: callersFlamegraphResponse.report.flamegraphArrow,
297
+ },
298
+ total: callersFlamegraphResponse.total?.toString() ?? '0',
299
+ }
300
+ : undefined
301
+ }
302
+ callersFlamegraphLoading={callersFlamegraphLoading}
303
+ callersFlamegraphError={callersFlamegraphError}
304
+ filtered={filtered}
305
+ profileSource={profileSource}
306
+ curPathArrow={curPathArrow}
307
+ setCurPathArrow={setCurPathArrow}
308
+ metadataMappingFiles={metadataMappingFiles}
309
+ />
310
+ <div className="h-4" />
311
+ <CalleesSection
312
+ calleesRef={calleesRef}
313
+ isHalfScreen={isHalfScreen}
314
+ calleesFlamegraphResponse={
315
+ calleesFlamegraphResponse?.report.oneofKind === 'flamegraphArrow'
316
+ ? {
317
+ report: {
318
+ oneofKind: 'flamegraphArrow',
319
+ flamegraphArrow: calleesFlamegraphResponse.report.flamegraphArrow,
320
+ },
321
+ total: calleesFlamegraphResponse.total?.toString() ?? '0',
322
+ }
323
+ : undefined
324
+ }
325
+ calleesFlamegraphLoading={calleesFlamegraphLoading}
326
+ calleesFlamegraphError={calleesFlamegraphError}
327
+ filtered={filtered}
328
+ profileSource={profileSource}
329
+ curPathArrow={curPathArrow}
330
+ setCurPathArrow={setCurPathArrow}
331
+ metadataMappingFiles={metadataMappingFiles}
332
+ />
333
+ </div>
334
+ )}
335
+ </div>
336
+ </motion.div>
337
+ </AnimatePresence>
338
+ </section>
339
+ );
340
+ });
341
+
342
+ export default Sandwich;
@@ -0,0 +1,78 @@
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 {type Table} from 'apache-arrow';
15
+
16
+ import {type colorByColors} from '../../ProfileIcicleGraph/IcicleGraphArrow/IcicleGraphNodes';
17
+ import {
18
+ FIELD_CUMULATIVE,
19
+ FIELD_CUMULATIVE_DIFF,
20
+ FIELD_FLAT,
21
+ FIELD_FLAT_DIFF,
22
+ FIELD_FUNCTION_FILE_NAME,
23
+ FIELD_FUNCTION_NAME,
24
+ FIELD_FUNCTION_SYSTEM_NAME,
25
+ FIELD_LOCATION_ADDRESS,
26
+ FIELD_MAPPING_FILE,
27
+ } from '../../Table';
28
+ import {RowName, getRowColor, type DataRow} from '../../Table/utils/functions';
29
+
30
+ interface ProcessRowDataProps {
31
+ table: Table | null;
32
+ colorByColors: colorByColors;
33
+ colorBy: string;
34
+ }
35
+
36
+ export function processRowData({table, colorByColors, colorBy}: ProcessRowDataProps): DataRow[] {
37
+ if (table == null || table.numRows === 0) {
38
+ return [];
39
+ }
40
+
41
+ const flatColumn = table.getChild(FIELD_FLAT);
42
+ const flatDiffColumn = table.getChild(FIELD_FLAT_DIFF);
43
+ const cumulativeColumn = table.getChild(FIELD_CUMULATIVE);
44
+ const cumulativeDiffColumn = table.getChild(FIELD_CUMULATIVE_DIFF);
45
+ const functionNameColumn = table.getChild(FIELD_FUNCTION_NAME);
46
+ const functionSystemNameColumn = table.getChild(FIELD_FUNCTION_SYSTEM_NAME);
47
+ const functionFileNameColumn = table.getChild(FIELD_FUNCTION_FILE_NAME);
48
+ const mappingFileColumn = table.getChild(FIELD_MAPPING_FILE);
49
+ const locationAddressColumn = table.getChild(FIELD_LOCATION_ADDRESS);
50
+
51
+ const getRow = (i: number): DataRow => {
52
+ const flat: bigint = flatColumn?.get(i) ?? 0n;
53
+ const flatDiff: bigint = flatDiffColumn?.get(i) ?? 0n;
54
+ const cumulative: bigint = cumulativeColumn?.get(i) ?? 0n;
55
+ const cumulativeDiff: bigint = cumulativeDiffColumn?.get(i) ?? 0n;
56
+ const functionSystemName: string = functionSystemNameColumn?.get(i) ?? '';
57
+ const functionFileName: string = functionFileNameColumn?.get(i) ?? '';
58
+ const mappingFile: string = mappingFileColumn?.get(i) ?? '';
59
+
60
+ return {
61
+ id: i,
62
+ colorProperty: {
63
+ color: getRowColor(colorByColors, mappingFileColumn, i, functionFileNameColumn, colorBy),
64
+ mappingFile,
65
+ },
66
+ name: RowName(mappingFileColumn, locationAddressColumn, functionNameColumn, i),
67
+ flat,
68
+ flatDiff,
69
+ cumulative,
70
+ cumulativeDiff,
71
+ functionSystemName,
72
+ functionFileName,
73
+ mappingFile,
74
+ };
75
+ };
76
+
77
+ return Array.from({length: table.numRows}, (_, i) => getRow(i));
78
+ }
@@ -0,0 +1,26 @@
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
+ interface ColorCellProps {
15
+ color: string;
16
+ mappingFile: string;
17
+ }
18
+
19
+ export const ColorCell = ({color, mappingFile}: ColorCellProps): JSX.Element => (
20
+ <div
21
+ className="w-4 h-4 rounded-[4px]"
22
+ style={{backgroundColor: color}}
23
+ data-tooltip-id="table-color-tooltip"
24
+ data-tooltip-content={mappingFile}
25
+ />
26
+ );
@@ -0,0 +1,75 @@
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 {Menu} from '@headlessui/react';
15
+ import {Icon} from '@iconify/react';
16
+
17
+ import {useURLState} from '@parca/components';
18
+
19
+ const MoreDropdown = ({functionName}: {functionName: string}): React.JSX.Element => {
20
+ const [_, setSandwichFunctionName] = useURLState<string | undefined>('sandwich_function_name');
21
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
22
+ const [dashboardItems, setDashboardItems] = useURLState<string[]>('dashboard_items', {
23
+ alwaysReturnArray: true,
24
+ });
25
+
26
+ const onSandwichViewSelect = (): void => {
27
+ setSandwichFunctionName(functionName.trim());
28
+ setDashboardItems(['sandwich']);
29
+ };
30
+
31
+ const menuItems = [
32
+ {
33
+ label: 'Show in Sandwich view',
34
+ action: () => onSandwichViewSelect(),
35
+ },
36
+ ];
37
+
38
+ return (
39
+ <div>
40
+ <Menu>
41
+ {({open, close}) => (
42
+ <>
43
+ <Menu.Button
44
+ onClick={() => {
45
+ if (open) {
46
+ close();
47
+ }
48
+ }}
49
+ className="inline-flex font-sans dark:bg-gray-900 dark:border-gray-600 justify-center w-full text-sm font-normal text-gray-600 dark:text-gray-200 bg-white rounded-md focus:outline-none focus-visible:ring-2 focus-visible:ring-white focus-visible:ring-opacity-75"
50
+ >
51
+ <Icon icon="mdi:dots-horizontal" />
52
+ </Menu.Button>
53
+ {open && (
54
+ <Menu.Items className="font-sans absolute z-30 left-0 w-56 mt-2 py-2 origin-top-right bg-white rounded-md shadow-lg ring-1 ring-black ring-opacity-5 focus:outline-none border dark:bg-gray-900 dark:border-gray-600">
55
+ <span className="text-xs text-gray-400 capitalize px-4 py-3">actions</span>
56
+
57
+ {menuItems.map(item => (
58
+ <Menu.Button
59
+ key={item.label}
60
+ className="group mb-px flex w-full items-center rounded-md px-4 py-2 text-sm text-gray-900 dark:text-white hover:bg-indigo-500 hover:text-white focus:outline-none focus-visible:ring-2 focus-visible:ring-indigo-500"
61
+ onClick={item.action}
62
+ >
63
+ {item.label}
64
+ </Menu.Button>
65
+ ))}
66
+ </Menu.Items>
67
+ )}
68
+ </>
69
+ )}
70
+ </Menu>
71
+ </div>
72
+ );
73
+ };
74
+
75
+ export default MoreDropdown;
@@ -0,0 +1,58 @@
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 {type ColorConfig} from '@parca/utilities';
17
+
18
+ import {getFilenameColors, getMappingColors} from '../../ProfileIcicleGraph/IcicleGraphArrow';
19
+
20
+ interface UseColorManagementProps {
21
+ isDarkMode: boolean;
22
+ currentColorProfile: ColorConfig;
23
+ mappingsList: string[];
24
+ filenamesList: string[];
25
+ colorBy: string;
26
+ }
27
+
28
+ export function useColorManagement({
29
+ isDarkMode,
30
+ currentColorProfile,
31
+ mappingsList,
32
+ filenamesList,
33
+ colorBy,
34
+ }: UseColorManagementProps): {
35
+ colorByColors: Record<string, string>;
36
+ colorByValue: string;
37
+ } {
38
+ const filenameColors = useMemo(() => {
39
+ return getFilenameColors(filenamesList, isDarkMode, currentColorProfile);
40
+ }, [isDarkMode, filenamesList, currentColorProfile]);
41
+
42
+ const mappingColors = useMemo(() => {
43
+ return getMappingColors(mappingsList, isDarkMode, currentColorProfile);
44
+ }, [isDarkMode, mappingsList, currentColorProfile]);
45
+
46
+ const colorByList = {
47
+ filename: filenameColors,
48
+ binary: mappingColors,
49
+ };
50
+
51
+ const colorByValue = colorBy === undefined || colorBy === '' ? 'binary' : colorBy;
52
+ const colorByColors = colorByList[colorByValue as keyof typeof colorByList];
53
+
54
+ return {
55
+ colorByColors,
56
+ colorByValue,
57
+ };
58
+ }