@grafana/scenes 6.30.3 → 6.30.4
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
CHANGED
|
@@ -1,3 +1,15 @@
|
|
|
1
|
+
# v6.30.4 (Mon Aug 25 2025)
|
|
2
|
+
|
|
3
|
+
#### 🐛 Bug Fix
|
|
4
|
+
|
|
5
|
+
- SceneRenderProfiler: Handle overlapping profiles by cancelling previous profile [#1225](https://github.com/grafana/scenes/pull/1225) ([@dprokop](https://github.com/dprokop))
|
|
6
|
+
|
|
7
|
+
#### Authors: 1
|
|
8
|
+
|
|
9
|
+
- Dominik Prokop ([@dprokop](https://github.com/dprokop))
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
1
13
|
# v6.30.3 (Mon Aug 25 2025)
|
|
2
14
|
|
|
3
15
|
#### 🐛 Bug Fix
|
|
@@ -123,13 +123,36 @@ class SceneRenderProfiler {
|
|
|
123
123
|
return;
|
|
124
124
|
}
|
|
125
125
|
if (__privateGet(this, _profileInProgress)) {
|
|
126
|
-
this
|
|
126
|
+
if (__privateGet(this, _trailAnimationFrameId)) {
|
|
127
|
+
this.cancelProfile();
|
|
128
|
+
this._startNewProfile(name, true);
|
|
129
|
+
} else {
|
|
130
|
+
this.addCrumb(name);
|
|
131
|
+
}
|
|
127
132
|
} else {
|
|
128
|
-
|
|
129
|
-
__privateSet(this, _profileStartTs, performance.now());
|
|
130
|
-
writeSceneLog("SceneRenderProfiler", "Profile started:", __privateGet(this, _profileInProgress), __privateGet(this, _profileStartTs));
|
|
133
|
+
this._startNewProfile(name);
|
|
131
134
|
}
|
|
132
135
|
}
|
|
136
|
+
/**
|
|
137
|
+
* Starts a new profile for performance measurement.
|
|
138
|
+
*
|
|
139
|
+
* @param name - The origin/trigger of the profile (e.g., 'time_range_change', 'variable_value_changed')
|
|
140
|
+
* @param force - Whether this is a "forced" profile (true) or "clean" profile (false)
|
|
141
|
+
* - "forced": Started by canceling an existing profile that was recording trailing frames
|
|
142
|
+
* This happens when a new user interaction occurs before the previous one
|
|
143
|
+
* finished measuring its performance impact
|
|
144
|
+
* - "clean": Started when no profile is currently active
|
|
145
|
+
*/
|
|
146
|
+
_startNewProfile(name, force = false) {
|
|
147
|
+
__privateSet(this, _profileInProgress, { origin: name, crumbs: [] });
|
|
148
|
+
__privateSet(this, _profileStartTs, performance.now());
|
|
149
|
+
writeSceneLog(
|
|
150
|
+
"SceneRenderProfiler",
|
|
151
|
+
`Profile started[${force ? "forced" : "clean"}]`,
|
|
152
|
+
__privateGet(this, _profileInProgress),
|
|
153
|
+
__privateGet(this, _profileStartTs)
|
|
154
|
+
);
|
|
155
|
+
}
|
|
133
156
|
recordProfileTail(measurementStartTime, profileStartTs) {
|
|
134
157
|
__privateSet(this, _trailAnimationFrameId, requestAnimationFrame(
|
|
135
158
|
() => this.measureTrailingFrames(measurementStartTime, measurementStartTime, profileStartTs)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SceneRenderProfiler.js","sources":["../../../src/behaviors/SceneRenderProfiler.ts"],"sourcesContent":["import { writeSceneLog } from '../utils/writeSceneLog';\nimport { SceneQueryControllerLike } from './types';\n\nconst POST_STORM_WINDOW = 2000; // Time after last query to observe slow frames\nconst SPAN_THRESHOLD = 30; // Frames longer than this will be considered slow\nconst TAB_INACTIVE_THRESHOLD = 1000; // Tab inactive threshold in ms\n\nexport class SceneRenderProfiler {\n #profileInProgress: {\n // Profile origin, i.e. scene refresh picker\n origin: string;\n crumbs: string[];\n } | null = null;\n\n #profileStartTs: number | null = null;\n #trailAnimationFrameId: number | null = null;\n\n // Will keep measured lengths trailing frames\n #recordedTrailingSpans: number[] = [];\n\n lastFrameTime = 0;\n #visibilityChangeHandler: (() => void) | null = null;\n\n public constructor(private queryController?: SceneQueryControllerLike) {\n this.setupVisibilityChangeHandler();\n }\n\n public setQueryController(queryController: SceneQueryControllerLike) {\n this.queryController = queryController;\n }\n\n private setupVisibilityChangeHandler() {\n // Ensure event listener is only added once\n if (this.#visibilityChangeHandler) {\n return;\n }\n\n // Handle tab switching with Page Visibility API\n this.#visibilityChangeHandler = () => {\n if (document.hidden && this.#profileInProgress) {\n writeSceneLog('SceneRenderProfiler', '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 // Remove event listener to prevent memory leaks\n if (this.#visibilityChangeHandler && typeof document !== 'undefined') {\n document.removeEventListener('visibilitychange', this.#visibilityChangeHandler);\n this.#visibilityChangeHandler = null;\n }\n\n // Cancel any ongoing profiling\n this.cancelProfile();\n }\n\n public startProfile(name: string) {\n // Only start profile if tab is active. This makes sure we don't start a profile when i.e. someone opens a dashboard in a new tab\n // and doesn't interact with it.\n if (document.hidden) {\n writeSceneLog('SceneRenderProfiler', 'Tab is inactive, skipping profile', name);\n return;\n }\n if (this.#profileInProgress) {\n this.addCrumb(name);\n } else {\n this.#profileInProgress = { origin: name, crumbs: [] };\n this.#profileStartTs = performance.now();\n writeSceneLog('SceneRenderProfiler', 'Profile started:', this.#profileInProgress, this.#profileStartTs);\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 // Fallback: Detect if tab was inactive (frame longer than reasonable threshold)\n // This serves as backup to Page Visibility API in case the event wasn't triggered\n if (frameLength > TAB_INACTIVE_THRESHOLD) {\n writeSceneLog('SceneRenderProfiler', 'Tab was inactive, cancelling profile measurement');\n this.cancelProfile();\n return;\n }\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 writeSceneLog(\n this.constructor.name,\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 writeSceneLog(\n this.constructor.name,\n 'Stoped recording, total measured time (network included):',\n profileDuration + slowFramesTime\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 performance.measure(`DashboardInteraction ${this.#profileInProgress.origin}`, {\n start: profileStartTs,\n end: profileEndTs,\n });\n\n const networkDuration = captureNetwork(profileStartTs, profileEndTs);\n\n if (this.queryController?.state.onProfileComplete && this.#profileInProgress) {\n this.queryController.state.onProfileComplete({\n origin: this.#profileInProgress.origin,\n crumbs: this.#profileInProgress.crumbs,\n duration: profileDuration + slowFramesTime,\n networkDuration,\n startTs: profileStartTs,\n endTs: profileEndTs,\n // @ts-ignore\n jsHeapSizeLimit: performance.memory ? performance.memory.jsHeapSizeLimit : 0,\n // @ts-ignore\n usedJSHeapSize: performance.memory ? performance.memory.usedJSHeapSize : 0,\n // @ts-ignore\n totalJSHeapSize: performance.memory ? performance.memory.totalJSHeapSize : 0,\n });\n\n this.#profileInProgress = null;\n this.#trailAnimationFrameId = null;\n }\n // @ts-ignore\n if (window.__runs) {\n // @ts-ignore\n window.__runs += `${Date.now()}, ${profileDuration + slowFramesTime}\\n`;\n } else {\n // @ts-ignore\n window.__runs = `${Date.now()}, ${profileDuration + slowFramesTime}\\n`;\n }\n }\n };\n\n public tryCompletingProfile() {\n writeSceneLog('SceneRenderProfiler', 'Trying to complete profile', this.#profileInProgress);\n if (this.queryController?.runningQueriesCount() === 0 && this.#profileInProgress) {\n writeSceneLog('SceneRenderProfiler', '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 writeSceneLog('SceneRenderProfiler', 'Cancelled recording frames, new profile started');\n }\n }\n\n // cancel profile\n public cancelProfile() {\n if (this.#profileInProgress) {\n writeSceneLog('SceneRenderProfiler', 'Cancelling profile', this.#profileInProgress);\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 // Reset recorded spans to ensure complete cleanup\n this.#recordedTrailingSpans = [];\n }\n }\n\n public addCrumb(crumb: string) {\n if (this.#profileInProgress) {\n writeSceneLog('SceneRenderProfiler', 'Adding crumb:', crumb);\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 SPAN_THRESHOLD\n for (let i = spans.length - 1; i >= 0; i--) {\n if (spans[i] > SPAN_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\nexport const REFRESH_INTERACTION = 'refresh';\nexport const TIME_RANGE_CHANGE_INTERACTION = 'time_range_change';\nexport const FILTER_ADDED_INTERACTION = 'filter_added';\nexport const FILTER_REMOVED_INTERACTION = 'filter_removed';\nexport const FILTER_CHANGED_INTERACTION = 'filter_changed';\nexport const FILTER_RESTORED_INTERACTION = 'filter_restored';\nexport const VARIABLE_VALUE_CHANGED_INTERACTION = 'variable_value_changed';\nexport const SCOPES_CHANGED_INTERACTION = 'scopes_changed';\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"SceneRenderProfiler.js","sources":["../../../src/behaviors/SceneRenderProfiler.ts"],"sourcesContent":["import { writeSceneLog } from '../utils/writeSceneLog';\nimport { SceneQueryControllerLike } from './types';\n\nconst POST_STORM_WINDOW = 2000; // Time after last query to observe slow frames\nconst SPAN_THRESHOLD = 30; // Frames longer than this will be considered slow\nconst TAB_INACTIVE_THRESHOLD = 1000; // Tab inactive threshold in ms\n\nexport class SceneRenderProfiler {\n #profileInProgress: {\n // Profile origin, i.e. scene refresh picker\n origin: string;\n crumbs: string[];\n } | null = null;\n\n #profileStartTs: number | null = null;\n #trailAnimationFrameId: number | null = null;\n\n // Will keep measured lengths trailing frames\n #recordedTrailingSpans: number[] = [];\n\n lastFrameTime = 0;\n #visibilityChangeHandler: (() => void) | null = null;\n\n public constructor(private queryController?: SceneQueryControllerLike) {\n this.setupVisibilityChangeHandler();\n }\n\n public setQueryController(queryController: SceneQueryControllerLike) {\n this.queryController = queryController;\n }\n\n private setupVisibilityChangeHandler() {\n // Ensure event listener is only added once\n if (this.#visibilityChangeHandler) {\n return;\n }\n\n // Handle tab switching with Page Visibility API\n this.#visibilityChangeHandler = () => {\n if (document.hidden && this.#profileInProgress) {\n writeSceneLog('SceneRenderProfiler', '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 // Remove event listener to prevent memory leaks\n if (this.#visibilityChangeHandler && typeof document !== 'undefined') {\n document.removeEventListener('visibilitychange', this.#visibilityChangeHandler);\n this.#visibilityChangeHandler = null;\n }\n\n // Cancel any ongoing profiling\n this.cancelProfile();\n }\n\n public startProfile(name: string) {\n // Only start profile if tab is active. This makes sure we don't start a profile when i.e. someone opens a dashboard in a new tab\n // and doesn't interact with it.\n if (document.hidden) {\n writeSceneLog('SceneRenderProfiler', '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 /**\n * Starts a new profile for performance measurement.\n *\n * @param name - The origin/trigger of the profile (e.g., 'time_range_change', 'variable_value_changed')\n * @param force - Whether this is a \"forced\" profile (true) or \"clean\" profile (false)\n * - \"forced\": Started by canceling an existing profile that was recording trailing frames\n * This happens when a new user interaction occurs before the previous one\n * finished measuring its performance impact\n * - \"clean\": Started when no profile is currently active\n */\n private _startNewProfile(name: string, force = false) {\n this.#profileInProgress = { origin: name, crumbs: [] };\n this.#profileStartTs = performance.now();\n writeSceneLog(\n 'SceneRenderProfiler',\n `Profile started[${force ? 'forced' : 'clean'}]`,\n this.#profileInProgress,\n this.#profileStartTs\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 // Fallback: Detect if tab was inactive (frame longer than reasonable threshold)\n // This serves as backup to Page Visibility API in case the event wasn't triggered\n if (frameLength > TAB_INACTIVE_THRESHOLD) {\n writeSceneLog('SceneRenderProfiler', 'Tab was inactive, cancelling profile measurement');\n this.cancelProfile();\n return;\n }\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 writeSceneLog(\n this.constructor.name,\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 writeSceneLog(\n this.constructor.name,\n 'Stoped recording, total measured time (network included):',\n profileDuration + slowFramesTime\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 performance.measure(`DashboardInteraction ${this.#profileInProgress.origin}`, {\n start: profileStartTs,\n end: profileEndTs,\n });\n\n const networkDuration = captureNetwork(profileStartTs, profileEndTs);\n\n if (this.queryController?.state.onProfileComplete && this.#profileInProgress) {\n this.queryController.state.onProfileComplete({\n origin: this.#profileInProgress.origin,\n crumbs: this.#profileInProgress.crumbs,\n duration: profileDuration + slowFramesTime,\n networkDuration,\n startTs: profileStartTs,\n endTs: profileEndTs,\n // @ts-ignore\n jsHeapSizeLimit: performance.memory ? performance.memory.jsHeapSizeLimit : 0,\n // @ts-ignore\n usedJSHeapSize: performance.memory ? performance.memory.usedJSHeapSize : 0,\n // @ts-ignore\n totalJSHeapSize: performance.memory ? performance.memory.totalJSHeapSize : 0,\n });\n\n this.#profileInProgress = null;\n this.#trailAnimationFrameId = null;\n }\n // @ts-ignore\n if (window.__runs) {\n // @ts-ignore\n window.__runs += `${Date.now()}, ${profileDuration + slowFramesTime}\\n`;\n } else {\n // @ts-ignore\n window.__runs = `${Date.now()}, ${profileDuration + slowFramesTime}\\n`;\n }\n }\n };\n\n public tryCompletingProfile() {\n writeSceneLog('SceneRenderProfiler', 'Trying to complete profile', this.#profileInProgress);\n if (this.queryController?.runningQueriesCount() === 0 && this.#profileInProgress) {\n writeSceneLog('SceneRenderProfiler', '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 writeSceneLog('SceneRenderProfiler', 'Cancelled recording frames, new profile started');\n }\n }\n\n // cancel profile\n public cancelProfile() {\n if (this.#profileInProgress) {\n writeSceneLog('SceneRenderProfiler', 'Cancelling profile', this.#profileInProgress);\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 // Reset recorded spans to ensure complete cleanup\n this.#recordedTrailingSpans = [];\n }\n }\n\n public addCrumb(crumb: string) {\n if (this.#profileInProgress) {\n writeSceneLog('SceneRenderProfiler', 'Adding crumb:', crumb);\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 SPAN_THRESHOLD\n for (let i = spans.length - 1; i >= 0; i--) {\n if (spans[i] > SPAN_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\nexport const REFRESH_INTERACTION = 'refresh';\nexport const TIME_RANGE_CHANGE_INTERACTION = 'time_range_change';\nexport const FILTER_ADDED_INTERACTION = 'filter_added';\nexport const FILTER_REMOVED_INTERACTION = 'filter_removed';\nexport const FILTER_CHANGED_INTERACTION = 'filter_changed';\nexport const FILTER_RESTORED_INTERACTION = 'filter_restored';\nexport const VARIABLE_VALUE_CHANGED_INTERACTION = 'variable_value_changed';\nexport const SCOPES_CHANGED_INTERACTION = 'scopes_changed';\n"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1525,6 +1525,17 @@ declare class SceneRenderProfiler {
|
|
|
1525
1525
|
private setupVisibilityChangeHandler;
|
|
1526
1526
|
cleanup(): void;
|
|
1527
1527
|
startProfile(name: string): void;
|
|
1528
|
+
/**
|
|
1529
|
+
* Starts a new profile for performance measurement.
|
|
1530
|
+
*
|
|
1531
|
+
* @param name - The origin/trigger of the profile (e.g., 'time_range_change', 'variable_value_changed')
|
|
1532
|
+
* @param force - Whether this is a "forced" profile (true) or "clean" profile (false)
|
|
1533
|
+
* - "forced": Started by canceling an existing profile that was recording trailing frames
|
|
1534
|
+
* This happens when a new user interaction occurs before the previous one
|
|
1535
|
+
* finished measuring its performance impact
|
|
1536
|
+
* - "clean": Started when no profile is currently active
|
|
1537
|
+
*/
|
|
1538
|
+
private _startNewProfile;
|
|
1528
1539
|
private recordProfileTail;
|
|
1529
1540
|
private measureTrailingFrames;
|
|
1530
1541
|
tryCompletingProfile(): void;
|
package/dist/index.js
CHANGED
|
@@ -976,13 +976,36 @@ class SceneRenderProfiler {
|
|
|
976
976
|
return;
|
|
977
977
|
}
|
|
978
978
|
if (__privateGet$2(this, _profileInProgress)) {
|
|
979
|
-
this
|
|
979
|
+
if (__privateGet$2(this, _trailAnimationFrameId)) {
|
|
980
|
+
this.cancelProfile();
|
|
981
|
+
this._startNewProfile(name, true);
|
|
982
|
+
} else {
|
|
983
|
+
this.addCrumb(name);
|
|
984
|
+
}
|
|
980
985
|
} else {
|
|
981
|
-
|
|
982
|
-
__privateSet$2(this, _profileStartTs, performance.now());
|
|
983
|
-
writeSceneLog("SceneRenderProfiler", "Profile started:", __privateGet$2(this, _profileInProgress), __privateGet$2(this, _profileStartTs));
|
|
986
|
+
this._startNewProfile(name);
|
|
984
987
|
}
|
|
985
988
|
}
|
|
989
|
+
/**
|
|
990
|
+
* Starts a new profile for performance measurement.
|
|
991
|
+
*
|
|
992
|
+
* @param name - The origin/trigger of the profile (e.g., 'time_range_change', 'variable_value_changed')
|
|
993
|
+
* @param force - Whether this is a "forced" profile (true) or "clean" profile (false)
|
|
994
|
+
* - "forced": Started by canceling an existing profile that was recording trailing frames
|
|
995
|
+
* This happens when a new user interaction occurs before the previous one
|
|
996
|
+
* finished measuring its performance impact
|
|
997
|
+
* - "clean": Started when no profile is currently active
|
|
998
|
+
*/
|
|
999
|
+
_startNewProfile(name, force = false) {
|
|
1000
|
+
__privateSet$2(this, _profileInProgress, { origin: name, crumbs: [] });
|
|
1001
|
+
__privateSet$2(this, _profileStartTs, performance.now());
|
|
1002
|
+
writeSceneLog(
|
|
1003
|
+
"SceneRenderProfiler",
|
|
1004
|
+
`Profile started[${force ? "forced" : "clean"}]`,
|
|
1005
|
+
__privateGet$2(this, _profileInProgress),
|
|
1006
|
+
__privateGet$2(this, _profileStartTs)
|
|
1007
|
+
);
|
|
1008
|
+
}
|
|
986
1009
|
recordProfileTail(measurementStartTime, profileStartTs) {
|
|
987
1010
|
__privateSet$2(this, _trailAnimationFrameId, requestAnimationFrame(
|
|
988
1011
|
() => this.measureTrailingFrames(measurementStartTime, measurementStartTime, profileStartTs)
|