Skip to content
This repository has been archived by the owner on Feb 22, 2023. It is now read-only.

Commit

Permalink
[devicelab] add benchmark for complex non-intersecting widgets with p…
Browse files Browse the repository at this point in the history
…latform views (#116436)
  • Loading branch information
jonahwilliams committed Dec 2, 2022
1 parent 4643f83 commit 08a2635
Show file tree
Hide file tree
Showing 8 changed files with 237 additions and 4 deletions.
10 changes: 10 additions & 0 deletions .ci.yaml
Expand Up @@ -3714,6 +3714,16 @@ targets:
["devicelab", "ios", "mac"]
task_name: platform_views_scroll_perf_impeller_ios__timeline_summary

- name: Mac_ios platform_views_scroll_perf_non_intersecting_impeller_ios__timeline_summary
recipe: devicelab/devicelab_drone
presubmit: false
bringup: true
timeout: 60
properties:
tags: >
["devicelab", "ios", "mac"]
task_name: platform_views_scroll_perf_non_intersecting_impeller_ios__timeline_summary

- name: Mac_ios post_backdrop_filter_perf_ios__timeline_summary
recipe: devicelab/devicelab_drone
presubmit: false
Expand Down
1 change: 1 addition & 0 deletions TESTOWNERS
Expand Up @@ -196,6 +196,7 @@
/dev/devicelab/bin/tasks/platform_interaction_test_ios.dart @zanderso @flutter/engine
/dev/devicelab/bin/tasks/platform_view_ios__start_up.dart @stuartmorgan @flutter/plugin
/dev/devicelab/bin/tasks/platform_views_scroll_perf_impeller_ios__timeline_summary.dart @zanderso @flutter/engine
/dev/devicelab/bin/tasks/platform_views_scroll_perf_non_intersecting_impeller_ios__timeline_summary.dart @jonahwilliams @flutter/engine
/dev/devicelab/bin/tasks/platform_views_scroll_perf_ios__timeline_summary.dart @zanderso @flutter/engine
/dev/devicelab/bin/tasks/post_backdrop_filter_perf_ios__timeline_summary.dart @zanderso @flutter/engine
/dev/devicelab/bin/tasks/route_test_ios.dart @jasguerrero @flutter/tool
Expand Down
Expand Up @@ -77,7 +77,6 @@
9740EEB11CF90186004384FC /* Flutter */,
97C146F01CF9000F007C117D /* Runner */,
97C146EF1CF9000F007C117D /* Products */,
CF3B75C9A7D2FA2A4C99F110 /* Frameworks */,
);
sourceTree = "<group>";
};
Expand Down Expand Up @@ -309,7 +308,10 @@
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
);
PRODUCT_BUNDLE_IDENTIFIER = com.yourcompany.platformViewsLayout;
PRODUCT_NAME = "$(TARGET_NAME)";
VERSIONING_SYSTEM = "apple-generic";
Expand Down Expand Up @@ -427,9 +429,13 @@
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
DEVELOPMENT_TEAM = S8QB4VV633;
ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
);
PRODUCT_BUNDLE_IDENTIFIER = com.yourcompany.platformViewsLayout;
PRODUCT_NAME = "$(TARGET_NAME)";
VERSIONING_SYSTEM = "apple-generic";
Expand All @@ -444,7 +450,10 @@
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
);
PRODUCT_BUNDLE_IDENTIFIER = com.yourcompany.platformViewsLayout;
PRODUCT_NAME = "$(TARGET_NAME)";
VERSIONING_SYSTEM = "apple-generic";
Expand Down
115 changes: 115 additions & 0 deletions dev/benchmarks/platform_views_layout/lib/main_non_intersecting.dart
@@ -0,0 +1,115 @@
// 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:io';

import 'package:flutter/material.dart';
import 'package:flutter/scheduler.dart' show timeDilation;

void main() {
runApp(
const PlatformViewApp()
);
}

class PlatformViewApp extends StatefulWidget {
const PlatformViewApp({
super.key,
});

@override
PlatformViewAppState createState() => PlatformViewAppState();
}

class PlatformViewAppState extends State<PlatformViewApp> {
@override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData.light(),
title: 'Advanced Layout',
home: const PlatformViewLayout(),
);
}

void toggleAnimationSpeed() {
setState(() {
timeDilation = (timeDilation != 1.0) ? 1.0 : 5.0;
});
}
}

class PlatformViewLayout extends StatelessWidget {
const PlatformViewLayout({ super.key });

@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Platform View Scrolling Layout')),
body: ListView.builder(
key: const Key('platform-views-scroll'), // This key is used by the driver test.
itemCount: 200,
itemBuilder: (BuildContext context, int index) {
return Padding(
padding: const EdgeInsets.all(5.0),
child: Material(
elevation: (index % 5 + 1).toDouble(),
color: Colors.white,
child: index.isEven
? CustomPaint(painter: ExpensivePainter(), size: const Size(400, 200))
: const DummyPlatformView()
),
);
},
),
);
}
}

class DummyPlatformView extends StatelessWidget {
const DummyPlatformView({super.key});

@override
Widget build(BuildContext context) {
const String viewType = 'benchmarks/platform_views_layout/DummyPlatformView';
late Widget nativeView;
if (Platform.isIOS) {
nativeView = const UiKitView(
viewType: viewType,
);
} else if (Platform.isAndroid) {
nativeView = const AndroidView(
viewType: viewType,
);
} else {
assert(false, 'Invalid platform');
}
return Container(
color: Colors.purple,
height: 200.0,
child: nativeView,
);
}
}

class ExpensivePainter extends CustomPainter {
@override
void paint(Canvas canvas, Size size) {
final double boxWidth = size.width / 50;
final double boxHeight = size.height / 50;
for (int i = 0; i < 50; i++) {
for (int j = 0; j < 50; j++) {
final Rect rect = Rect.fromLTWH(i * boxWidth, j * boxHeight, boxWidth, boxHeight);
canvas.drawRect(rect, Paint()
..style = PaintingStyle.fill
..color = Colors.red
);
}
}
}

@override
bool shouldRepaint(covariant CustomPainter oldDelegate) {
return false;
}
}
@@ -0,0 +1,62 @@
// 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_driver/flutter_driver.dart';
import 'package:test/test.dart' hide TypeMatcher, isInstanceOf;

void main() {
group('scrolling performance test', () {
late FlutterDriver driver;

setUpAll(() async {
driver = await FlutterDriver.connect();

await driver.waitUntilFirstFrameRasterized();
});

tearDownAll(() async {
driver.close();
});

Future<void> testScrollPerf(String listKey, String summaryName) async {
// The slight initial delay avoids starting the timing during a
// period of increased load on the device. Without this delay, the
// benchmark has greater noise.
// See: https://github.com/flutter/flutter/issues/19434
await Future<void>.delayed(const Duration(milliseconds: 250));

await driver.forceGC();

final Timeline timeline = await driver.traceAction(() async {
// Find the scrollable stock list
final SerializableFinder list = find.byValueKey(listKey);
expect(list, isNotNull);

for (int j = 0; j < 5; j ++) {
// Scroll down
for (int i = 0; i < 5; i += 1) {
await driver.scroll(list, 0.0, -300.0, const Duration(milliseconds: 300));
await Future<void>.delayed(const Duration(milliseconds: 500));
}

// Scroll up
for (int i = 0; i < 5; i += 1) {
await driver.scroll(list, 0.0, 300.0, const Duration(milliseconds: 300));
await Future<void>.delayed(const Duration(milliseconds: 500));
}
}
});

final TimelineSummary summary = TimelineSummary.summarize(timeline);
await summary.writeTimelineToFile(summaryName, pretty: true);
}

test('platform_views_scroll_perf', () async {
// Disable frame sync, since there are ongoing animations.
await driver.runUnsynchronized(() async {
await testScrollPerf('platform-views-scroll', 'platform_views_scroll_perf_non_intersecting');
});
}, timeout: Timeout.none);
});
}
@@ -0,0 +1,13 @@
// 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/widgets.dart';
import 'package:flutter_driver/driver_extension.dart';

import 'package:platform_views_layout/main_non_intersecting.dart' as app;

void main() {
enableFlutterDriverExtension();
runApp(const app.PlatformViewApp());
}
@@ -0,0 +1,12 @@
// 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_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(createUiKitViewScrollPerfNonIntersectingTest(enableImpeller: true));
}
11 changes: 11 additions & 0 deletions dev/devicelab/lib/tasks/perf_tests.dart
Expand Up @@ -59,6 +59,17 @@ TaskFunction createUiKitViewScrollPerfTest({bool enableImpeller = false}) {
).run;
}

TaskFunction createUiKitViewScrollPerfNonIntersectingTest({bool enableImpeller = false}) {
return PerfTest(
'${flutterDirectory.path}/dev/benchmarks/platform_views_layout',
'test_driver/uikit_view_scroll_perf_non_intersecting.dart',
'platform_views_scroll_perf_non_intersecting',
testDriver: 'test_driver/scroll_perf_non_intersecting_test.dart',
needsFullTimeline: false,
enableImpeller: enableImpeller,
).run;
}

TaskFunction createAndroidTextureScrollPerfTest() {
return PerfTest(
'${flutterDirectory.path}/dev/benchmarks/platform_views_layout',
Expand Down

0 comments on commit 08a2635

Please sign in to comment.