diff --git a/core/computed/metrics/total-blocking-time.js b/core/computed/metrics/total-blocking-time.js index bab555a31665..c06a37a968a6 100644 --- a/core/computed/metrics/total-blocking-time.js +++ b/core/computed/metrics/total-blocking-time.js @@ -9,7 +9,7 @@ import ComputedMetric from './metric.js'; import {TraceProcessor} from '../../lib/tracehouse/trace-processor.js'; import {LanternTotalBlockingTime} from './lantern-total-blocking-time.js'; import {Interactive} from './interactive.js'; -import {calculateSumOfBlockingTime} from './tbt-utils.js'; +import {calculateSumOfBlockingTime} from '../../lib/lantern/tbt-utils.js'; /** * @fileoverview This audit determines Total Blocking Time. diff --git a/core/computed/tbt-impact-tasks.js b/core/computed/tbt-impact-tasks.js index a1eab94e7637..77a053fa2326 100644 --- a/core/computed/tbt-impact-tasks.js +++ b/core/computed/tbt-impact-tasks.js @@ -10,7 +10,7 @@ import {FirstContentfulPaint} from './metrics/first-contentful-paint.js'; import {Interactive} from './metrics/interactive.js'; import {TotalBlockingTime} from './metrics/total-blocking-time.js'; import {ProcessedTrace} from './processed-trace.js'; -import {calculateTbtImpactForEvent} from './metrics/tbt-utils.js'; +import {calculateTbtImpactForEvent} from '../lib/lantern/tbt-utils.js'; class TBTImpactTasks { /** diff --git a/core/lib/lantern/metrics/total-blocking-time.js b/core/lib/lantern/metrics/total-blocking-time.js index 08c25680ca15..8c08280cc8c7 100644 --- a/core/lib/lantern/metrics/total-blocking-time.js +++ b/core/lib/lantern/metrics/total-blocking-time.js @@ -7,7 +7,7 @@ import * as Lantern from '../types/lantern.js'; import {Metric} from '../metric.js'; import {BaseNode} from '../base-node.js'; -import {BLOCKING_TIME_THRESHOLD, calculateSumOfBlockingTime} from '../../../computed/metrics/tbt-utils.js'; +import {BLOCKING_TIME_THRESHOLD, calculateSumOfBlockingTime} from '../tbt-utils.js'; /** @typedef {import('../base-node.js').Node} Node */ diff --git a/core/computed/metrics/tbt-utils.js b/core/lib/lantern/tbt-utils.js similarity index 100% rename from core/computed/metrics/tbt-utils.js rename to core/lib/lantern/tbt-utils.js diff --git a/core/test/computed/metrics/total-blocking-time-test.js b/core/test/computed/metrics/total-blocking-time-test.js index 5a3a6203223f..6637dc008179 100644 --- a/core/test/computed/metrics/total-blocking-time-test.js +++ b/core/test/computed/metrics/total-blocking-time-test.js @@ -5,7 +5,6 @@ */ import {TotalBlockingTime} from '../../../computed/metrics/total-blocking-time.js'; -import {calculateSumOfBlockingTime} from '../../../computed/metrics/tbt-utils.js'; import {getURLArtifactFromDevtoolsLog, readJson} from '../../test-utils.js'; const trace = readJson('../../fixtures/artifacts/blocking-time/trace.json.gz', import.meta); @@ -48,125 +47,4 @@ describe('Metrics: TotalBlockingTime', () => { ); expect(result.timing).toBeCloseTo(400, 1); }); - - describe('#calculateSumOfBlockingTime', () => { - it('reports 0 when no task is longer than 50ms', () => { - const events = [ - {start: 1000, end: 1050, duration: 50}, - {start: 2000, end: 2010, duration: 10}, - ]; - - const fcpTimeMs = 500; - const interactiveTimeMs = 4000; - - expect( - calculateSumOfBlockingTime(events, fcpTimeMs, interactiveTimeMs) - ).toBe(0); - }); - - it('only looks at tasks within FCP and TTI', () => { - const events = [ - {start: 1000, end: 1060, duration: 60}, - {start: 2000, end: 2100, duration: 100}, - {start: 2300, end: 2450, duration: 150}, - {start: 2600, end: 2800, duration: 200}, - ]; - - const fcpTimeMs = 1500; - const interactiveTimeMs = 2500; - - expect( - calculateSumOfBlockingTime(events, fcpTimeMs, interactiveTimeMs) - ).toBe(150); - }); - - it('clips before finding blocking regions', () => { - const fcpTimeMs = 150; - const interactiveTimeMs = 300; - - const events = [ - // The clipping is done first, so the task becomes [150, 200] after clipping and contributes - // 0ms of blocking time. This is in contrast to first calculating the blocking region ([100, - // 200]) and then clipping at FCP (150ms), which yields 50ms blocking time. - {start: 50, end: 200, duration: 150}, - // Similarly, the task is first clipped above to be [240, 300], and then contributes 10ms - // blocking time. - {start: 240, end: 460, duration: 120}, - ]; - - expect( - calculateSumOfBlockingTime(events, fcpTimeMs, interactiveTimeMs) - ).toBe(10); // 0ms + 10ms. - }); - - // TTI can happen in the middle of a task, for example, if TTI is at FMP which occurs as part - // of a larger task, or in the lantern case where we use estimate TTI using a different graph - // from the one used to estimate TBT. - it('clips properly if TTI falls in the middle of a task', () => { - const fcpTimeMs = 1000; - const interactiveTimeMs = 2000; - - expect( - calculateSumOfBlockingTime( - [{start: 1951, end: 2100, duration: 149}], - fcpTimeMs, - interactiveTimeMs - ) - ).toBe(0); // Duration after clipping is 49, which is < 50. - expect( - calculateSumOfBlockingTime( - [{start: 1950, end: 2100, duration: 150}], - fcpTimeMs, - interactiveTimeMs - ) - ).toBe(0); // Duration after clipping is 50, so time after 50ms is 0ms. - expect( - calculateSumOfBlockingTime( - [{start: 1949, end: 2100, duration: 151}], - fcpTimeMs, - interactiveTimeMs - ) - ).toBe(1); // Duration after clipping is 51, so time after 50ms is 1ms. - }); - - it('clips properly if FCP falls in the middle of a task', () => { - const fcpTimeMs = 1000; - const interactiveTimeMs = 2000; - - expect( - calculateSumOfBlockingTime( - [{start: 900, end: 1049, duration: 149}], - fcpTimeMs, - interactiveTimeMs - ) - ).toBe(0); // Duration after clipping is 49, which is < 50. - expect( - calculateSumOfBlockingTime( - [{start: 900, end: 1050, duration: 150}], - fcpTimeMs, - interactiveTimeMs - ) - ).toBe(0); // Duration after clipping is 50, so time after 50ms is 0ms. - expect( - calculateSumOfBlockingTime( - [{start: 900, end: 1051, duration: 151}], - fcpTimeMs, - interactiveTimeMs - ) - ).toBe(1); // Duration after clipping is 51, so time after 50ms is 1ms. - }); - - // This can happen in the lantern metric case, where we use the optimistic - // TTI and pessimistic FCP. - it('returns 0 if interactiveTime is earlier than FCP', () => { - const fcpTimeMs = 2050; - const interactiveTimeMs = 1050; - - const events = [{start: 500, end: 3000, duration: 2500}]; - - expect( - calculateSumOfBlockingTime(events, fcpTimeMs, interactiveTimeMs) - ).toBe(0); - }); - }); }); diff --git a/core/test/lib/lantern/tbt-utils-test.js b/core/test/lib/lantern/tbt-utils-test.js new file mode 100644 index 000000000000..94e09900eb17 --- /dev/null +++ b/core/test/lib/lantern/tbt-utils-test.js @@ -0,0 +1,128 @@ +/** + * @license + * Copyright 2024 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +import {calculateSumOfBlockingTime} from '../../../lib/lantern/tbt-utils.js'; + +describe('TotalBlockingTime utils', () => { + it('reports 0 when no task is longer than 50ms', () => { + const events = [ + {start: 1000, end: 1050, duration: 50}, + {start: 2000, end: 2010, duration: 10}, + ]; + + const fcpTimeMs = 500; + const interactiveTimeMs = 4000; + + expect( + calculateSumOfBlockingTime(events, fcpTimeMs, interactiveTimeMs) + ).toBe(0); + }); + + it('only looks at tasks within FCP and TTI', () => { + const events = [ + {start: 1000, end: 1060, duration: 60}, + {start: 2000, end: 2100, duration: 100}, + {start: 2300, end: 2450, duration: 150}, + {start: 2600, end: 2800, duration: 200}, + ]; + + const fcpTimeMs = 1500; + const interactiveTimeMs = 2500; + + expect( + calculateSumOfBlockingTime(events, fcpTimeMs, interactiveTimeMs) + ).toBe(150); + }); + + it('clips before finding blocking regions', () => { + const fcpTimeMs = 150; + const interactiveTimeMs = 300; + + const events = [ + // The clipping is done first, so the task becomes [150, 200] after clipping and contributes + // 0ms of blocking time. This is in contrast to first calculating the blocking region ([100, + // 200]) and then clipping at FCP (150ms), which yields 50ms blocking time. + {start: 50, end: 200, duration: 150}, + // Similarly, the task is first clipped above to be [240, 300], and then contributes 10ms + // blocking time. + {start: 240, end: 460, duration: 120}, + ]; + + expect( + calculateSumOfBlockingTime(events, fcpTimeMs, interactiveTimeMs) + ).toBe(10); // 0ms + 10ms. + }); + + // TTI can happen in the middle of a task, for example, if TTI is at FMP which occurs as part + // of a larger task, or in the lantern case where we use estimate TTI using a different graph + // from the one used to estimate TBT. + it('clips properly if TTI falls in the middle of a task', () => { + const fcpTimeMs = 1000; + const interactiveTimeMs = 2000; + + expect( + calculateSumOfBlockingTime( + [{start: 1951, end: 2100, duration: 149}], + fcpTimeMs, + interactiveTimeMs + ) + ).toBe(0); // Duration after clipping is 49, which is < 50. + expect( + calculateSumOfBlockingTime( + [{start: 1950, end: 2100, duration: 150}], + fcpTimeMs, + interactiveTimeMs + ) + ).toBe(0); // Duration after clipping is 50, so time after 50ms is 0ms. + expect( + calculateSumOfBlockingTime( + [{start: 1949, end: 2100, duration: 151}], + fcpTimeMs, + interactiveTimeMs + ) + ).toBe(1); // Duration after clipping is 51, so time after 50ms is 1ms. + }); + + it('clips properly if FCP falls in the middle of a task', () => { + const fcpTimeMs = 1000; + const interactiveTimeMs = 2000; + + expect( + calculateSumOfBlockingTime( + [{start: 900, end: 1049, duration: 149}], + fcpTimeMs, + interactiveTimeMs + ) + ).toBe(0); // Duration after clipping is 49, which is < 50. + expect( + calculateSumOfBlockingTime( + [{start: 900, end: 1050, duration: 150}], + fcpTimeMs, + interactiveTimeMs + ) + ).toBe(0); // Duration after clipping is 50, so time after 50ms is 0ms. + expect( + calculateSumOfBlockingTime( + [{start: 900, end: 1051, duration: 151}], + fcpTimeMs, + interactiveTimeMs + ) + ).toBe(1); // Duration after clipping is 51, so time after 50ms is 1ms. + }); + + // This can happen in the lantern metric case, where we use the optimistic + // TTI and pessimistic FCP. + it('returns 0 if interactiveTime is earlier than FCP', () => { + const fcpTimeMs = 2050; + const interactiveTimeMs = 1050; + + const events = [{start: 500, end: 3000, duration: 2500}]; + + expect( + calculateSumOfBlockingTime(events, fcpTimeMs, interactiveTimeMs) + ).toBe(0); + }); +});