@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.
- package/CHANGELOG.md +10 -0
- package/dist/GraphTooltipArrow/useGraphTooltip/index.d.ts.map +1 -1
- package/dist/GraphTooltipArrow/useGraphTooltip/index.js +6 -3
- package/dist/MetricsGraph/UtilizationMetrics/index.d.ts.map +1 -1
- package/dist/MetricsGraph/UtilizationMetrics/index.js +6 -2
- package/dist/MetricsGraph/index.d.ts.map +1 -1
- package/dist/MetricsGraph/index.js +8 -4
- package/dist/MetricsSeries/index.d.ts +2 -1
- package/dist/MetricsSeries/index.d.ts.map +1 -1
- package/dist/MetricsSeries/index.js +2 -1
- package/dist/ProfileIcicleGraph/IcicleGraphArrow/ContextMenu.d.ts +2 -1
- package/dist/ProfileIcicleGraph/IcicleGraphArrow/ContextMenu.d.ts.map +1 -1
- package/dist/ProfileIcicleGraph/IcicleGraphArrow/ContextMenu.js +13 -3
- package/dist/ProfileIcicleGraph/IcicleGraphArrow/ContextMenuWrapper.d.ts +1 -0
- package/dist/ProfileIcicleGraph/IcicleGraphArrow/ContextMenuWrapper.d.ts.map +1 -1
- package/dist/ProfileIcicleGraph/IcicleGraphArrow/IcicleGraphNodes.d.ts +4 -0
- package/dist/ProfileIcicleGraph/IcicleGraphArrow/IcicleGraphNodes.d.ts.map +1 -1
- package/dist/ProfileIcicleGraph/IcicleGraphArrow/IcicleGraphNodes.js +15 -6
- package/dist/ProfileIcicleGraph/IcicleGraphArrow/MemoizedTooltip.d.ts.map +1 -1
- package/dist/ProfileIcicleGraph/IcicleGraphArrow/MemoizedTooltip.js +5 -4
- package/dist/ProfileIcicleGraph/IcicleGraphArrow/TooltipContext.d.ts +2 -0
- package/dist/ProfileIcicleGraph/IcicleGraphArrow/TooltipContext.d.ts.map +1 -1
- package/dist/ProfileIcicleGraph/IcicleGraphArrow/TooltipContext.js +3 -2
- package/dist/ProfileIcicleGraph/IcicleGraphArrow/index.d.ts +3 -0
- package/dist/ProfileIcicleGraph/IcicleGraphArrow/index.d.ts.map +1 -1
- package/dist/ProfileIcicleGraph/IcicleGraphArrow/index.js +4 -4
- package/dist/ProfileIcicleGraph/IcicleGraphArrow/utils.js +1 -1
- package/dist/ProfileIcicleGraph/index.d.ts +4 -1
- package/dist/ProfileIcicleGraph/index.d.ts.map +1 -1
- package/dist/ProfileIcicleGraph/index.js +22 -6
- package/dist/ProfileView/components/DashboardItems/index.d.ts +3 -1
- package/dist/ProfileView/components/DashboardItems/index.d.ts.map +1 -1
- package/dist/ProfileView/components/DashboardItems/index.js +4 -1
- package/dist/ProfileView/components/Toolbars/TableColumnsDropdown.d.ts.map +1 -1
- package/dist/ProfileView/components/Toolbars/TableColumnsDropdown.js +0 -13
- package/dist/ProfileView/components/Toolbars/index.d.ts +8 -0
- package/dist/ProfileView/components/Toolbars/index.d.ts.map +1 -1
- package/dist/ProfileView/components/Toolbars/index.js +6 -2
- package/dist/ProfileView/components/ViewSelector/Dropdown.d.ts +1 -0
- package/dist/ProfileView/components/ViewSelector/Dropdown.d.ts.map +1 -1
- package/dist/ProfileView/components/ViewSelector/Dropdown.js +1 -1
- package/dist/ProfileView/components/ViewSelector/index.d.ts.map +1 -1
- package/dist/ProfileView/components/ViewSelector/index.js +9 -0
- package/dist/ProfileView/hooks/useVisualizationState.d.ts +4 -0
- package/dist/ProfileView/hooks/useVisualizationState.d.ts.map +1 -1
- package/dist/ProfileView/hooks/useVisualizationState.js +9 -1
- package/dist/ProfileView/index.d.ts.map +1 -1
- package/dist/ProfileView/index.js +3 -2
- package/dist/ProfileView/types/visualization.d.ts +1 -1
- package/dist/ProfileView/types/visualization.d.ts.map +1 -1
- package/dist/ProfileViewWithData.js +1 -1
- package/dist/Sandwich/components/CalleesSection.d.ts +25 -0
- package/dist/Sandwich/components/CalleesSection.d.ts.map +1 -0
- package/dist/Sandwich/components/CalleesSection.js +11 -0
- package/dist/Sandwich/components/CallersSection.d.ts +25 -0
- package/dist/Sandwich/components/CallersSection.d.ts.map +1 -0
- package/dist/Sandwich/components/CallersSection.js +11 -0
- package/dist/Sandwich/components/TableSection.d.ts +21 -0
- package/dist/Sandwich/components/TableSection.d.ts.map +1 -0
- package/dist/Sandwich/components/TableSection.js +7 -0
- package/dist/Sandwich/index.d.ts +19 -0
- package/dist/Sandwich/index.d.ts.map +1 -0
- package/dist/Sandwich/index.js +182 -0
- package/dist/Sandwich/utils/processRowData.d.ts +11 -0
- package/dist/Sandwich/utils/processRowData.d.ts.map +1 -0
- package/dist/Sandwich/utils/processRowData.js +53 -0
- package/dist/Table/ColorCell.d.ts +7 -0
- package/dist/Table/ColorCell.d.ts.map +1 -0
- package/dist/Table/ColorCell.js +2 -0
- package/dist/Table/MoreDropdown.d.ts +5 -0
- package/dist/Table/MoreDropdown.d.ts.map +1 -0
- package/dist/Table/MoreDropdown.js +39 -0
- package/dist/Table/hooks/useColorManagement.d.ts +14 -0
- package/dist/Table/hooks/useColorManagement.d.ts.map +1 -0
- package/dist/Table/hooks/useColorManagement.js +32 -0
- package/dist/Table/hooks/useTableConfiguration.d.ts +21 -0
- package/dist/Table/hooks/useTableConfiguration.d.ts.map +1 -0
- package/dist/Table/hooks/useTableConfiguration.js +204 -0
- package/dist/Table/index.d.ts +14 -4
- package/dist/Table/index.d.ts.map +1 -1
- package/dist/Table/index.js +34 -332
- package/dist/Table/utils/functions.d.ts +1 -0
- package/dist/Table/utils/functions.d.ts.map +1 -1
- package/dist/styles.css +1 -1
- package/dist/useQuery.d.ts +1 -0
- package/dist/useQuery.d.ts.map +1 -1
- package/dist/useQuery.js +7 -1
- package/package.json +7 -7
- package/src/GraphTooltipArrow/useGraphTooltip/index.ts +6 -3
- package/src/MetricsGraph/UtilizationMetrics/index.tsx +6 -2
- package/src/MetricsGraph/index.tsx +12 -2
- package/src/MetricsSeries/index.tsx +3 -0
- package/src/ProfileIcicleGraph/IcicleGraphArrow/ContextMenu.tsx +23 -1
- package/src/ProfileIcicleGraph/IcicleGraphArrow/ContextMenuWrapper.tsx +1 -0
- package/src/ProfileIcicleGraph/IcicleGraphArrow/IcicleGraphNodes.tsx +34 -5
- package/src/ProfileIcicleGraph/IcicleGraphArrow/MemoizedTooltip.tsx +6 -4
- package/src/ProfileIcicleGraph/IcicleGraphArrow/TooltipContext.tsx +5 -1
- package/src/ProfileIcicleGraph/IcicleGraphArrow/index.tsx +13 -1
- package/src/ProfileIcicleGraph/IcicleGraphArrow/utils.ts +1 -1
- package/src/ProfileIcicleGraph/index.tsx +50 -18
- package/src/ProfileView/components/DashboardItems/index.tsx +21 -0
- package/src/ProfileView/components/Toolbars/TableColumnsDropdown.tsx +11 -25
- package/src/ProfileView/components/Toolbars/index.tsx +42 -1
- package/src/ProfileView/components/ViewSelector/Dropdown.tsx +2 -1
- package/src/ProfileView/components/ViewSelector/index.tsx +11 -0
- package/src/ProfileView/hooks/useVisualizationState.ts +16 -1
- package/src/ProfileView/index.tsx +7 -0
- package/src/ProfileView/types/visualization.ts +7 -1
- package/src/ProfileViewWithData.tsx +1 -1
- package/src/Sandwich/components/CalleesSection.tsx +87 -0
- package/src/Sandwich/components/CallersSection.tsx +88 -0
- package/src/Sandwich/components/TableSection.tsx +67 -0
- package/src/Sandwich/index.tsx +342 -0
- package/src/Sandwich/utils/processRowData.ts +78 -0
- package/src/Table/ColorCell.tsx +26 -0
- package/src/Table/MoreDropdown.tsx +75 -0
- package/src/Table/hooks/useColorManagement.ts +58 -0
- package/src/Table/hooks/useTableConfiguration.tsx +237 -0
- package/src/Table/index.tsx +37 -470
- package/src/Table/utils/functions.ts +1 -0
- 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
|
+
}
|