Reland Add UI Benchmarks (#153368)
Reland https://github.com/flutter/flutter/pull/143799 which is part 1 of https://github.com/flutter/flutter/pull/138481 and https://github.com/flutter/flutter/issues/146211. Could someone run this in device-lab so we are 100% sure it works? I don't know if it was a flake or what last time. Locally it works well.
This commit is contained in:
parent
f0dc0b798f
commit
1fdb159d11
@ -16,6 +16,7 @@ import 'foundation/change_notifier_bench.dart' as change_notifier_bench;
|
|||||||
import 'foundation/clamp.dart' as clamp;
|
import 'foundation/clamp.dart' as clamp;
|
||||||
import 'foundation/decode_and_parse_asset_manifest.dart'
|
import 'foundation/decode_and_parse_asset_manifest.dart'
|
||||||
as decode_and_parse_asset_manifest;
|
as decode_and_parse_asset_manifest;
|
||||||
|
import 'foundation/observer_list_bench.dart' as observer_list_bench;
|
||||||
import 'foundation/platform_asset_bundle.dart' as platform_asset_bundle;
|
import 'foundation/platform_asset_bundle.dart' as platform_asset_bundle;
|
||||||
import 'foundation/standard_message_codec_bench.dart'
|
import 'foundation/standard_message_codec_bench.dart'
|
||||||
as standard_message_codec_bench;
|
as standard_message_codec_bench;
|
||||||
@ -64,6 +65,7 @@ Future<void> main() async {
|
|||||||
'foundation/decode_and_parse_asset_manifest.dart',
|
'foundation/decode_and_parse_asset_manifest.dart',
|
||||||
decode_and_parse_asset_manifest.execute
|
decode_and_parse_asset_manifest.execute
|
||||||
),
|
),
|
||||||
|
('foundation/observer_list_bench.dart', observer_list_bench.execute),
|
||||||
(
|
(
|
||||||
'geometry/matrix_utils_transform_bench.dart',
|
'geometry/matrix_utils_transform_bench.dart',
|
||||||
matrix_utils_transform_bench.execute
|
matrix_utils_transform_bench.execute
|
||||||
|
@ -0,0 +1,172 @@
|
|||||||
|
// 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/animation.dart';
|
||||||
|
import 'package:flutter/foundation.dart';
|
||||||
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
|
|
||||||
|
import '../common.dart';
|
||||||
|
|
||||||
|
const int _kNumIterationsList = 2 << 10;
|
||||||
|
const int _kNumIterationsHashed = 2 << 15;
|
||||||
|
const List<int> callbackCounts = <int>[1, 10, 100, 500];
|
||||||
|
|
||||||
|
class TestAnimationController extends AnimationController {
|
||||||
|
TestAnimationController() : super(vsync: const TestVSync());
|
||||||
|
|
||||||
|
@override
|
||||||
|
void notifyListeners() => super.notifyListeners();
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> execute() async {
|
||||||
|
assert(false,
|
||||||
|
"Don't run benchmarks in debug mode! Use 'flutter run --release'.");
|
||||||
|
|
||||||
|
final BenchmarkResultPrinter printer = BenchmarkResultPrinter();
|
||||||
|
|
||||||
|
void runNotifiyListenersLoopWithObserverList(
|
||||||
|
int totalIterations, {
|
||||||
|
bool failRemoval = false,
|
||||||
|
bool addResult = true,
|
||||||
|
}) {
|
||||||
|
final String suffix = failRemoval ? 'removalFail' : 'removalSuccess';
|
||||||
|
final String name = 'notifyListeners:ObserverList:$suffix';
|
||||||
|
|
||||||
|
void miss() {}
|
||||||
|
|
||||||
|
for (final int callbackCount in callbackCounts) {
|
||||||
|
final int iterations = totalIterations ~/ callbackCount;
|
||||||
|
|
||||||
|
final ObserverList<VoidCallback> observerList =
|
||||||
|
ObserverList<VoidCallback>();
|
||||||
|
for (int i = 0; i < callbackCount; ++i) {
|
||||||
|
observerList.add(
|
||||||
|
switch (failRemoval) {
|
||||||
|
false => () {
|
||||||
|
final VoidCallback first =
|
||||||
|
(observerList.iterator..moveNext()).current;
|
||||||
|
|
||||||
|
observerList.remove(first);
|
||||||
|
observerList.add(first);
|
||||||
|
},
|
||||||
|
true => () => observerList.remove(miss),
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
final Stopwatch watch = Stopwatch()..start();
|
||||||
|
|
||||||
|
for (int i = 0; i < iterations; ++i) {
|
||||||
|
final List<VoidCallback> list = observerList.toList(growable: false);
|
||||||
|
for (final VoidCallback cb in list) {
|
||||||
|
if (observerList.contains(cb)) {
|
||||||
|
cb();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
watch.stop();
|
||||||
|
|
||||||
|
if (addResult) {
|
||||||
|
printer.addResult(
|
||||||
|
description: '$name ($callbackCount callbacks)',
|
||||||
|
value: watch.elapsedMicroseconds / iterations,
|
||||||
|
unit: 'µs per iteration',
|
||||||
|
name: '$name$callbackCount',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void runNotifiyListenersLoopWithHashedObserverList(
|
||||||
|
int totalIterations, {
|
||||||
|
bool addResult = true,
|
||||||
|
}) {
|
||||||
|
const String name = 'notifyListeners:HashedObserverList';
|
||||||
|
|
||||||
|
for (final int callbackCount in callbackCounts) {
|
||||||
|
final int iterations = totalIterations ~/ callbackCount;
|
||||||
|
|
||||||
|
final HashedObserverList<VoidCallback> observerList =
|
||||||
|
HashedObserverList<VoidCallback>();
|
||||||
|
for (int i = 0; i < callbackCount; ++i) {
|
||||||
|
observerList.add(() {
|
||||||
|
final VoidCallback first =
|
||||||
|
(observerList.iterator..moveNext()).current;
|
||||||
|
|
||||||
|
observerList.remove(first);
|
||||||
|
observerList.add(first);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
final Stopwatch watch = Stopwatch()..start();
|
||||||
|
|
||||||
|
for (int i = 0; i < iterations; ++i) {
|
||||||
|
final List<VoidCallback> list = observerList.toList(growable: false);
|
||||||
|
for (final VoidCallback cb in list) {
|
||||||
|
if (observerList.contains(cb)) {
|
||||||
|
cb();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
watch.stop();
|
||||||
|
|
||||||
|
if (addResult) {
|
||||||
|
printer.addResult(
|
||||||
|
description: '$name ($callbackCount callbacks)',
|
||||||
|
value: watch.elapsedMicroseconds / iterations,
|
||||||
|
unit: 'µs per iteration',
|
||||||
|
name: '$name$callbackCount',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void runNotifiyListenersLoopWithAnimationController(
|
||||||
|
int totalIterations, {
|
||||||
|
bool addResult = true,
|
||||||
|
}) {
|
||||||
|
const String name = 'notifyListeners:AnimationController';
|
||||||
|
|
||||||
|
for (final int callbackCount in callbackCounts) {
|
||||||
|
final int iterations = totalIterations ~/ callbackCount;
|
||||||
|
|
||||||
|
final TestAnimationController controller = TestAnimationController();
|
||||||
|
for (int i = 0; i < callbackCount; ++i) {
|
||||||
|
late final VoidCallback cb;
|
||||||
|
cb = () {
|
||||||
|
controller.removeListener(cb);
|
||||||
|
controller.addListener(cb);
|
||||||
|
};
|
||||||
|
controller.addListener(cb);
|
||||||
|
}
|
||||||
|
|
||||||
|
final Stopwatch watch = Stopwatch()..start();
|
||||||
|
|
||||||
|
for (int i = 0; i < iterations; ++i) {
|
||||||
|
controller.notifyListeners();
|
||||||
|
}
|
||||||
|
|
||||||
|
watch.stop();
|
||||||
|
|
||||||
|
if (addResult) {
|
||||||
|
printer.addResult(
|
||||||
|
description: '$name ($callbackCount callbacks)',
|
||||||
|
value: watch.elapsedMicroseconds / iterations,
|
||||||
|
unit: 'µs per iteration',
|
||||||
|
name: '$name$callbackCount',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
runNotifiyListenersLoopWithObserverList(_kNumIterationsList);
|
||||||
|
runNotifiyListenersLoopWithObserverList(_kNumIterationsList,
|
||||||
|
failRemoval: true);
|
||||||
|
runNotifiyListenersLoopWithHashedObserverList(_kNumIterationsHashed);
|
||||||
|
runNotifiyListenersLoopWithAnimationController(_kNumIterationsHashed);
|
||||||
|
|
||||||
|
printer.printToStdout();
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user