mirror of
https://github.com/flutter/flutter.git
synced 2025-06-03 00:51:18 +00:00
Added performance benchmarks for platform channels (#81414)
This commit is contained in:
parent
dbc8826816
commit
a5f57b9e64
10
dev/benchmarks/platform_channels_benchmarks/.metadata
Normal file
10
dev/benchmarks/platform_channels_benchmarks/.metadata
Normal file
@ -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
|
6
dev/benchmarks/platform_channels_benchmarks/README.md
Normal file
6
dev/benchmarks/platform_channels_benchmarks/README.md
Normal file
@ -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 .`
|
@ -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)
|
||||||
|
}
|
||||||
|
}
|
@ -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)
|
||||||
|
}
|
||||||
|
}
|
130
dev/benchmarks/platform_channels_benchmarks/lib/main.dart
Normal file
130
dev/benchmarks/platform_channels_benchmarks/lib/main.dart
Normal file
@ -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<Object> _makeTestBuffer(int size) {
|
||||||
|
final List<Object> answer = <Object>[];
|
||||||
|
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(<int>[1234]);
|
||||||
|
break;
|
||||||
|
case 5:
|
||||||
|
answer.add(<String, int>{'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<void> _runTests() async {
|
||||||
|
if (kDebugMode) {
|
||||||
|
throw Exception(
|
||||||
|
"Must be run in profile mode! Use 'flutter run --profile'.");
|
||||||
|
}
|
||||||
|
const int numMessages = 2500;
|
||||||
|
|
||||||
|
const BasicMessageChannel<Object> channel = BasicMessageChannel<Object>(
|
||||||
|
'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<Object> largeBuffer = _makeTestBuffer(1000);
|
||||||
|
|
||||||
|
int size = 0;
|
||||||
|
watch.start();
|
||||||
|
for (int i = 0; i < numMessages; ++i) {
|
||||||
|
final List<Object> result = await channel.send(largeBuffer) as List<Object>;
|
||||||
|
// 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<void> 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));
|
||||||
|
}
|
77
dev/benchmarks/platform_channels_benchmarks/pubspec.yaml
Normal file
77
dev/benchmarks/platform_channels_benchmarks/pubspec.yaml
Normal file
@ -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
|
14
dev/devicelab/bin/tasks/platform_channels_benchmarks.dart
Normal file
14
dev/devicelab/bin/tasks/platform_channels_benchmarks.dart
Normal file
@ -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<void> main() async {
|
||||||
|
await task(
|
||||||
|
platform_channels_benchmarks.runTask(DeviceOperatingSystem.android));
|
||||||
|
}
|
@ -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<void> main() async {
|
||||||
|
await task(platform_channels_benchmarks.runTask(DeviceOperatingSystem.ios));
|
||||||
|
}
|
105
dev/devicelab/lib/microbenchmarks.dart
Normal file
105
dev/devicelab/lib/microbenchmarks.dart
Normal file
@ -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<Process> startFlutter({
|
||||||
|
List<String> options = const <String>[],
|
||||||
|
bool canFail = false,
|
||||||
|
Map<String, String> environment,
|
||||||
|
}) {
|
||||||
|
final List<String> 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<Map<String, double>> 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<Map<String, double>> completer = Completer<Map<String, double>>();
|
||||||
|
|
||||||
|
final StreamSubscription<String> stderrSub = process.stderr
|
||||||
|
.transform<String>(const Utf8Decoder())
|
||||||
|
.transform<String>(const LineSplitter())
|
||||||
|
.listen((String line) {
|
||||||
|
stderr.writeln('[STDERR] $line');
|
||||||
|
});
|
||||||
|
|
||||||
|
bool processWasKilledIntentionally = false;
|
||||||
|
bool resultsHaveBeenParsed = false;
|
||||||
|
final StreamSubscription<String> stdoutSub = process.stdout
|
||||||
|
.transform<String>(const Utf8Decoder())
|
||||||
|
.transform<String>(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<String, double>.from(json.decode(jsonOutput) as Map<String, dynamic>));
|
||||||
|
} 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<void>((int code) async {
|
||||||
|
await Future.wait<void>(<Future<void>>[
|
||||||
|
stdoutSub.cancel(),
|
||||||
|
stderrSub.cancel(),
|
||||||
|
]);
|
||||||
|
if (!processWasKilledIntentionally && code != 0) {
|
||||||
|
completer.completeError('flutter run failed: exit code=$code');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return completer.future;
|
||||||
|
}
|
@ -3,13 +3,13 @@
|
|||||||
// found in the LICENSE file.
|
// found in the LICENSE file.
|
||||||
|
|
||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
import 'dart:convert';
|
|
||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
|
|
||||||
import 'package:flutter_devicelab/framework/adb.dart';
|
import 'package:flutter_devicelab/framework/adb.dart';
|
||||||
import 'package:flutter_devicelab/framework/framework.dart';
|
import 'package:flutter_devicelab/framework/framework.dart';
|
||||||
import 'package:flutter_devicelab/framework/task_result.dart';
|
import 'package:flutter_devicelab/framework/task_result.dart';
|
||||||
import 'package:flutter_devicelab/framework/utils.dart';
|
import 'package:flutter_devicelab/framework/utils.dart';
|
||||||
|
import 'package:flutter_devicelab/microbenchmarks.dart';
|
||||||
import 'package:path/path.dart' as path;
|
import 'package:path/path.dart' as path;
|
||||||
|
|
||||||
/// Creates a device lab task that runs benchmarks in
|
/// Creates a device lab task that runs benchmarks in
|
||||||
@ -34,14 +34,15 @@ TaskFunction createMicrobenchmarkTask() {
|
|||||||
device.deviceId,
|
device.deviceId,
|
||||||
];
|
];
|
||||||
options.add(benchmarkPath);
|
options.add(benchmarkPath);
|
||||||
return _startFlutter(
|
return startFlutter(
|
||||||
options: options,
|
options: options,
|
||||||
canFail: false,
|
canFail: false,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
return _readJsonResults(flutterProcess);
|
return readJsonResults(flutterProcess);
|
||||||
}
|
}
|
||||||
|
|
||||||
return _run();
|
return _run();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -57,99 +58,9 @@ TaskFunction createMicrobenchmarkTask() {
|
|||||||
...await _runMicrobench('lib/language/sync_star_semantics_bench.dart'),
|
...await _runMicrobench('lib/language/sync_star_semantics_bench.dart'),
|
||||||
...await _runMicrobench('lib/foundation/all_elements_bench.dart'),
|
...await _runMicrobench('lib/foundation/all_elements_bench.dart'),
|
||||||
...await _runMicrobench('lib/foundation/change_notifier_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<Process> _startFlutter({
|
|
||||||
List<String> options = const <String>[],
|
|
||||||
bool canFail = false,
|
|
||||||
Map<String, String> environment,
|
|
||||||
}) {
|
|
||||||
final List<String> args = flutterCommandArgs('run', options);
|
|
||||||
return startProcess(path.join(flutterDirectory.path, 'bin', 'flutter'), args, environment: environment);
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<Map<String, double>> _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<Map<String, double>> completer = Completer<Map<String, double>>();
|
|
||||||
|
|
||||||
final StreamSubscription<String> stderrSub = process.stderr
|
|
||||||
.transform<String>(const Utf8Decoder())
|
|
||||||
.transform<String>(const LineSplitter())
|
|
||||||
.listen((String line) {
|
|
||||||
stderr.writeln('[STDERR] $line');
|
|
||||||
});
|
|
||||||
|
|
||||||
bool processWasKilledIntentionally = false;
|
|
||||||
bool resultsHaveBeenParsed = false;
|
|
||||||
final StreamSubscription<String> stdoutSub = process.stdout
|
|
||||||
.transform<String>(const Utf8Decoder())
|
|
||||||
.transform<String>(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<String, double>.from(json.decode(jsonOutput) as Map<String, dynamic>));
|
|
||||||
} 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<void>((int code) async {
|
|
||||||
await Future.wait<void>(<Future<void>>[
|
|
||||||
stdoutSub.cancel(),
|
|
||||||
stderrSub.cancel(),
|
|
||||||
]);
|
|
||||||
if (!processWasKilledIntentionally && code != 0) {
|
|
||||||
completer.completeError('flutter run failed: exit code=$code');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return completer.future;
|
|
||||||
}
|
|
||||||
|
55
dev/devicelab/lib/tasks/platform_channels_benchmarks.dart
Normal file
55
dev/devicelab/lib/tasks/platform_channels_benchmarks.dart
Normal file
@ -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<String> createArgs = <String>[
|
||||||
|
'create',
|
||||||
|
'--platforms',
|
||||||
|
'ios,android',
|
||||||
|
'--no-overwrite',
|
||||||
|
'-v',
|
||||||
|
'.'
|
||||||
|
];
|
||||||
|
print('\nExecuting: $flutterExe $createArgs $appDir');
|
||||||
|
utils.eval(flutterExe, createArgs);
|
||||||
|
|
||||||
|
final List<String> options = <String>[
|
||||||
|
'-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<String, double> results =
|
||||||
|
await microbenchmarks.readJsonResults(flutterProcess);
|
||||||
|
return TaskResult.success(results,
|
||||||
|
benchmarkScoreKeys: results.keys.toList());
|
||||||
|
};
|
||||||
|
}
|
@ -372,6 +372,12 @@
|
|||||||
"task_name": "linux_picture_cache_perf__e2e_summary",
|
"task_name": "linux_picture_cache_perf__e2e_summary",
|
||||||
"flaky": false
|
"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",
|
"name": "Linux platform_views_scroll_perf__timeline_summary",
|
||||||
"repo": "flutter",
|
"repo": "flutter",
|
||||||
@ -1152,6 +1158,12 @@
|
|||||||
"task_name": "mac_ios_platform_channel_sample_test_swift",
|
"task_name": "mac_ios_platform_channel_sample_test_swift",
|
||||||
"flaky": false
|
"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",
|
"name": "Mac_ios platform_interaction_test_ios",
|
||||||
"repo": "flutter",
|
"repo": "flutter",
|
||||||
|
Loading…
Reference in New Issue
Block a user