mirror of
https://github.com/dart-lang/sdk
synced 2024-10-14 09:01:42 +00:00
[benchmark] Benchmark for some .runtimeType patterns from Flutter
Change-Id: I3799d6c8d7d35b9d293ecf0fb79c61cb10837356 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/144813 Commit-Queue: Stephen Adams <sra@google.com> Reviewed-by: Jonas Termansen <sortie@google.com>
This commit is contained in:
parent
3e26a5d0dd
commit
b328cadaac
176
benchmarks/RuntimeType/dart/RuntimeType.dart
Normal file
176
benchmarks/RuntimeType/dart/RuntimeType.dart
Normal file
|
@ -0,0 +1,176 @@
|
||||||
|
// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
|
||||||
|
// for details. All rights reserved. Use of this source code is governed by a
|
||||||
|
// BSD-style license that can be found in the LICENSE file.
|
||||||
|
//
|
||||||
|
// Benchmark for runtimeType patterns as used in Flutter.
|
||||||
|
|
||||||
|
// ignore_for_file: prefer_const_constructors
|
||||||
|
// ignore_for_file: avoid_function_literals_in_foreach_calls
|
||||||
|
|
||||||
|
import 'dart:typed_data';
|
||||||
|
|
||||||
|
import 'package:benchmark_harness/benchmark_harness.dart';
|
||||||
|
|
||||||
|
abstract class Key {
|
||||||
|
const factory Key(String value) = ValueKey<String>;
|
||||||
|
const Key.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract class LocalKey extends Key {
|
||||||
|
const LocalKey() : super.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
class ValueKey<T> extends LocalKey {
|
||||||
|
const ValueKey(this.value);
|
||||||
|
final T value;
|
||||||
|
@override
|
||||||
|
bool operator ==(Object other) {
|
||||||
|
if (other.runtimeType != runtimeType) return false;
|
||||||
|
return other is ValueKey<T> && other.value == value;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
int get hashCode => value.hashCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract class Widget {
|
||||||
|
const Widget({this.key});
|
||||||
|
final Key key;
|
||||||
|
|
||||||
|
@pragma('dart2js:noInline')
|
||||||
|
static bool canUpdate(Widget oldWidget, Widget newWidget) {
|
||||||
|
return oldWidget.runtimeType == newWidget.runtimeType &&
|
||||||
|
oldWidget.key == newWidget.key;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class AWidget extends Widget {
|
||||||
|
const AWidget({Key key}) : super(key: key);
|
||||||
|
}
|
||||||
|
|
||||||
|
class BWidget extends Widget {
|
||||||
|
const BWidget({Key key}) : super(key: key);
|
||||||
|
}
|
||||||
|
|
||||||
|
class CWidget extends Widget {
|
||||||
|
const CWidget({Key key}) : super(key: key);
|
||||||
|
}
|
||||||
|
|
||||||
|
class DWidget extends Widget {
|
||||||
|
const DWidget({Key key}) : super(key: key);
|
||||||
|
}
|
||||||
|
|
||||||
|
class EWidget extends Widget {
|
||||||
|
const EWidget({Key key}) : super(key: key);
|
||||||
|
}
|
||||||
|
|
||||||
|
class FWidget extends Widget {
|
||||||
|
const FWidget({Key key}) : super(key: key);
|
||||||
|
}
|
||||||
|
|
||||||
|
class WWidget<W extends Widget> extends Widget {
|
||||||
|
final W /*?*/ ref;
|
||||||
|
const WWidget({this.ref, Key key}) : super(key: key);
|
||||||
|
}
|
||||||
|
|
||||||
|
class WidgetCanUpdateBenchmark extends BenchmarkBase {
|
||||||
|
WidgetCanUpdateBenchmark() : super('RuntimeType.Widget.canUpdate.byType');
|
||||||
|
|
||||||
|
// All widgets have different types.
|
||||||
|
static List<Widget> _widgets() => [
|
||||||
|
AWidget(),
|
||||||
|
BWidget(),
|
||||||
|
CWidget(),
|
||||||
|
DWidget(),
|
||||||
|
EWidget(),
|
||||||
|
FWidget(),
|
||||||
|
WWidget<AWidget>(),
|
||||||
|
WWidget<BWidget>(ref: const BWidget()),
|
||||||
|
WWidget<CWidget>(ref: CWidget()),
|
||||||
|
const WWidget<DWidget>(ref: DWidget()),
|
||||||
|
];
|
||||||
|
// Bulk up list to reduce loop overheads.
|
||||||
|
final List<Widget> widgets = _widgets() + _widgets() + _widgets();
|
||||||
|
|
||||||
|
@override
|
||||||
|
void exercise() => run();
|
||||||
|
|
||||||
|
@override
|
||||||
|
void run() {
|
||||||
|
for (var w1 in widgets) {
|
||||||
|
for (var w2 in widgets) {
|
||||||
|
if (Widget.canUpdate(w1, w2) != Widget.canUpdate(w2, w1)) {
|
||||||
|
throw 'Hmm $w1 $w2';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Normalize by number of calls to [Widgets.canUpdate].
|
||||||
|
@override
|
||||||
|
double measure() => super.measure() / (widgets.length * widgets.length * 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
class ValueKeyEqualBenchmark extends BenchmarkBase {
|
||||||
|
ValueKeyEqualBenchmark() : super('RuntimeType.Widget.canUpdate.byKey');
|
||||||
|
|
||||||
|
// All widgets the same class but distinguished on keys.
|
||||||
|
static List<Widget> _widgets() => [
|
||||||
|
AWidget(),
|
||||||
|
AWidget(key: ValueKey(1)),
|
||||||
|
AWidget(key: ValueKey(1)),
|
||||||
|
AWidget(key: ValueKey(2)),
|
||||||
|
AWidget(key: ValueKey(2)),
|
||||||
|
AWidget(key: ValueKey(3)),
|
||||||
|
AWidget(key: ValueKey('one')),
|
||||||
|
AWidget(key: ValueKey('two')),
|
||||||
|
AWidget(key: ValueKey('three')),
|
||||||
|
AWidget(key: ValueKey(Duration(seconds: 5))),
|
||||||
|
];
|
||||||
|
// Bulk up list to reduce loop overheads.
|
||||||
|
final List<Widget> widgets = _widgets() + _widgets() + _widgets();
|
||||||
|
|
||||||
|
@override
|
||||||
|
void exercise() => run();
|
||||||
|
|
||||||
|
@override
|
||||||
|
void run() {
|
||||||
|
for (var w1 in widgets) {
|
||||||
|
for (var w2 in widgets) {
|
||||||
|
if (Widget.canUpdate(w1, w2) != Widget.canUpdate(w2, w1)) {
|
||||||
|
throw 'Hmm $w1 $w2';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Normalize by number of calls to [Widgets.canUpdate].
|
||||||
|
@override
|
||||||
|
double measure() => super.measure() / (widgets.length * widgets.length * 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
void pollute() {
|
||||||
|
// Various bits of code to make environment less unrealistic.
|
||||||
|
void check(dynamic a, dynamic b) {
|
||||||
|
if (a.runtimeType != b.runtimeType) throw 'mismatch $a $b';
|
||||||
|
}
|
||||||
|
|
||||||
|
check(Uint8List(1), Uint8List(2)); // dart2js needs native interceptors.
|
||||||
|
check(Int16List(1), Int16List(2));
|
||||||
|
check([], []);
|
||||||
|
check(<bool>{}, <bool>{});
|
||||||
|
}
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
pollute();
|
||||||
|
|
||||||
|
final benchmarks = [
|
||||||
|
WidgetCanUpdateBenchmark(),
|
||||||
|
ValueKeyEqualBenchmark(),
|
||||||
|
];
|
||||||
|
|
||||||
|
// Warm up all benchmarks before running any.
|
||||||
|
benchmarks.forEach((bm) => bm.run());
|
||||||
|
|
||||||
|
benchmarks.forEach((bm) => bm.report());
|
||||||
|
}
|
Loading…
Reference in a new issue