@parca/profile 0.19.25 → 0.19.27

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 (36) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/dist/ProfileFlameGraph/FlameGraphArrow/FlameGraphNodes.d.ts.map +1 -1
  3. package/dist/ProfileFlameGraph/FlameGraphArrow/FlameGraphNodes.js +8 -0
  4. package/dist/ProfileFlameGraph/FlameGraphArrow/index.d.ts.map +1 -1
  5. package/dist/ProfileFlameGraph/FlameGraphArrow/index.js +33 -42
  6. package/dist/ProfileFlameGraph/FlameGraphArrow/useScrollViewport.d.ts +8 -0
  7. package/dist/ProfileFlameGraph/FlameGraphArrow/useScrollViewport.d.ts.map +1 -0
  8. package/dist/ProfileFlameGraph/FlameGraphArrow/useScrollViewport.js +70 -0
  9. package/dist/ProfileFlameGraph/FlameGraphArrow/useVisibleNodes.d.ts +24 -0
  10. package/dist/ProfileFlameGraph/FlameGraphArrow/useVisibleNodes.d.ts.map +1 -0
  11. package/dist/ProfileFlameGraph/FlameGraphArrow/useVisibleNodes.js +111 -0
  12. package/dist/ProfileFlameGraph/FlameGraphArrow/utils.d.ts +2 -1
  13. package/dist/ProfileFlameGraph/FlameGraphArrow/utils.d.ts.map +1 -1
  14. package/dist/ProfileFlameGraph/FlameGraphArrow/utils.js +11 -0
  15. package/dist/ProfileView/components/ProfileFilters/filterPresets.d.ts +1 -1
  16. package/dist/ProfileView/components/ProfileFilters/filterPresets.d.ts.map +1 -1
  17. package/dist/ProfileView/components/ProfileFilters/filterPresets.js +2 -1
  18. package/dist/ProfileView/components/ProfileFilters/useProfileFilters.d.ts +7 -4
  19. package/dist/ProfileView/components/ProfileFilters/useProfileFilters.d.ts.map +1 -1
  20. package/dist/ProfileView/components/ProfileFilters/useProfileFilters.js +39 -50
  21. package/dist/ProfileView/components/ProfileFilters/useProfileFiltersUrlState.d.ts +1 -1
  22. package/dist/ProfileView/components/ProfileFilters/useProfileFiltersUrlState.d.ts.map +1 -1
  23. package/dist/ProfileView/components/Toolbars/index.js +1 -1
  24. package/dist/ProfileView/components/ViewSelector/index.js +1 -1
  25. package/dist/styles.css +1 -1
  26. package/package.json +5 -5
  27. package/src/ProfileFlameGraph/FlameGraphArrow/FlameGraphNodes.tsx +214 -200
  28. package/src/ProfileFlameGraph/FlameGraphArrow/index.tsx +90 -90
  29. package/src/ProfileFlameGraph/FlameGraphArrow/useScrollViewport.ts +89 -0
  30. package/src/ProfileFlameGraph/FlameGraphArrow/useVisibleNodes.ts +167 -0
  31. package/src/ProfileFlameGraph/FlameGraphArrow/utils.ts +12 -1
  32. package/src/ProfileView/components/ProfileFilters/filterPresets.ts +4 -2
  33. package/src/ProfileView/components/ProfileFilters/useProfileFilters.ts +57 -76
  34. package/src/ProfileView/components/ProfileFilters/useProfileFiltersUrlState.ts +1 -1
  35. package/src/ProfileView/components/Toolbars/index.tsx +1 -1
  36. package/src/ProfileView/components/ViewSelector/index.tsx +1 -1
package/CHANGELOG.md CHANGED
@@ -3,6 +3,14 @@
3
3
  All notable changes to this project will be documented in this file.
4
4
  See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5
5
 
6
+ ## [0.19.27](https://github.com/parca-dev/parca/compare/@parca/profile@0.19.26...@parca/profile@0.19.27) (2025-07-21)
7
+
8
+ **Note:** Version bump only for package @parca/profile
9
+
10
+ ## [0.19.26](https://github.com/parca-dev/parca/compare/@parca/profile@0.19.25...@parca/profile@0.19.26) (2025-07-21)
11
+
12
+ **Note:** Version bump only for package @parca/profile
13
+
6
14
  ## [0.19.25](https://github.com/parca-dev/parca/compare/@parca/profile@0.19.24...@parca/profile@0.19.25) (2025-07-21)
7
15
 
8
16
  **Note:** Version bump only for package @parca/profile
@@ -1 +1 @@
1
- {"version":3,"file":"FlameGraphNodes.d.ts","sourceRoot":"","sources":["../../../src/ProfileFlameGraph/FlameGraphArrow/FlameGraphNodes.tsx"],"names":[],"mappings":"AAaA,OAAO,KAAgB,MAAM,OAAO,CAAC;AAErC,OAAO,EAAC,KAAK,EAAC,MAAM,cAAc,CAAC;AAKnC,OAAO,yCAAyC,CAAC;AAEjD,OAAO,EAAC,aAAa,EAAC,MAAM,qBAAqB,CAAC;AAelD,eAAO,MAAM,SAAS,KAAK,CAAC;AAE5B,MAAM,WAAW,aAAa;IAC5B,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC;IAClB,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,aAAa,CAAC;IACtB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,OAAO,CAAC;IAClB,WAAW,EAAE,OAAO,CAAC;IACrB,aAAa,EAAE,CAAC,CAAC,EAAE,KAAK,CAAC,UAAU,EAAE,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IAC1D,oBAAoB,EAAE,MAAM,CAAC;IAC7B,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,YAAY,EAAE,OAAO,CAAC;IACtB,aAAa,EAAE,aAAa,CAAC;IAC7B,sBAAsB,CAAC,EAAE,OAAO,CAAC;IACjC,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,SAAS,CAAC,EAAE,MAAM,CAAC;IAGnB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,cAAc,EAAE,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,KAAK,IAAI,CAAC;CACnD;AAED,eAAO,MAAM,eAAe;;;CAG3B,CAAC;AACF,eAAO,MAAM,oBAAoB;;;;CAIhC,CAAC;AAEF,eAAO,MAAM,SAAS,4CAgNpB,CAAC"}
1
+ {"version":3,"file":"FlameGraphNodes.d.ts","sourceRoot":"","sources":["../../../src/ProfileFlameGraph/FlameGraphArrow/FlameGraphNodes.tsx"],"names":[],"mappings":"AAaA,OAAO,KAAgB,MAAM,OAAO,CAAC;AAErC,OAAO,EAAC,KAAK,EAAC,MAAM,cAAc,CAAC;AAKnC,OAAO,yCAAyC,CAAC;AAEjD,OAAO,EAAC,aAAa,EAAC,MAAM,qBAAqB,CAAC;AAelD,eAAO,MAAM,SAAS,KAAK,CAAC;AAE5B,MAAM,WAAW,aAAa;IAC5B,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC;IAClB,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,aAAa,CAAC;IACtB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,OAAO,CAAC;IAClB,WAAW,EAAE,OAAO,CAAC;IACrB,aAAa,EAAE,CAAC,CAAC,EAAE,KAAK,CAAC,UAAU,EAAE,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IAC1D,oBAAoB,EAAE,MAAM,CAAC;IAC7B,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,YAAY,EAAE,OAAO,CAAC;IACtB,aAAa,EAAE,aAAa,CAAC;IAC7B,sBAAsB,CAAC,EAAE,OAAO,CAAC;IACjC,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,SAAS,CAAC,EAAE,MAAM,CAAC;IAGnB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,cAAc,EAAE,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,KAAK,IAAI,CAAC;CACnD;AAED,eAAO,MAAM,eAAe;;;CAG3B,CAAC;AACF,eAAO,MAAM,oBAAoB;;;;CAIhC,CAAC;AAEF,eAAO,MAAM,SAAS,4CA8NrB,CAAC"}
@@ -131,4 +131,12 @@ export const FlameNode = React.memo(function FlameNodeNoMemo({ table, row, color
131
131
  }, className: cx(shouldBeHighlighted
132
132
  ? `${colorForSimilarNodes} stroke-[3] [stroke-dasharray:6,4] [stroke-linecap:round] [stroke-linejoin:round] h-6`
133
133
  : 'stroke-white dark:stroke-gray-700') }), width > 5 && (_jsx("svg", { width: width - 5, height: height, children: _jsx(TextWithEllipsis, { text: name, x: 5, y: 15, width: width - 10 }) }))] }) }));
134
+ }, (prevProps, nextProps) => {
135
+ // Only re-render if the relevant props have changed
136
+ return (prevProps.row === nextProps.row &&
137
+ prevProps.selectedRow === nextProps.selectedRow &&
138
+ prevProps.hoveringRow === nextProps.hoveringRow &&
139
+ prevProps.totalWidth === nextProps.totalWidth &&
140
+ prevProps.height === nextProps.height &&
141
+ prevProps.effectiveDepth === nextProps.effectiveDepth);
134
142
  });
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/ProfileFlameGraph/FlameGraphArrow/index.tsx"],"names":[],"mappings":"AAaA,OAAO,KAQN,MAAM,OAAO,CAAC;AAKf,OAAO,EAAC,eAAe,EAAC,MAAM,eAAe,CAAC;AAG9C,OAAO,EAAC,WAAW,EAAC,MAAM,eAAe,CAAC;AAE1C,OAAO,EAAc,KAAK,WAAW,EAAC,MAAM,kBAAkB,CAAC;AAE/D,OAAO,EAAC,aAAa,EAAC,MAAM,qBAAqB,CAAC;AAIlD,OAAO,EAAuB,aAAa,EAAC,MAAM,mBAAmB,CAAC;AAItE,OAAO,EACL,gBAAgB,EAMjB,MAAM,SAAS,CAAC;AAEjB,eAAO,MAAM,iBAAiB,gBAAgB,CAAC;AAC/C,eAAO,MAAM,kBAAkB,iBAAiB,CAAC;AACjD,eAAO,MAAM,sBAAsB,qBAAqB,CAAC;AACzD,eAAO,MAAM,sBAAsB,qBAAqB,CAAC;AACzD,eAAO,MAAM,mBAAmB,kBAAkB,CAAC;AACnD,eAAO,MAAM,aAAa,YAAY,CAAC;AACvC,eAAO,MAAM,eAAe,cAAc,CAAC;AAC3C,eAAO,MAAM,cAAc,aAAa,CAAC;AACzC,eAAO,MAAM,sBAAsB,qBAAqB,CAAC;AACzD,eAAO,MAAM,mBAAmB,kBAAkB,CAAC;AACnD,eAAO,MAAM,0BAA0B,yBAAyB,CAAC;AACjE,eAAO,MAAM,wBAAwB,uBAAuB,CAAC;AAC7D,eAAO,MAAM,yBAAyB,uBAAuB,CAAC;AAC9D,eAAO,MAAM,cAAc,aAAa,CAAC;AACzC,eAAO,MAAM,YAAY,WAAW,CAAC;AACrC,eAAO,MAAM,gBAAgB,eAAe,CAAC;AAC7C,eAAO,MAAM,UAAU,SAAS,CAAC;AACjC,eAAO,MAAM,UAAU,SAAS,CAAC;AACjC,eAAO,MAAM,YAAY,WAAW,CAAC;AACrC,eAAO,MAAM,WAAW,UAAU,CAAC;AACnC,eAAO,MAAM,kBAAkB,iBAAiB,CAAC;AAEjD,UAAU,oBAAoB;IAC5B,KAAK,EAAE,eAAe,CAAC;IACvB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,aAAa,EAAE,aAAa,CAAC;IAC7B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,gBAAgB,EAAE,CAAC;IAC5B,UAAU,EAAE,CAAC,IAAI,EAAE,gBAAgB,EAAE,KAAK,IAAI,CAAC;IAC/C,YAAY,EAAE,OAAO,CAAC;IACtB,wBAAwB,EAAE,MAAM,EAAE,CAAC;IACnC,eAAe,EAAE,OAAO,CAAC;IACzB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,sBAAsB,CAAC,EAAE,OAAO,CAAC;IACjC,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AAED,eAAO,MAAM,gBAAgB,GAC3B,cAAc,MAAM,EAAE,EACtB,YAAY,OAAO,EACnB,qBAAqB,WAAW,KAC/B,aAQF,CAAC;AAEF,eAAO,MAAM,iBAAiB,GAC5B,eAAe,MAAM,EAAE,EACvB,YAAY,OAAO,EACnB,qBAAqB,WAAW,KAC/B,aAQF,CAAC;AAeF,eAAO,MAAM,eAAe,kDA+Q1B,CAAC;AAEH,eAAe,eAAe,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/ProfileFlameGraph/FlameGraphArrow/index.tsx"],"names":[],"mappings":"AAaA,OAAO,KAQN,MAAM,OAAO,CAAC;AAKf,OAAO,EAAC,eAAe,EAAC,MAAM,eAAe,CAAC;AAG9C,OAAO,EAAC,WAAW,EAAC,MAAM,eAAe,CAAC;AAE1C,OAAO,EAAc,KAAK,WAAW,EAAC,MAAM,kBAAkB,CAAC;AAE/D,OAAO,EAAC,aAAa,EAAC,MAAM,qBAAqB,CAAC;AAIlD,OAAO,EAAuB,aAAa,EAAC,MAAM,mBAAmB,CAAC;AAMtE,OAAO,EACL,gBAAgB,EAOjB,MAAM,SAAS,CAAC;AAEjB,eAAO,MAAM,iBAAiB,gBAAgB,CAAC;AAC/C,eAAO,MAAM,kBAAkB,iBAAiB,CAAC;AACjD,eAAO,MAAM,sBAAsB,qBAAqB,CAAC;AACzD,eAAO,MAAM,sBAAsB,qBAAqB,CAAC;AACzD,eAAO,MAAM,mBAAmB,kBAAkB,CAAC;AACnD,eAAO,MAAM,aAAa,YAAY,CAAC;AACvC,eAAO,MAAM,eAAe,cAAc,CAAC;AAC3C,eAAO,MAAM,cAAc,aAAa,CAAC;AACzC,eAAO,MAAM,sBAAsB,qBAAqB,CAAC;AACzD,eAAO,MAAM,mBAAmB,kBAAkB,CAAC;AACnD,eAAO,MAAM,0BAA0B,yBAAyB,CAAC;AACjE,eAAO,MAAM,wBAAwB,uBAAuB,CAAC;AAC7D,eAAO,MAAM,yBAAyB,uBAAuB,CAAC;AAC9D,eAAO,MAAM,cAAc,aAAa,CAAC;AACzC,eAAO,MAAM,YAAY,WAAW,CAAC;AACrC,eAAO,MAAM,gBAAgB,eAAe,CAAC;AAC7C,eAAO,MAAM,UAAU,SAAS,CAAC;AACjC,eAAO,MAAM,UAAU,SAAS,CAAC;AACjC,eAAO,MAAM,YAAY,WAAW,CAAC;AACrC,eAAO,MAAM,WAAW,UAAU,CAAC;AACnC,eAAO,MAAM,kBAAkB,iBAAiB,CAAC;AAEjD,UAAU,oBAAoB;IAC5B,KAAK,EAAE,eAAe,CAAC;IACvB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,aAAa,EAAE,aAAa,CAAC;IAC7B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,gBAAgB,EAAE,CAAC;IAC5B,UAAU,EAAE,CAAC,IAAI,EAAE,gBAAgB,EAAE,KAAK,IAAI,CAAC;IAC/C,YAAY,EAAE,OAAO,CAAC;IACtB,wBAAwB,EAAE,MAAM,EAAE,CAAC;IACnC,eAAe,EAAE,OAAO,CAAC;IACzB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,sBAAsB,CAAC,EAAE,OAAO,CAAC;IACjC,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AAED,eAAO,MAAM,gBAAgB,GAC3B,cAAc,MAAM,EAAE,EACtB,YAAY,OAAO,EACnB,qBAAqB,WAAW,KAC/B,aAQF,CAAC;AAEF,eAAO,MAAM,iBAAiB,GAC5B,eAAe,MAAM,EAAE,EACvB,YAAY,OAAO,EACnB,qBAAqB,WAAW,KAC/B,aAQF,CAAC;AAIF,eAAO,MAAM,eAAe,kDAuR1B,CAAC;AAEH,eAAe,eAAe,CAAC"}
@@ -25,7 +25,9 @@ import { FlameNode, RowHeight } from './FlameGraphNodes';
25
25
  import { MemoizedTooltip } from './MemoizedTooltip';
26
26
  import { TooltipProvider } from './TooltipContext';
27
27
  import { useFilenamesList } from './useMappingList';
28
- import { arrowToString, extractFeature, extractFilenameFeature, getCurrentPathFrameData, isCurrentPathFrameMatch, } from './utils';
28
+ import { useScrollViewport } from './useScrollViewport';
29
+ import { useVisibleNodes } from './useVisibleNodes';
30
+ import { arrowToString, extractFeature, extractFilenameFeature, getCurrentPathFrameData, getMaxDepth, isCurrentPathFrameMatch, } from './utils';
29
31
  export const FIELD_LABELS_ONLY = 'labels_only';
30
32
  export const FIELD_MAPPING_FILE = 'mapping_file';
31
33
  export const FIELD_MAPPING_BUILD_ID = 'mapping_build_id';
@@ -64,17 +66,6 @@ export const getFilenameColors = (filenamesList, isDarkMode, currentColorProfile
64
66
  return colors;
65
67
  };
66
68
  const noop = () => { };
67
- function getMaxDepth(depthColumn) {
68
- if (depthColumn === null)
69
- return 0;
70
- let max = 0;
71
- for (const val of depthColumn) {
72
- const numVal = Number(val);
73
- if (numVal > max)
74
- max = numVal;
75
- }
76
- return max;
77
- }
78
69
  export const FlameGraphArrow = memo(function FlameGraphArrow({ arrow, total, filtered, width, setCurPath, curPath, profileType, profileSource, compareAbsolute, isFlameChart = false, isRenderedAsFlamegraph = false, isInSandwichView = false, tooltipId = 'default', maxFrameCount, isExpanded = false, }) {
79
70
  const [highlightSimilarStacksPreference] = useUserPreference(USER_PREFERENCES.HIGHLIGHT_SIMILAR_STACKS.key);
80
71
  const [hoveringRow, setHoveringRow] = useState(undefined);
@@ -89,28 +80,9 @@ export const FlameGraphArrow = memo(function FlameGraphArrow({ arrow, total, fil
89
80
  return result;
90
81
  }, [arrow, perf]);
91
82
  const svg = useRef(null);
83
+ const containerRef = useRef(null);
92
84
  const renderStartTime = useRef(0);
93
85
  const [svgElement, setSvgElement] = useState(null);
94
- useEffect(() => {
95
- if (perf?.markInteraction != null) {
96
- renderStartTime.current = performance.now();
97
- }
98
- }, [table, width, curPath, perf]);
99
- useEffect(() => {
100
- if (perf?.setMeasurement != null && renderStartTime.current > 0) {
101
- const measureRenderTime = () => {
102
- const renderTime = performance.now() - renderStartTime.current;
103
- if (perf?.setMeasurement != null) {
104
- perf.setMeasurement('flamegraph.render_time', renderTime);
105
- }
106
- renderStartTime.current = 0;
107
- };
108
- requestAnimationFrame(measureRenderTime);
109
- }
110
- }, [table, width, curPath, perf]);
111
- useEffect(() => {
112
- setSvgElement(svg.current);
113
- }, [tooltipId]);
114
86
  const { excludeBinary } = useProfileFilters();
115
87
  const { compareMode } = useProfileViewContext();
116
88
  const currentColorProfile = useCurrentColorProfile();
@@ -176,7 +148,11 @@ export const FlameGraphArrow = memo(function FlameGraphArrow({ arrow, total, fil
176
148
  // Add a new frame filter to hide this binary using the new ProfileFilters system
177
149
  excludeBinary(binaryToRemove);
178
150
  };
179
- const handleRowClick = (row) => {
151
+ const handleRowClick = useCallback((row) => {
152
+ if (isFlameChart) {
153
+ // In flame charts, we don't want to expand the node, so we return early.
154
+ return;
155
+ }
180
156
  // Walk down the stack starting at row until we reach the root (row 0).
181
157
  const path = [];
182
158
  let currentRow = row;
@@ -188,16 +164,18 @@ export const FlameGraphArrow = memo(function FlameGraphArrow({ arrow, total, fil
188
164
  // Reverse the path so that the root is first.
189
165
  path.reverse();
190
166
  setCurPath(path);
191
- };
167
+ }, [table, setCurPath, isFlameChart]);
192
168
  const depthColumn = table.getChild(FIELD_DEPTH);
193
169
  const maxDepth = getMaxDepth(depthColumn);
194
170
  // Apply frame limit if maxFrameCount is provided and not expanded
195
171
  const effectiveDepth = maxFrameCount !== undefined && !isExpanded ? Math.min(maxDepth, maxFrameCount) : maxDepth;
196
172
  // Use deferred value to prevent UI blocking when expanding frames
197
173
  const deferredEffectiveDepth = useDeferredValue(effectiveDepth);
198
- const height = isInSandwichView
174
+ const totalHeight = isInSandwichView
199
175
  ? deferredEffectiveDepth * RowHeight
200
176
  : (deferredEffectiveDepth + 1) * RowHeight;
177
+ // Get the viewport of the container, this is used to determine which rows are visible.
178
+ const viewport = useScrollViewport(containerRef);
201
179
  // To find the selected row, we must walk the current path and look at which
202
180
  // children of the current frame matches the path element exactly. Until the
203
181
  // end, the row we find at the end is our selected row.
@@ -222,12 +200,25 @@ export const FlameGraphArrow = memo(function FlameGraphArrow({ arrow, total, fil
222
200
  currentRow = childRows[0];
223
201
  }
224
202
  const selectedRow = currentRow;
225
- return (_jsx(TooltipProvider, { table: table, total: total, totalUnfiltered: total + filtered, profileType: profileType, unit: arrow.unit, compareAbsolute: compareAbsolute, tooltipId: tooltipId, children: _jsxs("div", { className: "relative", children: [_jsx(ContextMenuWrapper, { ref: contextMenuRef, menuId: MENU_ID, table: table, total: total, totalUnfiltered: total + filtered, compareAbsolute: compareAbsolute, resetPath: () => setCurPath([]), hideMenu: hideAll, hideBinary: hideBinary, unit: arrow.unit, profileType: profileType, isInSandwichView: isInSandwichView }), _jsx(MemoizedTooltip, { contextElement: svgElement, dockedMetainfo: dockedMetainfo }), _jsx("svg", { className: "font-robotoMono", width: width, height: height, preserveAspectRatio: "xMinYMid", ref: svg, children: Array.from({ length: table.numRows }, (_, row) => (_jsx(FlameNode, { table: table, row: row, colors: colorByColors, colorBy: colorByValue, totalWidth: width ?? 1, height: RowHeight, darkMode: isDarkMode, compareMode: compareMode, colorForSimilarNodes: colorForSimilarNodes, selectedRow: selectedRow, onClick: () => {
226
- if (isFlameChart) {
227
- // We don't want to expand in flame charts.
228
- return;
229
- }
230
- handleRowClick(row);
231
- }, onContextMenu: displayMenu, hoveringRow: highlightSimilarStacksPreference ? hoveringRow : undefined, setHoveringRow: highlightSimilarStacksPreference ? setHoveringRow : noop, isFlameChart: isFlameChart, profileSource: profileSource, isRenderedAsFlamegraph: isRenderedAsFlamegraph, isInSandwichView: isInSandwichView, maxDepth: maxDepth, effectiveDepth: deferredEffectiveDepth, tooltipId: tooltipId }, row))) })] }) }));
203
+ const visibleNodes = useVisibleNodes({
204
+ table,
205
+ viewport,
206
+ total,
207
+ width: width ?? 1,
208
+ selectedRow,
209
+ effectiveDepth: deferredEffectiveDepth,
210
+ });
211
+ useEffect(() => {
212
+ if (perf?.markInteraction != null) {
213
+ renderStartTime.current = performance.now();
214
+ }
215
+ }, [table, width, curPath, perf]);
216
+ useEffect(() => {
217
+ setSvgElement(svg.current);
218
+ }, [tooltipId]);
219
+ return (_jsx(TooltipProvider, { table: table, total: total, totalUnfiltered: total + filtered, profileType: profileType, unit: arrow.unit, compareAbsolute: compareAbsolute, tooltipId: tooltipId, children: _jsxs("div", { className: "relative", children: [_jsx(ContextMenuWrapper, { ref: contextMenuRef, menuId: MENU_ID, table: table, total: total, totalUnfiltered: total + filtered, compareAbsolute: compareAbsolute, resetPath: () => setCurPath([]), hideMenu: hideAll, hideBinary: hideBinary, unit: arrow.unit, profileType: profileType, isInSandwichView: isInSandwichView }), _jsx(MemoizedTooltip, { contextElement: svgElement, dockedMetainfo: dockedMetainfo }), _jsx("div", { ref: containerRef, className: "overflow-auto scrollbar-thin scrollbar-thumb-gray-400 scrollbar-track-gray-100 dark:scrollbar-thumb-gray-600 dark:scrollbar-track-gray-800 will-change-transform scroll-smooth webkit-overflow-scrolling-touch contain", style: {
220
+ width: width ?? '100%',
221
+ contain: 'layout style paint',
222
+ }, children: _jsx("svg", { className: "font-robotoMono", width: width ?? 0, height: totalHeight, preserveAspectRatio: "xMinYMid", ref: svg, children: visibleNodes.map(row => (_jsx(FlameNode, { table: table, row: row, colors: colorByColors, colorBy: colorByValue, totalWidth: width ?? 1, height: RowHeight, darkMode: isDarkMode, compareMode: compareMode, colorForSimilarNodes: colorForSimilarNodes, selectedRow: selectedRow, onClick: () => handleRowClick(row), onContextMenu: displayMenu, hoveringRow: highlightSimilarStacksPreference ? hoveringRow : undefined, setHoveringRow: highlightSimilarStacksPreference ? setHoveringRow : noop, isFlameChart: isFlameChart, profileSource: profileSource, isRenderedAsFlamegraph: isRenderedAsFlamegraph, isInSandwichView: isInSandwichView, maxDepth: maxDepth, effectiveDepth: deferredEffectiveDepth, tooltipId: tooltipId }, row))) }) })] }) }));
232
223
  });
233
224
  export default FlameGraphArrow;
@@ -0,0 +1,8 @@
1
+ export interface ViewportState {
2
+ scrollTop: number;
3
+ scrollLeft: number;
4
+ containerHeight: number;
5
+ containerWidth: number;
6
+ }
7
+ export declare const useScrollViewport: (containerRef: React.RefObject<HTMLDivElement>) => ViewportState;
8
+ //# sourceMappingURL=useScrollViewport.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useScrollViewport.d.ts","sourceRoot":"","sources":["../../../src/ProfileFlameGraph/FlameGraphArrow/useScrollViewport.ts"],"names":[],"mappings":"AAeA,MAAM,WAAW,aAAa;IAC5B,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,eAAe,EAAE,MAAM,CAAC;IACxB,cAAc,EAAE,MAAM,CAAC;CACxB;AAED,eAAO,MAAM,iBAAiB,GAAI,cAAc,KAAK,CAAC,SAAS,CAAC,cAAc,CAAC,KAAG,aAkEjF,CAAC"}
@@ -0,0 +1,70 @@
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
+ import { useCallback, useEffect, useRef, useState } from 'react';
14
+ export const useScrollViewport = (containerRef) => {
15
+ const [viewport, setViewport] = useState({
16
+ scrollTop: 0,
17
+ scrollLeft: 0,
18
+ containerHeight: 0,
19
+ containerWidth: 0,
20
+ });
21
+ const throttleRef = useRef(null);
22
+ const updateViewport = useCallback(() => {
23
+ if (containerRef.current !== null) {
24
+ const container = containerRef.current;
25
+ const newViewport = {
26
+ scrollTop: container.scrollTop,
27
+ scrollLeft: container.scrollLeft,
28
+ containerHeight: container.clientHeight,
29
+ containerWidth: container.clientWidth,
30
+ };
31
+ setViewport(newViewport);
32
+ }
33
+ }, [containerRef]);
34
+ // Throttling Strategy:
35
+ // Use requestAnimationFrame to throttle scroll events to 60fps max
36
+ // This ensures smooth performance while preventing excessive re-renders
37
+ const throttledUpdateViewport = useCallback(() => {
38
+ if (throttleRef.current !== null) {
39
+ cancelAnimationFrame(throttleRef.current);
40
+ }
41
+ throttleRef.current = requestAnimationFrame(updateViewport);
42
+ }, [updateViewport]);
43
+ useEffect(() => {
44
+ const container = containerRef.current;
45
+ if (container === null)
46
+ return;
47
+ // ResizeObserver Strategy:
48
+ // Monitor container size changes (window resize, layout shifts)
49
+ // to update viewport dimensions for accurate culling calculations
50
+ const resizeObserver = new ResizeObserver(() => {
51
+ throttledUpdateViewport();
52
+ });
53
+ // Container Scroll Event Strategy:
54
+ // Use passive event listeners for better scroll performance
55
+ // Throttle with requestAnimationFrame to maintain 60fps target
56
+ container.addEventListener('scroll', throttledUpdateViewport, { passive: true });
57
+ resizeObserver.observe(container);
58
+ // Initialize viewport state on mount
59
+ updateViewport();
60
+ return () => {
61
+ // Cleanup: Remove event listeners and cancel pending animations
62
+ container.removeEventListener('scroll', throttledUpdateViewport);
63
+ resizeObserver.disconnect();
64
+ if (throttleRef.current !== null) {
65
+ cancelAnimationFrame(throttleRef.current);
66
+ }
67
+ };
68
+ }, [containerRef, throttledUpdateViewport, updateViewport]);
69
+ return viewport;
70
+ };
@@ -0,0 +1,24 @@
1
+ import { Table } from 'apache-arrow';
2
+ import { ViewportState } from './useScrollViewport';
3
+ export interface UseVisibleNodesParams {
4
+ table: Table<any>;
5
+ viewport: ViewportState;
6
+ total: bigint;
7
+ width: number;
8
+ selectedRow: number;
9
+ effectiveDepth: number;
10
+ }
11
+ /**
12
+ * useVisibleNodes returns row indices visible in the current viewport through multi-stage culling.
13
+ * Combines depth buckets, horizontal bounds checking, and size filtering to
14
+ * minimize rendered nodes from potentially 100K+ rows to ~hundreds.
15
+ *
16
+ * We use depth buckets to only iterate through the rows that are visible in the viewport vertically.
17
+ * After that we use horizontal bounds checking to only iterate through the rows that are visible in the viewport horizontally.
18
+ * Finally we use size filtering to only iterate through the rows that are visible in the viewport by size.
19
+ *
20
+ * Critical for maintaining 60fps performance on large flamegraphs where
21
+ * rendering all nodes would freeze the browser.
22
+ */
23
+ export declare const useVisibleNodes: ({ table, viewport, total, width, selectedRow, effectiveDepth, }: UseVisibleNodesParams) => number[];
24
+ //# sourceMappingURL=useVisibleNodes.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useVisibleNodes.d.ts","sourceRoot":"","sources":["../../../src/ProfileFlameGraph/FlameGraphArrow/useVisibleNodes.ts"],"names":[],"mappings":"AAeA,OAAO,EAAC,KAAK,EAAC,MAAM,cAAc,CAAC;AAInC,OAAO,EAAC,aAAa,EAAC,MAAM,qBAAqB,CAAC;AAiClD,MAAM,WAAW,qBAAqB;IACpC,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC;IAClB,QAAQ,EAAE,aAAa,CAAC;IACxB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,cAAc,EAAE,MAAM,CAAC;CACxB;AAED;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,eAAe,GAAI,iEAO7B,qBAAqB,KAAG,MAAM,EAsFhC,CAAC"}
@@ -0,0 +1,111 @@
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
+ import { useMemo, useRef } from 'react';
14
+ import { RowHeight } from './FlameGraphNodes';
15
+ import { FIELD_CUMULATIVE, FIELD_DEPTH, FIELD_VALUE_OFFSET } from './index';
16
+ import { getMaxDepth } from './utils';
17
+ /**
18
+ * This function groups rows by their depth level.
19
+ * Instead of scanning all rows to find depth matches, we pre-compute
20
+ * buckets so viewport rendering only examines depth ranges that are relevant.
21
+ */
22
+ const useDepthBuckets = (table) => {
23
+ return useMemo(() => {
24
+ if (table === undefined)
25
+ return [];
26
+ const depthColumn = table.getChild(FIELD_DEPTH);
27
+ if (depthColumn === null)
28
+ return [];
29
+ // Find max depth
30
+ const maxDepth = getMaxDepth(depthColumn);
31
+ // Create buckets for each depth level
32
+ const buckets = Array.from({ length: maxDepth + 1 }, () => []);
33
+ // Populate buckets with row indices
34
+ for (let row = 0; row < table.numRows; row++) {
35
+ const depth = depthColumn.get(row) ?? 0;
36
+ buckets[depth].push(row);
37
+ }
38
+ return buckets;
39
+ }, [table]);
40
+ };
41
+ /**
42
+ * useVisibleNodes returns row indices visible in the current viewport through multi-stage culling.
43
+ * Combines depth buckets, horizontal bounds checking, and size filtering to
44
+ * minimize rendered nodes from potentially 100K+ rows to ~hundreds.
45
+ *
46
+ * We use depth buckets to only iterate through the rows that are visible in the viewport vertically.
47
+ * After that we use horizontal bounds checking to only iterate through the rows that are visible in the viewport horizontally.
48
+ * Finally we use size filtering to only iterate through the rows that are visible in the viewport by size.
49
+ *
50
+ * Critical for maintaining 60fps performance on large flamegraphs where
51
+ * rendering all nodes would freeze the browser.
52
+ */
53
+ export const useVisibleNodes = ({ table, viewport, total, width, selectedRow, effectiveDepth, }) => {
54
+ const depthBuckets = useDepthBuckets(table);
55
+ const lastResultRef = useRef({ key: '', result: [] });
56
+ return useMemo(() => {
57
+ // Create a stable key for memoization to prevent unnecessary recalculations
58
+ const memoKey = `${viewport.scrollTop}-${viewport.containerHeight}-${selectedRow}-${effectiveDepth}-${width}`;
59
+ // Return cached result if viewport hasn't meaningfully changed
60
+ if (lastResultRef.current.key === memoKey) {
61
+ return lastResultRef.current.result;
62
+ }
63
+ if (table === null || viewport.containerHeight === 0)
64
+ return [];
65
+ const visibleRows = [];
66
+ const { scrollTop, containerHeight } = viewport;
67
+ // Viewport Culling Algorithm:
68
+ // 1. Calculate visible depth range based on scroll position and container height
69
+ // 2. Add 5-row buffer above/below for smooth scrolling experience
70
+ const startDepth = Math.max(0, Math.floor(scrollTop / RowHeight) - 5);
71
+ const endDepth = Math.min(effectiveDepth, Math.ceil((scrollTop + containerHeight) / RowHeight) + 5);
72
+ const cumulativeColumn = table.getChild(FIELD_CUMULATIVE);
73
+ const valueOffsetColumn = table.getChild(FIELD_VALUE_OFFSET);
74
+ const selectionOffset = valueOffsetColumn?.get(selectedRow) !== null &&
75
+ valueOffsetColumn?.get(selectedRow) !== undefined
76
+ ? BigInt(valueOffsetColumn?.get(selectedRow))
77
+ : 0n;
78
+ const selectionCumulative = cumulativeColumn?.get(selectedRow) !== null ? BigInt(cumulativeColumn?.get(selectedRow)) : 0n;
79
+ const totalNumber = Number(total);
80
+ const selectionOffsetNumber = Number(selectionOffset);
81
+ const selectionCumulativeNumber = Number(selectionCumulative);
82
+ // Iterate only through visible depth range instead of all rows
83
+ for (let depth = startDepth; depth <= endDepth && depth < depthBuckets.length; depth++) {
84
+ // Skip if depth is beyond effective depth limit
85
+ if (effectiveDepth !== undefined && depth > effectiveDepth) {
86
+ continue;
87
+ }
88
+ const rowsAtDepth = depthBuckets[depth];
89
+ for (const row of rowsAtDepth) {
90
+ const cumulative = cumulativeColumn?.get(row) !== null ? Number(cumulativeColumn?.get(row)) : 0;
91
+ const valueOffset = valueOffsetColumn?.get(row) !== null && valueOffsetColumn?.get(row) !== undefined
92
+ ? Number(valueOffsetColumn?.get(row))
93
+ : 0;
94
+ // Horizontal culling: Skip nodes outside selection bounds
95
+ if (valueOffset + cumulative <= selectionOffsetNumber ||
96
+ valueOffset >= selectionOffsetNumber + selectionCumulativeNumber) {
97
+ continue;
98
+ }
99
+ // Size culling: Skip nodes too small to be visible (< 1px width)
100
+ const computedWidth = (cumulative / totalNumber) * width;
101
+ if (computedWidth <= 1) {
102
+ continue;
103
+ }
104
+ visibleRows.push(row);
105
+ }
106
+ }
107
+ // Cache the result with the current key
108
+ lastResultRef.current = { key: memoKey, result: visibleRows };
109
+ return visibleRows;
110
+ }, [depthBuckets, viewport, total, width, selectedRow, effectiveDepth, table]);
111
+ };
@@ -1,4 +1,4 @@
1
- import { Table } from 'apache-arrow';
1
+ import { Table, Vector } from 'apache-arrow';
2
2
  import { type BinaryFeature, type FilenameFeature } from '@parca/store';
3
3
  import { ProfileSource } from '../../ProfileSource';
4
4
  import { BigIntDuo } from '../../utils';
@@ -20,4 +20,5 @@ export interface CurrentPathFrame {
20
20
  }
21
21
  export declare const getCurrentPathFrameData: (table: Table<any>, row: number) => CurrentPathFrame;
22
22
  export declare function isCurrentPathFrameMatch(table: Table<any>, row: number, b: CurrentPathFrame): boolean;
23
+ export declare function getMaxDepth(depthColumn: Vector<any> | null): number;
23
24
  //# sourceMappingURL=utils.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../../src/ProfileFlameGraph/FlameGraphArrow/utils.ts"],"names":[],"mappings":"AAaA,OAAO,EAAC,KAAK,EAAC,MAAM,cAAc,CAAC;AAEnC,OAAO,EAIL,KAAK,aAAa,EAClB,KAAK,eAAe,EACrB,MAAM,cAAc,CAAC;AAGtB,OAAO,EAAsB,aAAa,EAAC,MAAM,qBAAqB,CAAC;AACvE,OAAO,EAAC,SAAS,EAAgB,MAAM,aAAa,CAAC;AAWrD,wBAAgB,SAAS,CAAC,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,cAAc,EAAE,OAAO,GAAG,MAAM,CAuBzF;AAED,eAAO,MAAM,cAAc,GAAI,SAAS,MAAM,KAAG,aAMhD,CAAC;AAEF,eAAO,MAAM,sBAAsB,GAAI,UAAU,MAAM,KAAG,eAMzD,CAAC;AAEF,eAAO,MAAM,oBAAoB,GAC/B,wBAAwB,MAAM,EAC9B,iBAAiB,MAAM,EACvB,OAAO,MAAM,EACb,MAAM,MAAM,KACX,MAOF,CAAC;AAEF,eAAO,MAAM,6BAA6B,GACxC,wBAAwB,MAAM,EAC9B,MAAM,MAAM,KACX,MAMF,CAAC;AAEF,eAAO,MAAM,aAAa,GAAI,QAAQ,GAAG,KAAG,MAAM,GAAG,IAQpD,CAAC;AAEF,eAAO,MAAM,uBAAuB,GAAI,gBAAgB,aAAa,KAAG,SAyBvE,CAAC;AAEF,MAAM,WAAW,gBAAgB;IAC/B,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,eAAO,MAAM,uBAAuB,GAAI,OAAO,KAAK,CAAC,GAAG,CAAC,EAAE,KAAK,MAAM,KAAG,gBAwBxE,CAAC;AAgBF,wBAAgB,uBAAuB,CACrC,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,EACjB,GAAG,EAAE,MAAM,EACX,CAAC,EAAE,gBAAgB,GAClB,OAAO,CAWT"}
1
+ {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../../src/ProfileFlameGraph/FlameGraphArrow/utils.ts"],"names":[],"mappings":"AAaA,OAAO,EAAC,KAAK,EAAE,MAAM,EAAC,MAAM,cAAc,CAAC;AAE3C,OAAO,EAIL,KAAK,aAAa,EAClB,KAAK,eAAe,EACrB,MAAM,cAAc,CAAC;AAGtB,OAAO,EAAsB,aAAa,EAAC,MAAM,qBAAqB,CAAC;AACvE,OAAO,EAAC,SAAS,EAAgB,MAAM,aAAa,CAAC;AAWrD,wBAAgB,SAAS,CAAC,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,cAAc,EAAE,OAAO,GAAG,MAAM,CAuBzF;AAED,eAAO,MAAM,cAAc,GAAI,SAAS,MAAM,KAAG,aAMhD,CAAC;AAEF,eAAO,MAAM,sBAAsB,GAAI,UAAU,MAAM,KAAG,eAMzD,CAAC;AAEF,eAAO,MAAM,oBAAoB,GAC/B,wBAAwB,MAAM,EAC9B,iBAAiB,MAAM,EACvB,OAAO,MAAM,EACb,MAAM,MAAM,KACX,MAOF,CAAC;AAEF,eAAO,MAAM,6BAA6B,GACxC,wBAAwB,MAAM,EAC9B,MAAM,MAAM,KACX,MAMF,CAAC;AAEF,eAAO,MAAM,aAAa,GAAI,QAAQ,GAAG,KAAG,MAAM,GAAG,IAQpD,CAAC;AAEF,eAAO,MAAM,uBAAuB,GAAI,gBAAgB,aAAa,KAAG,SAyBvE,CAAC;AAEF,MAAM,WAAW,gBAAgB;IAC/B,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,eAAO,MAAM,uBAAuB,GAAI,OAAO,KAAK,CAAC,GAAG,CAAC,EAAE,KAAK,MAAM,KAAG,gBAwBxE,CAAC;AAgBF,wBAAgB,uBAAuB,CACrC,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,EACjB,GAAG,EAAE,MAAM,EACX,CAAC,EAAE,gBAAgB,GAClB,OAAO,CAWT;AAED,wBAAgB,WAAW,CAAC,WAAW,EAAE,MAAM,CAAC,GAAG,CAAC,GAAG,IAAI,GAAG,MAAM,CASnE"}
@@ -131,3 +131,14 @@ export function isCurrentPathFrameMatch(table, row, b) {
131
131
  a.inlined === b.inlined &&
132
132
  a.labels === b.labels);
133
133
  }
134
+ export function getMaxDepth(depthColumn) {
135
+ if (depthColumn === null)
136
+ return 0;
137
+ let max = 0;
138
+ for (const val of depthColumn) {
139
+ const numVal = Number(val);
140
+ if (numVal > max)
141
+ max = numVal;
142
+ }
143
+ return max;
144
+ }
@@ -1,4 +1,4 @@
1
- import type { ProfileFilter } from '@parca/store';
1
+ import type { ProfileFilter } from './useProfileFilters';
2
2
  export interface FilterPreset {
3
3
  key: string;
4
4
  name: string;
@@ -1 +1 @@
1
- {"version":3,"file":"filterPresets.d.ts","sourceRoot":"","sources":["../../../../src/ProfileView/components/ProfileFilters/filterPresets.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAC,aAAa,EAAC,MAAM,cAAc,CAAC;AAEhD,MAAM,WAAW,YAAY;IAC3B,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,KAAK,CAAC,IAAI,CAAC,aAAa,EAAE,IAAI,CAAC,CAAC,CAAC;CAC3C;AAED,eAAO,MAAM,aAAa,EAAE,YAAY,EA6CvC,CAAC;AAEF,eAAO,MAAM,WAAW,GAAI,KAAK,MAAM,KAAG,OAEzC,CAAC;AAEF,eAAO,MAAM,cAAc,GAAI,KAAK,MAAM,KAAG,YAAY,GAAG,SAE3D,CAAC"}
1
+ {"version":3,"file":"filterPresets.d.ts","sourceRoot":"","sources":["../../../../src/ProfileView/components/ProfileFilters/filterPresets.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAC,aAAa,EAAC,MAAM,qBAAqB,CAAC;AAEvD,MAAM,WAAW,YAAY;IAC3B,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,KAAK,CAAC,IAAI,CAAC,aAAa,EAAE,IAAI,CAAC,CAAC,CAAC;CAC3C;AAED,eAAO,MAAM,aAAa,EAAE,YAAY,EA6CvC,CAAC;AAIF,eAAO,MAAM,WAAW,GAAI,KAAK,MAAM,KAAG,OAEzC,CAAC;AAEF,eAAO,MAAM,cAAc,GAAI,KAAK,MAAM,KAAG,YAAY,GAAG,SAE3D,CAAC"}
@@ -56,8 +56,9 @@ export const filterPresets = [
56
56
  ],
57
57
  },
58
58
  ];
59
+ const presetKeys = new Set(filterPresets.map(preset => preset.key));
59
60
  export const isPresetKey = (key) => {
60
- return filterPresets.some(preset => preset.key === key);
61
+ return presetKeys.has(key);
61
62
  };
62
63
  export const getPresetByKey = (key) => {
63
64
  return filterPresets.find(preset => preset.key === key);
@@ -1,7 +1,11 @@
1
1
  import { type Filter } from '@parca/client';
2
- import { type ProfileFilter } from '@parca/store';
3
- import { type FilterPreset } from './filterPresets';
4
- export type { ProfileFilter };
2
+ export interface ProfileFilter {
3
+ id: string;
4
+ type?: 'stack' | 'frame' | string;
5
+ field?: 'function_name' | 'binary' | 'system_name' | 'filename' | 'address' | 'line_number';
6
+ matchType?: 'equal' | 'not_equal' | 'contains' | 'not_contains';
7
+ value: string;
8
+ }
5
9
  export declare const convertToProtoFilters: (profileFilters: ProfileFilter[]) => Filter[];
6
10
  export declare const useProfileFilters: () => {
7
11
  localFilters: ProfileFilter[];
@@ -15,6 +19,5 @@ export declare const useProfileFilters: () => {
15
19
  removeFilter: (id: string) => void;
16
20
  updateFilter: (id: string, updates: Partial<ProfileFilter>) => void;
17
21
  resetFilters: () => void;
18
- applyPreset: (preset: FilterPreset) => void;
19
22
  };
20
23
  //# sourceMappingURL=useProfileFilters.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"useProfileFilters.d.ts","sourceRoot":"","sources":["../../../../src/ProfileView/components/ProfileFilters/useProfileFilters.ts"],"names":[],"mappings":"AAeA,OAAO,EAAC,KAAK,MAAM,EAAC,MAAM,eAAe,CAAC;AAC1C,OAAO,EAKL,KAAK,aAAa,EACnB,MAAM,cAAc,CAAC;AAEtB,OAAO,EAA8B,KAAK,YAAY,EAAC,MAAM,iBAAiB,CAAC;AAG/E,YAAY,EAAC,aAAa,EAAC,CAAC;AAG5B,eAAO,MAAM,qBAAqB,GAAI,gBAAgB,aAAa,EAAE,KAAG,MAAM,EAoG7E,CAAC;AAEF,eAAO,MAAM,iBAAiB,QAAO;IACnC,YAAY,EAAE,aAAa,EAAE,CAAC;IAC9B,cAAc,EAAE,aAAa,EAAE,CAAC;IAChC,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,iBAAiB,EAAE,OAAO,CAAC;IAC3B,cAAc,EAAE,MAAM,IAAI,CAAC;IAC3B,SAAS,EAAE,MAAM,IAAI,CAAC;IACtB,aAAa,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,IAAI,CAAC;IAC5C,mBAAmB,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,IAAI,CAAC;IAClD,YAAY,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;IACnC,YAAY,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,CAAC,aAAa,CAAC,KAAK,IAAI,CAAC;IACpE,YAAY,EAAE,MAAM,IAAI,CAAC;IACzB,WAAW,EAAE,CAAC,MAAM,EAAE,YAAY,KAAK,IAAI,CAAC;CAwM7C,CAAC"}
1
+ {"version":3,"file":"useProfileFilters.d.ts","sourceRoot":"","sources":["../../../../src/ProfileView/components/ProfileFilters/useProfileFilters.ts"],"names":[],"mappings":"AAeA,OAAO,EAAC,KAAK,MAAM,EAAC,MAAM,eAAe,CAAC;AAK1C,MAAM,WAAW,aAAa;IAC5B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,CAAC,EAAE,OAAO,GAAG,OAAO,GAAG,MAAM,CAAC;IAClC,KAAK,CAAC,EAAE,eAAe,GAAG,QAAQ,GAAG,aAAa,GAAG,UAAU,GAAG,SAAS,GAAG,aAAa,CAAC;IAC5F,SAAS,CAAC,EAAE,OAAO,GAAG,WAAW,GAAG,UAAU,GAAG,cAAc,CAAC;IAChE,KAAK,EAAE,MAAM,CAAC;CACf;AAGD,eAAO,MAAM,qBAAqB,GAAI,gBAAgB,aAAa,EAAE,KAAG,MAAM,EAqG7E,CAAC;AAEF,eAAO,MAAM,iBAAiB,QAAO;IACnC,YAAY,EAAE,aAAa,EAAE,CAAC;IAC9B,cAAc,EAAE,aAAa,EAAE,CAAC;IAChC,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,iBAAiB,EAAE,OAAO,CAAC;IAC3B,cAAc,EAAE,MAAM,IAAI,CAAC;IAC3B,SAAS,EAAE,MAAM,IAAI,CAAC;IACtB,aAAa,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,IAAI,CAAC;IAC5C,mBAAmB,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,IAAI,CAAC;IAClD,YAAY,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;IACnC,YAAY,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,CAAC,aAAa,CAAC,KAAK,IAAI,CAAC;IACpE,YAAY,EAAE,MAAM,IAAI,CAAC;CAsL1B,CAAC"}