@paulirish/trace_engine 0.0.31 → 0.0.33
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/README.md +6 -10
- package/analyze-trace.mjs +9 -10
- package/core/platform/ArrayUtilities.js +1 -0
- package/core/platform/ArrayUtilities.js.map +1 -1
- package/core/platform/DevToolsPath.d.ts +1 -1
- package/core/platform/DevToolsPath.js.map +1 -1
- package/core/platform/MimeType.js +4 -2
- package/core/platform/MimeType.js.map +1 -1
- package/core/platform/NumberUtilities.js +8 -0
- package/core/platform/NumberUtilities.js.map +1 -1
- package/core/platform/ServerTiming.d.ts +31 -0
- package/core/platform/ServerTiming.js +212 -0
- package/core/platform/ServerTiming.js.map +1 -0
- package/core/platform/Timing.d.ts +1 -1
- package/core/platform/Timing.js.map +1 -1
- package/core/platform/TypescriptUtilities.d.ts +3 -0
- package/core/platform/TypescriptUtilities.js.map +1 -1
- package/core/platform/UIString.d.ts +1 -1
- package/core/platform/UIString.js.map +1 -1
- package/core/platform/UserVisibleError.d.ts +1 -1
- package/core/platform/UserVisibleError.js.map +1 -1
- package/core/platform/platform-tsconfig.json +1 -1
- package/core/platform/platform.d.ts +2 -2
- package/core/platform/platform.js +2 -2
- package/core/platform/platform.js.map +1 -1
- package/generated/protocol.d.ts +258 -14
- package/models/trace/LanternComputationData.d.ts +4 -4
- package/models/trace/LanternComputationData.js +22 -23
- package/models/trace/LanternComputationData.js.map +1 -1
- package/models/trace/ModelImpl.d.ts +11 -12
- package/models/trace/ModelImpl.js +22 -33
- package/models/trace/ModelImpl.js.map +1 -1
- package/models/trace/Processor.d.ts +21 -12
- package/models/trace/Processor.js +148 -67
- package/models/trace/Processor.js.map +1 -1
- package/models/trace/TracingManager.js.map +1 -1
- package/models/trace/extras/FetchNodes.d.ts +8 -8
- package/models/trace/extras/FetchNodes.js +16 -11
- package/models/trace/extras/FetchNodes.js.map +1 -1
- package/models/trace/extras/FilmStrip.d.ts +2 -2
- package/models/trace/extras/FilmStrip.js +8 -8
- package/models/trace/extras/FilmStrip.js.map +1 -1
- package/models/trace/extras/MainThreadActivity.d.ts +1 -1
- package/models/trace/extras/MainThreadActivity.js +1 -1
- package/models/trace/extras/MainThreadActivity.js.map +1 -1
- package/models/trace/extras/Metadata.js +2 -2
- package/models/trace/extras/Metadata.js.map +1 -1
- package/models/trace/extras/URLForEntry.d.ts +9 -1
- package/models/trace/extras/URLForEntry.js +18 -10
- package/models/trace/extras/URLForEntry.js.map +1 -1
- package/models/trace/extras/extras.js +1 -1
- package/models/trace/handlers/AnimationHandler.d.ts +2 -2
- package/models/trace/handlers/AnimationHandler.js +1 -1
- package/models/trace/handlers/AnimationHandler.js.map +1 -1
- package/models/trace/handlers/AuctionWorkletsHandler.d.ts +2 -2
- package/models/trace/handlers/AuctionWorkletsHandler.js +11 -11
- package/models/trace/handlers/AuctionWorkletsHandler.js.map +1 -1
- package/models/trace/handlers/ExtensionTraceDataHandler.d.ts +7 -5
- package/models/trace/handlers/ExtensionTraceDataHandler.js +16 -10
- package/models/trace/handlers/ExtensionTraceDataHandler.js.map +1 -1
- package/models/trace/handlers/FramesHandler.d.ts +24 -19
- package/models/trace/handlers/FramesHandler.js +46 -25
- package/models/trace/handlers/FramesHandler.js.map +1 -1
- package/models/trace/handlers/GPUHandler.d.ts +4 -4
- package/models/trace/handlers/GPUHandler.js +3 -3
- package/models/trace/handlers/GPUHandler.js.map +1 -1
- package/models/trace/handlers/ImagePaintingHandler.d.ts +3 -3
- package/models/trace/handlers/ImagePaintingHandler.js +6 -8
- package/models/trace/handlers/ImagePaintingHandler.js.map +1 -1
- package/models/trace/handlers/InitiatorsHandler.d.ts +3 -3
- package/models/trace/handlers/InitiatorsHandler.js +14 -14
- package/models/trace/handlers/InitiatorsHandler.js.map +1 -1
- package/models/trace/handlers/InvalidationsHandler.d.ts +4 -2
- package/models/trace/handlers/InvalidationsHandler.js +29 -11
- package/models/trace/handlers/InvalidationsHandler.js.map +1 -1
- package/models/trace/handlers/LargestImagePaintHandler.d.ts +2 -2
- package/models/trace/handlers/LargestImagePaintHandler.js +1 -1
- package/models/trace/handlers/LargestImagePaintHandler.js.map +1 -1
- package/models/trace/handlers/LargestTextPaintHandler.d.ts +2 -2
- package/models/trace/handlers/LargestTextPaintHandler.js +1 -1
- package/models/trace/handlers/LargestTextPaintHandler.js.map +1 -1
- package/models/trace/handlers/LayerTreeHandler.d.ts +6 -6
- package/models/trace/handlers/LayerTreeHandler.js +6 -6
- package/models/trace/handlers/LayerTreeHandler.js.map +1 -1
- package/models/trace/handlers/LayoutShiftsHandler.d.ts +12 -20
- package/models/trace/handlers/LayoutShiftsHandler.js +73 -12
- package/models/trace/handlers/LayoutShiftsHandler.js.map +1 -1
- package/models/trace/handlers/MemoryHandler.d.ts +2 -2
- package/models/trace/handlers/MemoryHandler.js +1 -1
- package/models/trace/handlers/MemoryHandler.js.map +1 -1
- package/models/trace/handlers/MetaHandler.d.ts +15 -14
- package/models/trace/handlers/MetaHandler.js +32 -30
- package/models/trace/handlers/MetaHandler.js.map +1 -1
- package/models/trace/handlers/ModelHandlers.d.ts +1 -1
- package/models/trace/handlers/ModelHandlers.js +1 -1
- package/models/trace/handlers/ModelHandlers.js.map +1 -1
- package/models/trace/handlers/NetworkRequestsHandler.d.ts +13 -12
- package/models/trace/handlers/NetworkRequestsHandler.js +68 -66
- package/models/trace/handlers/NetworkRequestsHandler.js.map +1 -1
- package/models/trace/handlers/PageFramesHandler.d.ts +2 -2
- package/models/trace/handlers/PageFramesHandler.js +2 -2
- package/models/trace/handlers/PageFramesHandler.js.map +1 -1
- package/models/trace/handlers/PageLoadMetricsHandler.d.ts +7 -7
- package/models/trace/handlers/PageLoadMetricsHandler.js +21 -24
- package/models/trace/handlers/PageLoadMetricsHandler.js.map +1 -1
- package/models/trace/handlers/RendererHandler.d.ts +19 -19
- package/models/trace/handlers/RendererHandler.js +5 -5
- package/models/trace/handlers/RendererHandler.js.map +1 -1
- package/models/trace/handlers/SamplesHandler.d.ts +6 -6
- package/models/trace/handlers/SamplesHandler.js +4 -4
- package/models/trace/handlers/SamplesHandler.js.map +1 -1
- package/models/trace/handlers/ScreenshotsHandler.d.ts +6 -4
- package/models/trace/handlers/ScreenshotsHandler.js +11 -9
- package/models/trace/handlers/ScreenshotsHandler.js.map +1 -1
- package/models/trace/handlers/SelectorStatsHandler.d.ts +3 -3
- package/models/trace/handlers/SelectorStatsHandler.js +2 -2
- package/models/trace/handlers/SelectorStatsHandler.js.map +1 -1
- package/models/trace/handlers/ServerTimingsHandler.d.ts +10 -0
- package/models/trace/handlers/ServerTimingsHandler.js +118 -0
- package/models/trace/handlers/ServerTimingsHandler.js.map +1 -0
- package/models/trace/handlers/Threads.d.ts +7 -7
- package/models/trace/handlers/Threads.js +5 -5
- package/models/trace/handlers/Threads.js.map +1 -1
- package/models/trace/handlers/UserInteractionsHandler.d.ts +13 -11
- package/models/trace/handlers/UserInteractionsHandler.js +13 -7
- package/models/trace/handlers/UserInteractionsHandler.js.map +1 -1
- package/models/trace/handlers/UserTimingsHandler.d.ts +5 -5
- package/models/trace/handlers/UserTimingsHandler.js +52 -9
- package/models/trace/handlers/UserTimingsHandler.js.map +1 -1
- package/models/trace/handlers/WarningsHandler.d.ts +5 -5
- package/models/trace/handlers/WarningsHandler.js +4 -5
- package/models/trace/handlers/WarningsHandler.js.map +1 -1
- package/models/trace/handlers/WorkersHandler.d.ts +4 -4
- package/models/trace/handlers/WorkersHandler.js +1 -1
- package/models/trace/handlers/WorkersHandler.js.map +1 -1
- package/models/trace/handlers/handlers-tsconfig.json +1 -1
- package/models/trace/handlers/types.d.ts +7 -7
- package/models/trace/handlers/types.js.map +1 -1
- package/models/trace/helpers/Extensions.d.ts +5 -1
- package/models/trace/helpers/Extensions.js +5 -3
- package/models/trace/helpers/Extensions.js.map +1 -1
- package/models/trace/helpers/Network.d.ts +2 -2
- package/models/trace/helpers/Network.js +19 -2
- package/models/trace/helpers/Network.js.map +1 -1
- package/models/trace/helpers/SamplesIntegrator.d.ts +5 -5
- package/models/trace/helpers/SamplesIntegrator.js +10 -11
- package/models/trace/helpers/SamplesIntegrator.js.map +1 -1
- package/models/trace/helpers/SyntheticEvents.d.ts +8 -14
- package/models/trace/helpers/SyntheticEvents.js +20 -31
- package/models/trace/helpers/SyntheticEvents.js.map +1 -1
- package/models/trace/helpers/Timing.d.ts +16 -5
- package/models/trace/helpers/Timing.js +33 -7
- package/models/trace/helpers/Timing.js.map +1 -1
- package/models/trace/helpers/Trace.d.ts +46 -33
- package/models/trace/helpers/Trace.js +53 -38
- package/models/trace/helpers/Trace.js.map +1 -1
- package/models/trace/helpers/TreeHelpers.d.ts +30 -8
- package/models/trace/helpers/TreeHelpers.js +91 -23
- package/models/trace/helpers/TreeHelpers.js.map +1 -1
- package/models/trace/insights/Common.d.ts +8 -2
- package/models/trace/insights/Common.js +33 -7
- package/models/trace/insights/Common.js.map +1 -1
- package/models/trace/insights/CumulativeLayoutShift.d.ts +34 -13
- package/models/trace/insights/CumulativeLayoutShift.js +151 -59
- package/models/trace/insights/CumulativeLayoutShift.js.map +1 -1
- package/models/trace/insights/DocumentLatency.d.ts +9 -4
- package/models/trace/insights/DocumentLatency.js +82 -7
- package/models/trace/insights/DocumentLatency.js.map +1 -1
- package/models/trace/insights/FontDisplay.d.ts +11 -0
- package/models/trace/insights/FontDisplay.js +44 -0
- package/models/trace/insights/FontDisplay.js.map +1 -0
- package/models/trace/insights/InsightRunners.d.ts +3 -0
- package/models/trace/insights/InsightRunners.js +3 -0
- package/models/trace/insights/InsightRunners.js.map +1 -1
- package/models/trace/insights/InteractionToNextPaint.d.ts +4 -5
- package/models/trace/insights/InteractionToNextPaint.js +5 -3
- package/models/trace/insights/InteractionToNextPaint.js.map +1 -1
- package/models/trace/insights/LargestContentfulPaint.d.ts +20 -7
- package/models/trace/insights/LargestContentfulPaint.js +57 -37
- package/models/trace/insights/LargestContentfulPaint.js.map +1 -1
- package/models/trace/insights/RenderBlocking.d.ts +3 -3
- package/models/trace/insights/RenderBlocking.js +29 -24
- package/models/trace/insights/RenderBlocking.js.map +1 -1
- package/models/trace/insights/SlowCSSSelector.d.ts +11 -0
- package/models/trace/insights/SlowCSSSelector.js +67 -0
- package/models/trace/insights/SlowCSSSelector.js.map +1 -0
- package/models/trace/insights/ThirdPartyWeb.d.ts +18 -0
- package/models/trace/insights/ThirdPartyWeb.js +174 -0
- package/models/trace/insights/ThirdPartyWeb.js.map +1 -0
- package/models/trace/insights/Viewport.d.ts +5 -2
- package/models/trace/insights/Viewport.js +14 -9
- package/models/trace/insights/Viewport.js.map +1 -1
- package/models/trace/insights/insights-tsconfig.json +9 -0
- package/models/trace/insights/insights.d.ts +1 -0
- package/models/trace/insights/insights.js +1 -0
- package/models/trace/insights/insights.js.map +1 -1
- package/models/trace/insights/types.d.ts +43 -25
- package/models/trace/insights/types.js.map +1 -1
- package/models/trace/lantern/core/NetworkAnalyzer.d.ts +6 -6
- package/models/trace/lantern/core/NetworkAnalyzer.js +12 -12
- package/models/trace/lantern/core/NetworkAnalyzer.js.map +1 -1
- package/models/trace/lantern/graph/BaseNode.d.ts +4 -4
- package/models/trace/lantern/graph/BaseNode.js +21 -21
- package/models/trace/lantern/graph/BaseNode.js.map +1 -1
- package/models/trace/lantern/graph/CPUNode.d.ts +1 -1
- package/models/trace/lantern/graph/CPUNode.js +5 -5
- package/models/trace/lantern/graph/CPUNode.js.map +1 -1
- package/models/trace/lantern/graph/PageDependencyGraph.d.ts +4 -4
- package/models/trace/lantern/graph/PageDependencyGraph.js +5 -5
- package/models/trace/lantern/graph/PageDependencyGraph.js.map +1 -1
- package/models/trace/lantern/simulation/ConnectionPool.d.ts +7 -7
- package/models/trace/lantern/simulation/ConnectionPool.js +26 -26
- package/models/trace/lantern/simulation/ConnectionPool.js.map +1 -1
- package/models/trace/lantern/simulation/DNSCache.d.ts +3 -3
- package/models/trace/lantern/simulation/DNSCache.js +11 -11
- package/models/trace/lantern/simulation/DNSCache.js.map +1 -1
- package/models/trace/lantern/simulation/SimulationTimingMap.d.ts +1 -1
- package/models/trace/lantern/simulation/SimulationTimingMap.js +15 -15
- package/models/trace/lantern/simulation/SimulationTimingMap.js.map +1 -1
- package/models/trace/lantern/simulation/Simulator.d.ts +28 -28
- package/models/trace/lantern/simulation/Simulator.js +113 -113
- package/models/trace/lantern/simulation/Simulator.js.map +1 -1
- package/models/trace/lantern/simulation/TCPConnection.d.ts +9 -9
- package/models/trace/lantern/simulation/TCPConnection.js +36 -36
- package/models/trace/lantern/simulation/TCPConnection.js.map +1 -1
- package/models/trace/root-causes/LayoutShift.d.ts +13 -13
- package/models/trace/root-causes/LayoutShift.js +7 -25
- package/models/trace/root-causes/LayoutShift.js.map +1 -1
- package/models/trace/types/Configuration.d.ts +16 -0
- package/models/trace/types/Configuration.js +1 -0
- package/models/trace/types/Configuration.js.map +1 -1
- package/models/trace/types/Extensions.d.ts +9 -12
- package/models/trace/types/Extensions.js +2 -1
- package/models/trace/types/Extensions.js.map +1 -1
- package/models/trace/types/File.d.ts +68 -25
- package/models/trace/types/File.js +15 -3
- package/models/trace/types/File.js.map +1 -1
- package/models/trace/types/TraceEvents.d.ts +819 -730
- package/models/trace/types/TraceEvents.js +270 -280
- package/models/trace/types/TraceEvents.js.map +1 -1
- package/models/trace/types/types.d.ts +1 -1
- package/models/trace/types/types.js +1 -1
- package/models/trace/types/types.js.map +1 -1
- package/package.json +4 -2
- package/test/test-trace-engine.mjs +47 -2
- package/third_party/third-party-web/third-party-web.js +1 -0
- package/core/platform/PromiseUtilities.d.ts +0 -10
- package/core/platform/PromiseUtilities.js +0 -18
- package/core/platform/PromiseUtilities.js.map +0 -1
- package/core/platform/SetUtilities.d.ts +0 -2
- package/core/platform/SetUtilities.js +0 -23
- package/core/platform/SetUtilities.js.map +0 -1
- package/models/trace/EntriesFilter.d.ts +0 -72
- package/models/trace/EntriesFilter.js +0 -296
- package/models/trace/EntriesFilter.js.map +0 -1
- package/models/trace/LegacyTracingModel.js.map +0 -1
- package/models/trace/handlers/EnhancedTracesHandler.d.ts +0 -48
- package/models/trace/handlers/EnhancedTracesHandler.js +0 -165
- package/models/trace/handlers/EnhancedTracesHandler.js.map +0 -1
- package/models/trace/lantern/BaseNode.d.ts +0 -91
- package/models/trace/lantern/BaseNode.js +0 -268
- package/models/trace/lantern/BaseNode.js.map +0 -1
- package/models/trace/lantern/CPUNode.d.ts +0 -24
- package/models/trace/lantern/CPUNode.js +0 -64
- package/models/trace/lantern/CPUNode.js.map +0 -1
- package/models/trace/lantern/LanternError.d.ts +0 -3
- package/models/trace/lantern/LanternError.js +0 -7
- package/models/trace/lantern/LanternError.js.map +0 -1
- package/models/trace/lantern/MetricsModule.d.ts +0 -11
- package/models/trace/lantern/MetricsModule.js +0 -14
- package/models/trace/lantern/MetricsModule.js.map +0 -1
- package/models/trace/lantern/NetworkNode.d.ts +0 -22
- package/models/trace/lantern/NetworkNode.js +0 -83
- package/models/trace/lantern/NetworkNode.js.map +0 -1
- package/models/trace/lantern/PageDependencyGraph.d.ts +0 -43
- package/models/trace/lantern/PageDependencyGraph.js +0 -509
- package/models/trace/lantern/PageDependencyGraph.js.map +0 -1
- package/models/trace/lantern/SimulationModule.d.ts +0 -17
- package/models/trace/lantern/SimulationModule.js +0 -13
- package/models/trace/lantern/SimulationModule.js.map +0 -1
- package/models/trace/lantern/simulation/NetworkAnalyzer.d.ts +0 -112
- package/models/trace/lantern/simulation/NetworkAnalyzer.js +0 -486
- package/models/trace/lantern/simulation/NetworkAnalyzer.js.map +0 -1
|
@@ -72,20 +72,20 @@ class Simulator {
|
|
|
72
72
|
}
|
|
73
73
|
return new Simulator(options);
|
|
74
74
|
}
|
|
75
|
-
|
|
75
|
+
options;
|
|
76
76
|
_rtt;
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
77
|
+
throughput;
|
|
78
|
+
maximumConcurrentRequests;
|
|
79
|
+
cpuSlowdownMultiplier;
|
|
80
|
+
layoutTaskMultiplier;
|
|
81
|
+
cachedNodeListByStartPosition;
|
|
82
|
+
nodeTimings;
|
|
83
|
+
numberInProgressByType;
|
|
84
|
+
nodes;
|
|
85
|
+
dns;
|
|
86
|
+
connectionPool;
|
|
87
87
|
constructor(options) {
|
|
88
|
-
this.
|
|
88
|
+
this.options = Object.assign({
|
|
89
89
|
rtt: defaultThrottling.rttMs,
|
|
90
90
|
throughput: defaultThrottling.throughputKbps * 1024,
|
|
91
91
|
maximumConcurrentRequests: DEFAULT_MAXIMUM_CONCURRENT_REQUESTS,
|
|
@@ -94,101 +94,101 @@ class Simulator {
|
|
|
94
94
|
additionalRttByOrigin: new Map(),
|
|
95
95
|
serverResponseTimeByOrigin: new Map(),
|
|
96
96
|
}, options);
|
|
97
|
-
this._rtt = this.
|
|
98
|
-
this.
|
|
99
|
-
this.
|
|
100
|
-
this.
|
|
101
|
-
this.
|
|
102
|
-
this.
|
|
97
|
+
this._rtt = this.options.rtt;
|
|
98
|
+
this.throughput = this.options.throughput;
|
|
99
|
+
this.maximumConcurrentRequests = Math.max(Math.min(TCPConnection.maximumSaturatedConnections(this._rtt, this.throughput), this.options.maximumConcurrentRequests), 1);
|
|
100
|
+
this.cpuSlowdownMultiplier = this.options.cpuSlowdownMultiplier;
|
|
101
|
+
this.layoutTaskMultiplier = this.cpuSlowdownMultiplier * this.options.layoutTaskMultiplier;
|
|
102
|
+
this.cachedNodeListByStartPosition = [];
|
|
103
103
|
// Properties reset on every `.simulate` call but duplicated here for type checking
|
|
104
|
-
this.
|
|
105
|
-
this.
|
|
106
|
-
this.
|
|
107
|
-
this.
|
|
104
|
+
this.nodeTimings = new SimulatorTimingMap();
|
|
105
|
+
this.numberInProgressByType = new Map();
|
|
106
|
+
this.nodes = {};
|
|
107
|
+
this.dns = new DNSCache({ rtt: this._rtt });
|
|
108
108
|
// @ts-expect-error
|
|
109
|
-
this.
|
|
109
|
+
this.connectionPool = null;
|
|
110
110
|
if (!Number.isFinite(this._rtt)) {
|
|
111
111
|
throw new Core.LanternError(`Invalid rtt ${this._rtt}`);
|
|
112
112
|
}
|
|
113
|
-
if (!Number.isFinite(this.
|
|
114
|
-
throw new Core.LanternError(`Invalid rtt ${this.
|
|
113
|
+
if (!Number.isFinite(this.throughput)) {
|
|
114
|
+
throw new Core.LanternError(`Invalid rtt ${this.throughput}`);
|
|
115
115
|
}
|
|
116
116
|
}
|
|
117
117
|
get rtt() {
|
|
118
118
|
return this._rtt;
|
|
119
119
|
}
|
|
120
|
-
|
|
120
|
+
initializeConnectionPool(graph) {
|
|
121
121
|
const records = [];
|
|
122
122
|
graph.getRootNode().traverse(node => {
|
|
123
123
|
if (node.type === Graph.BaseNode.types.NETWORK) {
|
|
124
124
|
records.push(node.request);
|
|
125
125
|
}
|
|
126
126
|
});
|
|
127
|
-
this.
|
|
127
|
+
this.connectionPool = new ConnectionPool(records, this.options);
|
|
128
128
|
}
|
|
129
129
|
/**
|
|
130
130
|
* Initializes the various state data structures such _nodeTimings and the _node Sets by state.
|
|
131
131
|
*/
|
|
132
|
-
|
|
133
|
-
this.
|
|
134
|
-
this.
|
|
135
|
-
this.
|
|
136
|
-
this.
|
|
132
|
+
initializeAuxiliaryData() {
|
|
133
|
+
this.nodeTimings = new SimulatorTimingMap();
|
|
134
|
+
this.numberInProgressByType = new Map();
|
|
135
|
+
this.nodes = {};
|
|
136
|
+
this.cachedNodeListByStartPosition = [];
|
|
137
137
|
// NOTE: We don't actually need *all* of these sets, but the clarity that each node progresses
|
|
138
138
|
// through the system is quite nice.
|
|
139
139
|
for (const state of Object.values(NodeState)) {
|
|
140
|
-
this.
|
|
140
|
+
this.nodes[state] = new Set();
|
|
141
141
|
}
|
|
142
142
|
}
|
|
143
|
-
|
|
144
|
-
return this.
|
|
143
|
+
numberInProgress(type) {
|
|
144
|
+
return this.numberInProgressByType.get(type) || 0;
|
|
145
145
|
}
|
|
146
|
-
|
|
147
|
-
const nodeStartPosition = Simulator.
|
|
148
|
-
const firstNodeIndexWithGreaterStartPosition = this.
|
|
149
|
-
const insertionIndex = firstNodeIndexWithGreaterStartPosition === -1 ? this.
|
|
146
|
+
markNodeAsReadyToStart(node, queuedTime) {
|
|
147
|
+
const nodeStartPosition = Simulator.computeNodeStartPosition(node);
|
|
148
|
+
const firstNodeIndexWithGreaterStartPosition = this.cachedNodeListByStartPosition.findIndex(candidate => Simulator.computeNodeStartPosition(candidate) > nodeStartPosition);
|
|
149
|
+
const insertionIndex = firstNodeIndexWithGreaterStartPosition === -1 ? this.cachedNodeListByStartPosition.length :
|
|
150
150
|
firstNodeIndexWithGreaterStartPosition;
|
|
151
|
-
this.
|
|
152
|
-
this.
|
|
153
|
-
this.
|
|
154
|
-
this.
|
|
151
|
+
this.cachedNodeListByStartPosition.splice(insertionIndex, 0, node);
|
|
152
|
+
this.nodes[NodeState.ReadyToStart].add(node);
|
|
153
|
+
this.nodes[NodeState.NotReadyToStart].delete(node);
|
|
154
|
+
this.nodeTimings.setReadyToStart(node, { queuedTime });
|
|
155
155
|
}
|
|
156
|
-
|
|
157
|
-
const indexOfNodeToStart = this.
|
|
158
|
-
this.
|
|
159
|
-
this.
|
|
160
|
-
this.
|
|
161
|
-
this.
|
|
162
|
-
this.
|
|
156
|
+
markNodeAsInProgress(node, startTime) {
|
|
157
|
+
const indexOfNodeToStart = this.cachedNodeListByStartPosition.indexOf(node);
|
|
158
|
+
this.cachedNodeListByStartPosition.splice(indexOfNodeToStart, 1);
|
|
159
|
+
this.nodes[NodeState.InProgress].add(node);
|
|
160
|
+
this.nodes[NodeState.ReadyToStart].delete(node);
|
|
161
|
+
this.numberInProgressByType.set(node.type, this.numberInProgress(node.type) + 1);
|
|
162
|
+
this.nodeTimings.setInProgress(node, { startTime });
|
|
163
163
|
}
|
|
164
|
-
|
|
165
|
-
this.
|
|
166
|
-
this.
|
|
167
|
-
this.
|
|
168
|
-
this.
|
|
164
|
+
markNodeAsComplete(node, endTime, connectionTiming) {
|
|
165
|
+
this.nodes[NodeState.Complete].add(node);
|
|
166
|
+
this.nodes[NodeState.InProgress].delete(node);
|
|
167
|
+
this.numberInProgressByType.set(node.type, this.numberInProgress(node.type) - 1);
|
|
168
|
+
this.nodeTimings.setCompleted(node, { endTime, connectionTiming });
|
|
169
169
|
// Try to add all its dependents to the queue
|
|
170
170
|
for (const dependent of node.getDependents()) {
|
|
171
171
|
// Skip dependent node if one of its dependencies hasn't finished yet
|
|
172
172
|
const dependencies = dependent.getDependencies();
|
|
173
|
-
if (dependencies.some(dep => !this.
|
|
173
|
+
if (dependencies.some(dep => !this.nodes[NodeState.Complete].has(dep))) {
|
|
174
174
|
continue;
|
|
175
175
|
}
|
|
176
176
|
// Otherwise add it to the queue
|
|
177
|
-
this.
|
|
177
|
+
this.markNodeAsReadyToStart(dependent, endTime);
|
|
178
178
|
}
|
|
179
179
|
}
|
|
180
|
-
|
|
181
|
-
return this.
|
|
180
|
+
acquireConnection(request) {
|
|
181
|
+
return this.connectionPool.acquire(request);
|
|
182
182
|
}
|
|
183
|
-
|
|
183
|
+
getNodesSortedByStartPosition() {
|
|
184
184
|
// Make a copy so we don't skip nodes due to concurrent modification
|
|
185
|
-
return Array.from(this.
|
|
185
|
+
return Array.from(this.cachedNodeListByStartPosition);
|
|
186
186
|
}
|
|
187
|
-
|
|
187
|
+
startNodeIfPossible(node, totalElapsedTime) {
|
|
188
188
|
if (node.type === Graph.BaseNode.types.CPU) {
|
|
189
189
|
// Start a CPU task if there's no other CPU task in process
|
|
190
|
-
if (this.
|
|
191
|
-
this.
|
|
190
|
+
if (this.numberInProgress(node.type) === 0) {
|
|
191
|
+
this.markNodeAsInProgress(node, totalElapsedTime);
|
|
192
192
|
}
|
|
193
193
|
return;
|
|
194
194
|
}
|
|
@@ -198,53 +198,53 @@ class Simulator {
|
|
|
198
198
|
// If a network request is connectionless, we can always start it, so skip the connection checks
|
|
199
199
|
if (!node.isConnectionless) {
|
|
200
200
|
// Start a network request if we're not at max requests and a connection is available
|
|
201
|
-
const numberOfActiveRequests = this.
|
|
202
|
-
if (numberOfActiveRequests >= this.
|
|
201
|
+
const numberOfActiveRequests = this.numberInProgress(node.type);
|
|
202
|
+
if (numberOfActiveRequests >= this.maximumConcurrentRequests) {
|
|
203
203
|
return;
|
|
204
204
|
}
|
|
205
|
-
const connection = this.
|
|
205
|
+
const connection = this.acquireConnection(node.request);
|
|
206
206
|
if (!connection) {
|
|
207
207
|
return;
|
|
208
208
|
}
|
|
209
209
|
}
|
|
210
|
-
this.
|
|
210
|
+
this.markNodeAsInProgress(node, totalElapsedTime);
|
|
211
211
|
}
|
|
212
212
|
/**
|
|
213
213
|
* Updates each connection in use with the available throughput based on the number of network requests
|
|
214
214
|
* currently in flight.
|
|
215
215
|
*/
|
|
216
|
-
|
|
217
|
-
const inFlight = this.
|
|
216
|
+
updateNetworkCapacity() {
|
|
217
|
+
const inFlight = this.numberInProgress(Graph.BaseNode.types.NETWORK);
|
|
218
218
|
if (inFlight === 0) {
|
|
219
219
|
return;
|
|
220
220
|
}
|
|
221
|
-
for (const connection of this.
|
|
222
|
-
connection.setThroughput(this.
|
|
221
|
+
for (const connection of this.connectionPool.connectionsInUse()) {
|
|
222
|
+
connection.setThroughput(this.throughput / inFlight);
|
|
223
223
|
}
|
|
224
224
|
}
|
|
225
225
|
/**
|
|
226
226
|
* Estimates the number of milliseconds remaining given current condidtions before the node is complete.
|
|
227
227
|
*/
|
|
228
|
-
|
|
228
|
+
estimateTimeRemaining(node) {
|
|
229
229
|
if (node.type === Graph.BaseNode.types.CPU) {
|
|
230
|
-
return this.
|
|
230
|
+
return this.estimateCPUTimeRemaining(node);
|
|
231
231
|
}
|
|
232
232
|
if (node.type === Graph.BaseNode.types.NETWORK) {
|
|
233
|
-
return this.
|
|
233
|
+
return this.estimateNetworkTimeRemaining(node);
|
|
234
234
|
}
|
|
235
235
|
throw new Core.LanternError('Unsupported');
|
|
236
236
|
}
|
|
237
|
-
|
|
238
|
-
const timingData = this.
|
|
239
|
-
const multiplier = cpuNode.didPerformLayout() ? this.
|
|
237
|
+
estimateCPUTimeRemaining(cpuNode) {
|
|
238
|
+
const timingData = this.nodeTimings.getCpuStarted(cpuNode);
|
|
239
|
+
const multiplier = cpuNode.didPerformLayout() ? this.layoutTaskMultiplier : this.cpuSlowdownMultiplier;
|
|
240
240
|
const totalDuration = Math.min(Math.round(cpuNode.duration / 1000 * multiplier), DEFAULT_MAXIMUM_CPU_TASK_DURATION);
|
|
241
241
|
const estimatedTimeElapsed = totalDuration - timingData.timeElapsed;
|
|
242
|
-
this.
|
|
242
|
+
this.nodeTimings.setCpuEstimated(cpuNode, { estimatedTimeElapsed });
|
|
243
243
|
return estimatedTimeElapsed;
|
|
244
244
|
}
|
|
245
|
-
|
|
245
|
+
estimateNetworkTimeRemaining(networkNode) {
|
|
246
246
|
const request = networkNode.request;
|
|
247
|
-
const timingData = this.
|
|
247
|
+
const timingData = this.nodeTimings.getNetworkStarted(networkNode);
|
|
248
248
|
let timeElapsed = 0;
|
|
249
249
|
if (networkNode.fromDiskCache) {
|
|
250
250
|
// Rough access time for seeking to location on disk and reading sequentially.
|
|
@@ -261,8 +261,8 @@ class Simulator {
|
|
|
261
261
|
timeElapsed = 2 + 10 * sizeInMb - timingData.timeElapsed;
|
|
262
262
|
}
|
|
263
263
|
else {
|
|
264
|
-
const connection = this.
|
|
265
|
-
const dnsResolutionTime = this.
|
|
264
|
+
const connection = this.connectionPool.acquireActiveConnectionFromRequest(request);
|
|
265
|
+
const dnsResolutionTime = this.dns.getTimeUntilResolution(request, {
|
|
266
266
|
requestedAt: timingData.startTime,
|
|
267
267
|
shouldUpdateCache: true,
|
|
268
268
|
});
|
|
@@ -271,28 +271,28 @@ class Simulator {
|
|
|
271
271
|
timeElapsed = calculation.timeElapsed;
|
|
272
272
|
}
|
|
273
273
|
const estimatedTimeElapsed = timeElapsed + timingData.timeElapsedOvershoot;
|
|
274
|
-
this.
|
|
274
|
+
this.nodeTimings.setNetworkEstimated(networkNode, { estimatedTimeElapsed });
|
|
275
275
|
return estimatedTimeElapsed;
|
|
276
276
|
}
|
|
277
277
|
/**
|
|
278
278
|
* Computes and returns the minimum estimated completion time of the nodes currently in progress.
|
|
279
279
|
*/
|
|
280
|
-
|
|
280
|
+
findNextNodeCompletionTime() {
|
|
281
281
|
let minimumTime = Infinity;
|
|
282
|
-
for (const node of this.
|
|
283
|
-
minimumTime = Math.min(minimumTime, this.
|
|
282
|
+
for (const node of this.nodes[NodeState.InProgress]) {
|
|
283
|
+
minimumTime = Math.min(minimumTime, this.estimateTimeRemaining(node));
|
|
284
284
|
}
|
|
285
285
|
return minimumTime;
|
|
286
286
|
}
|
|
287
287
|
/**
|
|
288
288
|
* Given a time period, computes the progress toward completion that the node made durin that time.
|
|
289
289
|
*/
|
|
290
|
-
|
|
291
|
-
const timingData = this.
|
|
290
|
+
updateProgressMadeInTimePeriod(node, timePeriodLength, totalElapsedTime) {
|
|
291
|
+
const timingData = this.nodeTimings.getInProgress(node);
|
|
292
292
|
const isFinished = timingData.estimatedTimeElapsed === timePeriodLength;
|
|
293
293
|
if (node.type === Graph.BaseNode.types.CPU || node.isConnectionless) {
|
|
294
294
|
if (isFinished) {
|
|
295
|
-
this.
|
|
295
|
+
this.markNodeAsComplete(node, totalElapsedTime);
|
|
296
296
|
}
|
|
297
297
|
else {
|
|
298
298
|
timingData.timeElapsed += timePeriodLength;
|
|
@@ -306,8 +306,8 @@ class Simulator {
|
|
|
306
306
|
throw new Core.LanternError('Invalid timing data');
|
|
307
307
|
}
|
|
308
308
|
const request = node.request;
|
|
309
|
-
const connection = this.
|
|
310
|
-
const dnsResolutionTime = this.
|
|
309
|
+
const connection = this.connectionPool.acquireActiveConnectionFromRequest(request);
|
|
310
|
+
const dnsResolutionTime = this.dns.getTimeUntilResolution(request, {
|
|
311
311
|
requestedAt: timingData.startTime,
|
|
312
312
|
shouldUpdateCache: true,
|
|
313
313
|
});
|
|
@@ -320,8 +320,8 @@ class Simulator {
|
|
|
320
320
|
connection.setH2OverflowBytesDownloaded(calculation.extraBytesDownloaded);
|
|
321
321
|
if (isFinished) {
|
|
322
322
|
connection.setWarmed(true);
|
|
323
|
-
this.
|
|
324
|
-
this.
|
|
323
|
+
this.connectionPool.release(request);
|
|
324
|
+
this.markNodeAsComplete(node, totalElapsedTime, calculation.connectionTiming);
|
|
325
325
|
}
|
|
326
326
|
else {
|
|
327
327
|
timingData.timeElapsed += calculation.timeElapsed;
|
|
@@ -329,9 +329,9 @@ class Simulator {
|
|
|
329
329
|
timingData.bytesDownloaded += calculation.bytesDownloaded;
|
|
330
330
|
}
|
|
331
331
|
}
|
|
332
|
-
|
|
333
|
-
const completeNodeTimingEntries = this.
|
|
334
|
-
return [node, this.
|
|
332
|
+
computeFinalNodeTimings() {
|
|
333
|
+
const completeNodeTimingEntries = this.nodeTimings.getNodes().map(node => {
|
|
334
|
+
return [node, this.nodeTimings.getCompleted(node)];
|
|
335
335
|
});
|
|
336
336
|
// Most consumers will want the entries sorted by startTime, so insert them in that order
|
|
337
337
|
completeNodeTimingEntries.sort((a, b) => a[1].startTime - b[1].startTime);
|
|
@@ -352,7 +352,7 @@ class Simulator {
|
|
|
352
352
|
};
|
|
353
353
|
}
|
|
354
354
|
getOptions() {
|
|
355
|
-
return this.
|
|
355
|
+
return this.options;
|
|
356
356
|
}
|
|
357
357
|
/**
|
|
358
358
|
* Estimates the time taken to process all of the graph's nodes, returns the overall time along with
|
|
@@ -371,23 +371,23 @@ class Simulator {
|
|
|
371
371
|
label: undefined,
|
|
372
372
|
}, options);
|
|
373
373
|
// initialize the necessary data containers
|
|
374
|
-
this.
|
|
375
|
-
this.
|
|
376
|
-
this.
|
|
377
|
-
const nodesNotReadyToStart = this.
|
|
378
|
-
const nodesReadyToStart = this.
|
|
379
|
-
const nodesInProgress = this.
|
|
374
|
+
this.dns = new DNSCache({ rtt: this._rtt });
|
|
375
|
+
this.initializeConnectionPool(graph);
|
|
376
|
+
this.initializeAuxiliaryData();
|
|
377
|
+
const nodesNotReadyToStart = this.nodes[NodeState.NotReadyToStart];
|
|
378
|
+
const nodesReadyToStart = this.nodes[NodeState.ReadyToStart];
|
|
379
|
+
const nodesInProgress = this.nodes[NodeState.InProgress];
|
|
380
380
|
const rootNode = graph.getRootNode();
|
|
381
381
|
rootNode.traverse(node => nodesNotReadyToStart.add(node));
|
|
382
382
|
let totalElapsedTime = 0;
|
|
383
383
|
let iteration = 0;
|
|
384
384
|
// root node is always ready to start
|
|
385
|
-
this.
|
|
385
|
+
this.markNodeAsReadyToStart(rootNode, totalElapsedTime);
|
|
386
386
|
// loop as long as we have nodes in the queue or currently in progress
|
|
387
387
|
while (nodesReadyToStart.size || nodesInProgress.size) {
|
|
388
388
|
// move all possible queued nodes to in progress
|
|
389
|
-
for (const node of this.
|
|
390
|
-
this.
|
|
389
|
+
for (const node of this.getNodesSortedByStartPosition()) {
|
|
390
|
+
this.startNodeIfPossible(node, totalElapsedTime);
|
|
391
391
|
}
|
|
392
392
|
if (!nodesInProgress.size) {
|
|
393
393
|
// Interplay between fromDiskCache and connectionReused can be incorrect,
|
|
@@ -395,9 +395,9 @@ class Simulator {
|
|
|
395
395
|
throw new Core.LanternError('Failed to start a node');
|
|
396
396
|
}
|
|
397
397
|
// set the available throughput for all connections based on # inflight
|
|
398
|
-
this.
|
|
398
|
+
this.updateNetworkCapacity();
|
|
399
399
|
// find the time that the next node will finish
|
|
400
|
-
const minimumTime = this.
|
|
400
|
+
const minimumTime = this.findNextNodeCompletionTime();
|
|
401
401
|
totalElapsedTime += minimumTime;
|
|
402
402
|
// While this is no longer strictly necessary, it's always better than hanging
|
|
403
403
|
if (!Number.isFinite(minimumTime) || iteration > 100000) {
|
|
@@ -406,11 +406,11 @@ class Simulator {
|
|
|
406
406
|
iteration++;
|
|
407
407
|
// update how far each node will progress until that point
|
|
408
408
|
for (const node of nodesInProgress) {
|
|
409
|
-
this.
|
|
409
|
+
this.updateProgressMadeInTimePeriod(node, minimumTime, totalElapsedTime);
|
|
410
410
|
}
|
|
411
411
|
}
|
|
412
412
|
// `nodeTimings` are used for simulator consumers, `completeNodeTimings` kept for debugging.
|
|
413
|
-
const { nodeTimings, completeNodeTimings } = this.
|
|
413
|
+
const { nodeTimings, completeNodeTimings } = this.computeFinalNodeTimings();
|
|
414
414
|
ALL_SIMULATION_NODE_TIMINGS.set(options.label || 'unlabeled', completeNodeTimings);
|
|
415
415
|
return {
|
|
416
416
|
timeInMs: totalElapsedTime,
|
|
@@ -418,7 +418,7 @@ class Simulator {
|
|
|
418
418
|
};
|
|
419
419
|
}
|
|
420
420
|
computeWastedMsFromWastedBytes(wastedBytes) {
|
|
421
|
-
const { throughput, observedThroughput } = this.
|
|
421
|
+
const { throughput, observedThroughput } = this.options;
|
|
422
422
|
// https://github.com/GoogleChrome/lighthouse/pull/13323#issuecomment-962031709
|
|
423
423
|
// 0 throughput means the no (additional) throttling is expected.
|
|
424
424
|
// This is common for desktop + devtools throttling where throttling is additive and we don't want any additional.
|
|
@@ -439,7 +439,7 @@ class Simulator {
|
|
|
439
439
|
* When simulating, just because a low priority image started 5ms before a high priority image doesn't mean
|
|
440
440
|
* it would have happened like that when the network was slower.
|
|
441
441
|
*/
|
|
442
|
-
static
|
|
442
|
+
static computeNodeStartPosition(node) {
|
|
443
443
|
if (node.type === 'cpu') {
|
|
444
444
|
return node.startTime;
|
|
445
445
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Simulator.js","sourceRoot":"","sources":["../../../../../../../../front_end/models/trace/lantern/simulation/Simulator.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright 2024 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 Core from '../core/core.js';\nimport * as Graph from '../graph/graph.js';\nimport type * as Lantern from '../types/types.js';\n\nimport {ConnectionPool} from './ConnectionPool.js';\nimport {Constants} from './Constants.js';\nimport {DNSCache} from './DNSCache.js';\nimport {type CompleteNodeTiming, type ConnectionTiming, SimulatorTimingMap} from './SimulationTimingMap.js';\nimport {TCPConnection} from './TCPConnection.js';\n\nexport interface Result<T = Lantern.AnyNetworkObject> {\n timeInMs: number;\n nodeTimings: Map<Graph.Node<T>, Lantern.Simulation.NodeTiming>;\n}\n\nconst defaultThrottling = Constants.throttling.mobileSlow4G;\n\n// see https://cs.chromium.org/search/?q=kDefaultMaxNumDelayableRequestsPerClient&sq=package:chromium&type=cs\nconst DEFAULT_MAXIMUM_CONCURRENT_REQUESTS = 10;\n// layout tasks tend to be less CPU-bound and do not experience the same increase in duration\nconst DEFAULT_LAYOUT_TASK_MULTIPLIER = 0.5;\n// if a task takes more than 10 seconds it's usually a sign it isn't actually CPU bound and we're overestimating\nconst DEFAULT_MAXIMUM_CPU_TASK_DURATION = 10000;\n\nconst NodeState = {\n NotReadyToStart: 0,\n ReadyToStart: 1,\n InProgress: 2,\n Complete: 3,\n};\n\nconst PriorityStartTimePenalty: Record<Lantern.ResourcePriority, number> = {\n VeryHigh: 0,\n High: 0.25,\n Medium: 0.5,\n Low: 1,\n VeryLow: 2,\n};\n\nconst ALL_SIMULATION_NODE_TIMINGS = new Map<string, Map<Graph.Node, CompleteNodeTiming>>();\n\nclass Simulator<T = Lantern.AnyNetworkObject> {\n static createSimulator(settings: Lantern.Simulation.Settings): Simulator {\n const {throttlingMethod, throttling, precomputedLanternData, networkAnalysis} = settings;\n\n const options: Lantern.Simulation.Options = {\n additionalRttByOrigin: networkAnalysis.additionalRttByOrigin,\n serverResponseTimeByOrigin: networkAnalysis.serverResponseTimeByOrigin,\n observedThroughput: networkAnalysis.throughput,\n };\n\n // If we have precomputed lantern data, overwrite our observed estimates and use precomputed instead\n // for increased stability.\n if (precomputedLanternData) {\n options.additionalRttByOrigin = new Map(Object.entries(precomputedLanternData.additionalRttByOrigin));\n options.serverResponseTimeByOrigin = new Map(Object.entries(precomputedLanternData.serverResponseTimeByOrigin));\n }\n\n switch (throttlingMethod) {\n case 'provided':\n options.rtt = networkAnalysis.rtt;\n options.throughput = networkAnalysis.throughput;\n options.cpuSlowdownMultiplier = 1;\n options.layoutTaskMultiplier = 1;\n break;\n case 'devtools':\n if (throttling) {\n options.rtt = throttling.requestLatencyMs / Constants.throttling.DEVTOOLS_RTT_ADJUSTMENT_FACTOR;\n options.throughput =\n throttling.downloadThroughputKbps * 1024 / Constants.throttling.DEVTOOLS_THROUGHPUT_ADJUSTMENT_FACTOR;\n }\n\n options.cpuSlowdownMultiplier = 1;\n options.layoutTaskMultiplier = 1;\n break;\n case 'simulate':\n if (throttling) {\n options.rtt = throttling.rttMs;\n options.throughput = throttling.throughputKbps * 1024;\n options.cpuSlowdownMultiplier = throttling.cpuSlowdownMultiplier;\n }\n break;\n default:\n // intentionally fallback to simulator defaults\n break;\n }\n\n return new Simulator(options);\n }\n\n _options: Required<Lantern.Simulation.Options>;\n _rtt: number;\n _throughput: number;\n _maximumConcurrentRequests: number;\n _cpuSlowdownMultiplier: number;\n _layoutTaskMultiplier: number;\n _cachedNodeListByStartPosition: Graph.Node[];\n _nodeTimings: SimulatorTimingMap;\n _numberInProgressByType: Map<string, number>;\n _nodes: Record<number, Set<Graph.Node>>;\n _dns: DNSCache;\n _connectionPool: ConnectionPool;\n\n constructor(options?: Lantern.Simulation.Options) {\n this._options = Object.assign(\n {\n rtt: defaultThrottling.rttMs,\n throughput: defaultThrottling.throughputKbps * 1024,\n maximumConcurrentRequests: DEFAULT_MAXIMUM_CONCURRENT_REQUESTS,\n cpuSlowdownMultiplier: defaultThrottling.cpuSlowdownMultiplier,\n layoutTaskMultiplier: DEFAULT_LAYOUT_TASK_MULTIPLIER,\n additionalRttByOrigin: new Map(),\n serverResponseTimeByOrigin: new Map(),\n },\n options,\n );\n\n this._rtt = this._options.rtt;\n this._throughput = this._options.throughput;\n this._maximumConcurrentRequests = Math.max(\n Math.min(\n TCPConnection.maximumSaturatedConnections(this._rtt, this._throughput),\n this._options.maximumConcurrentRequests,\n ),\n 1);\n this._cpuSlowdownMultiplier = this._options.cpuSlowdownMultiplier;\n this._layoutTaskMultiplier = this._cpuSlowdownMultiplier * this._options.layoutTaskMultiplier;\n this._cachedNodeListByStartPosition = [];\n\n // Properties reset on every `.simulate` call but duplicated here for type checking\n this._nodeTimings = new SimulatorTimingMap();\n this._numberInProgressByType = new Map<string, number>();\n this._nodes = {};\n this._dns = new DNSCache({rtt: this._rtt});\n // @ts-expect-error\n this._connectionPool = null;\n\n if (!Number.isFinite(this._rtt)) {\n throw new Core.LanternError(`Invalid rtt ${this._rtt}`);\n }\n if (!Number.isFinite(this._throughput)) {\n throw new Core.LanternError(`Invalid rtt ${this._throughput}`);\n }\n }\n\n get rtt(): number {\n return this._rtt;\n }\n\n _initializeConnectionPool(graph: Graph.Node): void {\n const records: Lantern.NetworkRequest[] = [];\n graph.getRootNode().traverse(node => {\n if (node.type === Graph.BaseNode.types.NETWORK) {\n records.push(node.request);\n }\n });\n\n this._connectionPool = new ConnectionPool(records, this._options);\n }\n\n /**\n * Initializes the various state data structures such _nodeTimings and the _node Sets by state.\n */\n _initializeAuxiliaryData(): void {\n this._nodeTimings = new SimulatorTimingMap();\n this._numberInProgressByType = new Map();\n\n this._nodes = {};\n this._cachedNodeListByStartPosition = [];\n // NOTE: We don't actually need *all* of these sets, but the clarity that each node progresses\n // through the system is quite nice.\n for (const state of Object.values(NodeState)) {\n this._nodes[state] = new Set();\n }\n }\n\n _numberInProgress(type: string): number {\n return this._numberInProgressByType.get(type) || 0;\n }\n\n _markNodeAsReadyToStart(node: Graph.Node, queuedTime: number): void {\n const nodeStartPosition = Simulator._computeNodeStartPosition(node);\n const firstNodeIndexWithGreaterStartPosition = this._cachedNodeListByStartPosition.findIndex(\n candidate => Simulator._computeNodeStartPosition(candidate) > nodeStartPosition);\n const insertionIndex = firstNodeIndexWithGreaterStartPosition === -1 ? this._cachedNodeListByStartPosition.length :\n firstNodeIndexWithGreaterStartPosition;\n this._cachedNodeListByStartPosition.splice(insertionIndex, 0, node);\n\n this._nodes[NodeState.ReadyToStart].add(node);\n this._nodes[NodeState.NotReadyToStart].delete(node);\n this._nodeTimings.setReadyToStart(node, {queuedTime});\n }\n\n _markNodeAsInProgress(node: Graph.Node, startTime: number): void {\n const indexOfNodeToStart = this._cachedNodeListByStartPosition.indexOf(node);\n this._cachedNodeListByStartPosition.splice(indexOfNodeToStart, 1);\n\n this._nodes[NodeState.InProgress].add(node);\n this._nodes[NodeState.ReadyToStart].delete(node);\n this._numberInProgressByType.set(node.type, this._numberInProgress(node.type) + 1);\n this._nodeTimings.setInProgress(node, {startTime});\n }\n\n _markNodeAsComplete(node: Graph.Node, endTime: number, connectionTiming?: ConnectionTiming): void {\n this._nodes[NodeState.Complete].add(node);\n this._nodes[NodeState.InProgress].delete(node);\n this._numberInProgressByType.set(node.type, this._numberInProgress(node.type) - 1);\n this._nodeTimings.setCompleted(node, {endTime, connectionTiming});\n\n // Try to add all its dependents to the queue\n for (const dependent of node.getDependents()) {\n // Skip dependent node if one of its dependencies hasn't finished yet\n const dependencies = dependent.getDependencies();\n if (dependencies.some(dep => !this._nodes[NodeState.Complete].has(dep))) {\n continue;\n }\n\n // Otherwise add it to the queue\n this._markNodeAsReadyToStart(dependent, endTime);\n }\n }\n\n _acquireConnection(request: Lantern.NetworkRequest): TCPConnection|null {\n return this._connectionPool.acquire(request);\n }\n\n _getNodesSortedByStartPosition(): Graph.Node[] {\n // Make a copy so we don't skip nodes due to concurrent modification\n return Array.from(this._cachedNodeListByStartPosition);\n }\n\n _startNodeIfPossible(node: Graph.Node, totalElapsedTime: number): void {\n if (node.type === Graph.BaseNode.types.CPU) {\n // Start a CPU task if there's no other CPU task in process\n if (this._numberInProgress(node.type) === 0) {\n this._markNodeAsInProgress(node, totalElapsedTime);\n }\n\n return;\n }\n\n if (node.type !== Graph.BaseNode.types.NETWORK) {\n throw new Core.LanternError('Unsupported');\n }\n\n // If a network request is connectionless, we can always start it, so skip the connection checks\n if (!node.isConnectionless) {\n // Start a network request if we're not at max requests and a connection is available\n const numberOfActiveRequests = this._numberInProgress(node.type);\n if (numberOfActiveRequests >= this._maximumConcurrentRequests) {\n return;\n }\n const connection = this._acquireConnection(node.request);\n if (!connection) {\n return;\n }\n }\n\n this._markNodeAsInProgress(node, totalElapsedTime);\n }\n\n /**\n * Updates each connection in use with the available throughput based on the number of network requests\n * currently in flight.\n */\n _updateNetworkCapacity(): void {\n const inFlight = this._numberInProgress(Graph.BaseNode.types.NETWORK);\n if (inFlight === 0) {\n return;\n }\n\n for (const connection of this._connectionPool.connectionsInUse()) {\n connection.setThroughput(this._throughput / inFlight);\n }\n }\n\n /**\n * Estimates the number of milliseconds remaining given current condidtions before the node is complete.\n */\n _estimateTimeRemaining(node: Graph.Node): number {\n if (node.type === Graph.BaseNode.types.CPU) {\n return this._estimateCPUTimeRemaining(node);\n }\n if (node.type === Graph.BaseNode.types.NETWORK) {\n return this._estimateNetworkTimeRemaining(node);\n }\n throw new Core.LanternError('Unsupported');\n }\n\n _estimateCPUTimeRemaining(cpuNode: Graph.CPUNode): number {\n const timingData = this._nodeTimings.getCpuStarted(cpuNode);\n const multiplier = cpuNode.didPerformLayout() ? this._layoutTaskMultiplier : this._cpuSlowdownMultiplier;\n const totalDuration = Math.min(\n Math.round(cpuNode.duration / 1000 * multiplier),\n DEFAULT_MAXIMUM_CPU_TASK_DURATION,\n );\n const estimatedTimeElapsed = totalDuration - timingData.timeElapsed;\n this._nodeTimings.setCpuEstimated(cpuNode, {estimatedTimeElapsed});\n return estimatedTimeElapsed;\n }\n\n _estimateNetworkTimeRemaining(networkNode: Graph.NetworkNode): number {\n const request = networkNode.request;\n const timingData = this._nodeTimings.getNetworkStarted(networkNode);\n\n let timeElapsed = 0;\n if (networkNode.fromDiskCache) {\n // Rough access time for seeking to location on disk and reading sequentially.\n // 8ms per seek + 20ms/MB\n // @see http://norvig.com/21-days.html#answers\n const sizeInMb = (request.resourceSize || 0) / 1024 / 1024;\n timeElapsed = 8 + 20 * sizeInMb - timingData.timeElapsed;\n } else if (networkNode.isNonNetworkProtocol) {\n // Estimates for the overhead of a data URL in Chromium and the decoding time for base64-encoded data.\n // 2ms per request + 10ms/MB\n // @see traces on https://dopiaza.org/tools/datauri/examples/index.php\n const sizeInMb = (request.resourceSize || 0) / 1024 / 1024;\n timeElapsed = 2 + 10 * sizeInMb - timingData.timeElapsed;\n } else {\n const connection = this._connectionPool.acquireActiveConnectionFromRequest(request);\n const dnsResolutionTime = this._dns.getTimeUntilResolution(request, {\n requestedAt: timingData.startTime,\n shouldUpdateCache: true,\n });\n const timeAlreadyElapsed = timingData.timeElapsed;\n const calculation = connection.simulateDownloadUntil(\n request.transferSize - timingData.bytesDownloaded,\n {timeAlreadyElapsed, dnsResolutionTime, maximumTimeToElapse: Infinity},\n );\n\n timeElapsed = calculation.timeElapsed;\n }\n\n const estimatedTimeElapsed = timeElapsed + timingData.timeElapsedOvershoot;\n this._nodeTimings.setNetworkEstimated(networkNode, {estimatedTimeElapsed});\n return estimatedTimeElapsed;\n }\n\n /**\n * Computes and returns the minimum estimated completion time of the nodes currently in progress.\n */\n _findNextNodeCompletionTime(): number {\n let minimumTime = Infinity;\n for (const node of this._nodes[NodeState.InProgress]) {\n minimumTime = Math.min(minimumTime, this._estimateTimeRemaining(node));\n }\n\n return minimumTime;\n }\n\n /**\n * Given a time period, computes the progress toward completion that the node made durin that time.\n */\n _updateProgressMadeInTimePeriod(node: Graph.Node, timePeriodLength: number, totalElapsedTime: number): void {\n const timingData = this._nodeTimings.getInProgress(node);\n const isFinished = timingData.estimatedTimeElapsed === timePeriodLength;\n\n if (node.type === Graph.BaseNode.types.CPU || node.isConnectionless) {\n if (isFinished) {\n this._markNodeAsComplete(node, totalElapsedTime);\n } else {\n timingData.timeElapsed += timePeriodLength;\n }\n return;\n }\n\n if (node.type !== Graph.BaseNode.types.NETWORK) {\n throw new Core.LanternError('Unsupported');\n }\n if (!('bytesDownloaded' in timingData)) {\n throw new Core.LanternError('Invalid timing data');\n }\n\n const request = node.request;\n const connection = this._connectionPool.acquireActiveConnectionFromRequest(request);\n const dnsResolutionTime = this._dns.getTimeUntilResolution(request, {\n requestedAt: timingData.startTime,\n shouldUpdateCache: true,\n });\n const calculation = connection.simulateDownloadUntil(\n request.transferSize - timingData.bytesDownloaded,\n {\n dnsResolutionTime,\n timeAlreadyElapsed: timingData.timeElapsed,\n maximumTimeToElapse: timePeriodLength - timingData.timeElapsedOvershoot,\n },\n );\n\n connection.setCongestionWindow(calculation.congestionWindow);\n connection.setH2OverflowBytesDownloaded(calculation.extraBytesDownloaded);\n\n if (isFinished) {\n connection.setWarmed(true);\n this._connectionPool.release(request);\n this._markNodeAsComplete(node, totalElapsedTime, calculation.connectionTiming);\n } else {\n timingData.timeElapsed += calculation.timeElapsed;\n timingData.timeElapsedOvershoot += calculation.timeElapsed - timePeriodLength;\n timingData.bytesDownloaded += calculation.bytesDownloaded;\n }\n }\n\n _computeFinalNodeTimings(): {\n nodeTimings: Map<Graph.Node, Lantern.Simulation.NodeTiming>,\n completeNodeTimings: Map<Graph.Node, CompleteNodeTiming>,\n } {\n const completeNodeTimingEntries: Array<[Graph.Node, CompleteNodeTiming]> =\n this._nodeTimings.getNodes().map(node => {\n return [node, this._nodeTimings.getCompleted(node)];\n });\n\n // Most consumers will want the entries sorted by startTime, so insert them in that order\n completeNodeTimingEntries.sort((a, b) => a[1].startTime - b[1].startTime);\n\n // Trimmed version of type `Lantern.Simulation.NodeTiming`.\n const nodeTimingEntries: Array<[Graph.Node, Lantern.Simulation.NodeTiming]> =\n completeNodeTimingEntries.map(([node, timing]) => {\n return [\n node,\n {\n startTime: timing.startTime,\n endTime: timing.endTime,\n duration: timing.endTime - timing.startTime,\n },\n ];\n });\n\n return {\n nodeTimings: new Map(nodeTimingEntries),\n completeNodeTimings: new Map(completeNodeTimingEntries),\n };\n }\n\n getOptions(): Required<Lantern.Simulation.Options> {\n return this._options;\n }\n\n /**\n * Estimates the time taken to process all of the graph's nodes, returns the overall time along with\n * each node annotated by start/end times.\n *\n * Simulator/connection pool are allowed to deviate from what was\n * observed in the trace/devtoolsLog and start requests as soon as they are queued (i.e. do not\n * wait around for a warm connection to be available if the original request was fetched on a warm\n * connection).\n */\n simulate(graph: Graph.Node, options?: {label?: string}): Result<T> {\n if (Graph.BaseNode.hasCycle(graph)) {\n throw new Core.LanternError('Cannot simulate graph with cycle');\n }\n\n options = Object.assign(\n {\n label: undefined,\n },\n options);\n\n // initialize the necessary data containers\n this._dns = new DNSCache({rtt: this._rtt});\n this._initializeConnectionPool(graph);\n this._initializeAuxiliaryData();\n\n const nodesNotReadyToStart = this._nodes[NodeState.NotReadyToStart];\n const nodesReadyToStart = this._nodes[NodeState.ReadyToStart];\n const nodesInProgress = this._nodes[NodeState.InProgress];\n\n const rootNode = graph.getRootNode();\n rootNode.traverse(node => nodesNotReadyToStart.add(node));\n let totalElapsedTime = 0;\n let iteration = 0;\n\n // root node is always ready to start\n this._markNodeAsReadyToStart(rootNode, totalElapsedTime);\n\n // loop as long as we have nodes in the queue or currently in progress\n while (nodesReadyToStart.size || nodesInProgress.size) {\n // move all possible queued nodes to in progress\n for (const node of this._getNodesSortedByStartPosition()) {\n this._startNodeIfPossible(node, totalElapsedTime);\n }\n\n if (!nodesInProgress.size) {\n // Interplay between fromDiskCache and connectionReused can be incorrect,\n // have to give up.\n throw new Core.LanternError('Failed to start a node');\n }\n\n // set the available throughput for all connections based on # inflight\n this._updateNetworkCapacity();\n\n // find the time that the next node will finish\n const minimumTime = this._findNextNodeCompletionTime();\n totalElapsedTime += minimumTime;\n\n // While this is no longer strictly necessary, it's always better than hanging\n if (!Number.isFinite(minimumTime) || iteration > 100000) {\n throw new Core.LanternError('Simulation failed, depth exceeded');\n }\n\n iteration++;\n // update how far each node will progress until that point\n for (const node of nodesInProgress) {\n this._updateProgressMadeInTimePeriod(node, minimumTime, totalElapsedTime);\n }\n }\n\n // `nodeTimings` are used for simulator consumers, `completeNodeTimings` kept for debugging.\n const {nodeTimings, completeNodeTimings} = this._computeFinalNodeTimings();\n ALL_SIMULATION_NODE_TIMINGS.set(options.label || 'unlabeled', completeNodeTimings);\n\n return {\n timeInMs: totalElapsedTime,\n nodeTimings,\n };\n }\n\n computeWastedMsFromWastedBytes(wastedBytes: number): number {\n const {throughput, observedThroughput} = this._options;\n\n // https://github.com/GoogleChrome/lighthouse/pull/13323#issuecomment-962031709\n // 0 throughput means the no (additional) throttling is expected.\n // This is common for desktop + devtools throttling where throttling is additive and we don't want any additional.\n const bitsPerSecond = throughput === 0 ? observedThroughput : throughput;\n if (bitsPerSecond === 0) {\n return 0;\n }\n\n const wastedBits = wastedBytes * 8;\n const wastedMs = wastedBits / bitsPerSecond * 1000;\n\n // This is an estimate of wasted time, so we won't be more precise than 10ms.\n return Math.round(wastedMs / 10) * 10;\n }\n\n static get allNodeTimings(): Map<string, Map<Graph.Node, CompleteNodeTiming>> {\n return ALL_SIMULATION_NODE_TIMINGS;\n }\n\n /**\n * We attempt to start nodes by their observed start time using the request priority as a tie breaker.\n * When simulating, just because a low priority image started 5ms before a high priority image doesn't mean\n * it would have happened like that when the network was slower.\n */\n static _computeNodeStartPosition(node: Graph.Node): number {\n if (node.type === 'cpu') {\n return node.startTime;\n }\n return node.startTime + (PriorityStartTimePenalty[node.request.priority] * 1000 * 1000 || 0);\n }\n}\n\nexport {Simulator};\n"]}
|
|
1
|
+
{"version":3,"file":"Simulator.js","sourceRoot":"","sources":["../../../../../../../../front_end/models/trace/lantern/simulation/Simulator.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright 2024 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 Core from '../core/core.js';\nimport * as Graph from '../graph/graph.js';\nimport type * as Lantern from '../types/types.js';\n\nimport {ConnectionPool} from './ConnectionPool.js';\nimport {Constants} from './Constants.js';\nimport {DNSCache} from './DNSCache.js';\nimport {type CompleteNodeTiming, type ConnectionTiming, SimulatorTimingMap} from './SimulationTimingMap.js';\nimport {TCPConnection} from './TCPConnection.js';\n\nexport interface Result<T = Lantern.AnyNetworkObject> {\n timeInMs: number;\n nodeTimings: Map<Graph.Node<T>, Lantern.Simulation.NodeTiming>;\n}\n\nconst defaultThrottling = Constants.throttling.mobileSlow4G;\n\n// see https://cs.chromium.org/search/?q=kDefaultMaxNumDelayableRequestsPerClient&sq=package:chromium&type=cs\nconst DEFAULT_MAXIMUM_CONCURRENT_REQUESTS = 10;\n// layout tasks tend to be less CPU-bound and do not experience the same increase in duration\nconst DEFAULT_LAYOUT_TASK_MULTIPLIER = 0.5;\n// if a task takes more than 10 seconds it's usually a sign it isn't actually CPU bound and we're overestimating\nconst DEFAULT_MAXIMUM_CPU_TASK_DURATION = 10000;\n\nconst NodeState = {\n NotReadyToStart: 0,\n ReadyToStart: 1,\n InProgress: 2,\n Complete: 3,\n};\n\nconst PriorityStartTimePenalty: Record<Lantern.ResourcePriority, number> = {\n VeryHigh: 0,\n High: 0.25,\n Medium: 0.5,\n Low: 1,\n VeryLow: 2,\n};\n\nconst ALL_SIMULATION_NODE_TIMINGS = new Map<string, Map<Graph.Node, CompleteNodeTiming>>();\n\nclass Simulator<T = Lantern.AnyNetworkObject> {\n static createSimulator(settings: Lantern.Simulation.Settings): Simulator {\n const {throttlingMethod, throttling, precomputedLanternData, networkAnalysis} = settings;\n\n const options: Lantern.Simulation.Options = {\n additionalRttByOrigin: networkAnalysis.additionalRttByOrigin,\n serverResponseTimeByOrigin: networkAnalysis.serverResponseTimeByOrigin,\n observedThroughput: networkAnalysis.throughput,\n };\n\n // If we have precomputed lantern data, overwrite our observed estimates and use precomputed instead\n // for increased stability.\n if (precomputedLanternData) {\n options.additionalRttByOrigin = new Map(Object.entries(precomputedLanternData.additionalRttByOrigin));\n options.serverResponseTimeByOrigin = new Map(Object.entries(precomputedLanternData.serverResponseTimeByOrigin));\n }\n\n switch (throttlingMethod) {\n case 'provided':\n options.rtt = networkAnalysis.rtt;\n options.throughput = networkAnalysis.throughput;\n options.cpuSlowdownMultiplier = 1;\n options.layoutTaskMultiplier = 1;\n break;\n case 'devtools':\n if (throttling) {\n options.rtt = throttling.requestLatencyMs / Constants.throttling.DEVTOOLS_RTT_ADJUSTMENT_FACTOR;\n options.throughput =\n throttling.downloadThroughputKbps * 1024 / Constants.throttling.DEVTOOLS_THROUGHPUT_ADJUSTMENT_FACTOR;\n }\n\n options.cpuSlowdownMultiplier = 1;\n options.layoutTaskMultiplier = 1;\n break;\n case 'simulate':\n if (throttling) {\n options.rtt = throttling.rttMs;\n options.throughput = throttling.throughputKbps * 1024;\n options.cpuSlowdownMultiplier = throttling.cpuSlowdownMultiplier;\n }\n break;\n default:\n // intentionally fallback to simulator defaults\n break;\n }\n\n return new Simulator(options);\n }\n\n options: Required<Lantern.Simulation.Options>;\n _rtt: number;\n throughput: number;\n maximumConcurrentRequests: number;\n cpuSlowdownMultiplier: number;\n layoutTaskMultiplier: number;\n cachedNodeListByStartPosition: Graph.Node[];\n nodeTimings: SimulatorTimingMap;\n numberInProgressByType: Map<string, number>;\n nodes: Record<number, Set<Graph.Node>>;\n dns: DNSCache;\n connectionPool: ConnectionPool;\n\n constructor(options?: Lantern.Simulation.Options) {\n this.options = Object.assign(\n {\n rtt: defaultThrottling.rttMs,\n throughput: defaultThrottling.throughputKbps * 1024,\n maximumConcurrentRequests: DEFAULT_MAXIMUM_CONCURRENT_REQUESTS,\n cpuSlowdownMultiplier: defaultThrottling.cpuSlowdownMultiplier,\n layoutTaskMultiplier: DEFAULT_LAYOUT_TASK_MULTIPLIER,\n additionalRttByOrigin: new Map(),\n serverResponseTimeByOrigin: new Map(),\n },\n options,\n );\n\n this._rtt = this.options.rtt;\n this.throughput = this.options.throughput;\n this.maximumConcurrentRequests = Math.max(\n Math.min(\n TCPConnection.maximumSaturatedConnections(this._rtt, this.throughput),\n this.options.maximumConcurrentRequests,\n ),\n 1);\n this.cpuSlowdownMultiplier = this.options.cpuSlowdownMultiplier;\n this.layoutTaskMultiplier = this.cpuSlowdownMultiplier * this.options.layoutTaskMultiplier;\n this.cachedNodeListByStartPosition = [];\n\n // Properties reset on every `.simulate` call but duplicated here for type checking\n this.nodeTimings = new SimulatorTimingMap();\n this.numberInProgressByType = new Map<string, number>();\n this.nodes = {};\n this.dns = new DNSCache({rtt: this._rtt});\n // @ts-expect-error\n this.connectionPool = null;\n\n if (!Number.isFinite(this._rtt)) {\n throw new Core.LanternError(`Invalid rtt ${this._rtt}`);\n }\n if (!Number.isFinite(this.throughput)) {\n throw new Core.LanternError(`Invalid rtt ${this.throughput}`);\n }\n }\n\n get rtt(): number {\n return this._rtt;\n }\n\n initializeConnectionPool(graph: Graph.Node): void {\n const records: Lantern.NetworkRequest[] = [];\n graph.getRootNode().traverse(node => {\n if (node.type === Graph.BaseNode.types.NETWORK) {\n records.push(node.request);\n }\n });\n\n this.connectionPool = new ConnectionPool(records, this.options);\n }\n\n /**\n * Initializes the various state data structures such _nodeTimings and the _node Sets by state.\n */\n initializeAuxiliaryData(): void {\n this.nodeTimings = new SimulatorTimingMap();\n this.numberInProgressByType = new Map();\n\n this.nodes = {};\n this.cachedNodeListByStartPosition = [];\n // NOTE: We don't actually need *all* of these sets, but the clarity that each node progresses\n // through the system is quite nice.\n for (const state of Object.values(NodeState)) {\n this.nodes[state] = new Set();\n }\n }\n\n numberInProgress(type: string): number {\n return this.numberInProgressByType.get(type) || 0;\n }\n\n markNodeAsReadyToStart(node: Graph.Node, queuedTime: number): void {\n const nodeStartPosition = Simulator.computeNodeStartPosition(node);\n const firstNodeIndexWithGreaterStartPosition = this.cachedNodeListByStartPosition.findIndex(\n candidate => Simulator.computeNodeStartPosition(candidate) > nodeStartPosition);\n const insertionIndex = firstNodeIndexWithGreaterStartPosition === -1 ? this.cachedNodeListByStartPosition.length :\n firstNodeIndexWithGreaterStartPosition;\n this.cachedNodeListByStartPosition.splice(insertionIndex, 0, node);\n\n this.nodes[NodeState.ReadyToStart].add(node);\n this.nodes[NodeState.NotReadyToStart].delete(node);\n this.nodeTimings.setReadyToStart(node, {queuedTime});\n }\n\n markNodeAsInProgress(node: Graph.Node, startTime: number): void {\n const indexOfNodeToStart = this.cachedNodeListByStartPosition.indexOf(node);\n this.cachedNodeListByStartPosition.splice(indexOfNodeToStart, 1);\n\n this.nodes[NodeState.InProgress].add(node);\n this.nodes[NodeState.ReadyToStart].delete(node);\n this.numberInProgressByType.set(node.type, this.numberInProgress(node.type) + 1);\n this.nodeTimings.setInProgress(node, {startTime});\n }\n\n markNodeAsComplete(node: Graph.Node, endTime: number, connectionTiming?: ConnectionTiming): void {\n this.nodes[NodeState.Complete].add(node);\n this.nodes[NodeState.InProgress].delete(node);\n this.numberInProgressByType.set(node.type, this.numberInProgress(node.type) - 1);\n this.nodeTimings.setCompleted(node, {endTime, connectionTiming});\n\n // Try to add all its dependents to the queue\n for (const dependent of node.getDependents()) {\n // Skip dependent node if one of its dependencies hasn't finished yet\n const dependencies = dependent.getDependencies();\n if (dependencies.some(dep => !this.nodes[NodeState.Complete].has(dep))) {\n continue;\n }\n\n // Otherwise add it to the queue\n this.markNodeAsReadyToStart(dependent, endTime);\n }\n }\n\n acquireConnection(request: Lantern.NetworkRequest): TCPConnection|null {\n return this.connectionPool.acquire(request);\n }\n\n getNodesSortedByStartPosition(): Graph.Node[] {\n // Make a copy so we don't skip nodes due to concurrent modification\n return Array.from(this.cachedNodeListByStartPosition);\n }\n\n startNodeIfPossible(node: Graph.Node, totalElapsedTime: number): void {\n if (node.type === Graph.BaseNode.types.CPU) {\n // Start a CPU task if there's no other CPU task in process\n if (this.numberInProgress(node.type) === 0) {\n this.markNodeAsInProgress(node, totalElapsedTime);\n }\n\n return;\n }\n\n if (node.type !== Graph.BaseNode.types.NETWORK) {\n throw new Core.LanternError('Unsupported');\n }\n\n // If a network request is connectionless, we can always start it, so skip the connection checks\n if (!node.isConnectionless) {\n // Start a network request if we're not at max requests and a connection is available\n const numberOfActiveRequests = this.numberInProgress(node.type);\n if (numberOfActiveRequests >= this.maximumConcurrentRequests) {\n return;\n }\n const connection = this.acquireConnection(node.request);\n if (!connection) {\n return;\n }\n }\n\n this.markNodeAsInProgress(node, totalElapsedTime);\n }\n\n /**\n * Updates each connection in use with the available throughput based on the number of network requests\n * currently in flight.\n */\n updateNetworkCapacity(): void {\n const inFlight = this.numberInProgress(Graph.BaseNode.types.NETWORK);\n if (inFlight === 0) {\n return;\n }\n\n for (const connection of this.connectionPool.connectionsInUse()) {\n connection.setThroughput(this.throughput / inFlight);\n }\n }\n\n /**\n * Estimates the number of milliseconds remaining given current condidtions before the node is complete.\n */\n estimateTimeRemaining(node: Graph.Node): number {\n if (node.type === Graph.BaseNode.types.CPU) {\n return this.estimateCPUTimeRemaining(node);\n }\n if (node.type === Graph.BaseNode.types.NETWORK) {\n return this.estimateNetworkTimeRemaining(node);\n }\n throw new Core.LanternError('Unsupported');\n }\n\n estimateCPUTimeRemaining(cpuNode: Graph.CPUNode): number {\n const timingData = this.nodeTimings.getCpuStarted(cpuNode);\n const multiplier = cpuNode.didPerformLayout() ? this.layoutTaskMultiplier : this.cpuSlowdownMultiplier;\n const totalDuration = Math.min(\n Math.round(cpuNode.duration / 1000 * multiplier),\n DEFAULT_MAXIMUM_CPU_TASK_DURATION,\n );\n const estimatedTimeElapsed = totalDuration - timingData.timeElapsed;\n this.nodeTimings.setCpuEstimated(cpuNode, {estimatedTimeElapsed});\n return estimatedTimeElapsed;\n }\n\n estimateNetworkTimeRemaining(networkNode: Graph.NetworkNode): number {\n const request = networkNode.request;\n const timingData = this.nodeTimings.getNetworkStarted(networkNode);\n\n let timeElapsed = 0;\n if (networkNode.fromDiskCache) {\n // Rough access time for seeking to location on disk and reading sequentially.\n // 8ms per seek + 20ms/MB\n // @see http://norvig.com/21-days.html#answers\n const sizeInMb = (request.resourceSize || 0) / 1024 / 1024;\n timeElapsed = 8 + 20 * sizeInMb - timingData.timeElapsed;\n } else if (networkNode.isNonNetworkProtocol) {\n // Estimates for the overhead of a data URL in Chromium and the decoding time for base64-encoded data.\n // 2ms per request + 10ms/MB\n // @see traces on https://dopiaza.org/tools/datauri/examples/index.php\n const sizeInMb = (request.resourceSize || 0) / 1024 / 1024;\n timeElapsed = 2 + 10 * sizeInMb - timingData.timeElapsed;\n } else {\n const connection = this.connectionPool.acquireActiveConnectionFromRequest(request);\n const dnsResolutionTime = this.dns.getTimeUntilResolution(request, {\n requestedAt: timingData.startTime,\n shouldUpdateCache: true,\n });\n const timeAlreadyElapsed = timingData.timeElapsed;\n const calculation = connection.simulateDownloadUntil(\n request.transferSize - timingData.bytesDownloaded,\n {timeAlreadyElapsed, dnsResolutionTime, maximumTimeToElapse: Infinity},\n );\n\n timeElapsed = calculation.timeElapsed;\n }\n\n const estimatedTimeElapsed = timeElapsed + timingData.timeElapsedOvershoot;\n this.nodeTimings.setNetworkEstimated(networkNode, {estimatedTimeElapsed});\n return estimatedTimeElapsed;\n }\n\n /**\n * Computes and returns the minimum estimated completion time of the nodes currently in progress.\n */\n findNextNodeCompletionTime(): number {\n let minimumTime = Infinity;\n for (const node of this.nodes[NodeState.InProgress]) {\n minimumTime = Math.min(minimumTime, this.estimateTimeRemaining(node));\n }\n\n return minimumTime;\n }\n\n /**\n * Given a time period, computes the progress toward completion that the node made durin that time.\n */\n updateProgressMadeInTimePeriod(node: Graph.Node, timePeriodLength: number, totalElapsedTime: number): void {\n const timingData = this.nodeTimings.getInProgress(node);\n const isFinished = timingData.estimatedTimeElapsed === timePeriodLength;\n\n if (node.type === Graph.BaseNode.types.CPU || node.isConnectionless) {\n if (isFinished) {\n this.markNodeAsComplete(node, totalElapsedTime);\n } else {\n timingData.timeElapsed += timePeriodLength;\n }\n return;\n }\n\n if (node.type !== Graph.BaseNode.types.NETWORK) {\n throw new Core.LanternError('Unsupported');\n }\n if (!('bytesDownloaded' in timingData)) {\n throw new Core.LanternError('Invalid timing data');\n }\n\n const request = node.request;\n const connection = this.connectionPool.acquireActiveConnectionFromRequest(request);\n const dnsResolutionTime = this.dns.getTimeUntilResolution(request, {\n requestedAt: timingData.startTime,\n shouldUpdateCache: true,\n });\n const calculation = connection.simulateDownloadUntil(\n request.transferSize - timingData.bytesDownloaded,\n {\n dnsResolutionTime,\n timeAlreadyElapsed: timingData.timeElapsed,\n maximumTimeToElapse: timePeriodLength - timingData.timeElapsedOvershoot,\n },\n );\n\n connection.setCongestionWindow(calculation.congestionWindow);\n connection.setH2OverflowBytesDownloaded(calculation.extraBytesDownloaded);\n\n if (isFinished) {\n connection.setWarmed(true);\n this.connectionPool.release(request);\n this.markNodeAsComplete(node, totalElapsedTime, calculation.connectionTiming);\n } else {\n timingData.timeElapsed += calculation.timeElapsed;\n timingData.timeElapsedOvershoot += calculation.timeElapsed - timePeriodLength;\n timingData.bytesDownloaded += calculation.bytesDownloaded;\n }\n }\n\n computeFinalNodeTimings(): {\n nodeTimings: Map<Graph.Node, Lantern.Simulation.NodeTiming>,\n completeNodeTimings: Map<Graph.Node, CompleteNodeTiming>,\n } {\n const completeNodeTimingEntries: Array<[Graph.Node, CompleteNodeTiming]> = this.nodeTimings.getNodes().map(node => {\n return [node, this.nodeTimings.getCompleted(node)];\n });\n\n // Most consumers will want the entries sorted by startTime, so insert them in that order\n completeNodeTimingEntries.sort((a, b) => a[1].startTime - b[1].startTime);\n\n // Trimmed version of type `Lantern.Simulation.NodeTiming`.\n const nodeTimingEntries: Array<[Graph.Node, Lantern.Simulation.NodeTiming]> =\n completeNodeTimingEntries.map(([node, timing]) => {\n return [\n node,\n {\n startTime: timing.startTime,\n endTime: timing.endTime,\n duration: timing.endTime - timing.startTime,\n },\n ];\n });\n\n return {\n nodeTimings: new Map(nodeTimingEntries),\n completeNodeTimings: new Map(completeNodeTimingEntries),\n };\n }\n\n getOptions(): Required<Lantern.Simulation.Options> {\n return this.options;\n }\n\n /**\n * Estimates the time taken to process all of the graph's nodes, returns the overall time along with\n * each node annotated by start/end times.\n *\n * Simulator/connection pool are allowed to deviate from what was\n * observed in the trace/devtoolsLog and start requests as soon as they are queued (i.e. do not\n * wait around for a warm connection to be available if the original request was fetched on a warm\n * connection).\n */\n simulate(graph: Graph.Node, options?: {label?: string}): Result<T> {\n if (Graph.BaseNode.hasCycle(graph)) {\n throw new Core.LanternError('Cannot simulate graph with cycle');\n }\n\n options = Object.assign(\n {\n label: undefined,\n },\n options);\n\n // initialize the necessary data containers\n this.dns = new DNSCache({rtt: this._rtt});\n this.initializeConnectionPool(graph);\n this.initializeAuxiliaryData();\n\n const nodesNotReadyToStart = this.nodes[NodeState.NotReadyToStart];\n const nodesReadyToStart = this.nodes[NodeState.ReadyToStart];\n const nodesInProgress = this.nodes[NodeState.InProgress];\n\n const rootNode = graph.getRootNode();\n rootNode.traverse(node => nodesNotReadyToStart.add(node));\n let totalElapsedTime = 0;\n let iteration = 0;\n\n // root node is always ready to start\n this.markNodeAsReadyToStart(rootNode, totalElapsedTime);\n\n // loop as long as we have nodes in the queue or currently in progress\n while (nodesReadyToStart.size || nodesInProgress.size) {\n // move all possible queued nodes to in progress\n for (const node of this.getNodesSortedByStartPosition()) {\n this.startNodeIfPossible(node, totalElapsedTime);\n }\n\n if (!nodesInProgress.size) {\n // Interplay between fromDiskCache and connectionReused can be incorrect,\n // have to give up.\n throw new Core.LanternError('Failed to start a node');\n }\n\n // set the available throughput for all connections based on # inflight\n this.updateNetworkCapacity();\n\n // find the time that the next node will finish\n const minimumTime = this.findNextNodeCompletionTime();\n totalElapsedTime += minimumTime;\n\n // While this is no longer strictly necessary, it's always better than hanging\n if (!Number.isFinite(minimumTime) || iteration > 100000) {\n throw new Core.LanternError('Simulation failed, depth exceeded');\n }\n\n iteration++;\n // update how far each node will progress until that point\n for (const node of nodesInProgress) {\n this.updateProgressMadeInTimePeriod(node, minimumTime, totalElapsedTime);\n }\n }\n\n // `nodeTimings` are used for simulator consumers, `completeNodeTimings` kept for debugging.\n const {nodeTimings, completeNodeTimings} = this.computeFinalNodeTimings();\n ALL_SIMULATION_NODE_TIMINGS.set(options.label || 'unlabeled', completeNodeTimings);\n\n return {\n timeInMs: totalElapsedTime,\n nodeTimings,\n };\n }\n\n computeWastedMsFromWastedBytes(wastedBytes: number): number {\n const {throughput, observedThroughput} = this.options;\n\n // https://github.com/GoogleChrome/lighthouse/pull/13323#issuecomment-962031709\n // 0 throughput means the no (additional) throttling is expected.\n // This is common for desktop + devtools throttling where throttling is additive and we don't want any additional.\n const bitsPerSecond = throughput === 0 ? observedThroughput : throughput;\n if (bitsPerSecond === 0) {\n return 0;\n }\n\n const wastedBits = wastedBytes * 8;\n const wastedMs = wastedBits / bitsPerSecond * 1000;\n\n // This is an estimate of wasted time, so we won't be more precise than 10ms.\n return Math.round(wastedMs / 10) * 10;\n }\n\n static get allNodeTimings(): Map<string, Map<Graph.Node, CompleteNodeTiming>> {\n return ALL_SIMULATION_NODE_TIMINGS;\n }\n\n /**\n * We attempt to start nodes by their observed start time using the request priority as a tie breaker.\n * When simulating, just because a low priority image started 5ms before a high priority image doesn't mean\n * it would have happened like that when the network was slower.\n */\n static computeNodeStartPosition(node: Graph.Node): number {\n if (node.type === 'cpu') {\n return node.startTime;\n }\n return node.startTime + (PriorityStartTimePenalty[node.request.priority] * 1000 * 1000 || 0);\n }\n}\n\nexport {Simulator};\n"]}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import type { ConnectionTiming } from './SimulationTimingMap.js';
|
|
2
2
|
interface DownloadOptions {
|
|
3
3
|
dnsResolutionTime?: number;
|
|
4
4
|
timeAlreadyElapsed?: number;
|
|
@@ -13,17 +13,17 @@ interface DownloadResults {
|
|
|
13
13
|
connectionTiming: ConnectionTiming;
|
|
14
14
|
}
|
|
15
15
|
declare class TCPConnection {
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
16
|
+
warmed: boolean;
|
|
17
|
+
ssl: boolean;
|
|
18
|
+
h2: boolean;
|
|
19
|
+
rtt: number;
|
|
20
|
+
throughput: number;
|
|
21
|
+
serverLatency: number;
|
|
22
22
|
_congestionWindow: number;
|
|
23
|
-
|
|
23
|
+
h2OverflowBytesDownloaded: number;
|
|
24
24
|
constructor(rtt: number, throughput: number, serverLatency?: number, ssl?: boolean, h2?: boolean);
|
|
25
25
|
static maximumSaturatedConnections(rtt: number, availableThroughput: number): number;
|
|
26
|
-
|
|
26
|
+
computeMaximumCongestionWindowInSegments(): number;
|
|
27
27
|
setThroughput(throughput: number): void;
|
|
28
28
|
setCongestionWindow(congestion: number): void;
|
|
29
29
|
setWarmed(warmed: boolean): void;
|