@parca/profile 0.16.443 → 0.16.445

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 (61) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/dist/MetricsGraphStrips/AreaGraph/index.d.ts +20 -0
  3. package/dist/MetricsGraphStrips/AreaGraph/index.d.ts.map +1 -0
  4. package/dist/MetricsGraphStrips/AreaGraph/index.js +166 -0
  5. package/dist/MetricsGraphStrips/MetricsGraphStrips.stories.d.ts +17 -0
  6. package/dist/MetricsGraphStrips/MetricsGraphStrips.stories.d.ts.map +1 -0
  7. package/dist/MetricsGraphStrips/MetricsGraphStrips.stories.js +48 -0
  8. package/dist/MetricsGraphStrips/TimelineGuide/index.d.ts +10 -0
  9. package/dist/MetricsGraphStrips/TimelineGuide/index.d.ts.map +1 -0
  10. package/dist/MetricsGraphStrips/TimelineGuide/index.js +40 -0
  11. package/dist/MetricsGraphStrips/index.d.ts +13 -0
  12. package/dist/MetricsGraphStrips/index.d.ts.map +1 -0
  13. package/dist/MetricsGraphStrips/index.js +41 -0
  14. package/dist/ProfileIcicleGraph/index.d.ts.map +1 -1
  15. package/dist/ProfileIcicleGraph/index.js +3 -11
  16. package/dist/ProfileView/ColorStackLegend.d.ts.map +1 -0
  17. package/dist/{ProfileIcicleGraph/IcicleGraphArrow → ProfileView}/ColorStackLegend.js +2 -2
  18. package/dist/ProfileView/VisualizationPanel.d.ts +4 -1
  19. package/dist/ProfileView/VisualizationPanel.d.ts.map +1 -1
  20. package/dist/ProfileView/VisualizationPanel.js +4 -6
  21. package/dist/ProfileView/index.d.ts.map +1 -1
  22. package/dist/ProfileView/index.js +33 -10
  23. package/dist/ProfileViewWithData.d.ts.map +1 -1
  24. package/dist/ProfileViewWithData.js +1 -3
  25. package/dist/Table/index.d.ts +2 -29
  26. package/dist/Table/index.d.ts.map +1 -1
  27. package/dist/Table/index.js +52 -159
  28. package/dist/Table/utils/functions.d.ts +49 -0
  29. package/dist/Table/utils/functions.d.ts.map +1 -0
  30. package/dist/Table/utils/functions.js +181 -0
  31. package/dist/components/ActionButtons/GroupByDropdown.js +1 -1
  32. package/dist/components/ActionButtons/SortByDropdown.d.ts +3 -0
  33. package/dist/components/ActionButtons/SortByDropdown.d.ts.map +1 -0
  34. package/dist/components/ActionButtons/SortByDropdown.js +49 -0
  35. package/dist/components/VisualisationToolbar/MultiLevelDropdown.d.ts.map +1 -1
  36. package/dist/components/VisualisationToolbar/MultiLevelDropdown.js +3 -27
  37. package/dist/components/VisualisationToolbar/TableColumnsDropdown.d.ts.map +1 -1
  38. package/dist/components/VisualisationToolbar/TableColumnsDropdown.js +3 -1
  39. package/dist/components/VisualisationToolbar/index.d.ts +11 -0
  40. package/dist/components/VisualisationToolbar/index.d.ts.map +1 -1
  41. package/dist/components/VisualisationToolbar/index.js +13 -6
  42. package/dist/styles.css +1 -1
  43. package/package.json +4 -3
  44. package/src/MetricsGraphStrips/AreaGraph/index.tsx +321 -0
  45. package/src/MetricsGraphStrips/MetricsGraphStrips.stories.tsx +57 -0
  46. package/src/MetricsGraphStrips/TimelineGuide/index.tsx +111 -0
  47. package/src/MetricsGraphStrips/index.tsx +93 -0
  48. package/src/ProfileIcicleGraph/index.tsx +2 -18
  49. package/src/{ProfileIcicleGraph/IcicleGraphArrow → ProfileView}/ColorStackLegend.tsx +2 -2
  50. package/src/ProfileView/VisualizationPanel.tsx +13 -10
  51. package/src/ProfileView/index.tsx +59 -9
  52. package/src/ProfileViewWithData.tsx +1 -3
  53. package/src/Table/index.tsx +121 -263
  54. package/src/Table/utils/functions.ts +284 -0
  55. package/src/components/ActionButtons/GroupByDropdown.tsx +1 -1
  56. package/src/components/ActionButtons/SortByDropdown.tsx +84 -0
  57. package/src/components/VisualisationToolbar/MultiLevelDropdown.tsx +7 -30
  58. package/src/components/VisualisationToolbar/TableColumnsDropdown.tsx +3 -1
  59. package/src/components/VisualisationToolbar/index.tsx +103 -58
  60. package/dist/ProfileIcicleGraph/IcicleGraphArrow/ColorStackLegend.d.ts.map +0 -1
  61. /package/dist/{ProfileIcicleGraph/IcicleGraphArrow → ProfileView}/ColorStackLegend.d.ts +0 -0
@@ -12,7 +12,8 @@ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-run
12
12
  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
13
  // See the License for the specific language governing permissions and
14
14
  // limitations under the License.
15
- import { Profiler, useCallback, useEffect, useState } from 'react';
15
+ import { Profiler, useCallback, useEffect, useMemo, useState } from 'react';
16
+ import { tableFromIPC } from 'apache-arrow';
16
17
  import cx from 'classnames';
17
18
  import { scaleLinear } from 'd3';
18
19
  import graphviz from 'graphviz-wasm';
@@ -25,9 +26,11 @@ import { Callgraph } from '../';
25
26
  import { jsonToDot } from '../Callgraph/utils';
26
27
  import ProfileIcicleGraph from '../ProfileIcicleGraph';
27
28
  import { FIELD_FUNCTION_NAME } from '../ProfileIcicleGraph/IcicleGraphArrow';
29
+ import useMappingList, { useFilenamesList, } from '../ProfileIcicleGraph/IcicleGraphArrow/useMappingList';
28
30
  import { SourceView } from '../SourceView';
29
31
  import { Table } from '../Table';
30
- import VisualisationToolbar from '../components/VisualisationToolbar';
32
+ import VisualisationToolbar, { IcicleGraphToolbar, TableToolbar, } from '../components/VisualisationToolbar';
33
+ import ColorStackLegend from './ColorStackLegend';
31
34
  import { ProfileViewContextProvider } from './ProfileViewContext';
32
35
  import { VisualizationPanel } from './VisualizationPanel';
33
36
  function arrayEquals(a, b) {
@@ -46,8 +49,17 @@ export const ProfileView = ({ total, filtered, flamegraphData, topTableData, cal
46
49
  const [graphvizLoaded, setGraphvizLoaded] = useState(false);
47
50
  const [callgraphSVG, setCallgraphSVG] = useState(undefined);
48
51
  const [currentSearchString, setSearchString] = useURLState('search_string');
52
+ const [colorStackLegend] = useURLState('color_stack_legend');
53
+ const [colorBy] = useURLState('color_by');
54
+ const isColorStackLegendEnabled = colorStackLegend === 'true';
55
+ const colorByValue = colorBy === undefined || colorBy === '' ? 'binary' : colorBy;
49
56
  const isDarkMode = useAppSelector(selectDarkMode);
50
57
  const isMultiPanelView = dashboardItems.length > 1;
58
+ const table = useMemo(() => {
59
+ return flamegraphData.arrow !== undefined ? tableFromIPC(flamegraphData.arrow.record) : null;
60
+ }, [flamegraphData.arrow]);
61
+ const mappingsList = useMappingList(flamegraphData.metadataMappingFiles);
62
+ const filenamesList = useFilenamesList(table);
51
63
  const { perf, profileViewExternalMainActions } = useParcaContext();
52
64
  useEffect(() => {
53
65
  // Reset the current path when the profile source changes
@@ -92,15 +104,15 @@ export const ProfileView = ({ total, filtered, flamegraphData, topTableData, cal
92
104
  setCurPath(path);
93
105
  }
94
106
  };
95
- const getDashboardItemByType = ({ type, isHalfScreen, setActionButtons, }) => {
107
+ const getDashboardItemByType = ({ type, isHalfScreen, }) => {
96
108
  switch (type) {
97
109
  case 'icicle': {
98
110
  return (_jsx(ConditionalWrapper, { condition: perf?.onRender != null, WrapperComponent: Profiler, wrapperProps: {
99
111
  id: 'icicleGraph',
100
112
  onRender: perf?.onRender,
101
- }, children: _jsx(ProfileIcicleGraph, { curPath: curPath, setNewCurPath: setNewCurPath, arrow: flamegraphData?.arrow, graph: flamegraphData?.data, total: total, filtered: filtered, profileType: profileSource?.ProfileType(), loading: flamegraphData.loading, setActionButtons: setActionButtons, error: flamegraphData.error, isHalfScreen: isHalfScreen, width: dimensions?.width !== undefined
113
+ }, children: _jsx(ProfileIcicleGraph, { curPath: curPath, setNewCurPath: setNewCurPath, arrow: flamegraphData?.arrow, graph: flamegraphData?.data, total: total, filtered: filtered, profileType: profileSource?.ProfileType(), loading: flamegraphData.loading, error: flamegraphData.error, isHalfScreen: isHalfScreen, width: dimensions?.width !== undefined
102
114
  ? isHalfScreen
103
- ? (dimensions.width - 40) / 2
115
+ ? (dimensions.width - 54) / 2
104
116
  : dimensions.width - 16
105
117
  : 0, metadataMappingFiles: flamegraphData.metadataMappingFiles, metadataLoading: flamegraphData.metadataLoading }) }));
106
118
  }
@@ -110,10 +122,10 @@ export const ProfileView = ({ total, filtered, flamegraphData, topTableData, cal
110
122
  dimensions?.width !== undefined ? (_jsx(Callgraph, { data: callgraphData.data, svgString: callgraphSVG, profileType: profileSource?.ProfileType(), width: isHalfScreen ? dimensions?.width / 2 : dimensions?.width })) : (_jsx(_Fragment, {}));
111
123
  }
112
124
  case 'table': {
113
- return topTableData != null ? (_jsx(Table, { total: total, filtered: filtered, loading: topTableData.loading, data: topTableData.arrow?.record, unit: topTableData.unit, profileType: profileSource?.ProfileType(), setActionButtons: setActionButtons, currentSearchString: currentSearchString, setSearchString: setSearchString, isHalfScreen: isHalfScreen })) : (_jsx(_Fragment, {}));
125
+ return topTableData != null ? (_jsx(Table, { total: total, filtered: filtered, loading: topTableData.loading, data: topTableData.arrow?.record, unit: topTableData.unit, profileType: profileSource?.ProfileType(), currentSearchString: currentSearchString, setSearchString: setSearchString, isHalfScreen: isHalfScreen, metadataMappingFiles: flamegraphData.metadataMappingFiles })) : (_jsx(_Fragment, {}));
114
126
  }
115
127
  case 'source': {
116
- return sourceData != null ? (_jsx(SourceView, { loading: sourceData.loading, data: sourceData.data, total: total, filtered: filtered, setActionButtons: setActionButtons })) : (_jsx(_Fragment, {}));
128
+ return sourceData != null ? (_jsx(SourceView, { loading: sourceData.loading, data: sourceData.data, total: total, filtered: filtered })) : (_jsx(_Fragment, {}));
117
129
  }
118
130
  default: {
119
131
  return _jsx(_Fragment, {});
@@ -155,6 +167,15 @@ export const ProfileView = ({ total, filtered, flamegraphData, topTableData, cal
155
167
  }, [groupBy, setGroupBy]);
156
168
  const showDivider = hasProfileSource &&
157
169
  (profileViewExternalMainActions === null || profileViewExternalMainActions === undefined);
170
+ const clearSelection = useCallback(() => {
171
+ setSearchString?.('');
172
+ }, [setSearchString]);
173
+ const getActionButtonsWithMultiPanelView = () => {
174
+ return {
175
+ icicle: _jsx(IcicleGraphToolbar, { curPath: curPath, setNewCurPath: setNewCurPath }),
176
+ table: (_jsx(TableToolbar, { profileType: profileSource?.ProfileType(), total: total, filtered: filtered, clearSelection: clearSelection, currentSearchString: currentSearchString })),
177
+ };
178
+ };
158
179
  return (_jsx(KeyDownProvider, { children: _jsxs(ProfileViewContextProvider, { value: { profileSource, compareMode }, children: [showDivider ? (_jsx(_Fragment, { children: _jsx("div", { className: "border-t border-gray-200 dark:border-gray-700 h-[1px] w-full pb-4" }) })) : null, _jsx("div", { className: cx('flex w-full', hasProfileSource || profileViewExternalMainActions != null
159
180
  ? 'justify-start'
160
181
  : 'justify-end', {
@@ -162,10 +183,12 @@ export const ProfileView = ({ total, filtered, flamegraphData, topTableData, cal
162
183
  'items-center mb-2': hasProfileSource,
163
184
  }), children: _jsxs("div", { children: [hasProfileSource && (_jsxs("div", { className: "flex items-center gap-1", children: [_jsx("div", { className: "text-xs font-medium", children: headerParts.length > 0 ? headerParts[0].replace(/"/g, '') : '' }), _jsx("div", { className: "text-xs font-medium", children: headerParts.length > 1
164
185
  ? headerParts[headerParts.length - 1].replace(/"/g, '')
165
- : '' })] })), profileViewExternalMainActions != null ? profileViewExternalMainActions : null] }) }), _jsx(VisualisationToolbar, { groupBy: groupBy, toggleGroupBy: toggleGroupBy, hasProfileSource: hasProfileSource, pprofdownloading: pprofDownloading, profileSource: profileSource, queryClient: queryClient, onDownloadPProf: onDownloadPProf, isMultiPanelView: isMultiPanelView, dashboardItems: dashboardItems, curPath: curPath, setNewCurPath: setNewCurPath, profileType: profileSource?.ProfileType(), total: total, filtered: filtered, currentSearchString: currentSearchString, setSearchString: setSearchString, groupByLabels: flamegraphData.metadataLabels ?? [] }), _jsx("div", { className: "w-full", ref: ref, children: _jsx(DragDropContext, { onDragEnd: onDragEnd, children: _jsx(Droppable, { droppableId: "droppable", direction: "horizontal", children: provided => (_jsx("div", { ref: provided.innerRef, className: cx('grid w-full gap-2', isMultiPanelView ? 'grid-cols-2' : 'grid-cols-1'), ...provided.droppableProps, children: dashboardItems.map((dashboardItem, index) => {
186
+ : '' })] })), profileViewExternalMainActions != null ? profileViewExternalMainActions : null] }) }), _jsx(VisualisationToolbar, { groupBy: groupBy, toggleGroupBy: toggleGroupBy, hasProfileSource: hasProfileSource, pprofdownloading: pprofDownloading, profileSource: profileSource, queryClient: queryClient, onDownloadPProf: onDownloadPProf, isMultiPanelView: isMultiPanelView, dashboardItems: dashboardItems, curPath: curPath, setNewCurPath: setNewCurPath, profileType: profileSource?.ProfileType(), total: total, filtered: filtered, currentSearchString: currentSearchString, setSearchString: setSearchString, groupByLabels: flamegraphData.metadataLabels ?? [] }), isColorStackLegendEnabled && (_jsx(ColorStackLegend, { compareMode: compareMode, mappings: colorByValue === 'binary' ? mappingsList : filenamesList, loading: flamegraphData.metadataLoading })), _jsx("div", { className: "w-full", ref: ref, children: _jsx(DragDropContext, { onDragEnd: onDragEnd, children: _jsx(Droppable, { droppableId: "droppable", direction: "horizontal", children: provided => (_jsx("div", { ref: provided.innerRef, className: cx('grid w-full gap-2', isMultiPanelView ? 'grid-cols-2' : 'grid-cols-1'), ...provided.droppableProps, children: dashboardItems.map((dashboardItem, index) => {
166
187
  return (_jsx(Draggable, { draggableId: dashboardItem, index: index, isDragDisabled: !isMultiPanelView, children: (provided, snapshot) => (_createElement("div", { ref: provided.innerRef, ...provided.draggableProps, key: dashboardItem, className: cx('w-full min-h-96', snapshot.isDragging
167
188
  ? 'bg-gray-200 dark:bg-gray-500'
168
- : 'bg-white dark:bg-gray-900') },
169
- _jsx(VisualizationPanel, { handleClosePanel: handleClosePanel, isMultiPanelView: isMultiPanelView, dashboardItem: dashboardItem, getDashboardItemByType: getDashboardItemByType, dragHandleProps: provided.dragHandleProps, index: index }))) }, dashboardItem));
189
+ : 'bg-white dark:bg-gray-900', isMultiPanelView
190
+ ? 'border-2 border-gray-100 dark:border-gray-700 rounded-md p-3'
191
+ : '') },
192
+ _jsx(VisualizationPanel, { handleClosePanel: handleClosePanel, isMultiPanelView: isMultiPanelView, dashboardItem: dashboardItem, getDashboardItemByType: getDashboardItemByType, dragHandleProps: provided.dragHandleProps, index: index, actionButtons: getActionButtonsWithMultiPanelView() }))) }, dashboardItem));
170
193
  }) })) }) }) })] }) }));
171
194
  };
@@ -1 +1 @@
1
- {"version":3,"file":"ProfileViewWithData.d.ts","sourceRoot":"","sources":["../src/ProfileViewWithData.tsx"],"names":[],"mappings":"AAeA,OAAO,EAA0B,kBAAkB,EAAC,MAAM,eAAe,CAAC;AAK1E,OAAO,EAAC,aAAa,EAAC,MAAM,iBAAiB,CAAC;AAK9C,UAAU,wBAAwB;IAChC,WAAW,EAAE,kBAAkB,CAAC;IAChC,aAAa,EAAE,aAAa,CAAC;IAC7B,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,eAAO,MAAM,mBAAmB,oCAG7B,wBAAwB,KAAG,GAAG,CAAC,OAmNjC,CAAC;AAEF,eAAe,mBAAmB,CAAC"}
1
+ {"version":3,"file":"ProfileViewWithData.d.ts","sourceRoot":"","sources":["../src/ProfileViewWithData.tsx"],"names":[],"mappings":"AAeA,OAAO,EAA0B,kBAAkB,EAAC,MAAM,eAAe,CAAC;AAK1E,OAAO,EAAC,aAAa,EAAC,MAAM,iBAAiB,CAAC;AAK9C,UAAU,wBAAwB;IAChC,WAAW,EAAE,kBAAkB,CAAC;IAChC,aAAa,EAAE,aAAa,CAAC;IAC7B,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,eAAO,MAAM,mBAAmB,oCAG7B,wBAAwB,KAAG,GAAG,CAAC,OAiNjC,CAAC;AAEF,eAAe,mBAAmB,CAAC"}
@@ -53,15 +53,13 @@ export const ProfileViewWithData = ({ queryClient, profileSource, }) => {
53
53
  binaryFrameFilter,
54
54
  });
55
55
  const { isLoading: profileMetadataLoading, response: profileMetadataResponse } = useQuery(queryClient, profileSource, QueryRequest_ReportType.PROFILE_METADATA, {
56
- skip: !dashboardItems.includes('icicle'),
57
56
  nodeTrimThreshold,
58
57
  groupBy,
59
- invertCallStack,
60
- binaryFrameFilter: undefined,
61
58
  });
62
59
  const { perf } = useParcaContext();
63
60
  const { isLoading: tableLoading, response: tableResponse, error: tableError, } = useQuery(queryClient, profileSource, QueryRequest_ReportType.TABLE_ARROW, {
64
61
  skip: !dashboardItems.includes('table'),
62
+ binaryFrameFilter,
65
63
  });
66
64
  const { isLoading: callgraphLoading, response: callgraphResponse, error: callgraphError, } = useQuery(queryClient, profileSource, QueryRequest_ReportType.CALLGRAPH, {
67
65
  skip: !dashboardItems.includes('callgraph'),
@@ -1,28 +1,6 @@
1
1
  import React from 'react';
2
- import { Vector } from 'apache-arrow';
3
2
  import { ProfileType } from '@parca/parser';
4
- export interface DataRow {
5
- id: number;
6
- name: string;
7
- flat: bigint;
8
- flatDiff: bigint;
9
- cumulative: bigint;
10
- cumulativeDiff: bigint;
11
- mappingFile: string;
12
- functionSystemName: string;
13
- functionFileName: string;
14
- callers?: DataRow[];
15
- callees?: DataRow[];
16
- subRows?: Row[];
17
- isTopSubRow?: boolean;
18
- isBottomSubRow?: boolean;
19
- }
20
- interface DummyRow {
21
- size: number;
22
- message?: string;
23
- isTopSubRow?: boolean;
24
- isBottomSubRow?: boolean;
25
- }
3
+ import { DataRow, DummyRow } from './utils/functions';
26
4
  export type Row = DataRow | DummyRow;
27
5
  export declare const isDummyRow: (row: Row) => row is DummyRow;
28
6
  interface TableProps {
@@ -36,13 +14,8 @@ interface TableProps {
36
14
  setActionButtons?: (buttons: React.JSX.Element) => void;
37
15
  isHalfScreen: boolean;
38
16
  unit?: string;
17
+ metadataMappingFiles?: string[];
39
18
  }
40
- export type ColumnName = 'flat' | 'flatPercentage' | 'flatDiff' | 'flatDiffPercentage' | 'cumulative' | 'cumulativePercentage' | 'cumulativeDiff' | 'cumulativeDiffPercentage' | 'name' | 'functionSystemName' | 'functionFileName' | 'mappingFile';
41
- export declare const getPercentageString: (value: bigint | number, total: bigint | number) => string;
42
- export declare const getRatioString: (value: bigint | number, total: bigint, filtered: bigint) => string;
43
- export declare const possibleColumns: string[];
44
19
  export declare const Table: React.NamedExoticComponent<TableProps>;
45
- export declare const addPlusSign: (num: string) => string;
46
- export declare const RowName: (mappingFileColumn: Vector | null, locationAddressColumn: Vector | null, functionNameColumn: Vector | null, row: number) => string;
47
20
  export default Table;
48
21
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/Table/index.tsx"],"names":[],"mappings":"AAaA,OAAO,KAA0D,MAAM,OAAO,CAAC;AAU/E,OAAO,EAAQ,MAAM,EAAgC,MAAM,cAAc,CAAC;AAW1E,OAAO,EAAC,WAAW,EAAC,MAAM,eAAe,CAAC;AAmB1C,MAAM,WAAW,OAAO;IACtB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,cAAc,EAAE,MAAM,CAAC;IACvB,WAAW,EAAE,MAAM,CAAC;IACpB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,gBAAgB,EAAE,MAAM,CAAC;IACzB,OAAO,CAAC,EAAE,OAAO,EAAE,CAAC;IACpB,OAAO,CAAC,EAAE,OAAO,EAAE,CAAC;IACpB,OAAO,CAAC,EAAE,GAAG,EAAE,CAAC;IAChB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,cAAc,CAAC,EAAE,OAAO,CAAC;CAC1B;AAED,UAAU,QAAQ;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,cAAc,CAAC,EAAE,OAAO,CAAC;CAC1B;AAED,MAAM,MAAM,GAAG,GAAG,OAAO,GAAG,QAAQ,CAAC;AAErC,eAAO,MAAM,UAAU,QAAS,GAAG,KAAG,GAAG,IAAI,QAE5C,CAAC;AAIF,UAAU,UAAU;IAClB,IAAI,CAAC,EAAE,UAAU,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,OAAO,EAAE,OAAO,CAAC;IACjB,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,eAAe,CAAC,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,IAAI,CAAC;IACjD,gBAAgB,CAAC,EAAE,CAAC,OAAO,EAAE,KAAK,CAAC,GAAG,CAAC,OAAO,KAAK,IAAI,CAAC;IACxD,YAAY,EAAE,OAAO,CAAC;IACtB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,MAAM,UAAU,GAClB,MAAM,GACN,gBAAgB,GAChB,UAAU,GACV,oBAAoB,GACpB,YAAY,GACZ,sBAAsB,GACtB,gBAAgB,GAChB,0BAA0B,GAC1B,MAAM,GACN,oBAAoB,GACpB,kBAAkB,GAClB,aAAa,CAAC;AA4LlB,eAAO,MAAM,mBAAmB,UAAW,MAAM,GAAG,MAAM,SAAS,MAAM,GAAG,MAAM,KAAG,MAOpF,CAAC;AAEF,eAAO,MAAM,cAAc,UAAW,MAAM,GAAG,MAAM,SAAS,MAAM,YAAY,MAAM,KAAG,MAMxF,CAAC;AAEF,eAAO,MAAM,eAAe,UAa3B,CAAC;AAEF,eAAO,MAAM,KAAK,wCAoZhB,CAAC;AAEH,eAAO,MAAM,WAAW,QAAS,MAAM,KAAG,MAMzC,CAAC;AAEF,eAAO,MAAM,OAAO,sBACC,MAAM,GAAG,IAAI,yBACT,MAAM,GAAG,IAAI,sBAChB,MAAM,GAAG,IAAI,OAC5B,MAAM,KACV,MAoBF,CAAC;AAgDF,eAAe,KAAK,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/Table/index.tsx"],"names":[],"mappings":"AAaA,OAAO,KAA0D,MAAM,OAAO,CAAC;AAsB/E,OAAO,EAAC,WAAW,EAAC,MAAM,eAAe,CAAC;AAS1C,OAAO,EAEL,OAAO,EACP,QAAQ,EAgBT,MAAM,mBAAmB,CAAC;AAe3B,MAAM,MAAM,GAAG,GAAG,OAAO,GAAG,QAAQ,CAAC;AAErC,eAAO,MAAM,UAAU,QAAS,GAAG,KAAG,GAAG,IAAI,QAE5C,CAAC;AAIF,UAAU,UAAU;IAClB,IAAI,CAAC,EAAE,UAAU,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,OAAO,EAAE,OAAO,CAAC;IACjB,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,eAAe,CAAC,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,IAAI,CAAC;IACjD,gBAAgB,CAAC,EAAE,CAAC,OAAO,EAAE,KAAK,CAAC,GAAG,CAAC,OAAO,KAAK,IAAI,CAAC;IACxD,YAAY,EAAE,OAAO,CAAC;IACtB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,oBAAoB,CAAC,EAAE,MAAM,EAAE,CAAC;CACjC;AAkID,eAAO,MAAM,KAAK,wCA6bhB,CAAC;AAEH,eAAe,KAAK,CAAC"}
@@ -18,9 +18,12 @@ import { tableFromIPC, vectorFromArray } from 'apache-arrow';
18
18
  import cx from 'classnames';
19
19
  import { AnimatePresence, motion } from 'framer-motion';
20
20
  import { Table as TableComponent, TableSkeleton, useParcaContext, useURLState, } from '@parca/components';
21
- import { getLastItem, isSearchMatch, valueFormatter } from '@parca/utilities';
21
+ import { useCurrentColorProfile } from '@parca/hooks';
22
+ import { isSearchMatch, valueFormatter } from '@parca/utilities';
23
+ import { getFilenameColors, getMappingColors } from '../ProfileIcicleGraph/IcicleGraphArrow/';
24
+ import useMappingList, { useFilenamesList, } from '../ProfileIcicleGraph/IcicleGraphArrow/useMappingList';
22
25
  import { useProfileViewContext } from '../ProfileView/ProfileViewContext';
23
- import { hexifyAddress } from '../utils';
26
+ import { ROW_HEIGHT, RowName, addPlusSign, getCalleeRows, getCallerRows, getRowColor, getScrollTargetIndex, isFirstSubRow, isLastSubRow, isSubRow, ratioString, rowBgClassNames, sizeToBottomStyle, sizeToHeightStyle, sizeToWidthStyle, } from './utils/functions';
24
27
  import { getTopAndBottomExpandedRowModel } from './utils/topAndBottomExpandedRowModel';
25
28
  const FIELD_MAPPING_FILE = 'mapping_file';
26
29
  const FIELD_LOCATION_ADDRESS = 'location_address';
@@ -37,29 +40,6 @@ export const isDummyRow = (row) => {
37
40
  return 'size' in row;
38
41
  };
39
42
  let doubleClickTimer = null;
40
- const rowBgClassNames = (isExpanded, isSubRow) => {
41
- return {
42
- relative: true,
43
- 'bg-indigo-100 dark:bg-gray-600': isSubRow,
44
- 'bg-indigo-50 dark:bg-gray-700': isExpanded,
45
- };
46
- };
47
- const ROW_HEIGHT = 29;
48
- const sizeToHeightStyle = (size) => {
49
- return {
50
- height: `${size * ROW_HEIGHT}px`,
51
- };
52
- };
53
- const sizeToWidthStyle = (size) => {
54
- return {
55
- width: `${size * ROW_HEIGHT}px`,
56
- };
57
- };
58
- const sizeToBottomStyle = (size) => {
59
- return {
60
- bottom: `-${size * ROW_HEIGHT}px`,
61
- };
62
- };
63
43
  const CustomRowRenderer = ({ row, usePointerCursor, onRowClick, onRowDoubleClick, enableHighlighting, shouldHighlightRow, rows, }) => {
64
44
  const data = row.original;
65
45
  const isExpanded = row.getIsExpanded();
@@ -121,85 +101,62 @@ const CustomRowRenderer = ({ row, usePointerCursor, onRowClick, onRowDoubleClick
121
101
  }, children: ['<-', " Callees"] })] })) : null, idx === 0 && _isSubRow ? paddingElement : null, flexRender(cell.column.columnDef.cell, cell.getContext())] }, cell.id));
122
102
  }) }, row.id));
123
103
  };
124
- const getCallerRows = (callers) => {
125
- if (callers.length === 0) {
126
- return [{ size: 3, message: 'No callers.', isTopSubRow: true }];
127
- }
128
- const rows = callers.map(row => {
129
- return { ...row, isTopSubRow: true };
130
- });
131
- if (rows.length >= 3) {
132
- return rows;
133
- }
134
- return [...rows, { size: 3 - rows.length, message: '', isTopSubRow: true }];
135
- };
136
- const getCalleeRows = (callees) => {
137
- if (callees.length === 0) {
138
- return [{ size: 3, message: 'No callees.', isBottomSubRow: true }];
139
- }
140
- const rows = callees.map(row => {
141
- return { ...row, isBottomSubRow: true };
142
- });
143
- if (rows.length >= 3) {
144
- return rows;
145
- }
146
- return [{ size: 3 - rows.length, message: '', isBottomSubRow: true }, ...rows];
147
- };
148
- export const getPercentageString = (value, total) => {
149
- if (total === 0n) {
150
- return '0%';
151
- }
152
- const percentage = (Number(value) / Number(total)) * 100;
153
- return `${percentage.toFixed(2)}%`;
154
- };
155
- export const getRatioString = (value, total, filtered) => {
156
- if (filtered === 0n) {
157
- return ` ${getPercentageString(value, total)}`;
158
- }
159
- return `${getPercentageString(value, total)} / ${getPercentageString(value, filtered)}`;
160
- };
161
- export const possibleColumns = [
162
- 'flat',
163
- 'flatPercentage',
164
- 'flatDiff',
165
- 'flatDiffPercentage',
166
- 'cumulative',
167
- 'cumulativePercentage',
168
- 'cumulativeDiff',
169
- 'cumulativeDiffPercentage',
170
- 'name',
171
- 'functionSystemName',
172
- 'functionFileName',
173
- 'mappingFile',
174
- ];
175
- export const Table = React.memo(function Table({ data, total, filtered, profileType, loading, currentSearchString, setSearchString = () => { }, isHalfScreen, unit, }) {
104
+ export const Table = React.memo(function Table({ data, total, filtered, profileType, loading, currentSearchString, setSearchString = () => { }, isHalfScreen, unit, metadataMappingFiles, }) {
105
+ const currentColorProfile = useCurrentColorProfile();
176
106
  const [dashboardItems] = useURLState('dashboard_items', {
177
107
  alwaysReturnArray: true,
178
108
  });
179
109
  const [tableColumns] = useURLState('table_columns', {
180
110
  alwaysReturnArray: true,
181
111
  });
112
+ const [colorBy, setColorBy] = useURLState('color_by');
182
113
  const { isDarkMode } = useParcaContext();
183
114
  const [expanded, setExpanded] = useState({});
184
115
  const [scrollToIndex, setScrollToIndex] = useState(undefined);
185
116
  const { compareMode } = useProfileViewContext();
186
- const percentageString = (value, total) => {
187
- if (total === 0n) {
188
- return '0%';
117
+ const table = useMemo(() => {
118
+ if (loading || data == null) {
119
+ return null;
189
120
  }
190
- const percentage = (Number(value) / Number(total)) * 100;
191
- return `${percentage.toFixed(2)}%`;
192
- };
193
- const ratioString = (value) => {
194
- if (filtered === 0n) {
195
- return ` ${percentageString(value, total)}`;
121
+ return tableFromIPC(data);
122
+ }, [data, loading]);
123
+ const mappingsList = useMappingList(metadataMappingFiles);
124
+ const filenamesList = useFilenamesList(table);
125
+ const colorByValue = colorBy === undefined || colorBy === '' ? 'binary' : colorBy;
126
+ const mappingsListCount = useMemo(() => mappingsList.filter(m => m !== '').length, [mappingsList]);
127
+ // If there is only one mapping file, we want to color by filename by default.
128
+ useEffect(() => {
129
+ if (mappingsListCount === 1 && colorBy !== 'filename') {
130
+ setColorBy('filename');
196
131
  }
197
- return `${percentageString(value, total)} / ${percentageString(value, filtered)}`;
132
+ // eslint-disable-next-line react-hooks/exhaustive-deps
133
+ }, [mappingsListCount]);
134
+ const filenameColors = useMemo(() => {
135
+ const colors = getFilenameColors(filenamesList, isDarkMode, currentColorProfile);
136
+ return colors;
137
+ }, [isDarkMode, filenamesList, currentColorProfile]);
138
+ const mappingColors = useMemo(() => {
139
+ const colors = getMappingColors(mappingsList, isDarkMode, currentColorProfile);
140
+ return colors;
141
+ }, [isDarkMode, mappingsList, currentColorProfile]);
142
+ const colorByList = {
143
+ filename: filenameColors,
144
+ binary: mappingColors,
198
145
  };
146
+ const colorByColors = colorByList[colorByValue];
199
147
  const columnHelper = createColumnHelper();
200
148
  unit = useMemo(() => unit ?? profileType?.sampleUnit ?? '', [unit, profileType?.sampleUnit]);
201
149
  const columns = useMemo(() => {
202
150
  return [
151
+ columnHelper.accessor('color', {
152
+ id: 'color',
153
+ header: '',
154
+ cell: info => {
155
+ const color = info.getValue();
156
+ return _jsx("div", { className: "w-4 h-4 rounded-[4px]", style: { backgroundColor: color } });
157
+ },
158
+ size: 10,
159
+ }),
203
160
  columnHelper.accessor('flat', {
204
161
  id: 'flat',
205
162
  header: 'Flat',
@@ -217,7 +174,7 @@ export const Table = React.memo(function Table({ data, total, filtered, profileT
217
174
  if (isDummyRow(info.row.original)) {
218
175
  return '';
219
176
  }
220
- return ratioString(info.getValue());
177
+ return ratioString(info.getValue(), total, filtered);
221
178
  },
222
179
  size: 120,
223
180
  meta: {
@@ -242,7 +199,7 @@ export const Table = React.memo(function Table({ data, total, filtered, profileT
242
199
  if (isDummyRow(info.row.original)) {
243
200
  return '';
244
201
  }
245
- return ratioString(info.getValue());
202
+ return ratioString(info.getValue(), total, filtered);
246
203
  },
247
204
  size: 120,
248
205
  meta: {
@@ -267,7 +224,7 @@ export const Table = React.memo(function Table({ data, total, filtered, profileT
267
224
  if (isDummyRow(info.row.original)) {
268
225
  return '';
269
226
  }
270
- return ratioString(info.getValue());
227
+ return ratioString(info.getValue(), total, filtered);
271
228
  },
272
229
  size: 150,
273
230
  meta: {
@@ -292,7 +249,7 @@ export const Table = React.memo(function Table({ data, total, filtered, profileT
292
249
  if (isDummyRow(info.row.original)) {
293
250
  return '';
294
251
  }
295
- return ratioString(info.getValue());
252
+ return ratioString(info.getValue(), total, filtered);
296
253
  },
297
254
  size: 170,
298
255
  meta: {
@@ -325,6 +282,7 @@ export const Table = React.memo(function Table({ data, total, filtered, profileT
325
282
  }, [profileType, unit]);
326
283
  const [columnVisibility, setColumnVisibility] = useState(() => {
327
284
  return {
285
+ color: true,
328
286
  flat: true,
329
287
  flatPercentage: false,
330
288
  flatDiff: compareMode,
@@ -388,7 +346,7 @@ export const Table = React.memo(function Table({ data, total, filtered, profileT
388
346
  }
389
347
  newRow.toggleExpanded();
390
348
  setScrollToIndex(getScrollTargetIndex(rows, parentRow, newRow));
391
- }, []);
349
+ }, [setScrollToIndex]);
392
350
  const shouldHighlightRow = useCallback((row) => {
393
351
  if (!('name' in row)) {
394
352
  return false;
@@ -407,12 +365,6 @@ export const Table = React.memo(function Table({ data, total, filtered, profileT
407
365
  },
408
366
  ];
409
367
  }, [compareMode]);
410
- const table = useMemo(() => {
411
- if (loading || data == null) {
412
- return null;
413
- }
414
- return tableFromIPC(data);
415
- }, [data, loading]);
416
368
  const rows = useMemo(() => {
417
369
  if (table == null || table.numRows === 0) {
418
370
  return [];
@@ -438,6 +390,7 @@ export const Table = React.memo(function Table({ data, total, filtered, profileT
438
390
  const mappingFile = mappingFileColumn?.get(i) ?? '';
439
391
  return {
440
392
  id: i,
393
+ color: getRowColor(colorByColors, mappingFileColumn, i, functionFileNameColumn, colorBy),
441
394
  name: RowName(mappingFileColumn, locationAddressColumn, functionNameColumn, i),
442
395
  flat,
443
396
  flatDiff,
@@ -465,7 +418,7 @@ export const Table = React.memo(function Table({ data, total, filtered, profileT
465
418
  rows.push(row);
466
419
  }
467
420
  return rows;
468
- }, [table]);
421
+ }, [table, colorByColors, colorBy]);
469
422
  if (loading) {
470
423
  return (_jsx("div", { className: "overflow-clip h-[700px] min-h-[700px]", children: _jsx(TableSkeleton, { isHalfScreen: isHalfScreen, isDarkMode: isDarkMode }) }));
471
424
  }
@@ -482,64 +435,4 @@ export const Table = React.memo(function Table({ data, total, filtered, profileT
482
435
  setExpanded(newState);
483
436
  }, CustomRowRenderer: CustomRowRenderer, scrollToIndex: scrollToIndex, estimatedRowHeight: ROW_HEIGHT }) }) }) }, "table-loaded") }));
484
437
  });
485
- export const addPlusSign = (num) => {
486
- if (num.charAt(0) === '0' || num.charAt(0) === '-') {
487
- return num;
488
- }
489
- return `+${num}`;
490
- };
491
- export const RowName = (mappingFileColumn, locationAddressColumn, functionNameColumn, row) => {
492
- if (mappingFileColumn === null) {
493
- console.error('mapping_file column not found');
494
- return '';
495
- }
496
- const mappingFile = mappingFileColumn?.get(row);
497
- let mapping = '';
498
- // Show the last item in the mapping file only if there are more than 1 mappings
499
- if (mappingFile != null && mappingFileColumn.data.length > 1) {
500
- mapping = `[${getLastItem(mappingFile) ?? ''}]`;
501
- }
502
- const functionName = functionNameColumn?.get(row) ?? '';
503
- if (functionName !== null && functionName !== '') {
504
- return `${mapping} ${functionName}`;
505
- }
506
- const address = locationAddressColumn?.get(row) ?? 0;
507
- return hexifyAddress(address);
508
- };
509
- const getRowsCount = (rows) => {
510
- if (rows.length < 6) {
511
- return 6;
512
- }
513
- return rows.length;
514
- };
515
- function getScrollTargetIndex(rows, parentRow, newRow) {
516
- const parentIndex = rows.indexOf(parentRow);
517
- const newRowIndex = rows.indexOf(newRow);
518
- let targetIndex = newRowIndex;
519
- if (parentIndex > newRowIndex) {
520
- // Adjusting the number of subs rows to scroll to the main row after expansion.
521
- targetIndex -= getRowsCount(newRow.subRows);
522
- }
523
- if (parentIndex < newRowIndex) {
524
- // If the parent row is above the new row, we need to adjust the number of subrows of the parent.
525
- targetIndex += getRowsCount(parentRow.subRows);
526
- }
527
- if (targetIndex < 0) {
528
- targetIndex = 0;
529
- }
530
- return targetIndex;
531
- }
532
- function isSubRow(row) {
533
- return row.isTopSubRow === true || row.isBottomSubRow === true;
534
- }
535
- function isLastSubRow(row, rows) {
536
- const index = rows.indexOf(row);
537
- const nextRow = rows[index + 1];
538
- return nextRow == null || (!isSubRow(nextRow.original) && !nextRow.getIsExpanded());
539
- }
540
- function isFirstSubRow(row, rows) {
541
- const index = rows.indexOf(row);
542
- const prevRow = rows[index - 1];
543
- return prevRow == null || (!isSubRow(prevRow.original) && !prevRow.getIsExpanded());
544
- }
545
438
  export default Table;
@@ -0,0 +1,49 @@
1
+ import { type Row as RowType } from '@tanstack/table-core';
2
+ import { Vector } from 'apache-arrow';
3
+ import { colorByColors } from '../../ProfileIcicleGraph/IcicleGraphArrow/IcicleGraphNodes';
4
+ export interface DataRow {
5
+ id: number;
6
+ color: string;
7
+ name: string;
8
+ flat: bigint;
9
+ flatDiff: bigint;
10
+ cumulative: bigint;
11
+ cumulativeDiff: bigint;
12
+ mappingFile: string;
13
+ functionSystemName: string;
14
+ functionFileName: string;
15
+ callers?: DataRow[];
16
+ callees?: DataRow[];
17
+ subRows?: Row[];
18
+ isTopSubRow?: boolean;
19
+ isBottomSubRow?: boolean;
20
+ }
21
+ export interface DummyRow {
22
+ size: number;
23
+ message?: string;
24
+ isTopSubRow?: boolean;
25
+ isBottomSubRow?: boolean;
26
+ }
27
+ export type Row = DataRow | DummyRow;
28
+ export declare const addPlusSign: (num: string) => string;
29
+ export declare const getRowColor: (colorByColors: colorByColors, mappingFileColumn: Vector | null, row: number, functionFileNameColumn: Vector | null, colorBy: string) => string;
30
+ export declare const RowName: (mappingFileColumn: Vector | null, locationAddressColumn: Vector | null, functionNameColumn: Vector | null, row: number) => string;
31
+ export declare const getRowsCount: (rows: Array<RowType<Row>>) => number;
32
+ export declare function getScrollTargetIndex(rows: Array<RowType<Row>>, parentRow: RowType<Row>, newRow: RowType<Row>): number;
33
+ export declare function isSubRow(row: Row): boolean;
34
+ export declare function isLastSubRow(row: RowType<Row>, rows: Array<RowType<Row>>): boolean;
35
+ export declare function isFirstSubRow(row: RowType<Row>, rows: Array<RowType<Row>>): boolean;
36
+ export type ColumnName = 'flat' | 'flatPercentage' | 'flatDiff' | 'flatDiffPercentage' | 'cumulative' | 'cumulativePercentage' | 'cumulativeDiff' | 'cumulativeDiffPercentage' | 'name' | 'functionSystemName' | 'functionFileName' | 'mappingFile';
37
+ export declare const rowBgClassNames: (isExpanded: boolean, isSubRow: boolean) => Record<string, boolean>;
38
+ export declare const ROW_HEIGHT = 29;
39
+ export declare const sizeToHeightStyle: (size: number) => Record<string, string>;
40
+ export declare const sizeToWidthStyle: (size: number) => Record<string, string>;
41
+ export declare const sizeToBottomStyle: (size: number) => Record<string, string>;
42
+ export declare const getCallerRows: (callers: DataRow[]) => Row[];
43
+ export declare const getCalleeRows: (callees: DataRow[]) => Row[];
44
+ export declare const getPercentageString: (value: bigint | number, total: bigint | number) => string;
45
+ export declare const getRatioString: (value: bigint | number, total: bigint, filtered: bigint) => string;
46
+ export declare const possibleColumns: string[];
47
+ export declare const percentageString: (value: bigint | number, total: bigint | number) => string;
48
+ export declare const ratioString: (value: bigint | number, total: bigint, filtered: bigint) => string;
49
+ //# sourceMappingURL=functions.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"functions.d.ts","sourceRoot":"","sources":["../../../src/Table/utils/functions.ts"],"names":[],"mappings":"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"}