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 index b30bf2ccaa7..a597100bb83 100644 --- 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 @@ -31,6 +31,9 @@ class MainActivity: FlutterActivity() { } reply.reply(byteBufferCache) } } + val taskQueue = flutterEngine.dartExecutor.getBinaryMessenger().makeBackgroundTaskQueue(); + val backgroundStandard = BasicMessageChannel(flutterEngine.dartExecutor, "dev.flutter.echo.background.standard", StandardMessageCodec.INSTANCE, taskQueue) + backgroundStandard.setMessageHandler { message, reply -> reply.reply(message) } super.configureFlutterEngine(flutterEngine) } } diff --git a/dev/benchmarks/platform_channels_benchmarks/lib/main.dart b/dev/benchmarks/platform_channels_benchmarks/lib/main.dart index a44e719b17f..f7e7b5efe41 100644 --- a/dev/benchmarks/platform_channels_benchmarks/lib/main.dart +++ b/dev/benchmarks/platform_channels_benchmarks/lib/main.dart @@ -2,13 +2,14 @@ // 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:io' show Platform; 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'; @@ -49,7 +50,9 @@ List _makeTestBuffer(int size) { } Future _runBasicStandardSmall( - BasicMessageChannel basicStandard, int count) async { + BasicMessageChannel basicStandard, + int count, +) async { final Stopwatch watch = Stopwatch(); watch.start(); for (int i = 0; i < count; ++i) { @@ -59,8 +62,54 @@ Future _runBasicStandardSmall( return watch.elapsedMicroseconds / count; } -Future _runBasicStandardLarge(BasicMessageChannel basicStandard, - List largeBuffer, int count) async { +class _Counter { + int count = 0; +} + +void _runBasicStandardParallelRecurse( + BasicMessageChannel basicStandard, + _Counter counter, + int count, + Completer completer, + Object? payload, +) { + counter.count += 1; + if (counter.count == count) { + completer.complete(counter.count); + } else if (counter.count < count) { + basicStandard.send(payload).then((Object? result) { + _runBasicStandardParallelRecurse( + basicStandard, counter, count, completer, payload); + }); + } +} + +Future _runBasicStandardParallel( + BasicMessageChannel basicStandard, + int count, + Object? payload, + int parallel, +) async { + final Stopwatch watch = Stopwatch(); + final Completer completer = Completer(); + final _Counter counter = _Counter(); + watch.start(); + for (int i = 0; i < parallel; ++i) { + basicStandard.send(payload).then((Object? result) { + _runBasicStandardParallelRecurse( + basicStandard, counter, count, completer, payload); + }); + } + await completer.future; + watch.stop(); + return watch.elapsedMicroseconds / count; +} + +Future _runBasicStandardLarge( + BasicMessageChannel basicStandard, + List largeBuffer, + int count, +) async { int size = 0; final Stopwatch watch = Stopwatch(); watch.start(); @@ -81,8 +130,11 @@ Future _runBasicStandardLarge(BasicMessageChannel basicStandard return watch.elapsedMicroseconds / count; } -Future _runBasicBinary(BasicMessageChannel basicBinary, - ByteData buffer, int count) async { +Future _runBasicBinary( + BasicMessageChannel basicBinary, + ByteData buffer, + int count, +) async { int size = 0; final Stopwatch watch = Stopwatch(); watch.start(); @@ -101,6 +153,25 @@ Future _runBasicBinary(BasicMessageChannel basicBinary, return watch.elapsedMicroseconds / count; } +Future _runTest({ + required Future Function(int) test, + required BasicMessageChannel resetChannel, + required BenchmarkResultPrinter printer, + required String description, + required String name, + required int numMessages, +}) async { + resetChannel.send(true); + // Prime test. + await test(1); + printer.addResult( + description: description, + value: await test(numMessages), + unit: 'µs', + name: name, + ); +} + Future _runTests() async { if (kDebugMode) { throw Exception( @@ -108,11 +179,13 @@ Future _runTests() async { ); } - const BasicMessageChannel resetChannel = BasicMessageChannel( + const BasicMessageChannel resetChannel = + BasicMessageChannel( 'dev.flutter.echo.reset', StandardMessageCodec(), ); - const BasicMessageChannel basicStandard = BasicMessageChannel( + const BasicMessageChannel basicStandard = + BasicMessageChannel( 'dev.flutter.echo.basic.standard', StandardMessageCodec(), ); @@ -133,39 +206,74 @@ Future _runTests() async { const int numMessages = 2500; final BenchmarkResultPrinter printer = BenchmarkResultPrinter(); - resetChannel.send(true); - await _runBasicStandardSmall(basicStandard, 1); // Warmup. - printer.addResult( + await _runTest( + test: (int x) => _runBasicStandardSmall(basicStandard, x), + resetChannel: resetChannel, + printer: printer, description: 'BasicMessageChannel/StandardMessageCodec/Flutter->Host/Small', - value: await _runBasicStandardSmall(basicStandard, numMessages), - unit: 'µs', name: 'platform_channel_basic_standard_2host_small', + numMessages: numMessages, ); - resetChannel.send(true); - await _runBasicStandardLarge(basicStandard, largeBuffer, 1); // Warmup. - printer.addResult( + await _runTest( + test: (int x) => _runBasicStandardLarge(basicStandard, largeBuffer, x), + resetChannel: resetChannel, + printer: printer, description: 'BasicMessageChannel/StandardMessageCodec/Flutter->Host/Large', - value: - await _runBasicStandardLarge(basicStandard, largeBuffer, numMessages), - unit: 'µs', name: 'platform_channel_basic_standard_2host_large', + numMessages: numMessages, ); - resetChannel.send(true); - await _runBasicBinary(basicBinary, largeBufferBytes, 1); // Warmup. - printer.addResult( + await _runTest( + test: (int x) => _runBasicBinary(basicBinary, largeBufferBytes, x), + resetChannel: resetChannel, + printer: printer, description: 'BasicMessageChannel/BinaryCodec/Flutter->Host/Large', - value: await _runBasicBinary(basicBinary, largeBufferBytes, numMessages), - unit: 'µs', name: 'platform_channel_basic_binary_2host_large', + numMessages: numMessages, ); - resetChannel.send(true); - await _runBasicBinary(basicBinary, oneMB, 1); // Warmup. - printer.addResult( + await _runTest( + test: (int x) => _runBasicBinary(basicBinary, oneMB, x), + resetChannel: resetChannel, + printer: printer, description: 'BasicMessageChannel/BinaryCodec/Flutter->Host/1MB', - value: await _runBasicBinary(basicBinary, oneMB, numMessages), - unit: 'µs', name: 'platform_channel_basic_binary_2host_1MB', + numMessages: numMessages, ); + await _runTest( + test: (int x) => _runBasicStandardParallel(basicStandard, x, 1234, 3), + resetChannel: resetChannel, + printer: printer, + description: + 'BasicMessageChannel/StandardMessageCodec/Flutter->Host/SmallParallel3', + name: 'platform_channel_basic_standard_2host_small_parallel_3', + numMessages: numMessages, + ); + if (Platform.isAndroid) { + // Background platform channels aren't yet implemented for iOS. + const BasicMessageChannel backgroundStandard = + BasicMessageChannel( + 'dev.flutter.echo.background.standard', + StandardMessageCodec(), + ); + await _runTest( + test: (int x) => _runBasicStandardSmall(backgroundStandard, x), + resetChannel: resetChannel, + printer: printer, + description: + 'BasicMessageChannel/StandardMessageCodec/Flutter->Host (background)/Small', + name: 'platform_channel_basic_standard_2hostbackground_small', + numMessages: numMessages, + ); + await _runTest( + test: (int x) => + _runBasicStandardParallel(backgroundStandard, x, 1234, 3), + resetChannel: resetChannel, + printer: printer, + description: + 'BasicMessageChannel/StandardMessageCodec/Flutter->Host (background)/SmallParallel3', + name: 'platform_channel_basic_standard_2hostbackground_small_parallel_3', + numMessages: numMessages, + ); + } printer.printToStdout(); }