UNPKG

chrome-devtools-frontend

Version:
197 lines (165 loc) • 6.43 kB
// Copyright 2024 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. /** * @fileoverview * * This class encapsulates the type-related validation logic for moving timing information for nodes * through the different simulation phases. Methods here ensure that the invariants of simulation hold * as nodes are queued, partially simulated, and completed. */ import * as Core from '../core/core.js'; import * as Graph from '../graph/graph.js'; interface NodeTimingComplete { startTime: number; endTime: number; queuedTime: number; estimatedTimeElapsed: number; timeElapsed: number; timeElapsedOvershoot: number; bytesDownloaded: number; } type NodeTimingQueued = Pick<NodeTimingComplete, 'queuedTime'>; type CpuNodeTimingStarted = NodeTimingQueued&Pick<NodeTimingComplete, 'startTime'|'timeElapsed'>; type NetworkNodeTimingStarted = CpuNodeTimingStarted&Pick<NodeTimingComplete, 'timeElapsedOvershoot'|'bytesDownloaded'>; type CpuNodeTimingInProgress = CpuNodeTimingStarted&Pick<NodeTimingComplete, 'estimatedTimeElapsed'>; type NetworkNodeTimingInProgress = NetworkNodeTimingStarted&Pick<NodeTimingComplete, 'estimatedTimeElapsed'>; export type CpuNodeTimingComplete = CpuNodeTimingInProgress&Pick<NodeTimingComplete, 'endTime'>; export type NetworkNodeTimingComplete = NetworkNodeTimingInProgress&Pick<NodeTimingComplete, 'endTime'>&{connectionTiming: ConnectionTiming}; export type CompleteNodeTiming = CpuNodeTimingComplete|NetworkNodeTimingComplete; type NodeTimingData = NodeTimingQueued|CpuNodeTimingStarted|NetworkNodeTimingStarted|CpuNodeTimingInProgress| NetworkNodeTimingInProgress|CpuNodeTimingComplete|NetworkNodeTimingComplete; export interface ConnectionTiming { dnsResolutionTime?: number; connectionTime?: number; sslTime?: number; timeToFirstByte: number; } class SimulatorTimingMap { nodeTimings: Map<Graph.Node, NodeTimingData>; constructor() { this.nodeTimings = new Map<Graph.Node, NodeTimingData>(); } getNodes(): Graph.Node[] { return Array.from(this.nodeTimings.keys()); } setReadyToStart(node: Graph.Node, values: {queuedTime: number}): void { this.nodeTimings.set(node, values); } setInProgress(node: Graph.Node, values: {startTime: number}): void { const nodeTiming = { ...this.getQueued(node), startTime: values.startTime, timeElapsed: 0, }; this.nodeTimings.set( node, node.type === Graph.BaseNode.types.NETWORK ? {...nodeTiming, timeElapsedOvershoot: 0, bytesDownloaded: 0} : nodeTiming, ); } setCompleted(node: Graph.Node, values: {endTime: number, connectionTiming?: ConnectionTiming}): void { const nodeTiming = { ...this.getInProgress(node), endTime: values.endTime, connectionTiming: values.connectionTiming, }; this.nodeTimings.set(node, nodeTiming); } setCpu(node: Graph.CPUNode, values: {timeElapsed: number}): void { const nodeTiming = { ...this.getCpuStarted(node), timeElapsed: values.timeElapsed, }; this.nodeTimings.set(node, nodeTiming); } setCpuEstimated(node: Graph.CPUNode, values: {estimatedTimeElapsed: number}): void { const nodeTiming = { ...this.getCpuStarted(node), estimatedTimeElapsed: values.estimatedTimeElapsed, }; this.nodeTimings.set(node, nodeTiming); } setNetwork( node: Graph.NetworkNode, values: {timeElapsed: number, timeElapsedOvershoot: number, bytesDownloaded: number}): void { const nodeTiming = { ...this.getNetworkStarted(node), timeElapsed: values.timeElapsed, timeElapsedOvershoot: values.timeElapsedOvershoot, bytesDownloaded: values.bytesDownloaded, }; this.nodeTimings.set(node, nodeTiming); } setNetworkEstimated(node: Graph.NetworkNode, values: {estimatedTimeElapsed: number}): void { const nodeTiming = { ...this.getNetworkStarted(node), estimatedTimeElapsed: values.estimatedTimeElapsed, }; this.nodeTimings.set(node, nodeTiming); } getQueued(node: Graph.Node): NodeTimingData { const timing = this.nodeTimings.get(node); if (!timing) { throw new Core.LanternError(`Node ${node.id} not yet queued`); } return timing; } getCpuStarted(node: Graph.CPUNode): CpuNodeTimingStarted { const timing = this.nodeTimings.get(node); if (!timing) { throw new Core.LanternError(`Node ${node.id} not yet queued`); } if (!('startTime' in timing)) { throw new Core.LanternError(`Node ${node.id} not yet started`); } if ('bytesDownloaded' in timing) { throw new Core.LanternError(`Node ${node.id} timing not valid`); } return timing; } getNetworkStarted(node: Graph.NetworkNode): NetworkNodeTimingStarted { const timing = this.nodeTimings.get(node); if (!timing) { throw new Core.LanternError(`Node ${node.id} not yet queued`); } if (!('startTime' in timing)) { throw new Core.LanternError(`Node ${node.id} not yet started`); } if (!('bytesDownloaded' in timing)) { throw new Core.LanternError(`Node ${node.id} timing not valid`); } return timing; } getInProgress(node: Graph.Node): CpuNodeTimingInProgress|NetworkNodeTimingInProgress { const timing = this.nodeTimings.get(node); if (!timing) { throw new Core.LanternError(`Node ${node.id} not yet queued`); } if (!('startTime' in timing)) { throw new Core.LanternError(`Node ${node.id} not yet started`); } if (!('estimatedTimeElapsed' in timing)) { throw new Core.LanternError(`Node ${node.id} not yet in progress`); } return timing; } getCompleted(node: Graph.Node): CpuNodeTimingComplete|NetworkNodeTimingComplete { const timing = this.nodeTimings.get(node); if (!timing) { throw new Core.LanternError(`Node ${node.id} not yet queued`); } if (!('startTime' in timing)) { throw new Core.LanternError(`Node ${node.id} not yet started`); } if (!('estimatedTimeElapsed' in timing)) { throw new Core.LanternError(`Node ${node.id} not yet in progress`); } if (!('endTime' in timing)) { throw new Core.LanternError(`Node ${node.id} not yet completed`); } return timing; } } export {SimulatorTimingMap};