Unverified Commit b51859ec authored by Jim Graham's avatar Jim Graham Committed by GitHub

Add benchmark for scrolling very long pictures (#133434)

This benchmark will track the performance of the RTree implementation to cull very large pictures down to just the portion visible on the screen.
parent 82ded603
......@@ -2114,6 +2114,16 @@ targets:
["devicelab", "android", "linux"]
task_name: fullscreen_textfield_perf__e2e_summary
- name: Linux_android very_long_picture_scrolling_perf__e2e_summary
recipe: devicelab/devicelab_drone
bringup: true
presubmit: false
timeout: 120
properties:
tags: >
["devicelab", "android", "linux"]
task_name: very_long_picture_scrolling_perf__e2e_summary
- name: Linux_android hello_world__memory
recipe: devicelab/devicelab_drone
presubmit: false
......@@ -4196,6 +4206,16 @@ targets:
["devicelab", "ios", "mac"]
task_name: fullscreen_textfield_perf_ios__e2e_summary
- name: Mac_ios very_long_picture_scrolling_perf_ios__e2e_summary
recipe: devicelab/devicelab_drone
bringup: true
presubmit: false
timeout: 120
properties:
tags: >
["devicelab", "ios", "mac"]
task_name: very_long_picture_scrolling_perf_ios__e2e_summary
- name: Mac_ios tiles_scroll_perf_ios__timeline_summary
recipe: devicelab/devicelab_drone
presubmit: false
......
......@@ -89,6 +89,7 @@
/dev/devicelab/bin/tasks/spell_check_test_ios.dart @camsim99 @flutter/android
/dev/devicelab/bin/tasks/spell_check_test.dart @camsim99 @flutter/android
/dev/devicelab/bin/tasks/textfield_perf__e2e_summary.dart @zanderso @flutter/engine
/dev/devicelab/bin/tasks/very_long_picture_scrolling_perf__e2e_summary.dart @flar @flutter/engine
/dev/devicelab/bin/tasks/web_size__compile_test.dart @yjbanov @flutter/web
/dev/devicelab/bin/tasks/wide_gamut_ios.dart @gaaclarke @flutter/engine
/dev/devicelab/bin/tasks/animated_advanced_blend_perf__timeline_summary.dart @gaaclarke @flutter/engine
......@@ -212,6 +213,7 @@
/dev/devicelab/bin/tasks/route_test_ios.dart @vashworth @flutter/tool
/dev/devicelab/bin/tasks/simple_animation_perf_ios.dart @cyanglaz @flutter/engine
/dev/devicelab/bin/tasks/tiles_scroll_perf_ios__timeline_summary.dart @cyanglaz @flutter/engine
/dev/devicelab/bin/tasks/very_long_picture_scrolling_perf_ios__e2e_summary.dart @flar @flutter/engine
/dev/devicelab/bin/tasks/animated_blur_backdrop_filter_perf_ios__timeline_summary.dart @jonahwilliams @flutter/engine
/dev/devicelab/bin/tasks/draw_points_perf_ios__timeline_summary.dart @jonahwilliams @flutter/engine
/dev/devicelab/bin/tasks/draw_vertices_perf_ios__timeline_summary.dart @jonahwilliams @flutter/engine
......
......@@ -13,6 +13,7 @@ const String kLargeImageChangerRouteName = '/large_image_changer';
const String kLargeImagesRouteName = '/large_images';
const String kPathTessellationRouteName = '/path_tessellation';
const String kTextRouteName = '/text';
const String kVeryLongPictureScrollingRouteName = '/very_long_picture_scrolling';
const String kFullscreenTextRouteName = '/fullscreen_text';
const String kAnimatedPlaceholderRouteName = '/animated_placeholder';
const String kClipperCacheRouteName = '/clipper_cache';
......
......@@ -42,6 +42,7 @@ import 'src/simple_scroll.dart';
import 'src/sliders.dart';
import 'src/stack_size.dart';
import 'src/text.dart';
import 'src/very_long_picture_scrolling.dart';
const String kMacrobenchmarks = 'Macrobenchmarks';
......@@ -97,6 +98,7 @@ class MacrobenchmarksApp extends StatelessWidget {
kDrawVerticesPageRouteName: (BuildContext context) => const DrawVerticesPage(),
kDrawAtlasPageRouteName: (BuildContext context) => const DrawAtlasPage(),
kAnimatedAdvancedBlend: (BuildContext context) => const AnimatedAdvancedBlend(),
kVeryLongPictureScrollingRouteName: (BuildContext context) => const VeryLongPictureScrollingPerf(),
},
);
}
......@@ -373,6 +375,13 @@ class HomePage extends StatelessWidget {
Navigator.pushNamed(context, kAnimatedAdvancedBlend);
},
),
ElevatedButton(
key: const Key(kVeryLongPictureScrollingRouteName),
child: const Text('Very Long Picture Scrolling'),
onPressed: () {
Navigator.pushNamed(context, kVeryLongPictureScrollingRouteName);
},
),
],
),
);
......
// 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:typed_data';
import 'dart:ui';
import 'package:flutter/material.dart';
// Adapted from test case submitted in
// https://github.com/flutter/flutter/issues/92366
// Converted to use fixed data rather than reading a waveform file
class VeryLongPictureScrollingPerf extends StatefulWidget {
const VeryLongPictureScrollingPerf({super.key});
@override
State createState() => VeryLongPictureScrollingPerfState();
}
class VeryLongPictureScrollingPerfState extends State<VeryLongPictureScrollingPerf> {
bool consolidate = false;
bool useList = false;
Int16List waveData = loadGraph();
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
actions: <Widget>[
Row(
children: <Widget>[
const Text('list:'),
Checkbox(value: useList, onChanged: (bool? value) => setState(() {
useList = value!;
}),),
],
),
Row(
children: <Widget>[
const Text('consolidate:'),
Checkbox(value: consolidate, onChanged: (bool? value) => setState(() {
consolidate = value!;
}),),
],
),
],
),
backgroundColor: Colors.transparent,
body: SizedBox(
width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.height,
child: useList
? ListView.builder(
key: const ValueKey<String>('vlp_list_view_scrollable'),
scrollDirection: Axis.horizontal,
clipBehavior: Clip.none,
itemCount: (waveData.length / 200).ceil(),
itemExtent: 100,
itemBuilder: (BuildContext context, int index) => CustomPaint(
painter: PaintSomeTest(
waveData: waveData,
from: index * 200,
to: min((index + 1) * 200, waveData.length - 1),
)
),
)
: SingleChildScrollView(
key: const ValueKey<String>('vlp_single_child_scrollable'),
scrollDirection: Axis.horizontal,
child: SizedBox(
width: MediaQuery.of(context).size.width * 20,
height: MediaQuery.of(context).size.height,
child: RepaintBoundary(
child: CustomPaint(
isComplex: true,
painter: PaintTest(
consolidate: consolidate,
waveData: waveData,
),
),
),
),
),
),
);
}
}
class PaintTest extends CustomPainter {
const PaintTest({
required this.consolidate,
required this.waveData,
});
final bool consolidate;
final Int16List waveData;
@override
void paint(Canvas canvas, Size size) {
final double height = size.height;
double x = 0;
const double strokeSize = .5;
const double zoomFactor = .5;
final Paint paintPos = Paint()
..color = Colors.pink
..strokeWidth = strokeSize
..isAntiAlias = false
..style = PaintingStyle.stroke;
final Paint paintNeg = Paint()
..color = Colors.pink
..strokeWidth = strokeSize
..isAntiAlias = false
..style = PaintingStyle.stroke;
final Paint paintZero = Paint()
..color = Colors.green
..strokeWidth = strokeSize
..isAntiAlias = false
..style = PaintingStyle.stroke;
int index = 0;
Paint? listPaint;
final Float32List offsets = Float32List(consolidate ? waveData.length * 4 : 4);
int used = 0;
for (index = 0; index < waveData.length; index++) {
Paint curPaint;
Offset p1;
if (waveData[index].isNegative) {
curPaint = paintPos;
p1 = Offset(x, height * 1 / 2 - waveData[index] / 32768 * (height / 2));
} else if (waveData[index] == 0) {
curPaint = paintZero;
p1 = Offset(x, height * 1 / 2 + 1);
} else {
curPaint = (waveData[index] == 0) ? paintZero : paintNeg;
p1 = Offset(x, height * 1 / 2 - waveData[index] / 32767 * (height / 2));
}
final Offset p0 = Offset(x, height * 1 / 2);
if (consolidate) {
if (listPaint != null && listPaint != curPaint) {
canvas.drawRawPoints(PointMode.lines, offsets.sublist(0, used), listPaint);
used = 0;
}
listPaint = curPaint;
offsets[used++] = p0.dx;
offsets[used++] = p0.dy;
offsets[used++] = p1.dx;
offsets[used++] = p1.dy;
} else {
canvas.drawLine(p0, p1, curPaint);
}
x += zoomFactor;
}
if (consolidate && used > 0) {
canvas.drawRawPoints(PointMode.lines, offsets.sublist(0, used), listPaint!);
}
}
@override
bool shouldRepaint(CustomPainter oldDelegate) {
return oldDelegate is! PaintTest ||
oldDelegate.consolidate != consolidate ||
oldDelegate.waveData != waveData;
}
}
class PaintSomeTest extends CustomPainter {
const PaintSomeTest({
required this.waveData,
int? from,
int? to,
}) : from = from ?? 0, to = to?? waveData.length;
final Int16List waveData;
final int from;
final int to;
@override
void paint(Canvas canvas, Size size) {
final double height = size.height;
double x = 0;
const double strokeSize = .5;
const double zoomFactor = .5;
final Paint paintPos = Paint()
..color = Colors.pink
..strokeWidth = strokeSize
..isAntiAlias = false
..style = PaintingStyle.stroke;
final Paint paintNeg = Paint()
..color = Colors.pink
..strokeWidth = strokeSize
..isAntiAlias = false
..style = PaintingStyle.stroke;
final Paint paintZero = Paint()
..color = Colors.green
..strokeWidth = strokeSize
..isAntiAlias = false
..style = PaintingStyle.stroke;
for (int index = from; index <= to; index++) {
Paint curPaint;
Offset p1;
if (waveData[index].isNegative) {
curPaint = paintPos;
p1 = Offset(x, height * 1 / 2 - waveData[index] / 32768 * (height / 2));
} else if (waveData[index] == 0) {
curPaint = paintZero;
p1 = Offset(x, height * 1 / 2 + 1);
} else {
curPaint = (waveData[index] == 0) ? paintZero : paintNeg;
p1 = Offset(x, height * 1 / 2 - waveData[index] / 32767 * (height / 2));
}
final Offset p0 = Offset(x, height * 1 / 2);
canvas.drawLine(p0, p1, curPaint);
x += zoomFactor;
}
}
@override
bool shouldRepaint(CustomPainter oldDelegate) {
return oldDelegate is! PaintSomeTest ||
oldDelegate.waveData != waveData ||
oldDelegate.from != from ||
oldDelegate.to != to;
}
}
Int16List loadGraph() {
final Int16List waveData = Int16List(350000);
final Random r = Random(0x42);
for (int i = 0; i < waveData.length; i++) {
waveData[i] = r.nextInt(32768) - 16384;
}
return waveData;
}
// 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/foundation.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:macrobenchmarks/common.dart';
import 'util.dart';
void main() {
macroPerfTestE2E(
'very_long_picture_scrolling_perf',
kVeryLongPictureScrollingRouteName,
pageDelay: const Duration(seconds: 1),
duration: const Duration(seconds: 30),
body: (WidgetController controller) async {
final Finder nestedScroll = find.byKey(const ValueKey<String>('vlp_single_child_scrollable'));
expect(nestedScroll, findsOneWidget);
Future<void> scrollOnce(double offset) async {
await controller.timedDrag(
nestedScroll,
Offset(offset, 0.0),
const Duration(milliseconds: 3500),
);
await Future<void>.delayed(const Duration(milliseconds: 500));
}
for (int i = 0; i < 2; i += 1) {
await scrollOnce(-3000.0);
await scrollOnce(-3000.0);
await scrollOnce(3000.0);
await scrollOnce(3000.0);
}
},
);
}
// 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(createVeryLongPictureScrollingPerfE2ETest(enableImpeller: false));
}
// 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.ios;
await task(createVeryLongPictureScrollingPerfE2ETest(enableImpeller: false));
}
......@@ -308,6 +308,13 @@ TaskFunction createTextfieldPerfE2ETest() {
).run;
}
TaskFunction createVeryLongPictureScrollingPerfE2ETest({required bool enableImpeller}) {
return PerfTest.e2e(
'${flutterDirectory.path}/dev/benchmarks/macrobenchmarks',
'test/very_long_picture_scrolling_perf_e2e.dart',
enableImpeller: enableImpeller,
).run;
}
TaskFunction createSlidersPerfTest() {
return PerfTest(
'${flutterDirectory.path}/dev/benchmarks/macrobenchmarks',
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment