watchPerformance method

Future<void> watchPerformance(
  1. Future<void> action(), {
  2. String reportKey = 'performance',
})

Watches the FrameTiming during action and report it to the binding with key reportKey.

This can be used to implement performance tests previously using traceAction and TimelineSummary from flutter_driver

Implementation

Future<void> watchPerformance(
  Future<void> Function() action, {
  String reportKey = 'performance',
}) async {
  assert(() {
    if (_firstRun) {
      debugPrint(kDebugWarning);
      _firstRun = false;
    }
    return true;
  }());

  // The engine could batch FrameTimings and send them only once per second.
  // Delay for a sufficient time so either old FrameTimings are flushed and not
  // interfering our measurements here, or new FrameTimings are all reported.
  // TODO(CareF): remove this when flush FrameTiming is readily in engine.
  //              See https://github.com/flutter/flutter/issues/64808
  //              and https://github.com/flutter/flutter/issues/67593
  final List<FrameTiming> frameTimings = <FrameTiming>[];
  Future<void> delayForFrameTimings() async {
    int count = 0;
    while (frameTimings.isEmpty) {
      count++;
      await Future<void>.delayed(const Duration(seconds: 2));
      if (count > 20) {
        debugPrint('delayForFrameTimings is taking longer than expected...');
      }
    }
  }

  await Future<void>.delayed(const Duration(seconds: 2)); // flush old FrameTimings
  final TimingsCallback watcher = frameTimings.addAll;
  addTimingsCallback(watcher);
  final _GarbageCollectionInfo gcInfo = await _runAndGetGCInfo(action);

  await delayForFrameTimings(); // make sure all FrameTimings are reported
  removeTimingsCallback(watcher);

  final FrameTimingSummarizer frameTimes = FrameTimingSummarizer(
    frameTimings,
    newGenGCCount: gcInfo.newCount,
    oldGenGCCount: gcInfo.oldCount,
  );
  reportData ??= <String, dynamic>{};
  reportData![reportKey] = frameTimes.summary;
}