@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.
- package/CHANGELOG.md +8 -0
- package/dist/ProfileFlameGraph/FlameGraphArrow/FlameGraphNodes.d.ts.map +1 -1
- package/dist/ProfileFlameGraph/FlameGraphArrow/FlameGraphNodes.js +8 -0
- package/dist/ProfileFlameGraph/FlameGraphArrow/index.d.ts.map +1 -1
- package/dist/ProfileFlameGraph/FlameGraphArrow/index.js +33 -42
- package/dist/ProfileFlameGraph/FlameGraphArrow/useScrollViewport.d.ts +8 -0
- package/dist/ProfileFlameGraph/FlameGraphArrow/useScrollViewport.d.ts.map +1 -0
- package/dist/ProfileFlameGraph/FlameGraphArrow/useScrollViewport.js +70 -0
- package/dist/ProfileFlameGraph/FlameGraphArrow/useVisibleNodes.d.ts +24 -0
- package/dist/ProfileFlameGraph/FlameGraphArrow/useVisibleNodes.d.ts.map +1 -0
- package/dist/ProfileFlameGraph/FlameGraphArrow/useVisibleNodes.js +111 -0
- package/dist/ProfileFlameGraph/FlameGraphArrow/utils.d.ts +2 -1
- package/dist/ProfileFlameGraph/FlameGraphArrow/utils.d.ts.map +1 -1
- package/dist/ProfileFlameGraph/FlameGraphArrow/utils.js +11 -0
- package/dist/ProfileView/components/ProfileFilters/filterPresets.d.ts +1 -1
- package/dist/ProfileView/components/ProfileFilters/filterPresets.d.ts.map +1 -1
- package/dist/ProfileView/components/ProfileFilters/filterPresets.js +2 -1
- package/dist/ProfileView/components/ProfileFilters/useProfileFilters.d.ts +7 -4
- package/dist/ProfileView/components/ProfileFilters/useProfileFilters.d.ts.map +1 -1
- package/dist/ProfileView/components/ProfileFilters/useProfileFilters.js +39 -50
- package/dist/ProfileView/components/ProfileFilters/useProfileFiltersUrlState.d.ts +1 -1
- package/dist/ProfileView/components/ProfileFilters/useProfileFiltersUrlState.d.ts.map +1 -1
- package/dist/ProfileView/components/Toolbars/index.js +1 -1
- package/dist/ProfileView/components/ViewSelector/index.js +1 -1
- package/dist/styles.css +1 -1
- package/package.json +5 -5
- package/src/ProfileFlameGraph/FlameGraphArrow/FlameGraphNodes.tsx +214 -200
- package/src/ProfileFlameGraph/FlameGraphArrow/index.tsx +90 -90
- package/src/ProfileFlameGraph/FlameGraphArrow/useScrollViewport.ts +89 -0
- package/src/ProfileFlameGraph/FlameGraphArrow/useVisibleNodes.ts +167 -0
- package/src/ProfileFlameGraph/FlameGraphArrow/utils.ts +12 -1
- package/src/ProfileView/components/ProfileFilters/filterPresets.ts +4 -2
- package/src/ProfileView/components/ProfileFilters/useProfileFilters.ts +57 -76
- package/src/ProfileView/components/ProfileFilters/useProfileFiltersUrlState.ts +1 -1
- package/src/ProfileView/components/Toolbars/index.tsx +1 -1
- 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,
|
|
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;
|
|
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 {
|
|
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
|
|
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
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
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;
|
|
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 +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,
|
|
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
|
|
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
|
-
|
|
3
|
-
|
|
4
|
-
|
|
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;
|
|
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"}
|