diff --git a/dev/devicelab/bin/tasks/service_extensions_test.dart b/dev/devicelab/bin/tasks/service_extensions_test.dart index bd8262f05c..ad44964fb2 100644 --- a/dev/devicelab/bin/tasks/service_extensions_test.dart +++ b/dev/devicelab/bin/tasks/service_extensions_test.dart @@ -6,11 +6,12 @@ import 'dart:async'; import 'dart:convert'; import 'dart:io'; +import 'package:path/path.dart' as path; +import 'package:vm_service_client/vm_service_client.dart'; + import 'package:flutter_devicelab/framework/adb.dart'; import 'package:flutter_devicelab/framework/framework.dart'; import 'package:flutter_devicelab/framework/utils.dart'; -import 'package:path/path.dart' as path; -import 'package:vm_service_client/vm_service_client.dart'; void main() { task(() async { @@ -56,19 +57,10 @@ void main() { final VMServiceClient client = VMServiceClient.connect('ws://localhost:$vmServicePort/ws'); final VM vm = await client.getVM(); final VMIsolateRef isolate = vm.isolates.first; - - final StreamController frameEventsController = StreamController(); - final StreamController navigationEventsController = StreamController(); - isolate.onExtensionEvent.listen((VMExtensionEvent event) { - if (event.kind == 'Flutter.Frame') { - frameEventsController.add(event); - } else if (event.kind == 'Flutter.Navigation') { - navigationEventsController.add(event); - } - }); - - final Stream frameEvents = frameEventsController.stream; - final Stream navigationEvents = navigationEventsController.stream; + final Stream frameEvents = isolate.onExtensionEvent.where( + (VMExtensionEvent e) => e.kind == 'Flutter.Frame'); + final Stream navigationEvents = isolate.onExtensionEvent.where( + (VMExtensionEvent e) => e.kind == 'Flutter.Navigation'); print('reassembling app...'); final Future frameFuture = frameEvents.first; @@ -79,17 +71,13 @@ void main() { print('${event.kind}: ${event.data}'); // validate the fields - // {number: 8, startTime: 0, elapsed: 1437, build: 600, raster: 800} + // {number: 8, startTime: 0, elapsed: 1437} expect(event.data['number'] is int); expect(event.data['number'] >= 0); expect(event.data['startTime'] is int); expect(event.data['startTime'] >= 0); expect(event.data['elapsed'] is int); expect(event.data['elapsed'] >= 0); - expect(event.data['build'] is int); - expect(event.data['build'] >= 0); - expect(event.data['raster'] is int); - expect(event.data['raster'] >= 0); final Future navigationFuture = navigationEvents.first; // This tap triggers a navigation event. diff --git a/packages/flutter/lib/src/scheduler/binding.dart b/packages/flutter/lib/src/scheduler/binding.dart index 50cd635f90..a5793a7cd5 100644 --- a/packages/flutter/lib/src/scheduler/binding.dart +++ b/packages/flutter/lib/src/scheduler/binding.dart @@ -4,8 +4,8 @@ import 'dart:async'; import 'dart:collection'; -import 'dart:developer' show Flow, Timeline; -import 'dart:ui' show AppLifecycleState, FramePhase, FrameTiming; +import 'dart:developer'; +import 'dart:ui' show AppLifecycleState; import 'package:collection/collection.dart' show PriorityQueue, HeapPriorityQueue; import 'package:flutter/foundation.dart'; @@ -198,17 +198,6 @@ mixin SchedulerBinding on BindingBase, ServicesBinding { window.onDrawFrame = _handleDrawFrame; SystemChannels.lifecycle.setMessageHandler(_handleLifecycleMessage); readInitialLifecycleStateFromNativeWindow(); - - if (!kReleaseMode) { - int frameNumber = 0; - - window.onReportTimings = (List timings) { - for (FrameTiming frameTiming in timings) { - frameNumber += 1; - _profileFramePostEvent(frameNumber, frameTiming); - } - }; - } } /// The current [SchedulerBinding], if one has been created. @@ -853,7 +842,8 @@ mixin SchedulerBinding on BindingBase, ServicesBinding { } Duration _currentFrameTimeStamp; - int _debugFrameNumber = 0; + int _profileFrameNumber = 0; + final Stopwatch _profileFrameStopwatch = Stopwatch(); String _debugBanner; bool _ignoreNextEngineDrawFrame = false; @@ -904,9 +894,13 @@ mixin SchedulerBinding on BindingBase, ServicesBinding { if (rawTimeStamp != null) _lastRawTimeStamp = rawTimeStamp; - assert(() { - _debugFrameNumber += 1; + if (!kReleaseMode) { + _profileFrameNumber += 1; + _profileFrameStopwatch.reset(); + _profileFrameStopwatch.start(); + } + assert(() { if (debugPrintBeginFrameBanner || debugPrintEndFrameBanner) { final StringBuffer frameTimeStampDescription = StringBuffer(); if (rawTimeStamp != null) { @@ -914,7 +908,7 @@ mixin SchedulerBinding on BindingBase, ServicesBinding { } else { frameTimeStampDescription.write('(warm-up frame)'); } - _debugBanner = '▄▄▄▄▄▄▄▄ Frame ${_debugFrameNumber.toString().padRight(7)} ${frameTimeStampDescription.toString().padLeft(18)} ▄▄▄▄▄▄▄▄'; + _debugBanner = '▄▄▄▄▄▄▄▄ Frame ${_profileFrameNumber.toString().padRight(7)} ${frameTimeStampDescription.toString().padLeft(18)} ▄▄▄▄▄▄▄▄'; if (debugPrintBeginFrameBanner) debugPrint(_debugBanner); } @@ -967,6 +961,10 @@ mixin SchedulerBinding on BindingBase, ServicesBinding { } finally { _schedulerPhase = SchedulerPhase.idle; Timeline.finishSync(); // end the Frame + if (!kReleaseMode) { + _profileFrameStopwatch.stop(); + _profileFramePostEvent(); + } assert(() { if (debugPrintEndFrameBanner) debugPrint('▀' * _debugBanner.length); @@ -977,13 +975,11 @@ mixin SchedulerBinding on BindingBase, ServicesBinding { } } - void _profileFramePostEvent(int frameNumber, FrameTiming frameTiming) { + void _profileFramePostEvent() { postEvent('Flutter.Frame', { - 'number': frameNumber, - 'startTime': frameTiming.timestampInMicroseconds(FramePhase.buildStart), - 'elapsed': frameTiming.totalSpan.inMicroseconds, - 'build': frameTiming.buildDuration.inMicroseconds, - 'raster': frameTiming.rasterDuration.inMicroseconds, + 'number': _profileFrameNumber, + 'startTime': _currentFrameTimeStamp.inMicroseconds, + 'elapsed': _profileFrameStopwatch.elapsedMicroseconds, }); } diff --git a/packages/flutter/test/scheduler/scheduler_test.dart b/packages/flutter/test/scheduler/scheduler_test.dart index 5eaa0fc6eb..debeaf2021 100644 --- a/packages/flutter/test/scheduler/scheduler_test.dart +++ b/packages/flutter/test/scheduler/scheduler_test.dart @@ -3,7 +3,6 @@ // found in the LICENSE file. import 'dart:async'; -import 'dart:ui' show window, FrameTiming; import 'package:flutter/foundation.dart'; import 'package:flutter/scheduler.dart'; @@ -11,18 +10,7 @@ import 'package:flutter/services.dart'; import '../flutter_test_alternative.dart'; -class TestSchedulerBinding extends BindingBase with ServicesBinding, SchedulerBinding { - final Map>> eventsDispatched = >>{}; - - @override - void postEvent(String eventKind, Map eventData) { - getEventsDispatched(eventKind).add(eventData); - } - - List> getEventsDispatched(String eventKind) { - return eventsDispatched.putIfAbsent(eventKind, () => >[]); - } -} +class TestSchedulerBinding extends BindingBase with ServicesBinding, SchedulerBinding { } class TestStrategy { int allowedPriority = 10000; @@ -33,8 +21,7 @@ class TestStrategy { } void main() { - TestSchedulerBinding scheduler; - + SchedulerBinding scheduler; setUpAll(() { scheduler = TestSchedulerBinding(); }); @@ -129,23 +116,4 @@ void main() { expect(timerQueueTasks.length, 2); expect(taskExecuted, false); }); - - test('Flutter.Frame event fired', () async { - window.onReportTimings([FrameTiming([ - // build start, build finish - 10000, 15000, - // raster start, raster finish - 16000, 20000, - ])]); - - final List> events = scheduler.getEventsDispatched('Flutter.Frame'); - expect(events, hasLength(1)); - - final Map event = events.first; - expect(event['number'], isNonNegative); - expect(event['startTime'], 10000); - expect(event['elapsed'], 10000); - expect(event['build'], 5000); - expect(event['raster'], 4000); - }); }