@paulirish/trace_engine 0.0.10 → 0.0.11
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/analyze-trace.mjs +1 -1
- package/core/platform/DevToolsPath.d.ts +4 -13
- package/core/platform/DevToolsPath.js +7 -4
- package/core/platform/DevToolsPath.js.map +1 -7
- package/core/platform/MimeType.d.ts +27 -0
- package/core/platform/MimeType.js +119 -86
- package/core/platform/MimeType.js.map +1 -7
- package/core/platform/Timing.d.ts +7 -0
- package/core/platform/Timing.js +7 -4
- package/core/platform/Timing.js.map +1 -7
- package/core/platform/UIString.d.ts +2 -5
- package/core/platform/UIString.js +5 -2
- package/core/platform/UIString.js.map +1 -7
- package/core/platform/UserVisibleError.js +19 -10
- package/core/platform/UserVisibleError.js.map +1 -7
- package/core/platform/array-utilities.d.ts +48 -10
- package/core/platform/array-utilities.js +160 -124
- package/core/platform/array-utilities.js.map +1 -7
- package/core/platform/brand.d.ts +14 -0
- package/core/platform/brand.js +5 -1
- package/core/platform/brand.js.map +1 -7
- package/core/platform/date-utilities.js +10 -6
- package/core/platform/date-utilities.js.map +1 -7
- package/core/platform/dom-utilities.d.ts +3 -1
- package/core/platform/dom-utilities.js +94 -83
- package/core/platform/dom-utilities.js.map +1 -7
- package/core/platform/keyboard-utilities.d.ts +2 -0
- package/core/platform/keyboard-utilities.js +15 -24
- package/core/platform/keyboard-utilities.js.map +1 -7
- package/core/platform/map-utilities.d.ts +4 -0
- package/core/platform/map-utilities.js +66 -60
- package/core/platform/map-utilities.js.map +1 -7
- package/core/platform/number-utilities.js +66 -55
- package/core/platform/number-utilities.js.map +1 -7
- package/core/platform/platform.d.ts +5 -1
- package/core/platform/platform.js +54 -37
- package/core/platform/platform.js.map +1 -7
- package/core/platform/promise-utilities.d.ts +10 -0
- package/core/platform/promise-utilities.js +16 -8
- package/core/platform/promise-utilities.js.map +1 -7
- package/core/platform/set-utilities.js +20 -17
- package/core/platform/set-utilities.js.map +1 -7
- package/core/platform/string-utilities.d.ts +32 -1
- package/core/platform/string-utilities.js +453 -379
- package/core/platform/string-utilities.js.map +1 -7
- package/core/platform/typescript-utilities.d.ts +5 -5
- package/core/platform/typescript-utilities.js +19 -7
- package/core/platform/typescript-utilities.js.map +1 -7
- package/generated/protocol.d.ts +2081 -347
- package/generated/protocol.js +5 -2230
- package/models/cpu_profile/CPUProfileDataModel.d.ts +77 -0
- package/models/cpu_profile/CPUProfileDataModel.js +492 -359
- package/models/cpu_profile/CPUProfileDataModel.js.map +1 -7
- package/models/cpu_profile/ProfileTreeModel.d.ts +29 -0
- package/models/cpu_profile/ProfileTreeModel.js +87 -82
- package/models/cpu_profile/ProfileTreeModel.js.map +1 -7
- package/models/cpu_profile/cpu_profile.d.ts +3 -0
- package/models/cpu_profile/cpu_profile.js +7 -7
- package/models/cpu_profile/cpu_profile.js.map +1 -7
- package/models/trace/EntriesFilter.d.ts +55 -0
- package/models/trace/EntriesFilter.js +227 -166
- package/models/trace/EntriesFilter.js.map +1 -7
- package/models/trace/LegacyTracingModel.js.map +1 -7
- package/models/trace/ModelImpl.d.ts +110 -0
- package/models/trace/ModelImpl.js +161 -102
- package/models/trace/ModelImpl.js.map +1 -7
- package/models/trace/Processor.d.ts +36 -0
- package/models/trace/Processor.js +197 -163
- package/models/trace/Processor.js.map +1 -7
- package/models/trace/TracingManager.js.map +1 -7
- package/models/trace/extras/FetchNodes.d.ts +46 -0
- package/models/trace/extras/FetchNodes.js +132 -91
- package/models/trace/extras/FetchNodes.js.map +1 -7
- package/models/trace/extras/FilmStrip.d.ts +19 -0
- package/models/trace/extras/FilmStrip.js +38 -31
- package/models/trace/extras/FilmStrip.js.map +1 -7
- package/models/trace/extras/MainThreadActivity.d.ts +2 -0
- package/models/trace/extras/MainThreadActivity.js +72 -56
- package/models/trace/extras/MainThreadActivity.js.map +1 -7
- package/models/trace/extras/Metadata.d.ts +2 -0
- package/models/trace/extras/Metadata.js +42 -26
- package/models/trace/extras/Metadata.js.map +1 -7
- package/models/trace/extras/extras.js.map +1 -7
- package/models/trace/handlers/AnimationHandler.d.ts +8 -0
- package/models/trace/handlers/AnimationHandler.js +22 -20
- package/models/trace/handlers/AnimationHandler.js.map +1 -7
- package/models/trace/handlers/AuctionWorkletsHandler.d.ts +8 -0
- package/models/trace/handlers/AuctionWorkletsHandler.js +143 -89
- package/models/trace/handlers/AuctionWorkletsHandler.js.map +1 -7
- package/models/trace/handlers/FramesHandler.d.ts +76 -0
- package/models/trace/handlers/FramesHandler.js +424 -355
- package/models/trace/handlers/FramesHandler.js.map +1 -7
- package/models/trace/handlers/GPUHandler.d.ts +11 -0
- package/models/trace/handlers/GPUHandler.js +41 -37
- package/models/trace/handlers/GPUHandler.js.map +1 -7
- package/models/trace/handlers/InitiatorsHandler.d.ts +10 -0
- package/models/trace/handlers/InitiatorsHandler.js +164 -113
- package/models/trace/handlers/InitiatorsHandler.js.map +1 -7
- package/models/trace/handlers/InvalidationsHandler.d.ts +10 -0
- package/models/trace/handlers/InvalidationsHandler.js +101 -79
- package/models/trace/handlers/InvalidationsHandler.js.map +1 -7
- package/models/trace/handlers/LargestImagePaintHandler.d.ts +5 -0
- package/models/trace/handlers/LargestImagePaintHandler.js +32 -12
- package/models/trace/handlers/LargestImagePaintHandler.js.map +1 -7
- package/models/trace/handlers/LargestTextPaintHandler.d.ts +5 -0
- package/models/trace/handlers/LargestTextPaintHandler.js +20 -12
- package/models/trace/handlers/LargestTextPaintHandler.js.map +1 -7
- package/models/trace/handlers/LayerTreeHandler.d.ts +13 -0
- package/models/trace/handlers/LayerTreeHandler.js +96 -70
- package/models/trace/handlers/LayerTreeHandler.js.map +1 -7
- package/models/trace/handlers/LayoutShiftsHandler.d.ts +44 -0
- package/models/trace/handlers/LayoutShiftsHandler.js +304 -227
- package/models/trace/handlers/LayoutShiftsHandler.js.map +1 -7
- package/models/trace/handlers/MemoryHandler.d.ts +7 -0
- package/models/trace/handlers/MemoryHandler.js +14 -11
- package/models/trace/handlers/MemoryHandler.js.map +1 -7
- package/models/trace/handlers/MetaHandler.d.ts +37 -0
- package/models/trace/handlers/MetaHandler.js +314 -226
- package/models/trace/handlers/MetaHandler.js.map +1 -7
- package/models/trace/handlers/ModelHandlers.d.ts +21 -0
- package/models/trace/handlers/ModelHandlers.js +25 -22
- package/models/trace/handlers/ModelHandlers.js.map +1 -7
- package/models/trace/handlers/NetworkRequestsHandler.d.ts +17 -0
- package/models/trace/handlers/NetworkRequestsHandler.js +342 -218
- package/models/trace/handlers/NetworkRequestsHandler.js.map +1 -7
- package/models/trace/handlers/PageLoadMetricsHandler.d.ts +67 -0
- package/models/trace/handlers/PageLoadMetricsHandler.js +357 -284
- package/models/trace/handlers/PageLoadMetricsHandler.js.map +1 -7
- package/models/trace/handlers/RendererHandler.d.ts +101 -0
- package/models/trace/handlers/RendererHandler.js +295 -191
- package/models/trace/handlers/RendererHandler.js.map +1 -7
- package/models/trace/handlers/SamplesHandler.d.ts +46 -0
- package/models/trace/handlers/SamplesHandler.js +195 -158
- package/models/trace/handlers/SamplesHandler.js.map +1 -7
- package/models/trace/handlers/ScreenshotsHandler.d.ts +7 -0
- package/models/trace/handlers/ScreenshotsHandler.js +63 -41
- package/models/trace/handlers/ScreenshotsHandler.js.map +1 -7
- package/models/trace/handlers/Threads.d.ts +33 -0
- package/models/trace/handlers/Threads.js +85 -67
- package/models/trace/handlers/Threads.js.map +1 -7
- package/models/trace/handlers/UserInteractionsHandler.d.ts +57 -0
- package/models/trace/handlers/UserInteractionsHandler.js +240 -141
- package/models/trace/handlers/UserInteractionsHandler.js.map +1 -7
- package/models/trace/handlers/UserTimingsHandler.d.ts +28 -0
- package/models/trace/handlers/UserTimingsHandler.js +91 -80
- package/models/trace/handlers/UserTimingsHandler.js.map +1 -7
- package/models/trace/handlers/WarningsHandler.d.ts +14 -0
- package/models/trace/handlers/WarningsHandler.js +100 -62
- package/models/trace/handlers/WarningsHandler.js.map +1 -7
- package/models/trace/handlers/WorkersHandler.d.ts +11 -0
- package/models/trace/handlers/WorkersHandler.js +40 -38
- package/models/trace/handlers/WorkersHandler.js.map +1 -7
- package/models/trace/handlers/handlers.d.ts +3 -0
- package/models/trace/handlers/handlers.js +7 -4
- package/models/trace/handlers/handlers.js.map +1 -7
- package/models/trace/handlers/types.d.ts +45 -0
- package/models/trace/handlers/types.js +15 -15
- package/models/trace/handlers/types.js.map +1 -7
- package/models/trace/helpers/SamplesIntegrator.d.ts +49 -0
- package/models/trace/helpers/SamplesIntegrator.js +381 -204
- package/models/trace/helpers/SamplesIntegrator.js.map +1 -7
- package/models/trace/helpers/Timing.d.ts +26 -0
- package/models/trace/helpers/Timing.js +131 -110
- package/models/trace/helpers/Timing.js.map +1 -7
- package/models/trace/helpers/Trace.d.ts +37 -0
- package/models/trace/helpers/Trace.js +200 -166
- package/models/trace/helpers/Trace.js.map +1 -7
- package/models/trace/helpers/TreeHelpers.d.ts +90 -0
- package/models/trace/helpers/TreeHelpers.js +203 -100
- package/models/trace/helpers/TreeHelpers.js.map +1 -7
- package/models/trace/helpers/helpers.d.ts +4 -0
- package/models/trace/helpers/helpers.js +8 -5
- package/models/trace/helpers/helpers.js.map +1 -7
- package/models/trace/root-causes/LayoutShift.d.ts +119 -0
- package/models/trace/root-causes/LayoutShift.js +470 -323
- package/models/trace/root-causes/LayoutShift.js.map +1 -7
- package/models/trace/root-causes/RootCauses.d.ts +14 -0
- package/models/trace/root-causes/RootCauses.js +9 -6
- package/models/trace/root-causes/RootCauses.js.map +1 -7
- package/models/trace/root-causes/root-causes.d.ts +1 -0
- package/models/trace/root-causes/root-causes.js +5 -2
- package/models/trace/root-causes/root-causes.js.map +1 -7
- package/models/trace/trace.d.ts +11 -0
- package/models/trace/trace.js +17 -23
- package/models/trace/trace.js.map +1 -7
- package/models/trace/types/Configuration.d.ts +33 -0
- package/models/trace/types/Configuration.js +25 -14
- package/models/trace/types/Configuration.js.map +1 -7
- package/models/trace/types/File.d.ts +23 -0
- package/models/trace/types/File.js +5 -6
- package/models/trace/types/File.js.map +1 -7
- package/models/trace/types/Timing.d.ts +25 -0
- package/models/trace/types/Timing.js +10 -11
- package/models/trace/types/Timing.js.map +1 -7
- package/models/trace/types/TraceEvents.d.ts +1571 -0
- package/models/trace/types/TraceEvents.js +174 -381
- package/models/trace/types/TraceEvents.js.map +1 -7
- package/models/trace/types/types.d.ts +4 -0
- package/models/trace/types/types.js +8 -5
- package/models/trace/types/types.js.map +1 -7
- package/package.json +1 -1
- package/TracingManager.js +0 -0
- package/extras/extras.js +0 -0
- package/trace.mjs +0 -6980
- package/trace.mjs.map +0 -8
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import type * as Protocol from '../../../generated/protocol.js';
|
|
2
|
+
import * as SDK from '../../../core/sdk/sdk.js';
|
|
3
|
+
import type * as Handlers from '../handlers/handlers.js';
|
|
4
|
+
import type * as Types from '../types/types.js';
|
|
5
|
+
export declare function _TEST_clearCache(): void;
|
|
6
|
+
/**
|
|
7
|
+
* Looks up the DOM Node on the page for the given BackendNodeId. Uses the
|
|
8
|
+
* provided TraceParseData as the cache and will cache the result after the
|
|
9
|
+
* first lookup.
|
|
10
|
+
*/
|
|
11
|
+
export declare function domNodeForBackendNodeID(modelData: Handlers.Types.TraceParseData, nodeId: Protocol.DOM.BackendNodeId): Promise<SDK.DOMModel.DOMNode | null>;
|
|
12
|
+
/**
|
|
13
|
+
* Takes a set of Protocol.DOM.BackendNodeId ids and will return a map of NodeId=>DOMNode.
|
|
14
|
+
* Results are cached based on 1) the provided TraceParseData and 2) the provided set of IDs.
|
|
15
|
+
*/
|
|
16
|
+
export declare function domNodesForMultipleBackendNodeIds(modelData: Handlers.Types.TraceParseData, nodeIds: Set<Protocol.DOM.BackendNodeId>): Promise<Map<Protocol.DOM.BackendNodeId, SDK.DOMModel.DOMNode | null>>;
|
|
17
|
+
export interface LayoutShiftSource {
|
|
18
|
+
previousRect: DOMRect;
|
|
19
|
+
currentRect: DOMRect;
|
|
20
|
+
node: SDK.DOMModel.DOMNode;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Calculates and returns a list of sources for a LayoutShift.
|
|
24
|
+
* Here, a source is considered as a node that moved and contributed to the
|
|
25
|
+
* given LayoutShift existing and the score it was given. Each source returned
|
|
26
|
+
* contains a reference to the DOM Node, and its dimensions (as a DOMRect), both
|
|
27
|
+
* before and now, so we can see how this node changed and how that impacted the
|
|
28
|
+
* layout shift.
|
|
29
|
+
*
|
|
30
|
+
* This data is cached based on the provided model data and the given layout
|
|
31
|
+
* shift, so it is is safe to call multiple times with the same input.
|
|
32
|
+
*/
|
|
33
|
+
export declare function sourcesForLayoutShift(modelData: Handlers.Types.TraceParseData, event: Types.TraceEvents.TraceEventLayoutShift): Promise<readonly LayoutShiftSource[]>;
|
|
34
|
+
/**
|
|
35
|
+
* Takes a LayoutShift and normalizes its node dimensions based on the device
|
|
36
|
+
* pixel ratio (DPR) of the user's display.
|
|
37
|
+
* This is required because the Layout Instability API is not based on CSS
|
|
38
|
+
* pixels, but physical pixels. Therefore we need to map these to normalized CSS
|
|
39
|
+
* pixels if we can. For example, if the user is on a device with a DPR of 2,
|
|
40
|
+
* the values of the node dimensions reported by the Instability API need to be
|
|
41
|
+
* divided by 2 to be accurate.
|
|
42
|
+
* This function is safe to call multiple times as results are cached based on
|
|
43
|
+
* the provided model data.
|
|
44
|
+
* See https://crbug.com/1300309 for details.
|
|
45
|
+
*/
|
|
46
|
+
export declare function normalizedImpactedNodesForLayoutShift(modelData: Handlers.Types.TraceParseData, event: Types.TraceEvents.TraceEventLayoutShift): Promise<readonly Types.TraceEvents.TraceImpactedNode[]>;
|
|
@@ -1,104 +1,145 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
// Copyright 2023 The Chromium Authors. All rights reserved.
|
|
2
|
+
// Use of this source code is governed by a BSD-style license that can be
|
|
3
|
+
// found in the LICENSE file.
|
|
4
|
+
import * as SDK from '../../../core/sdk/sdk.js';
|
|
5
|
+
const domLookUpSingleNodeCache = new Map();
|
|
6
|
+
const domLookUpBatchNodesCache = new Map();
|
|
7
|
+
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
4
8
|
export function _TEST_clearCache() {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
+
domLookUpSingleNodeCache.clear();
|
|
10
|
+
domLookUpBatchNodesCache.clear();
|
|
11
|
+
layoutShiftSourcesCache.clear();
|
|
12
|
+
normalizedLayoutShiftNodesCache.clear();
|
|
9
13
|
}
|
|
14
|
+
/**
|
|
15
|
+
* Looks up the DOM Node on the page for the given BackendNodeId. Uses the
|
|
16
|
+
* provided TraceParseData as the cache and will cache the result after the
|
|
17
|
+
* first lookup.
|
|
18
|
+
*/
|
|
10
19
|
export async function domNodeForBackendNodeID(modelData, nodeId) {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
20
|
+
const fromCache = domLookUpSingleNodeCache.get(modelData)?.get(nodeId);
|
|
21
|
+
if (fromCache !== undefined) {
|
|
22
|
+
return fromCache;
|
|
23
|
+
}
|
|
24
|
+
const target = SDK.TargetManager.TargetManager.instance().primaryPageTarget();
|
|
25
|
+
const domModel = target?.model(SDK.DOMModel.DOMModel);
|
|
26
|
+
if (!domModel) {
|
|
27
|
+
return null;
|
|
28
|
+
}
|
|
29
|
+
const domNodesMap = await domModel.pushNodesByBackendIdsToFrontend(new Set([nodeId]));
|
|
30
|
+
const result = domNodesMap?.get(nodeId) || null;
|
|
31
|
+
const cacheForModel = domLookUpSingleNodeCache.get(modelData) || new Map();
|
|
32
|
+
cacheForModel.set(nodeId, result);
|
|
33
|
+
domLookUpSingleNodeCache.set(modelData, cacheForModel);
|
|
34
|
+
return result;
|
|
26
35
|
}
|
|
36
|
+
/**
|
|
37
|
+
* Takes a set of Protocol.DOM.BackendNodeId ids and will return a map of NodeId=>DOMNode.
|
|
38
|
+
* Results are cached based on 1) the provided TraceParseData and 2) the provided set of IDs.
|
|
39
|
+
*/
|
|
27
40
|
export async function domNodesForMultipleBackendNodeIds(modelData, nodeIds) {
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
41
|
+
const fromCache = domLookUpBatchNodesCache.get(modelData)?.get(nodeIds);
|
|
42
|
+
if (fromCache) {
|
|
43
|
+
return fromCache;
|
|
44
|
+
}
|
|
45
|
+
const target = SDK.TargetManager.TargetManager.instance().primaryPageTarget();
|
|
46
|
+
const domModel = target?.model(SDK.DOMModel.DOMModel);
|
|
47
|
+
if (!domModel) {
|
|
48
|
+
return new Map();
|
|
49
|
+
}
|
|
50
|
+
const domNodesMap = await domModel.pushNodesByBackendIdsToFrontend(nodeIds) || new Map();
|
|
51
|
+
const cacheForModel = domLookUpBatchNodesCache.get(modelData) ||
|
|
52
|
+
new Map();
|
|
53
|
+
cacheForModel.set(nodeIds, domNodesMap);
|
|
54
|
+
domLookUpBatchNodesCache.set(modelData, cacheForModel);
|
|
55
|
+
return domNodesMap;
|
|
42
56
|
}
|
|
43
|
-
const layoutShiftSourcesCache =
|
|
44
|
-
const normalizedLayoutShiftNodesCache =
|
|
57
|
+
const layoutShiftSourcesCache = new Map();
|
|
58
|
+
const normalizedLayoutShiftNodesCache = new Map();
|
|
59
|
+
/**
|
|
60
|
+
* Calculates and returns a list of sources for a LayoutShift.
|
|
61
|
+
* Here, a source is considered as a node that moved and contributed to the
|
|
62
|
+
* given LayoutShift existing and the score it was given. Each source returned
|
|
63
|
+
* contains a reference to the DOM Node, and its dimensions (as a DOMRect), both
|
|
64
|
+
* before and now, so we can see how this node changed and how that impacted the
|
|
65
|
+
* layout shift.
|
|
66
|
+
*
|
|
67
|
+
* This data is cached based on the provided model data and the given layout
|
|
68
|
+
* shift, so it is is safe to call multiple times with the same input.
|
|
69
|
+
*/
|
|
45
70
|
export async function sourcesForLayoutShift(modelData, event) {
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
}
|
|
50
|
-
const impactedNodes = event.args.data?.impacted_nodes;
|
|
51
|
-
if (!impactedNodes) {
|
|
52
|
-
return [];
|
|
53
|
-
}
|
|
54
|
-
const sources = [];
|
|
55
|
-
await Promise.all(impactedNodes.map(async (node) => {
|
|
56
|
-
const domNode = await domNodeForBackendNodeID(modelData, node.node_id);
|
|
57
|
-
if (domNode) {
|
|
58
|
-
sources.push({
|
|
59
|
-
previousRect: new DOMRect(node.old_rect[0], node.old_rect[1], node.old_rect[2], node.old_rect[3]),
|
|
60
|
-
currentRect: new DOMRect(node.new_rect[0], node.new_rect[1], node.new_rect[2], node.new_rect[3]),
|
|
61
|
-
node: domNode
|
|
62
|
-
});
|
|
71
|
+
const fromCache = layoutShiftSourcesCache.get(modelData)?.get(event);
|
|
72
|
+
if (fromCache) {
|
|
73
|
+
return fromCache;
|
|
63
74
|
}
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
75
|
+
const impactedNodes = event.args.data?.impacted_nodes;
|
|
76
|
+
if (!impactedNodes) {
|
|
77
|
+
return [];
|
|
78
|
+
}
|
|
79
|
+
const sources = [];
|
|
80
|
+
await Promise.all(impactedNodes.map(async (node) => {
|
|
81
|
+
const domNode = await domNodeForBackendNodeID(modelData, node.node_id);
|
|
82
|
+
if (domNode) {
|
|
83
|
+
sources.push({
|
|
84
|
+
previousRect: new DOMRect(node.old_rect[0], node.old_rect[1], node.old_rect[2], node.old_rect[3]),
|
|
85
|
+
currentRect: new DOMRect(node.new_rect[0], node.new_rect[1], node.new_rect[2], node.new_rect[3]),
|
|
86
|
+
node: domNode,
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
}));
|
|
90
|
+
const cacheForModel = layoutShiftSourcesCache.get(modelData) || new Map();
|
|
91
|
+
cacheForModel.set(event, sources);
|
|
92
|
+
layoutShiftSourcesCache.set(modelData, cacheForModel);
|
|
93
|
+
return sources;
|
|
69
94
|
}
|
|
95
|
+
/**
|
|
96
|
+
* Takes a LayoutShift and normalizes its node dimensions based on the device
|
|
97
|
+
* pixel ratio (DPR) of the user's display.
|
|
98
|
+
* This is required because the Layout Instability API is not based on CSS
|
|
99
|
+
* pixels, but physical pixels. Therefore we need to map these to normalized CSS
|
|
100
|
+
* pixels if we can. For example, if the user is on a device with a DPR of 2,
|
|
101
|
+
* the values of the node dimensions reported by the Instability API need to be
|
|
102
|
+
* divided by 2 to be accurate.
|
|
103
|
+
* This function is safe to call multiple times as results are cached based on
|
|
104
|
+
* the provided model data.
|
|
105
|
+
* See https://crbug.com/1300309 for details.
|
|
106
|
+
*/
|
|
70
107
|
export async function normalizedImpactedNodesForLayoutShift(modelData, event) {
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
const newNode = { ...impactedNode };
|
|
91
|
-
for (let i = 0; i < impactedNode.old_rect.length; i++) {
|
|
92
|
-
newNode.old_rect[i] /= viewportScale;
|
|
108
|
+
const fromCache = normalizedLayoutShiftNodesCache.get(modelData)?.get(event);
|
|
109
|
+
if (fromCache) {
|
|
110
|
+
return fromCache;
|
|
111
|
+
}
|
|
112
|
+
const impactedNodes = event.args?.data?.impacted_nodes;
|
|
113
|
+
if (!impactedNodes) {
|
|
114
|
+
return [];
|
|
115
|
+
}
|
|
116
|
+
let viewportScale = null;
|
|
117
|
+
const target = SDK.TargetManager.TargetManager.instance().primaryPageTarget();
|
|
118
|
+
// Get the CSS-to-physical pixel ratio of the device the inspected
|
|
119
|
+
// target is running at.
|
|
120
|
+
const evaluateResult = await target?.runtimeAgent().invoke_evaluate({ expression: 'window.devicePixelRatio' });
|
|
121
|
+
if (evaluateResult?.result.type === 'number') {
|
|
122
|
+
viewportScale = evaluateResult?.result.value ?? null;
|
|
123
|
+
}
|
|
124
|
+
if (!viewportScale) {
|
|
125
|
+
// Bail and return the nodes as is.
|
|
126
|
+
return impactedNodes;
|
|
93
127
|
}
|
|
94
|
-
|
|
95
|
-
|
|
128
|
+
const normalizedNodes = [];
|
|
129
|
+
for (const impactedNode of impactedNodes) {
|
|
130
|
+
const newNode = { ...impactedNode };
|
|
131
|
+
for (let i = 0; i < impactedNode.old_rect.length; i++) {
|
|
132
|
+
newNode.old_rect[i] /= viewportScale;
|
|
133
|
+
}
|
|
134
|
+
for (let i = 0; i < impactedNode.new_rect.length; i++) {
|
|
135
|
+
newNode.new_rect[i] /= viewportScale;
|
|
136
|
+
}
|
|
137
|
+
normalizedNodes.push(newNode);
|
|
96
138
|
}
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
return normalizedNodes;
|
|
139
|
+
const cacheForModel = normalizedLayoutShiftNodesCache.get(modelData) ||
|
|
140
|
+
new Map();
|
|
141
|
+
cacheForModel.set(event, normalizedNodes);
|
|
142
|
+
normalizedLayoutShiftNodesCache.set(modelData, cacheForModel);
|
|
143
|
+
return normalizedNodes;
|
|
103
144
|
}
|
|
104
|
-
//# sourceMappingURL=FetchNodes.js.map
|
|
145
|
+
//# sourceMappingURL=FetchNodes.js.map
|
|
@@ -1,7 +1 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": 3,
|
|
3
|
-
"sources": ["../../../../../../../front_end/models/trace/extras/FetchNodes.ts"],
|
|
4
|
-
"sourcesContent": ["// Copyright 2023 The Chromium Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\nimport type * as Protocol from '../../../generated/protocol.js';\nimport * as SDK from '../../../core/sdk/sdk.js';\nimport type * as Handlers from '../handlers/handlers.js';\nimport type * as Types from '../types/types.js';\n\nconst domLookUpSingleNodeCache =\n new Map<Handlers.Types.TraceParseData, Map<Protocol.DOM.BackendNodeId, SDK.DOMModel.DOMNode|null>>();\nconst domLookUpBatchNodesCache = new Map<\n Handlers.Types.TraceParseData,\n Map<Set<Protocol.DOM.BackendNodeId>, Map<Protocol.DOM.BackendNodeId, SDK.DOMModel.DOMNode|null>>>();\n\n// eslint-disable-next-line @typescript-eslint/naming-convention\nexport function _TEST_clearCache(): void {\n domLookUpSingleNodeCache.clear();\n domLookUpBatchNodesCache.clear();\n layoutShiftSourcesCache.clear();\n normalizedLayoutShiftNodesCache.clear();\n}\n\n/**\n * Looks up the DOM Node on the page for the given BackendNodeId. Uses the\n * provided TraceParseData as the cache and will cache the result after the\n * first lookup.\n */\nexport async function domNodeForBackendNodeID(\n modelData: Handlers.Types.TraceParseData, nodeId: Protocol.DOM.BackendNodeId): Promise<SDK.DOMModel.DOMNode|null> {\n const fromCache = domLookUpSingleNodeCache.get(modelData)?.get(nodeId);\n if (fromCache !== undefined) {\n return fromCache;\n }\n\n const target = SDK.TargetManager.TargetManager.instance().primaryPageTarget();\n const domModel = target?.model(SDK.DOMModel.DOMModel);\n if (!domModel) {\n return null;\n }\n\n const domNodesMap = await domModel.pushNodesByBackendIdsToFrontend(new Set([nodeId]));\n const result = domNodesMap?.get(nodeId) || null;\n\n const cacheForModel =\n domLookUpSingleNodeCache.get(modelData) || new Map<Protocol.DOM.BackendNodeId, SDK.DOMModel.DOMNode|null>();\n cacheForModel.set(nodeId, result);\n domLookUpSingleNodeCache.set(modelData, cacheForModel);\n\n return result;\n}\n\n/**\n * Takes a set of Protocol.DOM.BackendNodeId ids and will return a map of NodeId=>DOMNode.\n * Results are cached based on 1) the provided TraceParseData and 2) the provided set of IDs.\n */\nexport async function domNodesForMultipleBackendNodeIds(\n modelData: Handlers.Types.TraceParseData,\n nodeIds: Set<Protocol.DOM.BackendNodeId>): Promise<Map<Protocol.DOM.BackendNodeId, SDK.DOMModel.DOMNode|null>> {\n const fromCache = domLookUpBatchNodesCache.get(modelData)?.get(nodeIds);\n if (fromCache) {\n return fromCache;\n }\n const target = SDK.TargetManager.TargetManager.instance().primaryPageTarget();\n const domModel = target?.model(SDK.DOMModel.DOMModel);\n if (!domModel) {\n return new Map();\n }\n\n const domNodesMap = await domModel.pushNodesByBackendIdsToFrontend(nodeIds) || new Map();\n\n const cacheForModel = domLookUpBatchNodesCache.get(modelData) ||\n new Map<Set<Protocol.DOM.BackendNodeId>, Map<Protocol.DOM.BackendNodeId, SDK.DOMModel.DOMNode|null>>();\n cacheForModel.set(nodeIds, domNodesMap);\n domLookUpBatchNodesCache.set(modelData, cacheForModel);\n\n return domNodesMap;\n}\n\nconst layoutShiftSourcesCache = new Map<\n Handlers.Types.TraceParseData, Map<Types.TraceEvents.TraceEventLayoutShift, readonly LayoutShiftSource[]>>();\n\nconst normalizedLayoutShiftNodesCache = new Map<\n Handlers.Types.TraceParseData,\n Map<Types.TraceEvents.TraceEventLayoutShift, readonly Types.TraceEvents.TraceImpactedNode[]>>();\n\nexport interface LayoutShiftSource {\n previousRect: DOMRect;\n currentRect: DOMRect;\n node: SDK.DOMModel.DOMNode;\n}\n\n/**\n * Calculates and returns a list of sources for a LayoutShift.\n * Here, a source is considered as a node that moved and contributed to the\n * given LayoutShift existing and the score it was given. Each source returned\n * contains a reference to the DOM Node, and its dimensions (as a DOMRect), both\n * before and now, so we can see how this node changed and how that impacted the\n * layout shift.\n *\n * This data is cached based on the provided model data and the given layout\n * shift, so it is is safe to call multiple times with the same input.\n */\nexport async function sourcesForLayoutShift(\n modelData: Handlers.Types.TraceParseData,\n event: Types.TraceEvents.TraceEventLayoutShift): Promise<readonly LayoutShiftSource[]> {\n const fromCache = layoutShiftSourcesCache.get(modelData)?.get(event);\n if (fromCache) {\n return fromCache;\n }\n const impactedNodes = event.args.data?.impacted_nodes;\n if (!impactedNodes) {\n return [];\n }\n const sources: LayoutShiftSource[] = [];\n await Promise.all(impactedNodes.map(async node => {\n const domNode = await domNodeForBackendNodeID(modelData, node.node_id);\n if (domNode) {\n sources.push({\n previousRect: new DOMRect(node.old_rect[0], node.old_rect[1], node.old_rect[2], node.old_rect[3]),\n currentRect: new DOMRect(node.new_rect[0], node.new_rect[1], node.new_rect[2], node.new_rect[3]),\n node: domNode,\n });\n }\n }));\n const cacheForModel =\n layoutShiftSourcesCache.get(modelData) || new Map<Types.TraceEvents.TraceEventLayoutShift, LayoutShiftSource[]>();\n cacheForModel.set(event, sources);\n layoutShiftSourcesCache.set(modelData, cacheForModel);\n return sources;\n}\n\n/**\n * Takes a LayoutShift and normalizes its node dimensions based on the device\n * pixel ratio (DPR) of the user's display.\n * This is required because the Layout Instability API is not based on CSS\n * pixels, but physical pixels. Therefore we need to map these to normalized CSS\n * pixels if we can. For example, if the user is on a device with a DPR of 2,\n * the values of the node dimensions reported by the Instability API need to be\n * divided by 2 to be accurate.\n * This function is safe to call multiple times as results are cached based on\n * the provided model data.\n * See https://crbug.com/1300309 for details.\n */\nexport async function normalizedImpactedNodesForLayoutShift(\n modelData: Handlers.Types.TraceParseData,\n event: Types.TraceEvents.TraceEventLayoutShift): Promise<readonly Types.TraceEvents.TraceImpactedNode[]> {\n const fromCache = normalizedLayoutShiftNodesCache.get(modelData)?.get(event);\n if (fromCache) {\n return fromCache;\n }\n const impactedNodes = event.args?.data?.impacted_nodes;\n if (!impactedNodes) {\n return [];\n }\n\n let viewportScale: number|null = null;\n const target = SDK.TargetManager.TargetManager.instance().primaryPageTarget();\n // Get the CSS-to-physical pixel ratio of the device the inspected\n // target is running at.\n const evaluateResult = await target?.runtimeAgent().invoke_evaluate({expression: 'window.devicePixelRatio'});\n if (evaluateResult?.result.type === 'number') {\n viewportScale = evaluateResult?.result.value as number ?? null;\n }\n\n if (!viewportScale) {\n // Bail and return the nodes as is.\n return impactedNodes;\n }\n\n const normalizedNodes: Types.TraceEvents.TraceImpactedNode[] = [];\n for (const impactedNode of impactedNodes) {\n const newNode = {...impactedNode};\n for (let i = 0; i < impactedNode.old_rect.length; i++) {\n newNode.old_rect[i] /= viewportScale;\n }\n for (let i = 0; i < impactedNode.new_rect.length; i++) {\n newNode.new_rect[i] /= viewportScale;\n }\n normalizedNodes.push(newNode);\n }\n\n const cacheForModel = normalizedLayoutShiftNodesCache.get(modelData) ||\n new Map<Types.TraceEvents.TraceEventLayoutShift, readonly Types.TraceEvents.TraceImpactedNode[]>();\n cacheForModel.set(event, normalizedNodes);\n normalizedLayoutShiftNodesCache.set(modelData, cacheForModel);\n\n return normalizedNodes;\n}\n"],
|
|
5
|
-
"mappings": "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",
|
|
6
|
-
"names": []
|
|
7
|
-
}
|
|
1
|
+
{"version":3,"file":"FetchNodes.js","sourceRoot":"","sources":["../../../../../../../front_end/models/trace/extras/FetchNodes.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright 2023 The Chromium Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\nimport type * as Protocol from '../../../generated/protocol.js';\nimport * as SDK from '../../../core/sdk/sdk.js';\nimport type * as Handlers from '../handlers/handlers.js';\nimport type * as Types from '../types/types.js';\n\nconst domLookUpSingleNodeCache =\n new Map<Handlers.Types.TraceParseData, Map<Protocol.DOM.BackendNodeId, SDK.DOMModel.DOMNode|null>>();\nconst domLookUpBatchNodesCache = new Map<\n Handlers.Types.TraceParseData,\n Map<Set<Protocol.DOM.BackendNodeId>, Map<Protocol.DOM.BackendNodeId, SDK.DOMModel.DOMNode|null>>>();\n\n// eslint-disable-next-line @typescript-eslint/naming-convention\nexport function _TEST_clearCache(): void {\n domLookUpSingleNodeCache.clear();\n domLookUpBatchNodesCache.clear();\n layoutShiftSourcesCache.clear();\n normalizedLayoutShiftNodesCache.clear();\n}\n\n/**\n * Looks up the DOM Node on the page for the given BackendNodeId. Uses the\n * provided TraceParseData as the cache and will cache the result after the\n * first lookup.\n */\nexport async function domNodeForBackendNodeID(\n modelData: Handlers.Types.TraceParseData, nodeId: Protocol.DOM.BackendNodeId): Promise<SDK.DOMModel.DOMNode|null> {\n const fromCache = domLookUpSingleNodeCache.get(modelData)?.get(nodeId);\n if (fromCache !== undefined) {\n return fromCache;\n }\n\n const target = SDK.TargetManager.TargetManager.instance().primaryPageTarget();\n const domModel = target?.model(SDK.DOMModel.DOMModel);\n if (!domModel) {\n return null;\n }\n\n const domNodesMap = await domModel.pushNodesByBackendIdsToFrontend(new Set([nodeId]));\n const result = domNodesMap?.get(nodeId) || null;\n\n const cacheForModel =\n domLookUpSingleNodeCache.get(modelData) || new Map<Protocol.DOM.BackendNodeId, SDK.DOMModel.DOMNode|null>();\n cacheForModel.set(nodeId, result);\n domLookUpSingleNodeCache.set(modelData, cacheForModel);\n\n return result;\n}\n\n/**\n * Takes a set of Protocol.DOM.BackendNodeId ids and will return a map of NodeId=>DOMNode.\n * Results are cached based on 1) the provided TraceParseData and 2) the provided set of IDs.\n */\nexport async function domNodesForMultipleBackendNodeIds(\n modelData: Handlers.Types.TraceParseData,\n nodeIds: Set<Protocol.DOM.BackendNodeId>): Promise<Map<Protocol.DOM.BackendNodeId, SDK.DOMModel.DOMNode|null>> {\n const fromCache = domLookUpBatchNodesCache.get(modelData)?.get(nodeIds);\n if (fromCache) {\n return fromCache;\n }\n const target = SDK.TargetManager.TargetManager.instance().primaryPageTarget();\n const domModel = target?.model(SDK.DOMModel.DOMModel);\n if (!domModel) {\n return new Map();\n }\n\n const domNodesMap = await domModel.pushNodesByBackendIdsToFrontend(nodeIds) || new Map();\n\n const cacheForModel = domLookUpBatchNodesCache.get(modelData) ||\n new Map<Set<Protocol.DOM.BackendNodeId>, Map<Protocol.DOM.BackendNodeId, SDK.DOMModel.DOMNode|null>>();\n cacheForModel.set(nodeIds, domNodesMap);\n domLookUpBatchNodesCache.set(modelData, cacheForModel);\n\n return domNodesMap;\n}\n\nconst layoutShiftSourcesCache = new Map<\n Handlers.Types.TraceParseData, Map<Types.TraceEvents.TraceEventLayoutShift, readonly LayoutShiftSource[]>>();\n\nconst normalizedLayoutShiftNodesCache = new Map<\n Handlers.Types.TraceParseData,\n Map<Types.TraceEvents.TraceEventLayoutShift, readonly Types.TraceEvents.TraceImpactedNode[]>>();\n\nexport interface LayoutShiftSource {\n previousRect: DOMRect;\n currentRect: DOMRect;\n node: SDK.DOMModel.DOMNode;\n}\n\n/**\n * Calculates and returns a list of sources for a LayoutShift.\n * Here, a source is considered as a node that moved and contributed to the\n * given LayoutShift existing and the score it was given. Each source returned\n * contains a reference to the DOM Node, and its dimensions (as a DOMRect), both\n * before and now, so we can see how this node changed and how that impacted the\n * layout shift.\n *\n * This data is cached based on the provided model data and the given layout\n * shift, so it is is safe to call multiple times with the same input.\n */\nexport async function sourcesForLayoutShift(\n modelData: Handlers.Types.TraceParseData,\n event: Types.TraceEvents.TraceEventLayoutShift): Promise<readonly LayoutShiftSource[]> {\n const fromCache = layoutShiftSourcesCache.get(modelData)?.get(event);\n if (fromCache) {\n return fromCache;\n }\n const impactedNodes = event.args.data?.impacted_nodes;\n if (!impactedNodes) {\n return [];\n }\n const sources: LayoutShiftSource[] = [];\n await Promise.all(impactedNodes.map(async node => {\n const domNode = await domNodeForBackendNodeID(modelData, node.node_id);\n if (domNode) {\n sources.push({\n previousRect: new DOMRect(node.old_rect[0], node.old_rect[1], node.old_rect[2], node.old_rect[3]),\n currentRect: new DOMRect(node.new_rect[0], node.new_rect[1], node.new_rect[2], node.new_rect[3]),\n node: domNode,\n });\n }\n }));\n const cacheForModel =\n layoutShiftSourcesCache.get(modelData) || new Map<Types.TraceEvents.TraceEventLayoutShift, LayoutShiftSource[]>();\n cacheForModel.set(event, sources);\n layoutShiftSourcesCache.set(modelData, cacheForModel);\n return sources;\n}\n\n/**\n * Takes a LayoutShift and normalizes its node dimensions based on the device\n * pixel ratio (DPR) of the user's display.\n * This is required because the Layout Instability API is not based on CSS\n * pixels, but physical pixels. Therefore we need to map these to normalized CSS\n * pixels if we can. For example, if the user is on a device with a DPR of 2,\n * the values of the node dimensions reported by the Instability API need to be\n * divided by 2 to be accurate.\n * This function is safe to call multiple times as results are cached based on\n * the provided model data.\n * See https://crbug.com/1300309 for details.\n */\nexport async function normalizedImpactedNodesForLayoutShift(\n modelData: Handlers.Types.TraceParseData,\n event: Types.TraceEvents.TraceEventLayoutShift): Promise<readonly Types.TraceEvents.TraceImpactedNode[]> {\n const fromCache = normalizedLayoutShiftNodesCache.get(modelData)?.get(event);\n if (fromCache) {\n return fromCache;\n }\n const impactedNodes = event.args?.data?.impacted_nodes;\n if (!impactedNodes) {\n return [];\n }\n\n let viewportScale: number|null = null;\n const target = SDK.TargetManager.TargetManager.instance().primaryPageTarget();\n // Get the CSS-to-physical pixel ratio of the device the inspected\n // target is running at.\n const evaluateResult = await target?.runtimeAgent().invoke_evaluate({expression: 'window.devicePixelRatio'});\n if (evaluateResult?.result.type === 'number') {\n viewportScale = evaluateResult?.result.value as number ?? null;\n }\n\n if (!viewportScale) {\n // Bail and return the nodes as is.\n return impactedNodes;\n }\n\n const normalizedNodes: Types.TraceEvents.TraceImpactedNode[] = [];\n for (const impactedNode of impactedNodes) {\n const newNode = {...impactedNode};\n for (let i = 0; i < impactedNode.old_rect.length; i++) {\n newNode.old_rect[i] /= viewportScale;\n }\n for (let i = 0; i < impactedNode.new_rect.length; i++) {\n newNode.new_rect[i] /= viewportScale;\n }\n normalizedNodes.push(newNode);\n }\n\n const cacheForModel = normalizedLayoutShiftNodesCache.get(modelData) ||\n new Map<Types.TraceEvents.TraceEventLayoutShift, readonly Types.TraceEvents.TraceImpactedNode[]>();\n cacheForModel.set(event, normalizedNodes);\n normalizedLayoutShiftNodesCache.set(modelData, cacheForModel);\n\n return normalizedNodes;\n}\n"]}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type * as Handlers from '../handlers/handlers.js';
|
|
2
|
+
import type * as Types from '../types/types.js';
|
|
3
|
+
export interface Data {
|
|
4
|
+
zeroTime: Types.Timing.MicroSeconds;
|
|
5
|
+
spanTime: Types.Timing.MicroSeconds;
|
|
6
|
+
frames: readonly Frame[];
|
|
7
|
+
}
|
|
8
|
+
export interface Frame {
|
|
9
|
+
screenshotEvent: Types.TraceEvents.SyntheticScreenshot;
|
|
10
|
+
index: number;
|
|
11
|
+
}
|
|
12
|
+
export type HandlersWithFilmStrip = Handlers.Types.HandlersWithMeta<{
|
|
13
|
+
Screenshots: typeof Handlers.ModelHandlers.Screenshots;
|
|
14
|
+
}>;
|
|
15
|
+
export type HandlerDataWithScreenshots = Handlers.Types.EnabledHandlerDataWithMeta<{
|
|
16
|
+
Screenshots: typeof Handlers.ModelHandlers.Screenshots;
|
|
17
|
+
}>;
|
|
18
|
+
export declare function fromTraceData(traceData: HandlerDataWithScreenshots, customZeroTime?: Types.Timing.MicroSeconds): Data;
|
|
19
|
+
export declare function frameClosestToTimestamp(filmStrip: Data, searchTimestamp: Types.Timing.MicroSeconds): Frame | null;
|
|
@@ -1,37 +1,44 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
// Copyright 2023 The Chromium Authors. All rights reserved.
|
|
2
|
+
// Use of this source code is governed by a BSD-style license that can be
|
|
3
|
+
// found in the LICENSE file.
|
|
4
|
+
//
|
|
5
|
+
import * as Platform from '../../../core/platform/platform.js';
|
|
6
|
+
// Cache film strips based on:
|
|
7
|
+
// 1. The trace parsed data object
|
|
8
|
+
// 2. The start time.
|
|
9
|
+
const filmStripCache = new Map();
|
|
3
10
|
export function fromTraceData(traceData, customZeroTime) {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
}
|
|
11
|
-
for (const screenshotEvent of traceData.Screenshots) {
|
|
12
|
-
if (screenshotEvent.ts < zeroTime) {
|
|
13
|
-
continue;
|
|
11
|
+
const frames = [];
|
|
12
|
+
const zeroTime = typeof customZeroTime !== 'undefined' ? customZeroTime : traceData.Meta.traceBounds.min;
|
|
13
|
+
const spanTime = traceData.Meta.traceBounds.range;
|
|
14
|
+
const fromCache = filmStripCache.get(traceData)?.get(zeroTime);
|
|
15
|
+
if (fromCache) {
|
|
16
|
+
return fromCache;
|
|
14
17
|
}
|
|
15
|
-
const
|
|
16
|
-
|
|
17
|
-
|
|
18
|
+
for (const screenshotEvent of traceData.Screenshots) {
|
|
19
|
+
if (screenshotEvent.ts < zeroTime) {
|
|
20
|
+
continue;
|
|
21
|
+
}
|
|
22
|
+
const frame = {
|
|
23
|
+
index: frames.length,
|
|
24
|
+
screenshotEvent: screenshotEvent,
|
|
25
|
+
};
|
|
26
|
+
frames.push(frame);
|
|
27
|
+
}
|
|
28
|
+
const result = {
|
|
29
|
+
zeroTime,
|
|
30
|
+
spanTime,
|
|
31
|
+
frames: Array.from(frames),
|
|
18
32
|
};
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
zeroTime,
|
|
23
|
-
spanTime,
|
|
24
|
-
frames: Array.from(frames)
|
|
25
|
-
};
|
|
26
|
-
const cachedForData = Platform.MapUtilities.getWithDefault(filmStripCache, traceData, () => /* @__PURE__ */ new Map());
|
|
27
|
-
cachedForData.set(zeroTime, result);
|
|
28
|
-
return result;
|
|
33
|
+
const cachedForData = Platform.MapUtilities.getWithDefault(filmStripCache, traceData, () => new Map());
|
|
34
|
+
cachedForData.set(zeroTime, result);
|
|
35
|
+
return result;
|
|
29
36
|
}
|
|
30
37
|
export function frameClosestToTimestamp(filmStrip, searchTimestamp) {
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
38
|
+
const closestFrameIndexBeforeTimestamp = Platform.ArrayUtilities.nearestIndexFromEnd(filmStrip.frames, frame => frame.screenshotEvent.ts < searchTimestamp);
|
|
39
|
+
if (closestFrameIndexBeforeTimestamp === null) {
|
|
40
|
+
return null;
|
|
41
|
+
}
|
|
42
|
+
return filmStrip.frames[closestFrameIndexBeforeTimestamp];
|
|
36
43
|
}
|
|
37
|
-
//# sourceMappingURL=FilmStrip.js.map
|
|
44
|
+
//# sourceMappingURL=FilmStrip.js.map
|
|
@@ -1,7 +1 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": 3,
|
|
3
|
-
"sources": ["../../../../../../../front_end/models/trace/extras/FilmStrip.ts"],
|
|
4
|
-
"sourcesContent": ["// Copyright 2023 The Chromium Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n//\nimport * as Platform from '../../../core/platform/platform.js';\nimport type * as Handlers from '../handlers/handlers.js';\nimport type * as Types from '../types/types.js';\n\nexport interface Data {\n zeroTime: Types.Timing.MicroSeconds;\n spanTime: Types.Timing.MicroSeconds;\n frames: readonly Frame[];\n}\n\nexport interface Frame {\n screenshotEvent: Types.TraceEvents.SyntheticScreenshot;\n index: number;\n}\n\nexport type HandlersWithFilmStrip = Handlers.Types.HandlersWithMeta<{\n // eslint-disable-next-line @typescript-eslint/naming-convention\n Screenshots: typeof Handlers.ModelHandlers.Screenshots,\n}>;\n\nexport type HandlerDataWithScreenshots = Handlers.Types.EnabledHandlerDataWithMeta<{\n // eslint-disable-next-line @typescript-eslint/naming-convention\n Screenshots: typeof Handlers.ModelHandlers.Screenshots,\n}>;\n\n// Cache film strips based on:\n// 1. The trace parsed data object\n// 2. The start time.\nconst filmStripCache = new Map<HandlerDataWithScreenshots, Map<Types.Timing.MicroSeconds, Data>>();\n\nexport function fromTraceData(traceData: HandlerDataWithScreenshots, customZeroTime?: Types.Timing.MicroSeconds): Data {\n const frames: Frame[] = [];\n\n const zeroTime = typeof customZeroTime !== 'undefined' ? customZeroTime : traceData.Meta.traceBounds.min;\n const spanTime = traceData.Meta.traceBounds.range;\n const fromCache = filmStripCache.get(traceData)?.get(zeroTime);\n if (fromCache) {\n return fromCache;\n }\n\n for (const screenshotEvent of traceData.Screenshots) {\n if (screenshotEvent.ts < zeroTime) {\n continue;\n }\n const frame: Frame = {\n index: frames.length,\n screenshotEvent: screenshotEvent,\n };\n frames.push(frame);\n }\n\n const result: Data = {\n zeroTime,\n spanTime,\n frames: Array.from(frames),\n };\n\n const cachedForData =\n Platform.MapUtilities.getWithDefault(filmStripCache, traceData, () => new Map<Types.Timing.MicroSeconds, Data>());\n cachedForData.set(zeroTime, result);\n\n return result;\n}\n\nexport function frameClosestToTimestamp(filmStrip: Data, searchTimestamp: Types.Timing.MicroSeconds): Frame|null {\n const closestFrameIndexBeforeTimestamp = Platform.ArrayUtilities.nearestIndexFromEnd(\n filmStrip.frames, frame => frame.screenshotEvent.ts < searchTimestamp);\n if (closestFrameIndexBeforeTimestamp === null) {\n return null;\n }\n return filmStrip.frames[closestFrameIndexBeforeTimestamp];\n}\n"],
|
|
5
|
-
"mappings": "AAIA;AA4BA,MAAM,iBAAiB,oBAAI;AAEpB,8BAAuB,WAAuC,gBAAkD;AACrH,QAAM,SAAkB;AAExB,QAAM,WAAW,OAAO,mBAAmB,cAAc,iBAAiB,UAAU,KAAK,YAAY;AACrG,QAAM,WAAW,UAAU,KAAK,YAAY;AAC5C,QAAM,YAAY,eAAe,IAAI,YAAY,IAAI;AACrD,MAAI,WAAW;AACb,WAAO;AAAA;AAGT,aAAW,mBAAmB,UAAU,aAAa;AACnD,QAAI,gBAAgB,KAAK,UAAU;AACjC;AAAA;AAEF,UAAM,QAAe;AAAA,MACnB,OAAO,OAAO;AAAA,MACd;AAAA;AAEF,WAAO,KAAK;AAAA;AAGd,QAAM,SAAe;AAAA,IACnB;AAAA,IACA;AAAA,IACA,QAAQ,MAAM,KAAK;AAAA;AAGrB,QAAM,gBACF,SAAS,aAAa,eAAe,gBAAgB,WAAW,MAAM,oBAAI;AAC9E,gBAAc,IAAI,UAAU;AAE5B,SAAO;AAAA;AAGF,wCAAiC,WAAiB,iBAAwD;AAC/G,QAAM,mCAAmC,SAAS,eAAe,oBAC7D,UAAU,QAAQ,WAAS,MAAM,gBAAgB,KAAK;AAC1D,MAAI,qCAAqC,MAAM;AAC7C,WAAO;AAAA;AAET,SAAO,UAAU,OAAO;AAAA;",
|
|
6
|
-
"names": []
|
|
7
|
-
}
|
|
1
|
+
{"version":3,"file":"FilmStrip.js","sourceRoot":"","sources":["../../../../../../../front_end/models/trace/extras/FilmStrip.ts"],"names":[],"mappings":"AAAA,4DAA4D;AAC5D,yEAAyE;AACzE,6BAA6B;AAC7B,EAAE;AACF,OAAO,KAAK,QAAQ,MAAM,oCAAoC,CAAC;AAyB/D,8BAA8B;AAC9B,kCAAkC;AAClC,qBAAqB;AACrB,MAAM,cAAc,GAAG,IAAI,GAAG,EAAoE,CAAC;AAEnG,MAAM,UAAU,aAAa,CAAC,SAAqC,EAAE,cAA0C;IAC7G,MAAM,MAAM,GAAY,EAAE,CAAC;IAE3B,MAAM,QAAQ,GAAG,OAAO,cAAc,KAAK,WAAW,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,SAAS,CAAC,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC;IACzG,MAAM,QAAQ,GAAG,SAAS,CAAC,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC;IAClD,MAAM,SAAS,GAAG,cAAc,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE,GAAG,CAAC,QAAQ,CAAC,CAAC;IAC/D,IAAI,SAAS,EAAE;QACb,OAAO,SAAS,CAAC;KAClB;IAED,KAAK,MAAM,eAAe,IAAI,SAAS,CAAC,WAAW,EAAE;QACnD,IAAI,eAAe,CAAC,EAAE,GAAG,QAAQ,EAAE;YACjC,SAAS;SACV;QACD,MAAM,KAAK,GAAU;YACnB,KAAK,EAAE,MAAM,CAAC,MAAM;YACpB,eAAe,EAAE,eAAe;SACjC,CAAC;QACF,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;KACpB;IAED,MAAM,MAAM,GAAS;QACnB,QAAQ;QACR,QAAQ;QACR,MAAM,EAAE,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC;KAC3B,CAAC;IAEF,MAAM,aAAa,GACf,QAAQ,CAAC,YAAY,CAAC,cAAc,CAAC,cAAc,EAAE,SAAS,EAAE,GAAG,EAAE,CAAC,IAAI,GAAG,EAAmC,CAAC,CAAC;IACtH,aAAa,CAAC,GAAG,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;IAEpC,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,MAAM,UAAU,uBAAuB,CAAC,SAAe,EAAE,eAA0C;IACjG,MAAM,gCAAgC,GAAG,QAAQ,CAAC,cAAc,CAAC,mBAAmB,CAChF,SAAS,CAAC,MAAM,EAAE,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC,eAAe,CAAC,EAAE,GAAG,eAAe,CAAC,CAAC;IAC3E,IAAI,gCAAgC,KAAK,IAAI,EAAE;QAC7C,OAAO,IAAI,CAAC;KACb;IACD,OAAO,SAAS,CAAC,MAAM,CAAC,gCAAgC,CAAC,CAAC;AAC5D,CAAC","sourcesContent":["// Copyright 2023 The Chromium Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n//\nimport * as Platform from '../../../core/platform/platform.js';\nimport type * as Handlers from '../handlers/handlers.js';\nimport type * as Types from '../types/types.js';\n\nexport interface Data {\n zeroTime: Types.Timing.MicroSeconds;\n spanTime: Types.Timing.MicroSeconds;\n frames: readonly Frame[];\n}\n\nexport interface Frame {\n screenshotEvent: Types.TraceEvents.SyntheticScreenshot;\n index: number;\n}\n\nexport type HandlersWithFilmStrip = Handlers.Types.HandlersWithMeta<{\n // eslint-disable-next-line @typescript-eslint/naming-convention\n Screenshots: typeof Handlers.ModelHandlers.Screenshots,\n}>;\n\nexport type HandlerDataWithScreenshots = Handlers.Types.EnabledHandlerDataWithMeta<{\n // eslint-disable-next-line @typescript-eslint/naming-convention\n Screenshots: typeof Handlers.ModelHandlers.Screenshots,\n}>;\n\n// Cache film strips based on:\n// 1. The trace parsed data object\n// 2. The start time.\nconst filmStripCache = new Map<HandlerDataWithScreenshots, Map<Types.Timing.MicroSeconds, Data>>();\n\nexport function fromTraceData(traceData: HandlerDataWithScreenshots, customZeroTime?: Types.Timing.MicroSeconds): Data {\n const frames: Frame[] = [];\n\n const zeroTime = typeof customZeroTime !== 'undefined' ? customZeroTime : traceData.Meta.traceBounds.min;\n const spanTime = traceData.Meta.traceBounds.range;\n const fromCache = filmStripCache.get(traceData)?.get(zeroTime);\n if (fromCache) {\n return fromCache;\n }\n\n for (const screenshotEvent of traceData.Screenshots) {\n if (screenshotEvent.ts < zeroTime) {\n continue;\n }\n const frame: Frame = {\n index: frames.length,\n screenshotEvent: screenshotEvent,\n };\n frames.push(frame);\n }\n\n const result: Data = {\n zeroTime,\n spanTime,\n frames: Array.from(frames),\n };\n\n const cachedForData =\n Platform.MapUtilities.getWithDefault(filmStripCache, traceData, () => new Map<Types.Timing.MicroSeconds, Data>());\n cachedForData.set(zeroTime, result);\n\n return result;\n}\n\nexport function frameClosestToTimestamp(filmStrip: Data, searchTimestamp: Types.Timing.MicroSeconds): Frame|null {\n const closestFrameIndexBeforeTimestamp = Platform.ArrayUtilities.nearestIndexFromEnd(\n filmStrip.frames, frame => frame.screenshotEvent.ts < searchTimestamp);\n if (closestFrameIndexBeforeTimestamp === null) {\n return null;\n }\n return filmStrip.frames[closestFrameIndexBeforeTimestamp];\n}\n"]}
|
|
@@ -1,61 +1,77 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
1
|
+
// Copyright 2023 The Chromium Authors. All rights reserved.
|
|
2
|
+
// Use of this source code is governed by a BSD-style license that can be
|
|
3
|
+
// found in the LICENSE file.
|
|
4
|
+
import * as Helpers from '../helpers/helpers.js';
|
|
5
|
+
import * as Types from '../types/types.js';
|
|
6
|
+
const IDLE_FUNCTION_CALL_NAMES = new Set([
|
|
7
|
+
'(program)',
|
|
8
|
+
'(idle)',
|
|
9
|
+
'(root)',
|
|
7
10
|
]);
|
|
8
11
|
export function calculateWindow(traceBounds, mainThreadEntries) {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
}
|
|
12
|
-
const entriesWithIdleRemoved = mainThreadEntries.filter((entry) => {
|
|
13
|
-
if (Types.TraceEvents.isProfileCall(entry) && (IDLE_FUNCTION_CALL_NAMES.has(entry.callFrame.functionName) || !entry.callFrame.functionName)) {
|
|
14
|
-
return false;
|
|
12
|
+
if (!mainThreadEntries.length) {
|
|
13
|
+
return traceBounds;
|
|
15
14
|
}
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
const timings = Helpers.Timing.eventTimingsMicroSeconds(entryAtCut);
|
|
26
|
-
let cutTime = (timings.startTime + timings.endTime) / 2;
|
|
27
|
-
let usedTime = 0;
|
|
28
|
-
const step = Math.sign(stopIndex - startIndex);
|
|
29
|
-
for (let i = startIndex; i !== stopIndex; i += step) {
|
|
30
|
-
const task = entriesWithIdleRemoved[i];
|
|
31
|
-
const taskTimings = Helpers.Timing.eventTimingsMicroSeconds(task);
|
|
32
|
-
const taskTime = (taskTimings.startTime + taskTimings.endTime) / 2;
|
|
33
|
-
const interval = Math.abs(cutTime - taskTime);
|
|
34
|
-
if (usedTime < threshold * interval) {
|
|
35
|
-
cutIndex = i;
|
|
36
|
-
cutTime = taskTime;
|
|
37
|
-
usedTime = 0;
|
|
38
|
-
}
|
|
39
|
-
usedTime += taskTimings.duration;
|
|
15
|
+
const entriesWithIdleRemoved = mainThreadEntries.filter(entry => {
|
|
16
|
+
if (Types.TraceEvents.isProfileCall(entry) &&
|
|
17
|
+
(IDLE_FUNCTION_CALL_NAMES.has(entry.callFrame.functionName) || !entry.callFrame.functionName)) {
|
|
18
|
+
return false;
|
|
19
|
+
}
|
|
20
|
+
return true;
|
|
21
|
+
});
|
|
22
|
+
if (entriesWithIdleRemoved.length === 0) {
|
|
23
|
+
return traceBounds;
|
|
40
24
|
}
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
25
|
+
/**
|
|
26
|
+
* Calculates regions of low utilization and returns the index of the event
|
|
27
|
+
* that is the first event that should be included.
|
|
28
|
+
**/
|
|
29
|
+
function findLowUtilizationRegion(startIndex, stopIndex) {
|
|
30
|
+
const threshold = 0.1;
|
|
31
|
+
let cutIndex = startIndex;
|
|
32
|
+
const entryAtCut = entriesWithIdleRemoved[cutIndex];
|
|
33
|
+
const timings = Helpers.Timing.eventTimingsMicroSeconds(entryAtCut);
|
|
34
|
+
let cutTime = (timings.startTime + timings.endTime) / 2;
|
|
35
|
+
let usedTime = 0;
|
|
36
|
+
const step = Math.sign(stopIndex - startIndex);
|
|
37
|
+
for (let i = startIndex; i !== stopIndex; i += step) {
|
|
38
|
+
const task = entriesWithIdleRemoved[i];
|
|
39
|
+
const taskTimings = Helpers.Timing.eventTimingsMicroSeconds(task);
|
|
40
|
+
const taskTime = (taskTimings.startTime + taskTimings.endTime) / 2;
|
|
41
|
+
const interval = Math.abs(cutTime - taskTime);
|
|
42
|
+
if (usedTime < threshold * interval) {
|
|
43
|
+
cutIndex = i;
|
|
44
|
+
cutTime = taskTime;
|
|
45
|
+
usedTime = 0;
|
|
46
|
+
}
|
|
47
|
+
usedTime += taskTimings.duration;
|
|
48
|
+
}
|
|
49
|
+
return cutIndex;
|
|
50
|
+
}
|
|
51
|
+
const rightIndex = findLowUtilizationRegion(entriesWithIdleRemoved.length - 1, 0);
|
|
52
|
+
const leftIndex = findLowUtilizationRegion(0, rightIndex);
|
|
53
|
+
const leftTimings = Helpers.Timing.eventTimingsMicroSeconds(entriesWithIdleRemoved[leftIndex]);
|
|
54
|
+
const rightTimings = Helpers.Timing.eventTimingsMicroSeconds(entriesWithIdleRemoved[rightIndex]);
|
|
55
|
+
let leftTime = leftTimings.startTime;
|
|
56
|
+
let rightTime = rightTimings.endTime;
|
|
57
|
+
const zoomedInSpan = rightTime - leftTime;
|
|
58
|
+
if (zoomedInSpan < traceBounds.range * 0.1) {
|
|
59
|
+
// If the area we have chosen to zoom into is less than 10% of the entire
|
|
60
|
+
// span, we bail and show the entire trace. It would not be so useful to
|
|
61
|
+
// the user to zoom in on such a small area; we assume they have
|
|
62
|
+
// purposefully recorded a trace that contains empty periods of time.
|
|
63
|
+
return traceBounds;
|
|
64
|
+
}
|
|
65
|
+
// Adjust the left time down by 5%, and the right time up by 5%, so that
|
|
66
|
+
// we give the range we want to zoom a bit of breathing space. At the
|
|
67
|
+
// same time, ensure that we do not stray beyond the bounds of the
|
|
68
|
+
// min/max time of the entire trace.
|
|
69
|
+
leftTime = Types.Timing.MicroSeconds(Math.max(leftTime - 0.05 * zoomedInSpan, traceBounds.min));
|
|
70
|
+
rightTime = Types.Timing.MicroSeconds(Math.min(rightTime + 0.05 * zoomedInSpan, traceBounds.max));
|
|
71
|
+
return {
|
|
72
|
+
min: leftTime,
|
|
73
|
+
max: rightTime,
|
|
74
|
+
range: Types.Timing.MicroSeconds(rightTime - leftTime),
|
|
75
|
+
};
|
|
60
76
|
}
|
|
61
|
-
//# sourceMappingURL=MainThreadActivity.js.map
|
|
77
|
+
//# sourceMappingURL=MainThreadActivity.js.map
|