UNPKG

chrome-devtools-frontend

Version:
249 lines (203 loc) • 12.1 kB
// Copyright 2023 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. import {describeWithMockConnection} from '../../../testing/MockConnection.js'; import {TraceLoader} from '../../../testing/TraceLoader.js'; import * as Trace from '../trace.js'; async function processTrace(events: readonly Trace.Types.Events.Event[]): Promise<void> { // The FramesHandler depends on a few other handlers, so we run all of them as part of these tests. const handlersInOrder: Trace.Handlers.Types.HandlerName[] = [ 'Meta', 'Samples', 'AuctionWorklets', 'Renderer', 'LayerTree', 'Frames', ]; for (const handlerName of handlersInOrder) { const handler = Trace.Handlers.ModelHandlers[handlerName]; handler.reset(); } for (const event of events) { for (const handlerName of handlersInOrder) { Trace.Handlers.ModelHandlers[handlerName].handleEvent(event); } } for (const handlerName of handlersInOrder) { const handler = Trace.Handlers.ModelHandlers[handlerName]; await handler.finalize({}); } } describeWithMockConnection('FramesHandler', () => { it('can parse out a trace and return the frames', async function() { const rawEvents = await TraceLoader.rawEvents(this, 'web-dev-with-commit.json.gz'); await processTrace(rawEvents); const parsedFrames = Trace.Handlers.ModelHandlers.Frames.data().frames; assert.lengthOf(parsedFrames, 18); // Assert a couple of frames to check the data, including one that is partial and was dropped. assert.strictEqual(parsedFrames[0].startTime, 122411104714); assert.strictEqual(parsedFrames[0].duration, 37847); assert.isFalse(parsedFrames[0].isPartial); assert.isFalse(parsedFrames[0].isPartial); assert.strictEqual(parsedFrames[2].startTime, 122411159244); assert.strictEqual(parsedFrames[2].duration, 16683); assert.isTrue(parsedFrames[2].isPartial); assert.isTrue(parsedFrames[2].dropped); }); it('assigns each frame an index', async function() { const rawEvents = await TraceLoader.rawEvents(this, 'web-dev-with-commit.json.gz'); await processTrace(rawEvents); const parsedFrames = Trace.Handlers.ModelHandlers.Frames.data().frames; assert.lengthOf(parsedFrames, 18); parsedFrames.forEach((frame, arrayIndex) => { // Seems silly, but this means we know the frame's index without having // to look it up in the trace data. assert.strictEqual(frame.index, arrayIndex); }); }); it('can create LayerPaintEvents from Paint and snapshot events', async function() { // Advanced instrumentation trace file is large: allow the bots more time // to process it. this.timeout(20_000); const rawEvents = await TraceLoader.rawEvents(this, 'web-dev-with-advanced-instrumentation.json.gz'); await processTrace(rawEvents); const parsedFrames = Trace.Handlers.ModelHandlers.Frames.data().frames; assert.lengthOf(parsedFrames, 25); const frameWithPaints = parsedFrames.at(2); if (!frameWithPaints) { throw new Error('Could not find frame at index 2'); } // Check we have the right one. assert.strictEqual(frameWithPaints.seqId, 1127448); assert.lengthOf(frameWithPaints.paints, 7); }); it('can return frames within a given window', async function() { const rawEvents = await TraceLoader.rawEvents(this, 'web-dev-with-commit.json.gz'); await processTrace(rawEvents); const parsedFrames = Trace.Handlers.ModelHandlers.Frames.data().frames; assert.lengthOf(parsedFrames, 18); const startTime = Trace.Types.Timing.Micro(parsedFrames[0].startTime); const endTime = Trace.Types.Timing.Micro(parsedFrames[3].endTime); const framesWithinWindow = Trace.Handlers.ModelHandlers.Frames.framesWithinWindow(parsedFrames, startTime, endTime); assert.deepEqual(framesWithinWindow, [ parsedFrames[0], parsedFrames[1], parsedFrames[2], parsedFrames[3], ]); }); }); describe('FramesHandler', () => { it('visualizes zero frames when no BeginFrames are added', () => { const beginFrameQueue = new Trace.Handlers.ModelHandlers.Frames.TimelineFrameBeginFrameQueue(); const framesToVisualize = beginFrameQueue.processPendingBeginFramesOnDrawFrame(100); assert.isEmpty(framesToVisualize); }); it('visualizes zero frames when no BeginFrame in queue matches DrawFrame', () => { const beginFrameQueue = new Trace.Handlers.ModelHandlers.Frames.TimelineFrameBeginFrameQueue(); beginFrameQueue.addFrameIfNotExists(100, Trace.Types.Timing.Micro(1000000), false, false); beginFrameQueue.addFrameIfNotExists(101, Trace.Types.Timing.Micro(1000016), false, false); beginFrameQueue.addFrameIfNotExists(102, Trace.Types.Timing.Micro(1000032), false, false); const framesToVisualize = beginFrameQueue.processPendingBeginFramesOnDrawFrame(103); assert.isEmpty(framesToVisualize); }); it('ignores BeginFrames without corresponding DrawFrames', () => { const beginFrameQueue = new Trace.Handlers.ModelHandlers.Frames.TimelineFrameBeginFrameQueue(); beginFrameQueue.addFrameIfNotExists(100, Trace.Types.Timing.Micro(1000000), false, false); beginFrameQueue.addFrameIfNotExists(101, Trace.Types.Timing.Micro(1000016), false, false); beginFrameQueue.addFrameIfNotExists(102, Trace.Types.Timing.Micro(1000032), false, false); beginFrameQueue.addFrameIfNotExists(103, Trace.Types.Timing.Micro(Trace.Types.Timing.Micro(1000048)), false, false); const framesToVisualize = beginFrameQueue.processPendingBeginFramesOnDrawFrame(102); // Visualized frame: 102 (non-dropped). // The other frames that are neither drawn nor dropped (100, 101) are // excluded from visualization. assert.lengthOf(framesToVisualize, 1); assert.isFalse(framesToVisualize[0].isDropped); assert.strictEqual(framesToVisualize[0].seqId, 102); assert.strictEqual(framesToVisualize[0].startTime, Trace.Types.Timing.Micro(1000032)); }); it('visualizes dropped BeginFrames before a presented frame', () => { const beginFrameQueue = new Trace.Handlers.ModelHandlers.Frames.TimelineFrameBeginFrameQueue(); beginFrameQueue.addFrameIfNotExists(100, Trace.Types.Timing.Micro(1000000), false, false); beginFrameQueue.addFrameIfNotExists(101, Trace.Types.Timing.Micro(1000016), true, false); beginFrameQueue.addFrameIfNotExists(102, Trace.Types.Timing.Micro(1000032), false, false); beginFrameQueue.addFrameIfNotExists(103, Trace.Types.Timing.Micro(1000048), true, false); beginFrameQueue.addFrameIfNotExists(104, Trace.Types.Timing.Micro(1000064), false, false); beginFrameQueue.addFrameIfNotExists(105, Trace.Types.Timing.Micro(1000080), false, false); beginFrameQueue.addFrameIfNotExists(106, Trace.Types.Timing.Micro(1000096), false, false); const framesToVisualize = beginFrameQueue.processPendingBeginFramesOnDrawFrame(105); // Visualized frames: 101 (dropped), 103 (dropped) and 105 (non-dropped). // The other frames that are neither drawn nor dropped (100, 102 and 104) // are excluded from visualization. assert.lengthOf(framesToVisualize, 3); assert.isTrue(framesToVisualize[0].isDropped); assert.strictEqual(framesToVisualize[0].seqId, 101); assert.strictEqual(framesToVisualize[0].startTime, Trace.Types.Timing.Micro(1000016)); assert.isTrue(framesToVisualize[1].isDropped); assert.strictEqual(framesToVisualize[1].seqId, 103); assert.strictEqual(framesToVisualize[1].startTime, Trace.Types.Timing.Micro(1000048)); assert.isFalse(framesToVisualize[2].isDropped); assert.strictEqual(framesToVisualize[2].seqId, 105); assert.strictEqual(framesToVisualize[2].startTime, Trace.Types.Timing.Micro(1000080)); }); it('changes dropped status of specified frames via setDropped()', () => { const beginFrameQueue = new Trace.Handlers.ModelHandlers.Frames.TimelineFrameBeginFrameQueue(); beginFrameQueue.addFrameIfNotExists(100, Trace.Types.Timing.Micro(1000000), false, false); beginFrameQueue.setDropped(100, true); beginFrameQueue.addFrameIfNotExists(101, Trace.Types.Timing.Micro(1000016), true, false); beginFrameQueue.addFrameIfNotExists(102, Trace.Types.Timing.Micro(1000032), false, false); beginFrameQueue.addFrameIfNotExists(103, Trace.Types.Timing.Micro(1000048), true, false); beginFrameQueue.addFrameIfNotExists(104, Trace.Types.Timing.Micro(1000064), false, false); beginFrameQueue.addFrameIfNotExists(105, Trace.Types.Timing.Micro(1000080), false, false); beginFrameQueue.addFrameIfNotExists(106, Trace.Types.Timing.Micro(1000096), true, false); beginFrameQueue.setDropped(101, false); const framesToVisualize = beginFrameQueue.processPendingBeginFramesOnDrawFrame(105); // Visualized frames: 100 (dropped), 103 (dropped) and 105 (non-dropped). // The other frames that are neither drawn nor dropped (101, 102 and 104) // are excluded from visualization. assert.lengthOf(framesToVisualize, 3); assert.isTrue(framesToVisualize[0].isDropped); assert.strictEqual(framesToVisualize[0].seqId, 100); assert.strictEqual(framesToVisualize[0].startTime, Trace.Types.Timing.Micro(1000000)); assert.isTrue(framesToVisualize[1].isDropped); assert.strictEqual(framesToVisualize[1].seqId, 103); assert.strictEqual(framesToVisualize[1].startTime, Trace.Types.Timing.Micro(1000048)); assert.isFalse(framesToVisualize[2].isDropped); assert.strictEqual(framesToVisualize[2].seqId, 105); assert.strictEqual(framesToVisualize[2].startTime, Trace.Types.Timing.Micro(1000080)); }); it('pops processed frames out of the queue', () => { const beginFrameQueue = new Trace.Handlers.ModelHandlers.Frames.TimelineFrameBeginFrameQueue(); beginFrameQueue.addFrameIfNotExists(100, Trace.Types.Timing.Micro(1000000), true, false); beginFrameQueue.addFrameIfNotExists(101, Trace.Types.Timing.Micro(1000016), false, false); beginFrameQueue.addFrameIfNotExists(102, Trace.Types.Timing.Micro(1000032), false, false); beginFrameQueue.addFrameIfNotExists(103, Trace.Types.Timing.Micro(1000048), true, false); beginFrameQueue.addFrameIfNotExists(104, Trace.Types.Timing.Micro(1000064), false, false); beginFrameQueue.addFrameIfNotExists(105, Trace.Types.Timing.Micro(1000080), true, false); beginFrameQueue.addFrameIfNotExists(106, Trace.Types.Timing.Micro(1000096), true, false); // Pop frame 100, 101 (not visualized) and 102 from queue. let framesToVisualize = beginFrameQueue.processPendingBeginFramesOnDrawFrame(102); assert.lengthOf(framesToVisualize, 2); assert.isTrue(framesToVisualize[0].isDropped); assert.strictEqual(framesToVisualize[0].seqId, 100); assert.strictEqual(framesToVisualize[0].startTime, Trace.Types.Timing.Micro(1000000)); assert.isFalse(framesToVisualize[1].isDropped); assert.strictEqual(framesToVisualize[1].seqId, 102); assert.strictEqual(framesToVisualize[1].startTime, Trace.Types.Timing.Micro(1000032)); // Pop frame 103, 104 (not visualized) and 105 from queue framesToVisualize = beginFrameQueue.processPendingBeginFramesOnDrawFrame(105); assert.lengthOf(framesToVisualize, 2); assert.isTrue(framesToVisualize[0].isDropped); assert.strictEqual(framesToVisualize[0].seqId, 103); assert.strictEqual(framesToVisualize[0].startTime, Trace.Types.Timing.Micro(1000048)); assert.isTrue(framesToVisualize[1].isDropped); assert.strictEqual(framesToVisualize[1].seqId, 105); assert.strictEqual(framesToVisualize[1].startTime, Trace.Types.Timing.Micro(1000080)); // Pop frame 106 from queue framesToVisualize = beginFrameQueue.processPendingBeginFramesOnDrawFrame(106); assert.lengthOf(framesToVisualize, 1); assert.isTrue(framesToVisualize[0].isDropped); assert.strictEqual(framesToVisualize[0].seqId, 106); assert.strictEqual(framesToVisualize[0].startTime, Trace.Types.Timing.Micro(1000096)); }); });