blob: a44e719b17f6f2832e7e019545eda49c0ae53696 [file] [log] [blame]
// 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<double> _runBasicStandardSmall(
BasicMessageChannel<Object?> basicStandard, int count) async {
final Stopwatch watch = Stopwatch();
watch.start();
for (int i = 0; i < count; ++i) {
await basicStandard.send(1234);
}
watch.stop();
return watch.elapsedMicroseconds / count;
}
Future<double> _runBasicStandardLarge(BasicMessageChannel<Object?> basicStandard,
List<Object?> largeBuffer, int count) async {
int size = 0;
final Stopwatch watch = Stopwatch();
watch.start();
for (int i = 0; i < count; ++i) {
final List<Object?>? result =
await basicStandard.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();
if (size != largeBuffer.length * count) {
throw Exception(
"There is an error with the echo channel, the results don't add up: $size",
);
}
return watch.elapsedMicroseconds / count;
}
Future<double> _runBasicBinary(BasicMessageChannel<ByteData> basicBinary,
ByteData buffer, int count) async {
int size = 0;
final Stopwatch watch = Stopwatch();
watch.start();
for (int i = 0; i < count; ++i) {
final ByteData? result = await basicBinary.send(buffer);
// This check should be tiny compared to the actual channel send/receive.
size += (result == null) ? 0 : result.lengthInBytes;
}
watch.stop();
if (size != buffer.lengthInBytes * count) {
throw Exception(
"There is an error with the echo channel, the results don't add up: $size",
);
}
return watch.elapsedMicroseconds / count;
}
Future<void> _runTests() async {
if (kDebugMode) {
throw Exception(
"Must be run in profile mode! Use 'flutter run --profile'.",
);
}
const BasicMessageChannel<Object?> resetChannel = BasicMessageChannel<Object?>(
'dev.flutter.echo.reset',
StandardMessageCodec(),
);
const BasicMessageChannel<Object?> basicStandard = BasicMessageChannel<Object?>(
'dev.flutter.echo.basic.standard',
StandardMessageCodec(),
);
const BasicMessageChannel<ByteData> basicBinary =
BasicMessageChannel<ByteData>(
'dev.flutter.echo.basic.binary',
BinaryCodec(),
);
/// 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);
final ByteData largeBufferBytes =
const StandardMessageCodec().encodeMessage(largeBuffer)!;
final ByteData oneMB = ByteData(1024 * 1024);
const int numMessages = 2500;
final BenchmarkResultPrinter printer = BenchmarkResultPrinter();
resetChannel.send(true);
await _runBasicStandardSmall(basicStandard, 1); // Warmup.
printer.addResult(
description: 'BasicMessageChannel/StandardMessageCodec/Flutter->Host/Small',
value: await _runBasicStandardSmall(basicStandard, numMessages),
unit: 'µs',
name: 'platform_channel_basic_standard_2host_small',
);
resetChannel.send(true);
await _runBasicStandardLarge(basicStandard, largeBuffer, 1); // Warmup.
printer.addResult(
description: 'BasicMessageChannel/StandardMessageCodec/Flutter->Host/Large',
value:
await _runBasicStandardLarge(basicStandard, largeBuffer, numMessages),
unit: 'µs',
name: 'platform_channel_basic_standard_2host_large',
);
resetChannel.send(true);
await _runBasicBinary(basicBinary, largeBufferBytes, 1); // Warmup.
printer.addResult(
description: 'BasicMessageChannel/BinaryCodec/Flutter->Host/Large',
value: await _runBasicBinary(basicBinary, largeBufferBytes, numMessages),
unit: 'µs',
name: 'platform_channel_basic_binary_2host_large',
);
resetChannel.send(true);
await _runBasicBinary(basicBinary, oneMB, 1); // Warmup.
printer.addResult(
description: 'BasicMessageChannel/BinaryCodec/Flutter->Host/1MB',
value: await _runBasicBinary(basicBinary, oneMB, numMessages),
unit: 'µs',
name: 'platform_channel_basic_binary_2host_1MB',
);
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));
}