mirror of
https://github.com/flutter/flutter
synced 2024-10-02 14:34:22 +00:00
add gradient benchmarks (#101549)
This commit is contained in:
parent
c14ca6d321
commit
493323506f
33
.ci.yaml
33
.ci.yaml
|
@ -2374,6 +2374,39 @@ targets:
|
|||
task_name: opacity_peephole_col_of_alpha_savelayer_rows_perf__e2e_summary
|
||||
scheduler: luci
|
||||
|
||||
- name: Linux_android gradient_dynamic_perf__e2e_summary
|
||||
bringup: true
|
||||
recipe: devicelab/devicelab_drone
|
||||
presubmit: false
|
||||
timeout: 60
|
||||
properties:
|
||||
tags: >
|
||||
["devicelab","android","linux"]
|
||||
task_name: gradient_dynamic_perf__e2e_summary
|
||||
scheduler: luci
|
||||
|
||||
- name: Linux_android gradient_consistent_perf__e2e_summary
|
||||
bringup: true
|
||||
recipe: devicelab/devicelab_drone
|
||||
presubmit: false
|
||||
timeout: 60
|
||||
properties:
|
||||
tags: >
|
||||
["devicelab","android","linux"]
|
||||
task_name: gradient_consistent_perf__e2e_summary
|
||||
scheduler: luci
|
||||
|
||||
- name: Linux_android gradient_static_perf__e2e_summary
|
||||
bringup: true
|
||||
recipe: devicelab/devicelab_drone
|
||||
presubmit: false
|
||||
timeout: 60
|
||||
properties:
|
||||
tags: >
|
||||
["devicelab","android","linux"]
|
||||
task_name: gradient_static_perf__e2e_summary
|
||||
scheduler: luci
|
||||
|
||||
- name: Linux_android android_choreographer_do_frame_test
|
||||
recipe: devicelab/devicelab_drone
|
||||
presubmit: false
|
||||
|
|
|
@ -75,6 +75,9 @@
|
|||
/dev/devicelab/bin/tasks/opacity_peephole_fade_transition_text_perf__e2e_summary.dart @flar @flutter/engine
|
||||
/dev/devicelab/bin/tasks/opacity_peephole_col_of_alpha_savelayer_rows_perf__e2e_summary.dart @flar @flutter/engine
|
||||
/dev/devicelab/bin/tasks/opacity_peephole_grid_of_alpha_savelayers_perf__e2e_summary.dart @flar @flutter/engine
|
||||
/dev/devicelab/bin/tasks/gradient_consistent_perf__e2e_summary.dart @flar @flutter/engine
|
||||
/dev/devicelab/bin/tasks/gradient_dynamic_perf__e2e_summary.dart @flar @flutter/engine
|
||||
/dev/devicelab/bin/tasks/gradient_static_perf__e2e_summary.dart @flar @flutter/engine
|
||||
|
||||
## Windows Android DeviceLab tests
|
||||
/dev/devicelab/bin/tasks/basic_material_app_win__compile.dart @zanderso @flutter/tool
|
||||
|
|
|
@ -26,6 +26,7 @@ const String kStackSizeRouteName = '/stack_size';
|
|||
const String kAnimationWithMicrotasksRouteName = '/animation_with_microtasks';
|
||||
const String kAnimatedImageRouteName = '/animated_image';
|
||||
const String kOpacityPeepholeRouteName = '/opacity_peephole';
|
||||
const String kGradientPerfRouteName = '/gradient_perf';
|
||||
|
||||
const String kOpacityPeepholeOneRectRouteName = '$kOpacityPeepholeRouteName/one_big_rect';
|
||||
const String kOpacityPeepholeColumnOfOpacityRouteName = '$kOpacityPeepholeRouteName/column_of_opacity';
|
||||
|
@ -39,7 +40,12 @@ const String kOpacityPeepholeGridOfRectsWithAlphaRouteName = '$kOpacityPeepholeR
|
|||
const String kOpacityPeepholeGridOfAlphaSaveLayerRectsRouteName = '$kOpacityPeepholeRouteName/grid_of_alpha_savelayer_rects';
|
||||
const String kOpacityPeepholeColumnOfAlphaSaveLayerRowsOfRectsRouteName = '$kOpacityPeepholeRouteName/column_of_alpha_save_layer_rows_of_rects';
|
||||
|
||||
const String kGradientPerfRecreateDynamicRouteName = '$kGradientPerfRouteName/recreate_dynamic';
|
||||
const String kGradientPerfRecreateConsistentRouteName = '$kGradientPerfRouteName/recreate_consistent';
|
||||
const String kGradientPerfStaticConsistentRouteName = '$kGradientPerfRouteName/static_consistent';
|
||||
|
||||
const String kScrollableName = '/macrobenchmark_listview';
|
||||
const String kOpacityScrollableName = '$kOpacityPeepholeRouteName/listview';
|
||||
const String kGradientPerfScrollableName = '$kGradientPerfRouteName/listview';
|
||||
|
||||
const String kStackSizeKey = 'stack_size';
|
||||
|
|
|
@ -16,6 +16,7 @@ import 'src/cubic_bezier.dart';
|
|||
import 'src/cull_opacity.dart';
|
||||
import 'src/filtered_child_animation.dart';
|
||||
import 'src/fullscreen_textfield.dart';
|
||||
import 'src/gradient_perf.dart';
|
||||
import 'src/heavy_grid_view.dart';
|
||||
import 'src/large_image_changer.dart';
|
||||
import 'src/large_images.dart';
|
||||
|
@ -69,6 +70,8 @@ class MacrobenchmarksApp extends StatelessWidget {
|
|||
kAnimatedImageRouteName: (BuildContext context) => const AnimatedImagePage(),
|
||||
kOpacityPeepholeRouteName: (BuildContext context) => const OpacityPeepholePage(),
|
||||
...opacityPeepholeRoutes,
|
||||
kGradientPerfRouteName: (BuildContext context) => const GradientPerfHomePage(),
|
||||
...gradientPerfRoutes,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
@ -247,6 +250,13 @@ class HomePage extends StatelessWidget {
|
|||
Navigator.pushNamed(context, kOpacityPeepholeRouteName);
|
||||
},
|
||||
),
|
||||
ElevatedButton(
|
||||
key: const Key(kGradientPerfRouteName),
|
||||
child: const Text('Gradient performance tests'),
|
||||
onPressed: () {
|
||||
Navigator.pushNamed(context, kGradientPerfRouteName);
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
|
|
265
dev/benchmarks/macrobenchmarks/lib/src/gradient_perf.dart
Normal file
265
dev/benchmarks/macrobenchmarks/lib/src/gradient_perf.dart
Normal file
|
@ -0,0 +1,265 @@
|
|||
// 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';
|
||||
import 'dart:ui' as ui;
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import '../common.dart';
|
||||
|
||||
Map<String, WidgetBuilder> gradientPerfRoutes = <String, WidgetBuilder>{
|
||||
kGradientPerfRecreateDynamicRouteName: (BuildContext _) => const RecreateDynamicPainterPage(),
|
||||
kGradientPerfRecreateConsistentRouteName: (BuildContext _) => const RecreateConsistentPainterPage(),
|
||||
kGradientPerfStaticConsistentRouteName: (BuildContext _) => const StaticConsistentPainterPage(),
|
||||
};
|
||||
|
||||
typedef CustomPaintFactory = CustomPainter Function(double hue);
|
||||
|
||||
class GradientPerfHomePage extends StatelessWidget {
|
||||
const GradientPerfHomePage({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(title: const Text('Gradient Perf')),
|
||||
body: ListView(
|
||||
key: const Key(kGradientPerfScrollableName),
|
||||
children: <Widget>[
|
||||
ElevatedButton(
|
||||
key: const Key(kGradientPerfRecreateDynamicRouteName),
|
||||
child: const Text('Recreate Dynamic Gradients'),
|
||||
onPressed: () {
|
||||
Navigator.pushNamed(context, kGradientPerfRecreateDynamicRouteName);
|
||||
},
|
||||
),
|
||||
ElevatedButton(
|
||||
key: const Key(kGradientPerfRecreateConsistentRouteName),
|
||||
child: const Text('Recreate Same Gradients'),
|
||||
onPressed: () {
|
||||
Navigator.pushNamed(context, kGradientPerfRecreateConsistentRouteName);
|
||||
},
|
||||
),
|
||||
ElevatedButton(
|
||||
key: const Key(kGradientPerfStaticConsistentRouteName),
|
||||
child: const Text('Static Gradients'),
|
||||
onPressed: () {
|
||||
Navigator.pushNamed(context, kGradientPerfStaticConsistentRouteName);
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _PainterPage extends StatefulWidget {
|
||||
const _PainterPage({Key? key, required this.title, required this.factory}) : super(key: key);
|
||||
|
||||
final String title;
|
||||
final CustomPaintFactory factory;
|
||||
|
||||
@override
|
||||
State<_PainterPage> createState() => _PainterPageState();
|
||||
}
|
||||
|
||||
class RecreateDynamicPainterPage extends _PainterPage {
|
||||
const RecreateDynamicPainterPage({Key? key})
|
||||
: super(key: key, title: 'Recreate Dynamic Gradients', factory: makePainter);
|
||||
|
||||
static CustomPainter makePainter(double f) {
|
||||
return RecreatedDynamicGradients(baseFactor: f);
|
||||
}
|
||||
}
|
||||
|
||||
class RecreateConsistentPainterPage extends _PainterPage {
|
||||
const RecreateConsistentPainterPage({Key? key})
|
||||
: super(key: key, title: 'Recreate Same Gradients', factory: makePainter);
|
||||
|
||||
static CustomPainter makePainter(double f) {
|
||||
return RecreatedConsistentGradients(baseFactor: f);
|
||||
}
|
||||
}
|
||||
|
||||
class StaticConsistentPainterPage extends _PainterPage {
|
||||
const StaticConsistentPainterPage({Key? key})
|
||||
: super(key: key, title: 'Reuse Same Gradients', factory: makePainter);
|
||||
|
||||
static CustomPainter makePainter(double f) {
|
||||
return StaticConsistentGradients(baseFactor: f);
|
||||
}
|
||||
}
|
||||
|
||||
class _PainterPageState extends State<_PainterPage> with SingleTickerProviderStateMixin {
|
||||
late AnimationController _controller;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_controller = AnimationController(vsync: this);
|
||||
_controller.repeat(period: const Duration(seconds: 2));
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_controller.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: Text(widget.title),
|
||||
),
|
||||
body: Center(
|
||||
child: AnimatedBuilder(
|
||||
animation: _controller,
|
||||
builder: (BuildContext context, Widget? child) {
|
||||
return CustomPaint(
|
||||
size: const Size(paintW, paintH),
|
||||
painter: widget.factory(_controller.value),
|
||||
willChange: true,
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Color color(double factor) {
|
||||
int v = ((factor * 255 * 3) % (255 * 3)).round();
|
||||
if (v < 0) {
|
||||
v += 255 * 3;
|
||||
}
|
||||
int r = 0;
|
||||
int g = 0;
|
||||
int b = 0;
|
||||
if (v < 255) {
|
||||
r = 255 - v;
|
||||
g = v;
|
||||
} else {
|
||||
v -= 255;
|
||||
if (v < 255) {
|
||||
g = 255 - v;
|
||||
b = v;
|
||||
} else {
|
||||
v -= 255;
|
||||
b = 255 - v;
|
||||
r = v;
|
||||
}
|
||||
}
|
||||
return Color.fromARGB(255, r, g, b);
|
||||
}
|
||||
|
||||
Shader rotatingGradient(double factor, double x, double y, double h) {
|
||||
final double s = sin(factor * 2 * pi) * h/8;
|
||||
final double c = cos(factor * 2 * pi) * h/8;
|
||||
final double cx = x;
|
||||
final double cy = y + h/2;
|
||||
final Offset p0 = Offset(cx + s, cy + c);
|
||||
final Offset p1 = Offset(cx - s, cy - c);
|
||||
return ui.Gradient.linear(p0, p1, <Color>[
|
||||
color(factor),
|
||||
color(factor + 0.5),
|
||||
]);
|
||||
}
|
||||
|
||||
const int nAcross = 12;
|
||||
const int nDown = 16;
|
||||
const double cellW = 20;
|
||||
const double cellH = 20;
|
||||
const double hGap = 5;
|
||||
const double vGap = 5;
|
||||
const double paintW = hGap + (cellW + hGap) * nAcross;
|
||||
const double paintH = vGap + (cellH + vGap) * nDown;
|
||||
|
||||
double x(int i, int j) {
|
||||
return hGap + i * (cellW + hGap);
|
||||
}
|
||||
|
||||
double y(int i, int j) {
|
||||
return vGap + j * (cellH + vGap);
|
||||
}
|
||||
|
||||
Shader gradient(double baseFactor, int i, int j) {
|
||||
final double lineFactor = baseFactor + 1/3 + 0.5 * (j + 1) / (nDown + 1);
|
||||
final double cellFactor = lineFactor + 1/3 * (i + 1) / (nAcross + 1);
|
||||
return rotatingGradient(cellFactor, x(i, j) + cellW / 2, y(i, j), cellH);
|
||||
}
|
||||
|
||||
class RecreatedDynamicGradients extends CustomPainter {
|
||||
RecreatedDynamicGradients({required this.baseFactor});
|
||||
|
||||
final double baseFactor;
|
||||
|
||||
@override
|
||||
void paint(Canvas canvas, Size size) {
|
||||
final Paint p = Paint();
|
||||
p.color = color(baseFactor);
|
||||
canvas.drawRect(Offset.zero & size, p);
|
||||
for (int j = 0; j < nDown; j++) {
|
||||
for (int i = 0; i < nAcross; i++) {
|
||||
p.shader = gradient(baseFactor, i, j);
|
||||
canvas.drawRect(Rect.fromLTWH(x(i, j), y(i, j), cellW, cellH), p);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
bool shouldRepaint(CustomPainter oldDelegate) => true;
|
||||
}
|
||||
|
||||
class RecreatedConsistentGradients extends CustomPainter {
|
||||
RecreatedConsistentGradients({required this.baseFactor});
|
||||
|
||||
final double baseFactor;
|
||||
|
||||
@override
|
||||
void paint(Canvas canvas, Size size) {
|
||||
final Paint p = Paint();
|
||||
p.color = color(baseFactor);
|
||||
canvas.drawRect(Offset.zero & size, p);
|
||||
for (int j = 0; j < nDown; j++) {
|
||||
for (int i = 0; i < nAcross; i++) {
|
||||
p.shader = gradient(0, i, j);
|
||||
canvas.drawRect(Rect.fromLTWH(x(i, j), y(i, j), cellW, cellH), p);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
bool shouldRepaint(CustomPainter oldDelegate) => true;
|
||||
}
|
||||
|
||||
class StaticConsistentGradients extends CustomPainter {
|
||||
StaticConsistentGradients({required this.baseFactor});
|
||||
|
||||
final double baseFactor;
|
||||
|
||||
static List<List<Shader>> gradients = <List<Shader>>[
|
||||
for (int j = 0; j < nDown; j++)
|
||||
<Shader>[
|
||||
for (int i = 0; i < nAcross; i++)
|
||||
gradient(0, i, j),
|
||||
],
|
||||
];
|
||||
|
||||
@override
|
||||
void paint(Canvas canvas, Size size) {
|
||||
final Paint p = Paint();
|
||||
p.color = color(baseFactor);
|
||||
canvas.drawRect(Offset.zero & size, p);
|
||||
for (int j = 0; j < nDown; j++) {
|
||||
for (int i = 0; i < nAcross; i++) {
|
||||
p.shader = gradients[j][i];
|
||||
canvas.drawRect(Rect.fromLTWH(x(i, j), y(i, j), cellW, cellH), p);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
bool shouldRepaint(CustomPainter oldDelegate) => true;
|
||||
}
|
|
@ -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.
|
||||
|
||||
import 'package:macrobenchmarks/common.dart';
|
||||
|
||||
import 'util.dart';
|
||||
|
||||
void main() {
|
||||
macroPerfTestMultiPageE2E(
|
||||
'gradient_consistent_perf',
|
||||
<ScrollableButtonRoute>[
|
||||
ScrollableButtonRoute(kScrollableName, kGradientPerfRouteName),
|
||||
ScrollableButtonRoute(kGradientPerfScrollableName, kGradientPerfRecreateConsistentRouteName),
|
||||
],
|
||||
pageDelay: const Duration(seconds: 1),
|
||||
duration: const Duration(seconds: 10),
|
||||
);
|
||||
}
|
|
@ -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.
|
||||
|
||||
import 'package:macrobenchmarks/common.dart';
|
||||
|
||||
import 'util.dart';
|
||||
|
||||
void main() {
|
||||
macroPerfTestMultiPageE2E(
|
||||
'gradient_dynamic_perf',
|
||||
<ScrollableButtonRoute>[
|
||||
ScrollableButtonRoute(kScrollableName, kGradientPerfRouteName),
|
||||
ScrollableButtonRoute(kGradientPerfScrollableName, kGradientPerfRecreateDynamicRouteName),
|
||||
],
|
||||
pageDelay: const Duration(seconds: 1),
|
||||
duration: const Duration(seconds: 10),
|
||||
);
|
||||
}
|
|
@ -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.
|
||||
|
||||
import 'package:macrobenchmarks/common.dart';
|
||||
|
||||
import 'util.dart';
|
||||
|
||||
void main() {
|
||||
macroPerfTestMultiPageE2E(
|
||||
'gradient_static_perf',
|
||||
<ScrollableButtonRoute>[
|
||||
ScrollableButtonRoute(kScrollableName, kGradientPerfRouteName),
|
||||
ScrollableButtonRoute(kGradientPerfScrollableName, kGradientPerfStaticConsistentRouteName),
|
||||
],
|
||||
pageDelay: const Duration(seconds: 1),
|
||||
duration: const Duration(seconds: 10),
|
||||
);
|
||||
}
|
|
@ -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 'dart:async';
|
||||
|
||||
import 'package:flutter_devicelab/framework/devices.dart';
|
||||
import 'package:flutter_devicelab/framework/framework.dart';
|
||||
import 'package:flutter_devicelab/tasks/perf_tests.dart';
|
||||
|
||||
Future<void> main() async {
|
||||
deviceOperatingSystem = DeviceOperatingSystem.android;
|
||||
await task(createGradientConsistentPerfE2ETest());
|
||||
}
|
|
@ -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 'dart:async';
|
||||
|
||||
import 'package:flutter_devicelab/framework/devices.dart';
|
||||
import 'package:flutter_devicelab/framework/framework.dart';
|
||||
import 'package:flutter_devicelab/tasks/perf_tests.dart';
|
||||
|
||||
Future<void> main() async {
|
||||
deviceOperatingSystem = DeviceOperatingSystem.android;
|
||||
await task(createGradientDynamicPerfE2ETest());
|
||||
}
|
|
@ -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 'dart:async';
|
||||
|
||||
import 'package:flutter_devicelab/framework/devices.dart';
|
||||
import 'package:flutter_devicelab/framework/framework.dart';
|
||||
import 'package:flutter_devicelab/tasks/perf_tests.dart';
|
||||
|
||||
Future<void> main() async {
|
||||
deviceOperatingSystem = DeviceOperatingSystem.android;
|
||||
await task(createGradientStaticPerfE2ETest());
|
||||
}
|
|
@ -556,6 +556,27 @@ TaskFunction createOpacityPeepholeColOfAlphaSaveLayerRowsPerfE2ETest() {
|
|||
).run;
|
||||
}
|
||||
|
||||
TaskFunction createGradientDynamicPerfE2ETest() {
|
||||
return PerfTest.e2e(
|
||||
'${flutterDirectory.path}/dev/benchmarks/macrobenchmarks',
|
||||
'test/gradient_dynamic_perf_e2e.dart',
|
||||
).run;
|
||||
}
|
||||
|
||||
TaskFunction createGradientConsistentPerfE2ETest() {
|
||||
return PerfTest.e2e(
|
||||
'${flutterDirectory.path}/dev/benchmarks/macrobenchmarks',
|
||||
'test/gradient_consistent_perf_e2e.dart',
|
||||
).run;
|
||||
}
|
||||
|
||||
TaskFunction createGradientStaticPerfE2ETest() {
|
||||
return PerfTest.e2e(
|
||||
'${flutterDirectory.path}/dev/benchmarks/macrobenchmarks',
|
||||
'test/gradient_static_perf_e2e.dart',
|
||||
).run;
|
||||
}
|
||||
|
||||
Map<String, dynamic> _average(List<Map<String, dynamic>> results, int iterations) {
|
||||
final Map<String, dynamic> tally = <String, dynamic>{};
|
||||
for (final Map<String, dynamic> item in results) {
|
||||
|
|
Loading…
Reference in a new issue