@grafana/scenes 6.40.0--canary.1280.18680778214.0 → 6.40.0--canary.1265.18710211578.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/esm/behaviors/SceneInteractionTracker.js.map +1 -1
- package/dist/esm/behaviors/SceneQueryController.js.map +1 -1
- package/dist/esm/components/SceneRefreshPicker.js +1 -1
- package/dist/esm/components/SceneRefreshPicker.js.map +1 -1
- package/dist/esm/components/SceneTimeRangeCompare.js +0 -2
- package/dist/esm/components/SceneTimeRangeCompare.js.map +1 -1
- package/dist/esm/components/VizPanel/VizPanel.js +26 -0
- package/dist/esm/components/VizPanel/VizPanel.js.map +1 -1
- package/dist/esm/components/VizPanel/VizPanelRenderer.js +18 -1
- package/dist/esm/components/VizPanel/VizPanelRenderer.js.map +1 -1
- package/dist/esm/core/SceneTimeRange.js +1 -1
- package/dist/esm/core/SceneTimeRange.js.map +1 -1
- package/dist/esm/index.js +5 -3
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/{behaviors → performance}/LongFrameDetector.js +11 -11
- package/dist/esm/performance/LongFrameDetector.js.map +1 -0
- package/dist/esm/performance/PanelProfilingManager.js +65 -0
- package/dist/esm/performance/PanelProfilingManager.js.map +1 -0
- package/dist/esm/performance/ScenePerformanceTracker.js +78 -0
- package/dist/esm/performance/ScenePerformanceTracker.js.map +1 -0
- package/dist/esm/{behaviors → performance}/SceneRenderProfiler.js +87 -132
- package/dist/esm/performance/SceneRenderProfiler.js.map +1 -0
- package/dist/esm/performance/VizPanelRenderProfiler.js +316 -0
- package/dist/esm/performance/VizPanelRenderProfiler.js.map +1 -0
- package/dist/esm/performance/index.js +3 -0
- package/dist/esm/performance/index.js.map +1 -0
- package/dist/esm/performance/interactionConstants.js +13 -0
- package/dist/esm/performance/interactionConstants.js.map +1 -0
- package/dist/esm/querying/SceneDataTransformer.js +57 -0
- package/dist/esm/querying/SceneDataTransformer.js.map +1 -1
- package/dist/esm/querying/SceneQueryRunner.js +11 -6
- package/dist/esm/querying/SceneQueryRunner.js.map +1 -1
- package/dist/esm/querying/registerQueryWithController.js +39 -2
- package/dist/esm/querying/registerQueryWithController.js.map +1 -1
- package/dist/esm/services/UniqueUrlKeyMapper.js +0 -1
- package/dist/esm/services/UniqueUrlKeyMapper.js.map +1 -1
- package/dist/esm/services/UrlSyncManager.js +0 -1
- package/dist/esm/services/UrlSyncManager.js.map +1 -1
- package/dist/esm/utils/findPanelProfiler.js +18 -0
- package/dist/esm/utils/findPanelProfiler.js.map +1 -0
- package/dist/esm/utils/writePerformanceLog.js +12 -0
- package/dist/esm/utils/writePerformanceLog.js.map +1 -0
- package/dist/esm/utils/writeSceneLog.js +1 -10
- package/dist/esm/utils/writeSceneLog.js.map +1 -1
- package/dist/esm/variables/adhoc/AdHocFiltersCombobox/AdHocFiltersCombobox.js +1 -1
- package/dist/esm/variables/adhoc/AdHocFiltersCombobox/AdHocFiltersCombobox.js.map +1 -1
- package/dist/esm/variables/adhoc/AdHocFiltersVariable.js +1 -1
- package/dist/esm/variables/adhoc/AdHocFiltersVariable.js.map +1 -1
- package/dist/esm/variables/components/VariableValueSelect.js +1 -1
- package/dist/esm/variables/components/VariableValueSelect.js.map +1 -1
- package/dist/esm/variables/groupby/GroupByVariable.js +1 -1
- package/dist/esm/variables/groupby/GroupByVariable.js.map +1 -1
- package/dist/esm/variables/variants/MultiValueVariable.js +1 -1
- package/dist/esm/variables/variants/MultiValueVariable.js.map +1 -1
- package/dist/esm/variables/variants/ScopesVariable.js +1 -1
- package/dist/esm/variables/variants/ScopesVariable.js.map +1 -1
- package/dist/index.d.ts +324 -95
- package/dist/index.js +6691 -6130
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
- package/dist/esm/behaviors/LongFrameDetector.js.map +0 -1
- package/dist/esm/behaviors/SceneRenderProfiler.js.map +0 -1
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { writePerformanceLog } from '../utils/writePerformanceLog.js';
|
|
2
|
+
import { generateOperationId, getScenePerformanceTracker } from './ScenePerformanceTracker.js';
|
|
3
|
+
import { PanelProfilingManager } from './PanelProfilingManager.js';
|
|
2
4
|
import { LongFrameDetector } from './LongFrameDetector.js';
|
|
3
5
|
|
|
4
6
|
var __typeError = (msg) => {
|
|
@@ -16,17 +18,20 @@ var __privateWrapper = (obj, member, setter, getter) => ({
|
|
|
16
18
|
return __privateGet(obj, member, getter);
|
|
17
19
|
}
|
|
18
20
|
});
|
|
19
|
-
var _profileInProgress, _interactionInProgress, _profileStartTs, _trailAnimationFrameId, _recordedTrailingSpans, _longFrameDetector, _longFramesCount, _longFramesTotalTime, _visibilityChangeHandler, _onInteractionComplete;
|
|
21
|
+
var _profileInProgress, _interactionInProgress, _profileStartTs, _trailAnimationFrameId, _currentOperationId, _recordedTrailingSpans, _longFrameDetector, _longFramesCount, _longFramesTotalTime, _visibilityChangeHandler, _onInteractionComplete;
|
|
20
22
|
const POST_STORM_WINDOW = 2e3;
|
|
21
23
|
const DEFAULT_LONG_FRAME_THRESHOLD = 30;
|
|
22
24
|
class SceneRenderProfiler {
|
|
23
|
-
constructor(
|
|
24
|
-
this.queryController = queryController;
|
|
25
|
+
constructor(panelProfilingConfig) {
|
|
25
26
|
__privateAdd(this, _profileInProgress, null);
|
|
26
27
|
__privateAdd(this, _interactionInProgress, null);
|
|
27
28
|
__privateAdd(this, _profileStartTs, null);
|
|
28
29
|
__privateAdd(this, _trailAnimationFrameId, null);
|
|
29
|
-
//
|
|
30
|
+
// Generic metadata for observer notifications
|
|
31
|
+
this.metadata = {};
|
|
32
|
+
// Operation ID for correlating dashboard interaction events
|
|
33
|
+
__privateAdd(this, _currentOperationId);
|
|
34
|
+
// Trailing frame measurements
|
|
30
35
|
__privateAdd(this, _recordedTrailingSpans, []);
|
|
31
36
|
// Long frame tracking
|
|
32
37
|
__privateAdd(this, _longFrameDetector);
|
|
@@ -35,7 +40,6 @@ class SceneRenderProfiler {
|
|
|
35
40
|
__privateAdd(this, _visibilityChangeHandler, null);
|
|
36
41
|
__privateAdd(this, _onInteractionComplete, null);
|
|
37
42
|
this.measureTrailingFrames = (measurementStartTs, lastFrameTime, profileStartTs) => {
|
|
38
|
-
var _a, _b, _c, _d;
|
|
39
43
|
const currentFrameTime = performance.now();
|
|
40
44
|
const frameLength = currentFrameTime - lastFrameTime;
|
|
41
45
|
__privateGet(this, _recordedTrailingSpans).push(frameLength);
|
|
@@ -48,108 +52,73 @@ class SceneRenderProfiler {
|
|
|
48
52
|
} else {
|
|
49
53
|
const slowFrames = processRecordedSpans(__privateGet(this, _recordedTrailingSpans));
|
|
50
54
|
const slowFramesTime = slowFrames.reduce((acc, val) => acc + val, 0);
|
|
51
|
-
|
|
52
|
-
"
|
|
53
|
-
|
|
55
|
+
writePerformanceLog(
|
|
56
|
+
"SRP",
|
|
57
|
+
"Profile tail recorded, slow frames duration:",
|
|
58
|
+
slowFramesTime,
|
|
59
|
+
slowFrames,
|
|
60
|
+
__privateGet(this, _profileInProgress)
|
|
54
61
|
);
|
|
55
|
-
writeSceneLog("", ` \u251C\u2500 Origin: ${((_a = __privateGet(this, _profileInProgress)) == null ? void 0 : _a.origin) || "unknown"}`);
|
|
56
|
-
writeSceneLog("", ` \u2514\u2500 Crumbs:`, ((_b = __privateGet(this, _profileInProgress)) == null ? void 0 : _b.crumbs) || []);
|
|
57
62
|
__privateSet(this, _recordedTrailingSpans, []);
|
|
58
63
|
const profileDuration = measurementStartTs - profileStartTs;
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
`Dashboard Profile: ${profileName} (${totalTime.toFixed(1)}ms)`,
|
|
67
|
-
startMarkName,
|
|
68
|
-
`Dashboard Profile End: ${profileName}`
|
|
69
|
-
);
|
|
70
|
-
} catch (e) {
|
|
71
|
-
performance.mark(`Dashboard Profile Complete: ${profileName} (${totalTime.toFixed(1)}ms)`);
|
|
72
|
-
}
|
|
73
|
-
if (slowFrames.length > 0) {
|
|
74
|
-
const slowFramesMarkName = `Slow Frames Summary: ${slowFrames.length} frames (${slowFramesTime.toFixed(
|
|
75
|
-
1
|
|
76
|
-
)}ms)`;
|
|
77
|
-
performance.mark(slowFramesMarkName);
|
|
78
|
-
slowFrames.forEach((frameTime, index) => {
|
|
79
|
-
if (frameTime > 16) {
|
|
80
|
-
try {
|
|
81
|
-
const frameStartTime = __privateGet(this, _profileStartTs) + profileDuration + (index > 0 ? slowFrames.slice(0, index).reduce((sum, t) => sum + t, 0) : 0);
|
|
82
|
-
const frameId = `slow-frame-${index}`;
|
|
83
|
-
const frameStartMark = `${frameId}-start`;
|
|
84
|
-
const frameEndMark = `${frameId}-end`;
|
|
85
|
-
performance.mark(frameStartMark, { startTime: frameStartTime });
|
|
86
|
-
performance.mark(frameEndMark, { startTime: frameStartTime + frameTime });
|
|
87
|
-
performance.measure(`Slow Frame ${index + 1}: ${frameTime.toFixed(1)}ms`, frameStartMark, frameEndMark);
|
|
88
|
-
} catch (e) {
|
|
89
|
-
performance.mark(`Slow Frame ${index + 1}: ${frameTime.toFixed(1)}ms`);
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
});
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
const completionTimestamp = performance.now();
|
|
96
|
-
writeSceneLog("SceneRenderProfiler", "Profile completed");
|
|
97
|
-
writeSceneLog("", ` \u251C\u2500 Timestamp: ${completionTimestamp.toFixed(1)}ms`);
|
|
98
|
-
writeSceneLog("", ` \u251C\u2500 Total time: ${(profileDuration + slowFramesTime).toFixed(1)}ms`);
|
|
99
|
-
writeSceneLog("", ` \u251C\u2500 Slow frames: ${slowFramesTime}ms (${slowFrames.length} frames)`);
|
|
100
|
-
writeSceneLog("", ` \u2514\u2500 Long frames: ${__privateGet(this, _longFramesTotalTime)}ms (${__privateGet(this, _longFramesCount)} frames)`);
|
|
101
|
-
__privateGet(this, _longFrameDetector).stop();
|
|
102
|
-
writeSceneLogStyled(
|
|
103
|
-
"SceneRenderProfiler",
|
|
104
|
-
`Stopped long frame detection - profile complete at ${completionTimestamp.toFixed(1)}ms`,
|
|
105
|
-
"color: #00CC00; font-weight: bold;"
|
|
64
|
+
const slowFrameSummary = slowFrames.length > 0 ? `${slowFramesTime.toFixed(1)}ms slow frames[tail recording] (${slowFrames.length}) \u26A0\uFE0F` : `${slowFramesTime.toFixed(1)}ms slow frames[tail recording] (${slowFrames.length})`;
|
|
65
|
+
const longFrameSummary = __privateGet(this, _longFramesCount) > 0 ? `${__privateGet(this, _longFramesTotalTime).toFixed(1)}ms long frames[LoAF] (${__privateGet(this, _longFramesCount)}) \u26A0\uFE0F` : `${__privateGet(this, _longFramesTotalTime).toFixed(1)}ms long frames[LoAF] (${__privateGet(this, _longFramesCount)})`;
|
|
66
|
+
writePerformanceLog(
|
|
67
|
+
"SRP",
|
|
68
|
+
`[PROFILER] Complete: ${(profileDuration + slowFramesTime).toFixed(
|
|
69
|
+
1
|
|
70
|
+
)}ms total | ${slowFrameSummary} | ${longFrameSummary}`
|
|
106
71
|
);
|
|
72
|
+
__privateGet(this, _longFrameDetector).stop();
|
|
107
73
|
__privateSet(this, _trailAnimationFrameId, null);
|
|
108
74
|
const profileEndTs = profileStartTs + profileDuration + slowFramesTime;
|
|
109
75
|
if (!__privateGet(this, _profileInProgress)) {
|
|
110
76
|
return;
|
|
111
77
|
}
|
|
112
|
-
performance.measure(`DashboardInteraction ${__privateGet(this, _profileInProgress).origin}`, {
|
|
113
|
-
start: profileStartTs,
|
|
114
|
-
end: profileEndTs
|
|
115
|
-
});
|
|
116
78
|
const networkDuration = captureNetwork(profileStartTs, profileEndTs);
|
|
117
|
-
if (
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
79
|
+
if (__privateGet(this, _profileInProgress)) {
|
|
80
|
+
const dashboardData = {
|
|
81
|
+
operationId: __privateGet(this, _currentOperationId) || generateOperationId("dashboard-fallback"),
|
|
82
|
+
interactionType: __privateGet(this, _profileInProgress).origin,
|
|
83
|
+
timestamp: profileEndTs,
|
|
121
84
|
duration: profileDuration + slowFramesTime,
|
|
122
85
|
networkDuration,
|
|
123
|
-
startTs: profileStartTs,
|
|
124
|
-
endTs: profileEndTs,
|
|
125
86
|
longFramesCount: __privateGet(this, _longFramesCount),
|
|
126
87
|
longFramesTotalTime: __privateGet(this, _longFramesTotalTime),
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
// @ts-ignore
|
|
132
|
-
totalJSHeapSize: performance.memory ? performance.memory.totalJSHeapSize : 0
|
|
133
|
-
});
|
|
88
|
+
metadata: this.metadata
|
|
89
|
+
};
|
|
90
|
+
const tracker = getScenePerformanceTracker();
|
|
91
|
+
tracker.notifyDashboardInteractionComplete(dashboardData);
|
|
134
92
|
__privateSet(this, _profileInProgress, null);
|
|
135
93
|
__privateSet(this, _trailAnimationFrameId, null);
|
|
136
94
|
}
|
|
137
|
-
if (window.__runs) {
|
|
138
|
-
window.__runs += `${Date.now()}, ${profileDuration + slowFramesTime}
|
|
139
|
-
`;
|
|
140
|
-
} else {
|
|
141
|
-
window.__runs = `${Date.now()}, ${profileDuration + slowFramesTime}
|
|
142
|
-
`;
|
|
143
|
-
}
|
|
144
95
|
}
|
|
145
96
|
};
|
|
146
97
|
__privateSet(this, _longFrameDetector, new LongFrameDetector());
|
|
147
98
|
this.setupVisibilityChangeHandler();
|
|
148
99
|
__privateSet(this, _interactionInProgress, null);
|
|
100
|
+
if (panelProfilingConfig) {
|
|
101
|
+
this._panelProfilingManager = new PanelProfilingManager(panelProfilingConfig);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
/** Set generic metadata for observer notifications */
|
|
105
|
+
setMetadata(metadata) {
|
|
106
|
+
this.metadata = { ...metadata };
|
|
149
107
|
}
|
|
150
108
|
setQueryController(queryController) {
|
|
151
109
|
this.queryController = queryController;
|
|
152
110
|
}
|
|
111
|
+
/** Attach panel profiling to a scene object */
|
|
112
|
+
attachPanelProfiling(sceneObject) {
|
|
113
|
+
var _a;
|
|
114
|
+
(_a = this._panelProfilingManager) == null ? void 0 : _a.attachToScene(sceneObject);
|
|
115
|
+
}
|
|
116
|
+
/** Attach profiler to a specific panel */
|
|
117
|
+
attachProfilerToPanel(panel) {
|
|
118
|
+
var _a;
|
|
119
|
+
writePerformanceLog("SRP", "Attaching profiler to panel", panel.state.key);
|
|
120
|
+
(_a = this._panelProfilingManager) == null ? void 0 : _a.attachProfilerToPanel(panel);
|
|
121
|
+
}
|
|
153
122
|
setInteractionCompleteHandler(handler) {
|
|
154
123
|
__privateSet(this, _onInteractionComplete, handler != null ? handler : null);
|
|
155
124
|
}
|
|
@@ -159,7 +128,7 @@ class SceneRenderProfiler {
|
|
|
159
128
|
}
|
|
160
129
|
__privateSet(this, _visibilityChangeHandler, () => {
|
|
161
130
|
if (document.hidden && __privateGet(this, _profileInProgress)) {
|
|
162
|
-
|
|
131
|
+
writePerformanceLog("SRP", "Tab became inactive, cancelling profile");
|
|
163
132
|
this.cancelProfile();
|
|
164
133
|
}
|
|
165
134
|
});
|
|
@@ -168,16 +137,18 @@ class SceneRenderProfiler {
|
|
|
168
137
|
}
|
|
169
138
|
}
|
|
170
139
|
cleanup() {
|
|
140
|
+
var _a;
|
|
171
141
|
if (__privateGet(this, _visibilityChangeHandler) && typeof document !== "undefined") {
|
|
172
142
|
document.removeEventListener("visibilitychange", __privateGet(this, _visibilityChangeHandler));
|
|
173
143
|
__privateSet(this, _visibilityChangeHandler, null);
|
|
174
144
|
}
|
|
175
145
|
__privateGet(this, _longFrameDetector).stop();
|
|
176
146
|
this.cancelProfile();
|
|
147
|
+
(_a = this._panelProfilingManager) == null ? void 0 : _a.cleanup();
|
|
177
148
|
}
|
|
178
149
|
startProfile(name) {
|
|
179
150
|
if (document.hidden) {
|
|
180
|
-
|
|
151
|
+
writePerformanceLog("SRP", "Tab is inactive, skipping profile", name);
|
|
181
152
|
return;
|
|
182
153
|
}
|
|
183
154
|
if (__privateGet(this, _profileInProgress)) {
|
|
@@ -193,14 +164,14 @@ class SceneRenderProfiler {
|
|
|
193
164
|
}
|
|
194
165
|
startInteraction(interaction) {
|
|
195
166
|
if (__privateGet(this, _interactionInProgress)) {
|
|
196
|
-
|
|
167
|
+
writePerformanceLog("SRP", "Cancelled interaction:", __privateGet(this, _interactionInProgress));
|
|
197
168
|
__privateSet(this, _interactionInProgress, null);
|
|
198
169
|
}
|
|
199
170
|
__privateSet(this, _interactionInProgress, {
|
|
200
171
|
interaction,
|
|
201
172
|
startTs: performance.now()
|
|
202
173
|
});
|
|
203
|
-
|
|
174
|
+
writePerformanceLog("SRP", "Started interaction:", interaction);
|
|
204
175
|
}
|
|
205
176
|
stopInteraction() {
|
|
206
177
|
if (!__privateGet(this, _interactionInProgress)) {
|
|
@@ -209,11 +180,10 @@ class SceneRenderProfiler {
|
|
|
209
180
|
const endTs = performance.now();
|
|
210
181
|
const interactionDuration = endTs - __privateGet(this, _interactionInProgress).startTs;
|
|
211
182
|
const networkDuration = captureNetwork(__privateGet(this, _interactionInProgress).startTs, endTs);
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
writeSceneLog("", ` \u2514\u2500 EndTs: ${endTs.toFixed(1)}ms`);
|
|
183
|
+
writePerformanceLog(
|
|
184
|
+
"SRP",
|
|
185
|
+
`[INTERACTION] Complete: ${interactionDuration.toFixed(1)}ms total | ${networkDuration.toFixed(1)}ms network`
|
|
186
|
+
);
|
|
217
187
|
if (__privateGet(this, _onInteractionComplete) && __privateGet(this, _profileInProgress)) {
|
|
218
188
|
__privateGet(this, _onInteractionComplete).call(this, {
|
|
219
189
|
origin: __privateGet(this, _interactionInProgress).interaction,
|
|
@@ -241,32 +211,24 @@ class SceneRenderProfiler {
|
|
|
241
211
|
return (_b = (_a = __privateGet(this, _interactionInProgress)) == null ? void 0 : _a.interaction) != null ? _b : null;
|
|
242
212
|
}
|
|
243
213
|
/**
|
|
244
|
-
*
|
|
245
|
-
*
|
|
246
|
-
* @param
|
|
247
|
-
* @param force - Whether this is a "forced" profile (true) or "clean" profile (false)
|
|
248
|
-
* - "forced": Started by canceling an existing profile that was recording trailing frames
|
|
249
|
-
* This happens when a new user interaction occurs before the previous one
|
|
250
|
-
* finished measuring its performance impact
|
|
251
|
-
* - "clean": Started when no profile is currently active
|
|
214
|
+
* Start new performance profile
|
|
215
|
+
* @param name - Profile trigger (e.g., 'time_range_change')
|
|
216
|
+
* @param force - True if canceling existing profile, false if starting clean
|
|
252
217
|
*/
|
|
253
218
|
_startNewProfile(name, force = false) {
|
|
254
|
-
|
|
219
|
+
const profileType = force ? "forced" : "clean";
|
|
220
|
+
writePerformanceLog("SRP", `[PROFILER] ${name} started (${profileType})`);
|
|
255
221
|
__privateSet(this, _profileInProgress, { origin: name, crumbs: [] });
|
|
256
222
|
__privateSet(this, _profileStartTs, performance.now());
|
|
257
223
|
__privateSet(this, _longFramesCount, 0);
|
|
258
224
|
__privateSet(this, _longFramesTotalTime, 0);
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
"color: #FFCC00; font-weight: bold;"
|
|
267
|
-
);
|
|
268
|
-
writeSceneLog("", ` \u251C\u2500 Origin: ${((_a = __privateGet(this, _profileInProgress)) == null ? void 0 : _a.origin) || "unknown"}`);
|
|
269
|
-
writeSceneLog("", ` \u2514\u2500 Timestamp: ${__privateGet(this, _profileStartTs).toFixed(1)}ms`);
|
|
225
|
+
__privateSet(this, _currentOperationId, generateOperationId("dashboard"));
|
|
226
|
+
getScenePerformanceTracker().notifyDashboardInteractionStart({
|
|
227
|
+
operationId: __privateGet(this, _currentOperationId),
|
|
228
|
+
interactionType: name,
|
|
229
|
+
timestamp: __privateGet(this, _profileStartTs),
|
|
230
|
+
metadata: this.metadata
|
|
231
|
+
});
|
|
270
232
|
__privateGet(this, _longFrameDetector).start((event) => {
|
|
271
233
|
if (!__privateGet(this, _profileInProgress) || !__privateGet(this, _profileStartTs)) {
|
|
272
234
|
return;
|
|
@@ -285,12 +247,9 @@ class SceneRenderProfiler {
|
|
|
285
247
|
}
|
|
286
248
|
tryCompletingProfile() {
|
|
287
249
|
var _a;
|
|
288
|
-
|
|
289
|
-
return;
|
|
290
|
-
}
|
|
291
|
-
writeSceneLog("SceneRenderProfiler", "Trying to complete profile", __privateGet(this, _profileInProgress));
|
|
250
|
+
writePerformanceLog("SRP", "Trying to complete profile", __privateGet(this, _profileInProgress));
|
|
292
251
|
if (((_a = this.queryController) == null ? void 0 : _a.runningQueriesCount()) === 0 && __privateGet(this, _profileInProgress)) {
|
|
293
|
-
|
|
252
|
+
writePerformanceLog("SRP", "All queries completed, stopping profile");
|
|
294
253
|
this.recordProfileTail(performance.now(), __privateGet(this, _profileStartTs));
|
|
295
254
|
}
|
|
296
255
|
}
|
|
@@ -301,20 +260,19 @@ class SceneRenderProfiler {
|
|
|
301
260
|
if (__privateGet(this, _trailAnimationFrameId)) {
|
|
302
261
|
cancelAnimationFrame(__privateGet(this, _trailAnimationFrameId));
|
|
303
262
|
__privateSet(this, _trailAnimationFrameId, null);
|
|
304
|
-
|
|
263
|
+
writePerformanceLog("SRP", "Cancelled recording frames, new profile started");
|
|
305
264
|
}
|
|
306
265
|
}
|
|
307
|
-
// cancel profile
|
|
308
266
|
cancelProfile() {
|
|
309
267
|
if (__privateGet(this, _profileInProgress)) {
|
|
310
|
-
|
|
268
|
+
writePerformanceLog("SRP", "Cancelling profile", __privateGet(this, _profileInProgress));
|
|
311
269
|
__privateSet(this, _profileInProgress, null);
|
|
312
270
|
if (__privateGet(this, _trailAnimationFrameId)) {
|
|
313
271
|
cancelAnimationFrame(__privateGet(this, _trailAnimationFrameId));
|
|
314
272
|
__privateSet(this, _trailAnimationFrameId, null);
|
|
315
273
|
}
|
|
316
274
|
__privateGet(this, _longFrameDetector).stop();
|
|
317
|
-
|
|
275
|
+
writePerformanceLog("SRP", "Stopped long frame detection - profile cancelled");
|
|
318
276
|
__privateSet(this, _recordedTrailingSpans, []);
|
|
319
277
|
__privateSet(this, _longFramesCount, 0);
|
|
320
278
|
__privateSet(this, _longFramesTotalTime, 0);
|
|
@@ -322,7 +280,13 @@ class SceneRenderProfiler {
|
|
|
322
280
|
}
|
|
323
281
|
addCrumb(crumb) {
|
|
324
282
|
if (__privateGet(this, _profileInProgress)) {
|
|
325
|
-
|
|
283
|
+
getScenePerformanceTracker().notifyDashboardInteractionMilestone({
|
|
284
|
+
operationId: generateOperationId("dashboard-milestone"),
|
|
285
|
+
interactionType: __privateGet(this, _profileInProgress).origin,
|
|
286
|
+
timestamp: performance.now(),
|
|
287
|
+
milestone: crumb,
|
|
288
|
+
metadata: this.metadata
|
|
289
|
+
});
|
|
326
290
|
__privateGet(this, _profileInProgress).crumbs.push(crumb);
|
|
327
291
|
}
|
|
328
292
|
}
|
|
@@ -331,6 +295,7 @@ _profileInProgress = new WeakMap();
|
|
|
331
295
|
_interactionInProgress = new WeakMap();
|
|
332
296
|
_profileStartTs = new WeakMap();
|
|
333
297
|
_trailAnimationFrameId = new WeakMap();
|
|
298
|
+
_currentOperationId = new WeakMap();
|
|
334
299
|
_recordedTrailingSpans = new WeakMap();
|
|
335
300
|
_longFrameDetector = new WeakMap();
|
|
336
301
|
_longFramesCount = new WeakMap();
|
|
@@ -379,16 +344,6 @@ function calculateNetworkTime(requests) {
|
|
|
379
344
|
totalNetworkTime += currentEnd - currentStart;
|
|
380
345
|
return totalNetworkTime;
|
|
381
346
|
}
|
|
382
|
-
const REFRESH_INTERACTION = "refresh";
|
|
383
|
-
const TIME_RANGE_CHANGE_INTERACTION = "time_range_change";
|
|
384
|
-
const FILTER_REMOVED_INTERACTION = "filter_removed";
|
|
385
|
-
const FILTER_CHANGED_INTERACTION = "filter_changed";
|
|
386
|
-
const FILTER_RESTORED_INTERACTION = "filter_restored";
|
|
387
|
-
const VARIABLE_VALUE_CHANGED_INTERACTION = "variable_value_changed";
|
|
388
|
-
const SCOPES_CHANGED_INTERACTION = "scopes_changed";
|
|
389
|
-
const ADHOC_KEYS_DROPDOWN_INTERACTION = "adhoc_keys_dropdown";
|
|
390
|
-
const ADHOC_VALUES_DROPDOWN_INTERACTION = "adhoc_values_dropdown";
|
|
391
|
-
const GROUPBY_DIMENSIONS_INTERACTION = "groupby_dimensions";
|
|
392
347
|
|
|
393
|
-
export {
|
|
348
|
+
export { SceneRenderProfiler, calculateNetworkTime, captureNetwork, processRecordedSpans };
|
|
394
349
|
//# sourceMappingURL=SceneRenderProfiler.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SceneRenderProfiler.js","sources":["../../../src/performance/SceneRenderProfiler.ts"],"sourcesContent":["import { writePerformanceLog } from '../utils/writePerformanceLog';\nimport { SceneQueryControllerLike, LongFrameEvent, SceneComponentInteractionEvent } from '../behaviors/types';\nimport {\n getScenePerformanceTracker,\n generateOperationId,\n DashboardInteractionCompleteData,\n} from './ScenePerformanceTracker';\nimport { PanelProfilingManager, PanelProfilingConfig } from './PanelProfilingManager';\nimport { SceneObject } from '../core/types';\nimport { VizPanel } from '../components/VizPanel/VizPanel';\nimport { LongFrameDetector } from './LongFrameDetector';\n\nconst POST_STORM_WINDOW = 2000; // Time after last query to observe slow frames\nconst DEFAULT_LONG_FRAME_THRESHOLD = 30; // Threshold for tail recording slow frames\n\n/**\n * SceneRenderProfiler tracks dashboard interaction performance including:\n * - Total interaction duration\n * - Network time\n * - Long frame detection (50ms threshold) during interaction using LoAF API (default) or manual tracking (fallback)\n * - Slow frame detection (30ms threshold) for tail recording after interaction\n *\n * Long frame detection during interaction:\n * - 50ms threshold aligned with LoAF API default\n * - LoAF API preferred (Chrome 123+) with manual fallback\n * - Provides script attribution when using LoAF API\n *\n * Slow frame detection for tail recording:\n * - 30ms threshold for post-interaction monitoring\n * - Manual frame timing measurement\n * - Captures rendering delays after user interaction completes\n */\n\nexport class SceneRenderProfiler {\n #profileInProgress: {\n origin: string; // Profile trigger (e.g., 'time_range_change')\n crumbs: string[];\n } | null = null;\n\n #interactionInProgress: {\n interaction: string;\n startTs: number;\n } | null = null;\n\n #profileStartTs: number | null = null;\n #trailAnimationFrameId: number | null = null;\n\n // Generic metadata for observer notifications\n private metadata: Record<string, unknown> = {};\n\n // Operation ID for correlating dashboard interaction events\n #currentOperationId?: string;\n\n // Trailing frame measurements\n #recordedTrailingSpans: number[] = [];\n\n // Long frame tracking\n #longFrameDetector: LongFrameDetector;\n #longFramesCount = 0;\n #longFramesTotalTime = 0;\n\n #visibilityChangeHandler: (() => void) | null = null;\n #onInteractionComplete: ((event: SceneComponentInteractionEvent) => void) | null = null;\n\n // Panel profiling composition\n private _panelProfilingManager?: PanelProfilingManager;\n\n // Query controller for monitoring query completion\n private queryController?: SceneQueryControllerLike;\n\n public constructor(panelProfilingConfig?: PanelProfilingConfig) {\n this.#longFrameDetector = new LongFrameDetector();\n this.setupVisibilityChangeHandler();\n this.#interactionInProgress = null;\n\n // Compose with panel profiling manager if provided\n if (panelProfilingConfig) {\n this._panelProfilingManager = new PanelProfilingManager(panelProfilingConfig);\n }\n }\n\n /** Set generic metadata for observer notifications */\n public setMetadata(metadata: Record<string, unknown>) {\n this.metadata = { ...metadata };\n }\n\n public setQueryController(queryController: SceneQueryControllerLike) {\n this.queryController = queryController;\n }\n\n /** Attach panel profiling to a scene object */\n public attachPanelProfiling(sceneObject: SceneObject) {\n this._panelProfilingManager?.attachToScene(sceneObject);\n }\n\n /** Attach profiler to a specific panel */\n public attachProfilerToPanel(panel: VizPanel): void {\n writePerformanceLog('SRP', 'Attaching profiler to panel', panel.state.key);\n this._panelProfilingManager?.attachProfilerToPanel(panel);\n }\n\n public setInteractionCompleteHandler(handler?: (event: SceneComponentInteractionEvent) => void) {\n this.#onInteractionComplete = handler ?? null;\n }\n\n private setupVisibilityChangeHandler() {\n if (this.#visibilityChangeHandler) {\n return;\n }\n\n // Cancel profiling when tab becomes inactive\n this.#visibilityChangeHandler = () => {\n if (document.hidden && this.#profileInProgress) {\n writePerformanceLog('SRP', 'Tab became inactive, cancelling profile');\n this.cancelProfile();\n }\n };\n\n if (typeof document !== 'undefined') {\n document.addEventListener('visibilitychange', this.#visibilityChangeHandler);\n }\n }\n\n public cleanup() {\n if (this.#visibilityChangeHandler && typeof document !== 'undefined') {\n document.removeEventListener('visibilitychange', this.#visibilityChangeHandler);\n this.#visibilityChangeHandler = null;\n }\n\n // Cleanup long frame tracking\n this.#longFrameDetector.stop();\n\n // Cancel any ongoing profiling\n this.cancelProfile();\n\n // Cleanup composed panel profiling manager\n this._panelProfilingManager?.cleanup();\n }\n\n public startProfile(name: string) {\n // Skip profiling if tab is inactive\n if (document.hidden) {\n writePerformanceLog('SRP', 'Tab is inactive, skipping profile', name);\n return;\n }\n\n if (this.#profileInProgress) {\n if (this.#trailAnimationFrameId) {\n this.cancelProfile();\n this._startNewProfile(name, true);\n } else {\n this.addCrumb(name);\n }\n } else {\n this._startNewProfile(name);\n }\n }\n\n public startInteraction(interaction: string) {\n // Cancel any existing interaction recording\n if (this.#interactionInProgress) {\n writePerformanceLog('SRP', 'Cancelled interaction:', this.#interactionInProgress);\n this.#interactionInProgress = null;\n }\n\n this.#interactionInProgress = {\n interaction,\n startTs: performance.now(),\n };\n\n writePerformanceLog('SRP', 'Started interaction:', interaction);\n }\n\n public stopInteraction() {\n if (!this.#interactionInProgress) {\n return;\n }\n\n const endTs = performance.now();\n const interactionDuration = endTs - this.#interactionInProgress.startTs;\n\n // Capture network requests that occurred during the interaction\n const networkDuration = captureNetwork(this.#interactionInProgress.startTs, endTs);\n\n writePerformanceLog(\n 'SRP',\n `[INTERACTION] Complete: ${interactionDuration.toFixed(1)}ms total | ${networkDuration.toFixed(1)}ms network`\n );\n\n if (this.#onInteractionComplete && this.#profileInProgress) {\n this.#onInteractionComplete({\n origin: this.#interactionInProgress.interaction,\n duration: interactionDuration,\n networkDuration,\n startTs: this.#interactionInProgress.startTs,\n endTs,\n });\n }\n\n // Create performance marks for browser dev tools\n performance.mark(`${this.#interactionInProgress.interaction}_start`, {\n startTime: this.#interactionInProgress.startTs,\n });\n performance.mark(`${this.#interactionInProgress.interaction}_end`, {\n startTime: endTs,\n });\n performance.measure(\n `Interaction_${this.#interactionInProgress.interaction}`,\n `${this.#interactionInProgress.interaction}_start`,\n `${this.#interactionInProgress.interaction}_end`\n );\n\n this.#interactionInProgress = null;\n }\n\n public getCurrentInteraction(): string | null {\n return this.#interactionInProgress?.interaction ?? null;\n }\n\n /**\n * Start new performance profile\n * @param name - Profile trigger (e.g., 'time_range_change')\n * @param force - True if canceling existing profile, false if starting clean\n */\n private _startNewProfile(name: string, force = false) {\n const profileType = force ? 'forced' : 'clean';\n writePerformanceLog('SRP', `[PROFILER] ${name} started (${profileType})`);\n this.#profileInProgress = { origin: name, crumbs: [] };\n this.#profileStartTs = performance.now();\n this.#longFramesCount = 0;\n this.#longFramesTotalTime = 0;\n\n this.#currentOperationId = generateOperationId('dashboard');\n getScenePerformanceTracker().notifyDashboardInteractionStart({\n operationId: this.#currentOperationId,\n interactionType: name,\n timestamp: this.#profileStartTs,\n metadata: this.metadata,\n });\n\n // Start long frame detection with callback\n this.#longFrameDetector.start((event: LongFrameEvent) => {\n // Only record long frames during active profiling\n if (!this.#profileInProgress || !this.#profileStartTs) {\n return;\n }\n\n // Only record frames that occur after profile started\n if (event.timestamp < this.#profileStartTs) {\n return;\n }\n\n this.#longFramesCount++;\n this.#longFramesTotalTime += event.duration;\n });\n }\n\n private recordProfileTail(measurementStartTime: number, profileStartTs: number) {\n this.#trailAnimationFrameId = requestAnimationFrame(() =>\n this.measureTrailingFrames(measurementStartTime, measurementStartTime, profileStartTs)\n );\n }\n\n private measureTrailingFrames = (measurementStartTs: number, lastFrameTime: number, profileStartTs: number) => {\n const currentFrameTime = performance.now();\n const frameLength = currentFrameTime - lastFrameTime;\n\n this.#recordedTrailingSpans.push(frameLength);\n\n if (currentFrameTime - measurementStartTs! < POST_STORM_WINDOW) {\n if (this.#profileInProgress) {\n this.#trailAnimationFrameId = requestAnimationFrame(() =>\n this.measureTrailingFrames(measurementStartTs, currentFrameTime, profileStartTs)\n );\n }\n } else {\n const slowFrames = processRecordedSpans(this.#recordedTrailingSpans);\n const slowFramesTime = slowFrames.reduce((acc, val) => acc + val, 0);\n\n writePerformanceLog(\n 'SRP',\n 'Profile tail recorded, slow frames duration:',\n slowFramesTime,\n slowFrames,\n this.#profileInProgress\n );\n\n this.#recordedTrailingSpans = [];\n\n const profileDuration = measurementStartTs - profileStartTs;\n\n const slowFrameSummary =\n slowFrames.length > 0\n ? `${slowFramesTime.toFixed(1)}ms slow frames[tail recording] (${slowFrames.length}) ⚠️`\n : `${slowFramesTime.toFixed(1)}ms slow frames[tail recording] (${slowFrames.length})`;\n\n const longFrameSummary =\n this.#longFramesCount > 0\n ? `${this.#longFramesTotalTime.toFixed(1)}ms long frames[LoAF] (${this.#longFramesCount}) ⚠️`\n : `${this.#longFramesTotalTime.toFixed(1)}ms long frames[LoAF] (${this.#longFramesCount})`;\n\n writePerformanceLog(\n 'SRP',\n `[PROFILER] Complete: ${(profileDuration + slowFramesTime).toFixed(\n 1\n )}ms total | ${slowFrameSummary} | ${longFrameSummary}`\n );\n this.#longFrameDetector.stop();\n\n this.#trailAnimationFrameId = null;\n\n const profileEndTs = profileStartTs + profileDuration + slowFramesTime;\n\n // Guard against race condition where profile might be cancelled during execution\n if (!this.#profileInProgress) {\n return;\n }\n\n const networkDuration = captureNetwork(profileStartTs, profileEndTs);\n\n if (this.#profileInProgress) {\n // Notify performance observers of dashboard interaction completion\n const dashboardData: DashboardInteractionCompleteData = {\n operationId: this.#currentOperationId || generateOperationId('dashboard-fallback'),\n interactionType: this.#profileInProgress.origin,\n timestamp: profileEndTs,\n duration: profileDuration + slowFramesTime,\n networkDuration: networkDuration,\n longFramesCount: this.#longFramesCount,\n longFramesTotalTime: this.#longFramesTotalTime,\n metadata: this.metadata,\n };\n\n const tracker = getScenePerformanceTracker();\n tracker.notifyDashboardInteractionComplete(dashboardData);\n\n this.#profileInProgress = null;\n this.#trailAnimationFrameId = null;\n }\n }\n };\n\n public tryCompletingProfile() {\n writePerformanceLog('SRP', 'Trying to complete profile', this.#profileInProgress);\n if (this.queryController?.runningQueriesCount() === 0 && this.#profileInProgress) {\n writePerformanceLog('SRP', 'All queries completed, stopping profile');\n this.recordProfileTail(performance.now(), this.#profileStartTs!);\n }\n }\n\n public isTailRecording() {\n return Boolean(this.#trailAnimationFrameId);\n }\n\n public cancelTailRecording() {\n if (this.#trailAnimationFrameId) {\n cancelAnimationFrame(this.#trailAnimationFrameId);\n this.#trailAnimationFrameId = null;\n writePerformanceLog('SRP', 'Cancelled recording frames, new profile started');\n }\n }\n\n public cancelProfile() {\n if (this.#profileInProgress) {\n writePerformanceLog('SRP', 'Cancelling profile', this.#profileInProgress);\n\n this.#profileInProgress = null;\n // Cancel any pending animation frame to prevent accessing null profileInProgress\n if (this.#trailAnimationFrameId) {\n cancelAnimationFrame(this.#trailAnimationFrameId);\n this.#trailAnimationFrameId = null;\n }\n // Stop long frame tracking\n this.#longFrameDetector.stop();\n writePerformanceLog('SRP', 'Stopped long frame detection - profile cancelled');\n // Reset recorded spans to ensure complete cleanup\n this.#recordedTrailingSpans = [];\n this.#longFramesCount = 0;\n this.#longFramesTotalTime = 0;\n }\n }\n\n public addCrumb(crumb: string) {\n if (this.#profileInProgress) {\n // Notify performance observers of milestone\n getScenePerformanceTracker().notifyDashboardInteractionMilestone({\n operationId: generateOperationId('dashboard-milestone'),\n interactionType: this.#profileInProgress.origin,\n timestamp: performance.now(),\n milestone: crumb,\n metadata: this.metadata,\n });\n this.#profileInProgress.crumbs.push(crumb);\n }\n }\n}\n\nexport function processRecordedSpans(spans: number[]) {\n // identify last span in spans that's bigger than default threshold\n for (let i = spans.length - 1; i >= 0; i--) {\n if (spans[i] > DEFAULT_LONG_FRAME_THRESHOLD) {\n return spans.slice(0, i + 1);\n }\n }\n return [spans[0]];\n}\n\nexport function captureNetwork(startTs: number, endTs: number) {\n const entries = performance.getEntriesByType('resource') as PerformanceResourceTiming[];\n performance.clearResourceTimings();\n // Only include network entries that both started AND ended within the time window\n const networkEntries = entries.filter(\n (entry) =>\n entry.startTime >= startTs &&\n entry.startTime <= endTs &&\n entry.responseEnd >= startTs &&\n entry.responseEnd <= endTs\n );\n for (const entry of networkEntries) {\n performance.measure('Network entry ' + entry.name, {\n start: entry.startTime,\n end: entry.responseEnd,\n });\n }\n\n return calculateNetworkTime(networkEntries);\n}\n\n// Will calculate total time spent on Network\nexport function calculateNetworkTime(requests: PerformanceResourceTiming[]): number {\n if (requests.length === 0) {\n return 0;\n }\n\n // Step 1: Sort the requests by startTs\n requests.sort((a, b) => a.startTime - b.startTime);\n\n // Step 2: Initialize variables\n let totalNetworkTime = 0;\n let currentStart = requests[0].startTime;\n let currentEnd = requests[0].responseEnd;\n\n // Step 3: Iterate through the sorted list and merge overlapping intervals\n for (let i = 1; i < requests.length; i++) {\n if (requests[i].startTime <= currentEnd) {\n // Overlapping intervals, merge them\n currentEnd = Math.max(currentEnd, requests[i].responseEnd);\n } else {\n // Non-overlapping interval, add the duration to total time\n totalNetworkTime += currentEnd - currentStart;\n\n // Update current interval\n currentStart = requests[i].startTime;\n currentEnd = requests[i].responseEnd;\n }\n }\n\n // Step 4: Add the last interval\n totalNetworkTime += currentEnd - currentStart;\n\n return totalNetworkTime;\n}\n"],"names":[],"mappings":"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"}
|