Skip to content

Commit 08a2635

Browse files
[devicelab] add benchmark for complex non-intersecting widgets with platform views (flutter#116436)
1 parent 4643f83 commit 08a2635

8 files changed

+237
-4
lines changed

.ci.yaml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3714,6 +3714,16 @@ targets:
37143714
["devicelab", "ios", "mac"]
37153715
task_name: platform_views_scroll_perf_impeller_ios__timeline_summary
37163716

3717+
- name: Mac_ios platform_views_scroll_perf_non_intersecting_impeller_ios__timeline_summary
3718+
recipe: devicelab/devicelab_drone
3719+
presubmit: false
3720+
bringup: true
3721+
timeout: 60
3722+
properties:
3723+
tags: >
3724+
["devicelab", "ios", "mac"]
3725+
task_name: platform_views_scroll_perf_non_intersecting_impeller_ios__timeline_summary
3726+
37173727
- name: Mac_ios post_backdrop_filter_perf_ios__timeline_summary
37183728
recipe: devicelab/devicelab_drone
37193729
presubmit: false

TESTOWNERS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,7 @@
196196
/dev/devicelab/bin/tasks/platform_interaction_test_ios.dart @zanderso @flutter/engine
197197
/dev/devicelab/bin/tasks/platform_view_ios__start_up.dart @stuartmorgan @flutter/plugin
198198
/dev/devicelab/bin/tasks/platform_views_scroll_perf_impeller_ios__timeline_summary.dart @zanderso @flutter/engine
199+
/dev/devicelab/bin/tasks/platform_views_scroll_perf_non_intersecting_impeller_ios__timeline_summary.dart @jonahwilliams @flutter/engine
199200
/dev/devicelab/bin/tasks/platform_views_scroll_perf_ios__timeline_summary.dart @zanderso @flutter/engine
200201
/dev/devicelab/bin/tasks/post_backdrop_filter_perf_ios__timeline_summary.dart @zanderso @flutter/engine
201202
/dev/devicelab/bin/tasks/route_test_ios.dart @jasguerrero @flutter/tool

dev/benchmarks/platform_views_layout/ios/Runner.xcodeproj/project.pbxproj

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,6 @@
7777
9740EEB11CF90186004384FC /* Flutter */,
7878
97C146F01CF9000F007C117D /* Runner */,
7979
97C146EF1CF9000F007C117D /* Products */,
80-
CF3B75C9A7D2FA2A4C99F110 /* Frameworks */,
8180
);
8281
sourceTree = "<group>";
8382
};
@@ -309,7 +308,10 @@
309308
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
310309
ENABLE_BITCODE = NO;
311310
INFOPLIST_FILE = Runner/Info.plist;
312-
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
311+
LD_RUNPATH_SEARCH_PATHS = (
312+
"$(inherited)",
313+
"@executable_path/Frameworks",
314+
);
313315
PRODUCT_BUNDLE_IDENTIFIER = com.yourcompany.platformViewsLayout;
314316
PRODUCT_NAME = "$(TARGET_NAME)";
315317
VERSIONING_SYSTEM = "apple-generic";
@@ -427,9 +429,13 @@
427429
buildSettings = {
428430
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
429431
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
432+
DEVELOPMENT_TEAM = S8QB4VV633;
430433
ENABLE_BITCODE = NO;
431434
INFOPLIST_FILE = Runner/Info.plist;
432-
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
435+
LD_RUNPATH_SEARCH_PATHS = (
436+
"$(inherited)",
437+
"@executable_path/Frameworks",
438+
);
433439
PRODUCT_BUNDLE_IDENTIFIER = com.yourcompany.platformViewsLayout;
434440
PRODUCT_NAME = "$(TARGET_NAME)";
435441
VERSIONING_SYSTEM = "apple-generic";
@@ -444,7 +450,10 @@
444450
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
445451
ENABLE_BITCODE = NO;
446452
INFOPLIST_FILE = Runner/Info.plist;
447-
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
453+
LD_RUNPATH_SEARCH_PATHS = (
454+
"$(inherited)",
455+
"@executable_path/Frameworks",
456+
);
448457
PRODUCT_BUNDLE_IDENTIFIER = com.yourcompany.platformViewsLayout;
449458
PRODUCT_NAME = "$(TARGET_NAME)";
450459
VERSIONING_SYSTEM = "apple-generic";
Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
// Copyright 2014 The Flutter Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
5+
import 'dart:io';
6+
7+
import 'package:flutter/material.dart';
8+
import 'package:flutter/scheduler.dart' show timeDilation;
9+
10+
void main() {
11+
runApp(
12+
const PlatformViewApp()
13+
);
14+
}
15+
16+
class PlatformViewApp extends StatefulWidget {
17+
const PlatformViewApp({
18+
super.key,
19+
});
20+
21+
@override
22+
PlatformViewAppState createState() => PlatformViewAppState();
23+
}
24+
25+
class PlatformViewAppState extends State<PlatformViewApp> {
26+
@override
27+
Widget build(BuildContext context) {
28+
return MaterialApp(
29+
theme: ThemeData.light(),
30+
title: 'Advanced Layout',
31+
home: const PlatformViewLayout(),
32+
);
33+
}
34+
35+
void toggleAnimationSpeed() {
36+
setState(() {
37+
timeDilation = (timeDilation != 1.0) ? 1.0 : 5.0;
38+
});
39+
}
40+
}
41+
42+
class PlatformViewLayout extends StatelessWidget {
43+
const PlatformViewLayout({ super.key });
44+
45+
@override
46+
Widget build(BuildContext context) {
47+
return Scaffold(
48+
appBar: AppBar(title: const Text('Platform View Scrolling Layout')),
49+
body: ListView.builder(
50+
key: const Key('platform-views-scroll'), // This key is used by the driver test.
51+
itemCount: 200,
52+
itemBuilder: (BuildContext context, int index) {
53+
return Padding(
54+
padding: const EdgeInsets.all(5.0),
55+
child: Material(
56+
elevation: (index % 5 + 1).toDouble(),
57+
color: Colors.white,
58+
child: index.isEven
59+
? CustomPaint(painter: ExpensivePainter(), size: const Size(400, 200))
60+
: const DummyPlatformView()
61+
),
62+
);
63+
},
64+
),
65+
);
66+
}
67+
}
68+
69+
class DummyPlatformView extends StatelessWidget {
70+
const DummyPlatformView({super.key});
71+
72+
@override
73+
Widget build(BuildContext context) {
74+
const String viewType = 'benchmarks/platform_views_layout/DummyPlatformView';
75+
late Widget nativeView;
76+
if (Platform.isIOS) {
77+
nativeView = const UiKitView(
78+
viewType: viewType,
79+
);
80+
} else if (Platform.isAndroid) {
81+
nativeView = const AndroidView(
82+
viewType: viewType,
83+
);
84+
} else {
85+
assert(false, 'Invalid platform');
86+
}
87+
return Container(
88+
color: Colors.purple,
89+
height: 200.0,
90+
child: nativeView,
91+
);
92+
}
93+
}
94+
95+
class ExpensivePainter extends CustomPainter {
96+
@override
97+
void paint(Canvas canvas, Size size) {
98+
final double boxWidth = size.width / 50;
99+
final double boxHeight = size.height / 50;
100+
for (int i = 0; i < 50; i++) {
101+
for (int j = 0; j < 50; j++) {
102+
final Rect rect = Rect.fromLTWH(i * boxWidth, j * boxHeight, boxWidth, boxHeight);
103+
canvas.drawRect(rect, Paint()
104+
..style = PaintingStyle.fill
105+
..color = Colors.red
106+
);
107+
}
108+
}
109+
}
110+
111+
@override
112+
bool shouldRepaint(covariant CustomPainter oldDelegate) {
113+
return false;
114+
}
115+
}
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
// Copyright 2014 The Flutter Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
5+
import 'package:flutter_driver/flutter_driver.dart';
6+
import 'package:test/test.dart' hide TypeMatcher, isInstanceOf;
7+
8+
void main() {
9+
group('scrolling performance test', () {
10+
late FlutterDriver driver;
11+
12+
setUpAll(() async {
13+
driver = await FlutterDriver.connect();
14+
15+
await driver.waitUntilFirstFrameRasterized();
16+
});
17+
18+
tearDownAll(() async {
19+
driver.close();
20+
});
21+
22+
Future<void> testScrollPerf(String listKey, String summaryName) async {
23+
// The slight initial delay avoids starting the timing during a
24+
// period of increased load on the device. Without this delay, the
25+
// benchmark has greater noise.
26+
// See: https://github.com/flutter/flutter/issues/19434
27+
await Future<void>.delayed(const Duration(milliseconds: 250));
28+
29+
await driver.forceGC();
30+
31+
final Timeline timeline = await driver.traceAction(() async {
32+
// Find the scrollable stock list
33+
final SerializableFinder list = find.byValueKey(listKey);
34+
expect(list, isNotNull);
35+
36+
for (int j = 0; j < 5; j ++) {
37+
// Scroll down
38+
for (int i = 0; i < 5; i += 1) {
39+
await driver.scroll(list, 0.0, -300.0, const Duration(milliseconds: 300));
40+
await Future<void>.delayed(const Duration(milliseconds: 500));
41+
}
42+
43+
// Scroll up
44+
for (int i = 0; i < 5; i += 1) {
45+
await driver.scroll(list, 0.0, 300.0, const Duration(milliseconds: 300));
46+
await Future<void>.delayed(const Duration(milliseconds: 500));
47+
}
48+
}
49+
});
50+
51+
final TimelineSummary summary = TimelineSummary.summarize(timeline);
52+
await summary.writeTimelineToFile(summaryName, pretty: true);
53+
}
54+
55+
test('platform_views_scroll_perf', () async {
56+
// Disable frame sync, since there are ongoing animations.
57+
await driver.runUnsynchronized(() async {
58+
await testScrollPerf('platform-views-scroll', 'platform_views_scroll_perf_non_intersecting');
59+
});
60+
}, timeout: Timeout.none);
61+
});
62+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// Copyright 2014 The Flutter Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
5+
import 'package:flutter/widgets.dart';
6+
import 'package:flutter_driver/driver_extension.dart';
7+
8+
import 'package:platform_views_layout/main_non_intersecting.dart' as app;
9+
10+
void main() {
11+
enableFlutterDriverExtension();
12+
runApp(const app.PlatformViewApp());
13+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
// Copyright 2014 The Flutter Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
5+
import 'package:flutter_devicelab/framework/devices.dart';
6+
import 'package:flutter_devicelab/framework/framework.dart';
7+
import 'package:flutter_devicelab/tasks/perf_tests.dart';
8+
9+
Future<void> main() async {
10+
deviceOperatingSystem = DeviceOperatingSystem.ios;
11+
await task(createUiKitViewScrollPerfNonIntersectingTest(enableImpeller: true));
12+
}

dev/devicelab/lib/tasks/perf_tests.dart

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,17 @@ TaskFunction createUiKitViewScrollPerfTest({bool enableImpeller = false}) {
5959
).run;
6060
}
6161

62+
TaskFunction createUiKitViewScrollPerfNonIntersectingTest({bool enableImpeller = false}) {
63+
return PerfTest(
64+
'${flutterDirectory.path}/dev/benchmarks/platform_views_layout',
65+
'test_driver/uikit_view_scroll_perf_non_intersecting.dart',
66+
'platform_views_scroll_perf_non_intersecting',
67+
testDriver: 'test_driver/scroll_perf_non_intersecting_test.dart',
68+
needsFullTimeline: false,
69+
enableImpeller: enableImpeller,
70+
).run;
71+
}
72+
6273
TaskFunction createAndroidTextureScrollPerfTest() {
6374
return PerfTest(
6475
'${flutterDirectory.path}/dev/benchmarks/platform_views_layout',

0 commit comments

Comments
 (0)