Unverified Commit 1c7e2afc authored by Matej Knopp's avatar Matej Knopp Committed by GitHub

Add static_path_tessellation macrobenchmark (#131837)

This adds a macrobenchmark representative of a real world application that uses SVG icons. The scenario of rasterizing complex paths that don't change over time does not seem to be covered by any other macrobenchmark and shows a significantly slower impeller performance compared to skia.

It's actually bit problematic to measure this because on A15 the CPU load with impeller is high enough to trigger CPU frequency change. So in order to get consistent reading I had to add a spinning background thread that would keep the CPU at highest frequency.

```objc
  [NSThread detachNewThreadWithBlock:^{
    while (true) {
      pthread_yield_np();
    }
  }];
```

```bash
flutter drive --profile --local-engine=ios_profile -t test_driver/run_app.dart --driver test_driver/path_tessellation_static_perf_test.dart
```

| average_frame_build_time_millis |Time|
|--|--|
| Impeller | 0.46686524822695047 |
| Skia | 0.4625749999999999 |
| Skia - No RasterCache | 0.47173750000000086|

| average_frame_rasterizer_time_millis | Time |
|--|--|
| Impeller | 6.654328519855595 |
| Skia - Raster Cache |  0.2534123711340209 * |
| Skia - No RasterCache |  0.53424375 |

* Adding the `GeometryPainter` seems to have triggered the complexity threshold for raster cache.

<img alt="screenshot" width="320" src="https://github.com/flutter/flutter/assets/96958/7a2f9384-b512-477b-bffa-058d4d284a41"/>
parent ad0dbc8d
......@@ -11,6 +11,7 @@ const String kPictureCacheRouteName = '/picture_cache';
const String kPictureCacheComplexityScoringRouteName = '/picture_cache_complexity_scoring';
const String kLargeImageChangerRouteName = '/large_image_changer';
const String kLargeImagesRouteName = '/large_images';
const String kPathTessellationRouteName = '/path_tessellation';
const String kTextRouteName = '/text';
const String kFullscreenTextRouteName = '/fullscreen_text';
const String kAnimatedPlaceholderRouteName = '/animated_placeholder';
......
......@@ -28,6 +28,7 @@ import 'src/large_images.dart';
import 'src/list_text_layout.dart';
import 'src/multi_widget_construction.dart';
import 'src/opacity_peephole.dart';
import 'src/path_tessellation.dart';
import 'src/picture_cache.dart';
import 'src/picture_cache_complexity_scoring.dart';
import 'src/post_backdrop_filter.dart';
......@@ -63,6 +64,7 @@ class MacrobenchmarksApp extends StatelessWidget {
kLargeImageChangerRouteName: (BuildContext context) => const LargeImageChangerPage(),
kLargeImagesRouteName: (BuildContext context) => const LargeImagesPage(),
kTextRouteName: (BuildContext context) => const TextPage(),
kPathTessellationRouteName: (BuildContext context) => const PathTessellationPage(),
kFullscreenTextRouteName: (BuildContext context) => const TextFieldPage(),
kAnimatedPlaceholderRouteName: (BuildContext context) => const AnimatedPlaceholderPage(),
kClipperCacheRouteName: (BuildContext context) => const ClipperCachePage(),
......@@ -162,6 +164,13 @@ class HomePage extends StatelessWidget {
Navigator.pushNamed(context, kLargeImagesRouteName);
},
),
ElevatedButton(
key: const Key(kPathTessellationRouteName),
child: const Text('Path Tessellation'),
onPressed: () {
Navigator.pushNamed(context, kPathTessellationRouteName);
},
),
ElevatedButton(
key: const Key(kTextRouteName),
child: const Text('Text'),
......
This diff is collapsed.
......@@ -181,7 +181,6 @@
33CC10EB2044A3C60003C045 /* Resources */,
33CC110E2044A8840003C045 /* Bundle Framework */,
3399D490228B24CF009A79C7 /* ShellScript */,
A7656B4F0E64AD6C5DDAE467 /* [CP] Embed Pods Frameworks */,
);
buildRules = (
);
......@@ -310,23 +309,6 @@
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
showEnvVarsInLog = 0;
};
A7656B4F0E64AD6C5DDAE467 /* [CP] Embed Pods Frameworks */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist",
);
name = "[CP] Embed Pods Frameworks";
outputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n";
showEnvVarsInLog = 0;
};
/* End PBXShellScriptBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
......
// 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:macrobenchmarks/common.dart';
import 'util.dart';
void main() {
macroPerfTest(
'tessellation_perf_dynamic',
kPathTessellationRouteName,
pageDelay: const Duration(seconds: 1),
duration: const Duration(seconds: 10),
setupOps: (FlutterDriver driver) async {
final SerializableFinder animateButton =
find.byValueKey('animate_button');
await driver.tap(animateButton);
await Future<void>.delayed(const Duration(seconds: 1));
},
);
}
// 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:macrobenchmarks/common.dart';
import 'util.dart';
void main() {
macroPerfTest(
'tessellation_perf_static',
kPathTessellationRouteName,
pageDelay: const Duration(seconds: 1),
driverOps: (FlutterDriver driver) async {
final SerializableFinder listView = find.byValueKey('list_view');
Future<void> scrollOnce(double offset) async {
await driver.scroll(
listView, 0.0, offset, const Duration(milliseconds: 450));
await Future<void>.delayed(const Duration(milliseconds: 500));
}
for (int i = 0; i < 3; i += 1) {
await scrollOnce(-600.0);
await scrollOnce(-600.0);
await scrollOnce(600.0);
await scrollOnce(600.0);
}
},
);
}
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