static async compute_(trace, context) {
    const processedTrace = await ProcessedTrace.request(trace, context);

    const allFrameShiftEvents =
        CumulativeLayoutShift.getLayoutShiftEvents(processedTrace);
    const impactByNodeId = CumulativeLayoutShift.getImpactByNodeId(allFrameShiftEvents);
    const mainFrameShiftEvents = allFrameShiftEvents.filter(e => e.isMainFrame);
    const cumulativeLayoutShift = CumulativeLayoutShift.calculate(allFrameShiftEvents);
    const cumulativeLayoutShiftMainFrame = CumulativeLayoutShift.calculate(mainFrameShiftEvents);

    // Run with the new trace engine, and only throw an error if we are running our unit tests.
    // Otherwise, simply report any differences or errors to Sentry.
    // TODO: TraceEngine always drops `had_recent_input` events, but Lighthouse is more lenient.
    //       See comment in `getLayoutShiftEvents`. We need to upstream this.
    let newEngineResult;
    let newEngineResultDiffered = false;
    let tryNewTraceEngine = true;
    if (allFrameShiftEvents.some(e => e.event.args.data?.had_recent_input)) {
      tryNewTraceEngine = false;
    }
    if (tryNewTraceEngine) {
      try {
        newEngineResult =
          await this.computeWithSharedTraceEngine(allFrameShiftEvents, mainFrameShiftEvents);
        newEngineResultDiffered =
          newEngineResult.cumulativeLayoutShift !== cumulativeLayoutShift ||
          newEngineResult.cumulativeLayoutShiftMainFrame !== cumulativeLayoutShiftMainFrame;
        if (newEngineResultDiffered) {
          newEngineResultDiffered = true;
          const expected = JSON.stringify({cumulativeLayoutShift, cumulativeLayoutShiftMainFrame});
          const got = JSON.stringify(newEngineResult);
          throw new Error(`new trace engine differed. expected: ${expected}, got: ${got}`);
        }
      } catch (err) {
        // eslint-disable-next-line no-console
        console.error(err);
        newEngineResultDiffered = true;

        const error = new Error('Error when using new trace engine', {cause: err});
        // @ts-expect-error Check for running from tests.
        if (global.expect) {
          throw error;
        } else {
          Sentry.captureException(error, {
            tags: {computed: 'new-trace-engine'},
            level: 'error',
            extra: {
              // Not sure if Sentry handles `cause`, so just in case add the info in a second place.
              errorMsg: err.toString(),
            },
          });
        }
      }
    }

    return {
      cumulativeLayoutShift,
      cumulativeLayoutShiftMainFrame,
      impactByNodeId,
      newEngineResult,
      newEngineResultDiffered,
    };
  }
@param {LH.Trace} trace
@param {LH.Artifacts.ComputedContext} context
@return {Promise<{cumulativeLayoutShift: number, cumulativeLayoutShiftMainFrame: number, impactByNodeId: Map<number, number>, newEngineResult?: {cumulativeLayoutShift: number, cumulativeLayoutShiftMainFrame: number}, newEngineResultDiffered: boolean}>}