diff --git a/dev/benchmarks/platform_channels_benchmarks/.metadata b/dev/benchmarks/platform_channels_benchmarks/.metadata new file mode 100644 index 0000000000..53bc69b75d --- /dev/null +++ b/dev/benchmarks/platform_channels_benchmarks/.metadata @@ -0,0 +1,10 @@ +# This file tracks properties of this Flutter project. +# Used by Flutter tool to assess capabilities and perform upgrades etc. +# +# This file should be version controlled and should not be manually edited. + +version: + revision: ce18d702e90d3dff9fee53d61a770c94f14f2811 + channel: master + +project_type: app diff --git a/dev/benchmarks/platform_channels_benchmarks/README.md b/dev/benchmarks/platform_channels_benchmarks/README.md new file mode 100644 index 0000000000..151abd3327 --- /dev/null +++ b/dev/benchmarks/platform_channels_benchmarks/README.md @@ -0,0 +1,6 @@ +# platform_channels_benchmarks + +The harness for running performance benchmark tests for Platform Channels. + +If you want to run these benchmarks outside of devicelab you need to first run: +`flutter create --platforms="ios,android" --no-overwrite .` diff --git a/dev/benchmarks/platform_channels_benchmarks/android/app/src/main/kotlin/com/example/platform_channels_benchmarks/MainActivity.kt b/dev/benchmarks/platform_channels_benchmarks/android/app/src/main/kotlin/com/example/platform_channels_benchmarks/MainActivity.kt new file mode 100644 index 0000000000..c75a6da863 --- /dev/null +++ b/dev/benchmarks/platform_channels_benchmarks/android/app/src/main/kotlin/com/example/platform_channels_benchmarks/MainActivity.kt @@ -0,0 +1,19 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package com.example.platform_channels_benchmarks + +import io.flutter.embedding.android.FlutterActivity +import io.flutter.embedding.engine.FlutterEngine +import io.flutter.plugin.common.BasicMessageChannel +import io.flutter.plugin.common.StandardMessageCodec + +class MainActivity: FlutterActivity() { + + override fun configureFlutterEngine(flutterEngine: FlutterEngine) { + val basicStandard = BasicMessageChannel(flutterEngine.dartExecutor, "dev.flutter.echo.basic.standard", StandardMessageCodec.INSTANCE) + basicStandard.setMessageHandler { message, reply -> reply.reply(message) } + super.configureFlutterEngine(flutterEngine) + } +} diff --git a/dev/benchmarks/platform_channels_benchmarks/ios/Runner/AppDelegate.swift b/dev/benchmarks/platform_channels_benchmarks/ios/Runner/AppDelegate.swift new file mode 100644 index 0000000000..8cb092ebd4 --- /dev/null +++ b/dev/benchmarks/platform_channels_benchmarks/ios/Runner/AppDelegate.swift @@ -0,0 +1,26 @@ +// Copyright 2014 The Flutter 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 Flutter +import UIKit + +@UIApplicationMain +@objc class AppDelegate: FlutterAppDelegate { + override func application( + _ application: UIApplication, + didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? + ) -> Bool { + GeneratedPluginRegistrant.register(with: self) + + let registrar = self.registrar(forPlugin: "Echo")! + let basicStandard = FlutterBasicMessageChannel( + name: "dev.flutter.echo.basic.standard", binaryMessenger: registrar.messenger(), + codec: FlutterStandardMessageCodec.sharedInstance()) + basicStandard.setMessageHandler { (input, reply) in + reply(input) + } + + return super.application(application, didFinishLaunchingWithOptions: launchOptions) + } +} diff --git a/dev/benchmarks/platform_channels_benchmarks/lib/main.dart b/dev/benchmarks/platform_channels_benchmarks/lib/main.dart new file mode 100644 index 0000000000..2ea21d057d --- /dev/null +++ b/dev/benchmarks/platform_channels_benchmarks/lib/main.dart @@ -0,0 +1,130 @@ +// Copyright 2014 The Flutter 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 'dart:math' as math; +import 'dart:typed_data'; + +import 'package:flutter/foundation.dart' show kDebugMode; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter_test/flutter_test.dart'; + +import 'package:microbenchmarks/common.dart'; + +List _makeTestBuffer(int size) { + final List answer = []; + for (int i = 0; i < size; ++i) { + switch (i % 9) { + case 0: + answer.add(1); + break; + case 1: + answer.add(math.pow(2, 65)); + break; + case 2: + answer.add(1234.0); + break; + case 3: + answer.add(null); + break; + case 4: + answer.add([1234]); + break; + case 5: + answer.add({'hello': 1234}); + break; + case 6: + answer.add('this is a test'); + break; + case 7: + answer.add(true); + break; + case 8: + answer.add(Uint8List(64)); + break; + } + } + return answer; +} + +Future _runTests() async { + if (kDebugMode) { + throw Exception( + "Must be run in profile mode! Use 'flutter run --profile'."); + } + const int numMessages = 2500; + + const BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.echo.basic.standard', + StandardMessageCodec(), + ); + final Stopwatch watch = Stopwatch(); + + watch.start(); + for (int i = 0; i < numMessages; ++i) { + await channel.send(1234); + } + watch.stop(); + final double smallPayloadTime = watch.elapsedMicroseconds / numMessages; + + watch.reset(); + /// WARNING: Don't change the following line of code, it will invalidate + /// `Large` tests. Instead make a different test. The size of largeBuffer + /// serialized is 14214 bytes. + final List largeBuffer = _makeTestBuffer(1000); + + int size = 0; + watch.start(); + for (int i = 0; i < numMessages; ++i) { + final List result = await channel.send(largeBuffer) as List; + // This check should be tiny compared to the actual channel send/receive. + size += (result == null) ? 0 : result.length; + } + watch.stop(); + final double largePayloadTime = watch.elapsedMicroseconds / numMessages; + + if (size != largeBuffer.length * numMessages) { + throw Exception( + 'There is an error with the echo channel, the results don\'t add up: $size'); + } + + final BenchmarkResultPrinter printer = BenchmarkResultPrinter(); + printer.addResult( + description: 'BasicMessageChannel/StandardMessageCodec/Flutter->Host/Small', + value: smallPayloadTime, + unit: 'µs', + name: 'platform_channel_basic_standard_2host_small', + ); + printer.addResult( + description: 'BasicMessageChannel/StandardMessageCodec/Flutter->Host/Large', + value: largePayloadTime, + unit: 'µs', + name: 'platform_channel_basic_standard_2host_large', + ); + printer.printToStdout(); +} + +class _BenchmarkWidget extends StatefulWidget { + const _BenchmarkWidget(this.tests, {Key key}) : super(key: key); + + final Future Function() tests; + + @override + _BenchmarkWidgetState createState() => _BenchmarkWidgetState(); +} + +class _BenchmarkWidgetState extends State<_BenchmarkWidget> { + @override + void initState() { + widget.tests(); + super.initState(); + } + + @override + Widget build(BuildContext context) => Container(); +} + +void main() { + runApp(const _BenchmarkWidget(_runTests)); +} diff --git a/dev/benchmarks/platform_channels_benchmarks/pubspec.yaml b/dev/benchmarks/platform_channels_benchmarks/pubspec.yaml new file mode 100644 index 0000000000..0d229d1b40 --- /dev/null +++ b/dev/benchmarks/platform_channels_benchmarks/pubspec.yaml @@ -0,0 +1,77 @@ +name: platform_channels_benchmarks +description: Test harness for Platform Channel performance tests. +publish_to: 'none' # Remove this line if you wish to publish to pub.dev + +version: 1.0.0+1 + +environment: + sdk: ">=2.9.0 <3.0.0" + +dependencies: + flutter: + sdk: flutter + microbenchmarks: + path: ../microbenchmarks + cupertino_icons: 1.0.2 + + _fe_analyzer_shared: 21.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 1.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + args: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + async: 2.6.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + boolean_selector: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + characters: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + charcode: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + cli_util: 0.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + collection: 1.15.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + convert: 3.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + coverage: 1.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + crypto: 3.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + file: 6.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + glob: 2.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + http_multi_server: 3.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + http_parser: 4.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + io: 1.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + js: 0.6.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + logging: 1.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + matcher: 0.12.10 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + meta: 1.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + mime: 1.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + node_preamble: 2.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + package_config: 2.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + path: 1.8.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + pedantic: 1.11.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + pool: 1.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + pub_semver: 2.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + shelf: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + shelf_packages_handler: 3.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + shelf_static: 1.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + shelf_web_socket: 1.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + source_map_stack_trace: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + source_maps: 0.10.10 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + source_span: 1.8.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + stack_trace: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + stream_channel: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + string_scanner: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + term_glyph: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test: 1.16.8 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_api: 0.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_core: 0.3.19 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + typed_data: 1.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vector_math: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vm_service: 6.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + watcher: 1.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + web_socket_channel: 2.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + webkit_inspection_protocol: 1.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + yaml: 3.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + +dev_dependencies: + flutter_test: + sdk: flutter + + clock: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + fake_async: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + +flutter: + uses-material-design: true + +# PUBSPEC CHECKSUM: 77ad diff --git a/dev/devicelab/bin/tasks/platform_channels_benchmarks.dart b/dev/devicelab/bin/tasks/platform_channels_benchmarks.dart new file mode 100644 index 0000000000..8a317f1f22 --- /dev/null +++ b/dev/devicelab/bin/tasks/platform_channels_benchmarks.dart @@ -0,0 +1,14 @@ +// Copyright 2014 The Flutter 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 'package:flutter_devicelab/framework/adb.dart' + show DeviceOperatingSystem; +import 'package:flutter_devicelab/framework/framework.dart' show task; +import 'package:flutter_devicelab/tasks/platform_channels_benchmarks.dart' + as platform_channels_benchmarks; + +Future main() async { + await task( + platform_channels_benchmarks.runTask(DeviceOperatingSystem.android)); +} diff --git a/dev/devicelab/bin/tasks/platform_channels_benchmarks_ios.dart b/dev/devicelab/bin/tasks/platform_channels_benchmarks_ios.dart new file mode 100644 index 0000000000..fecbbf370d --- /dev/null +++ b/dev/devicelab/bin/tasks/platform_channels_benchmarks_ios.dart @@ -0,0 +1,13 @@ +// Copyright 2014 The Flutter 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 'package:flutter_devicelab/framework/adb.dart' + show DeviceOperatingSystem; +import 'package:flutter_devicelab/framework/framework.dart' show task; +import 'package:flutter_devicelab/tasks/platform_channels_benchmarks.dart' + as platform_channels_benchmarks; + +Future main() async { + await task(platform_channels_benchmarks.runTask(DeviceOperatingSystem.ios)); +} diff --git a/dev/devicelab/lib/microbenchmarks.dart b/dev/devicelab/lib/microbenchmarks.dart new file mode 100644 index 0000000000..e1ca30766a --- /dev/null +++ b/dev/devicelab/lib/microbenchmarks.dart @@ -0,0 +1,105 @@ +// Copyright 2014 The Flutter 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 'dart:async'; +import 'dart:convert'; +import 'dart:io'; + +import 'package:flutter_devicelab/framework/utils.dart'; +import 'package:path/path.dart' as path; + +/// Launches a new Flutter process. +Future startFlutter({ + List options = const [], + bool canFail = false, + Map environment, +}) { + final List args = flutterCommandArgs('run', options); + return startProcess(path.join(flutterDirectory.path, 'bin', 'flutter'), args, environment: environment); +} + +/// Reades through the print commands from [process] waiting for the magic phase +/// that contains microbenchmarks results as defined in +/// `dev/benchmarks/microbenchmarks/lib/common.dart`. +Future> readJsonResults(Process process) { + // IMPORTANT: keep these values in sync with dev/benchmarks/microbenchmarks/lib/common.dart + const String jsonStart = '================ RESULTS ================'; + const String jsonEnd = '================ FORMATTED =============='; + const String jsonPrefix = ':::JSON:::'; + bool jsonStarted = false; + final StringBuffer jsonBuf = StringBuffer(); + final Completer> completer = Completer>(); + + final StreamSubscription stderrSub = process.stderr + .transform(const Utf8Decoder()) + .transform(const LineSplitter()) + .listen((String line) { + stderr.writeln('[STDERR] $line'); + }); + + bool processWasKilledIntentionally = false; + bool resultsHaveBeenParsed = false; + final StreamSubscription stdoutSub = process.stdout + .transform(const Utf8Decoder()) + .transform(const LineSplitter()) + .listen((String line) async { + print(line); + + if (line.contains(jsonStart)) { + jsonStarted = true; + return; + } + + if (line.contains(jsonEnd)) { + final String jsonOutput = jsonBuf.toString(); + + // If we end up here and have already parsed the results, it suggests that + // we have received output from another test because our `flutter run` + // process did not terminate correctly. + // https://github.com/flutter/flutter/issues/19096#issuecomment-402756549 + if (resultsHaveBeenParsed) { + throw 'Additional JSON was received after results has already been ' + 'processed. This suggests the `flutter run` process may have lived ' + 'past the end of our test and collected additional output from the ' + 'next test.\n\n' + 'The JSON below contains all collected output, including both from ' + 'the original test and what followed.\n\n' + '$jsonOutput'; + } + + jsonStarted = false; + processWasKilledIntentionally = true; + resultsHaveBeenParsed = true; + // Sending a SIGINT/SIGTERM to the process here isn't reliable because [process] is + // the shell (flutter is a shell script) and doesn't pass the signal on. + // Sending a `q` is an instruction to quit using the console runner. + // See https://github.com/flutter/flutter/issues/19208 + process.stdin.write('q'); + await process.stdin.flush(); + // Also send a kill signal in case the `q` above didn't work. + process.kill(ProcessSignal.sigint); + try { + completer.complete(Map.from(json.decode(jsonOutput) as Map)); + } catch (ex) { + completer.completeError('Decoding JSON failed ($ex). JSON string was: $jsonOutput'); + } + return; + } + + if (jsonStarted && line.contains(jsonPrefix)) + jsonBuf.writeln(line.substring(line.indexOf(jsonPrefix) + jsonPrefix.length)); + }); + + process.exitCode.then((int code) async { + await Future.wait(>[ + stdoutSub.cancel(), + stderrSub.cancel(), + ]); + if (!processWasKilledIntentionally && code != 0) { + completer.completeError('flutter run failed: exit code=$code'); + } + }); + + return completer.future; +} diff --git a/dev/devicelab/lib/tasks/microbenchmarks.dart b/dev/devicelab/lib/tasks/microbenchmarks.dart index 3b3b105c9a..a88d8de98b 100644 --- a/dev/devicelab/lib/tasks/microbenchmarks.dart +++ b/dev/devicelab/lib/tasks/microbenchmarks.dart @@ -3,13 +3,13 @@ // found in the LICENSE file. import 'dart:async'; -import 'dart:convert'; import 'dart:io'; import 'package:flutter_devicelab/framework/adb.dart'; import 'package:flutter_devicelab/framework/framework.dart'; import 'package:flutter_devicelab/framework/task_result.dart'; import 'package:flutter_devicelab/framework/utils.dart'; +import 'package:flutter_devicelab/microbenchmarks.dart'; import 'package:path/path.dart' as path; /// Creates a device lab task that runs benchmarks in @@ -34,14 +34,15 @@ TaskFunction createMicrobenchmarkTask() { device.deviceId, ]; options.add(benchmarkPath); - return _startFlutter( + return startFlutter( options: options, canFail: false, ); }); - return _readJsonResults(flutterProcess); + return readJsonResults(flutterProcess); } + return _run(); } @@ -57,99 +58,9 @@ TaskFunction createMicrobenchmarkTask() { ...await _runMicrobench('lib/language/sync_star_semantics_bench.dart'), ...await _runMicrobench('lib/foundation/all_elements_bench.dart'), ...await _runMicrobench('lib/foundation/change_notifier_bench.dart'), - }; + }; - return TaskResult.success(allResults, benchmarkScoreKeys: allResults.keys.toList()); + return TaskResult.success(allResults, + benchmarkScoreKeys: allResults.keys.toList()); }; } - -Future _startFlutter({ - List options = const [], - bool canFail = false, - Map environment, -}) { - final List args = flutterCommandArgs('run', options); - return startProcess(path.join(flutterDirectory.path, 'bin', 'flutter'), args, environment: environment); -} - -Future> _readJsonResults(Process process) { - // IMPORTANT: keep these values in sync with dev/benchmarks/microbenchmarks/lib/common.dart - const String jsonStart = '================ RESULTS ================'; - const String jsonEnd = '================ FORMATTED =============='; - const String jsonPrefix = ':::JSON:::'; - bool jsonStarted = false; - final StringBuffer jsonBuf = StringBuffer(); - final Completer> completer = Completer>(); - - final StreamSubscription stderrSub = process.stderr - .transform(const Utf8Decoder()) - .transform(const LineSplitter()) - .listen((String line) { - stderr.writeln('[STDERR] $line'); - }); - - bool processWasKilledIntentionally = false; - bool resultsHaveBeenParsed = false; - final StreamSubscription stdoutSub = process.stdout - .transform(const Utf8Decoder()) - .transform(const LineSplitter()) - .listen((String line) async { - print(line); - - if (line.contains(jsonStart)) { - jsonStarted = true; - return; - } - - if (line.contains(jsonEnd)) { - final String jsonOutput = jsonBuf.toString(); - - // If we end up here and have already parsed the results, it suggests that - // we have received output from another test because our `flutter run` - // process did not terminate correctly. - // https://github.com/flutter/flutter/issues/19096#issuecomment-402756549 - if (resultsHaveBeenParsed) { - throw 'Additional JSON was received after results has already been ' - 'processed. This suggests the `flutter run` process may have lived ' - 'past the end of our test and collected additional output from the ' - 'next test.\n\n' - 'The JSON below contains all collected output, including both from ' - 'the original test and what followed.\n\n' - '$jsonOutput'; - } - - jsonStarted = false; - processWasKilledIntentionally = true; - resultsHaveBeenParsed = true; - // Sending a SIGINT/SIGTERM to the process here isn't reliable because [process] is - // the shell (flutter is a shell script) and doesn't pass the signal on. - // Sending a `q` is an instruction to quit using the console runner. - // See https://github.com/flutter/flutter/issues/19208 - process.stdin.write('q'); - await process.stdin.flush(); - // Also send a kill signal in case the `q` above didn't work. - process.kill(ProcessSignal.sigint); - try { - completer.complete(Map.from(json.decode(jsonOutput) as Map)); - } catch (ex) { - completer.completeError('Decoding JSON failed ($ex). JSON string was: $jsonOutput'); - } - return; - } - - if (jsonStarted && line.contains(jsonPrefix)) - jsonBuf.writeln(line.substring(line.indexOf(jsonPrefix) + jsonPrefix.length)); - }); - - process.exitCode.then((int code) async { - await Future.wait(>[ - stdoutSub.cancel(), - stderrSub.cancel(), - ]); - if (!processWasKilledIntentionally && code != 0) { - completer.completeError('flutter run failed: exit code=$code'); - } - }); - - return completer.future; -} diff --git a/dev/devicelab/lib/tasks/platform_channels_benchmarks.dart b/dev/devicelab/lib/tasks/platform_channels_benchmarks.dart new file mode 100644 index 0000000000..74d84d50e7 --- /dev/null +++ b/dev/devicelab/lib/tasks/platform_channels_benchmarks.dart @@ -0,0 +1,55 @@ +// Copyright 2014 The Flutter 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 'dart:io' show Process, Directory; + +import 'package:flutter_devicelab/framework/adb.dart' as adb; +import 'package:flutter_devicelab/framework/framework.dart' show TaskFunction; +import 'package:flutter_devicelab/framework/task_result.dart' show TaskResult; +import 'package:flutter_devicelab/framework/utils.dart' as utils; +import 'package:flutter_devicelab/microbenchmarks.dart' as microbenchmarks; +import 'package:path/path.dart' as path; + +TaskFunction runTask(adb.DeviceOperatingSystem operatingSystem) { + return () async { + adb.deviceOperatingSystem = operatingSystem; + final adb.Device device = await adb.devices.workingDevice; + await device.unlock(); + + final Directory appDir = utils.dir(path.join(utils.flutterDirectory.path, + 'dev/benchmarks/platform_channels_benchmarks')); + final Process flutterProcess = await utils.inDirectory(appDir, () async { + final String flutterExe = + path.join(utils.flutterDirectory.path, 'bin', 'flutter'); + final List createArgs = [ + 'create', + '--platforms', + 'ios,android', + '--no-overwrite', + '-v', + '.' + ]; + print('\nExecuting: $flutterExe $createArgs $appDir'); + utils.eval(flutterExe, createArgs); + + final List options = [ + '-v', + // --release doesn't work on iOS due to code signing issues + '--profile', + '--no-publish-port', + '-d', + device.deviceId, + ]; + return microbenchmarks.startFlutter( + options: options, + canFail: false, + ); + }); + + final Map results = + await microbenchmarks.readJsonResults(flutterProcess); + return TaskResult.success(results, + benchmarkScoreKeys: results.keys.toList()); + }; +} diff --git a/dev/prod_builders.json b/dev/prod_builders.json index c0a228adf8..11fb8b214e 100644 --- a/dev/prod_builders.json +++ b/dev/prod_builders.json @@ -372,6 +372,12 @@ "task_name": "linux_picture_cache_perf__e2e_summary", "flaky": false }, + { + "name": "Linux platform channels benchmarks", + "repo": "flutter", + "task_name": "linux_platform_channels_benchmarks", + "flaky": true + }, { "name": "Linux platform_views_scroll_perf__timeline_summary", "repo": "flutter", @@ -1152,6 +1158,12 @@ "task_name": "mac_ios_platform_channel_sample_test_swift", "flaky": false }, + { + "name": "Mac_ios platform channels benchmarks", + "repo": "flutter", + "task_name": "mac_ios_platform_channels_benchmarks", + "flaky": true + }, { "name": "Mac_ios platform_interaction_test_ios", "repo": "flutter",