Add benchmark for number of GCs in animated GIF (#81240)
This commit is contained in:
parent
08d7811f7f
commit
0866005f70
@ -21,6 +21,7 @@ const String kHeavyGridViewRouteName = '/heavy_gridview';
|
||||
const String kSimpleScrollRouteName = '/simple_scroll';
|
||||
const String kStackSizeRouteName = '/stack_size';
|
||||
const String kAnimationWithMicrotasksRouteName = '/animation_with_microtasks';
|
||||
const String kAnimatedImageRouteName = '/animated_image';
|
||||
|
||||
const String kScrollableName = '/macrobenchmark_listview';
|
||||
|
||||
|
@ -6,6 +6,7 @@ import 'package:flutter/material.dart';
|
||||
|
||||
import 'common.dart';
|
||||
|
||||
import 'src/animated_image.dart';
|
||||
import 'src/animated_placeholder.dart';
|
||||
import 'src/animation_with_microtasks.dart';
|
||||
import 'src/backdrop_filter.dart';
|
||||
@ -58,6 +59,7 @@ class MacrobenchmarksApp extends StatelessWidget {
|
||||
kSimpleScrollRouteName: (BuildContext context) => const SimpleScroll(),
|
||||
kStackSizeRouteName: (BuildContext context) => const StackSizePage(),
|
||||
kAnimationWithMicrotasksRouteName: (BuildContext context) => const AnimationWithMicrotasks(),
|
||||
kAnimatedImageRouteName: (BuildContext context) => const AnimatedImagePage(),
|
||||
},
|
||||
);
|
||||
}
|
||||
@ -201,6 +203,13 @@ class HomePage extends StatelessWidget {
|
||||
Navigator.pushNamed(context, kAnimationWithMicrotasksRouteName);
|
||||
},
|
||||
),
|
||||
ElevatedButton(
|
||||
key: const Key(kAnimatedImageRouteName),
|
||||
child: const Text('Animated Image'),
|
||||
onPressed: () {
|
||||
Navigator.pushNamed(context, kAnimatedImageRouteName);
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
|
30
dev/benchmarks/macrobenchmarks/lib/src/animated_image.dart
Normal file
30
dev/benchmarks/macrobenchmarks/lib/src/animated_image.dart
Normal file
@ -0,0 +1,30 @@
|
||||
// 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/material.dart';
|
||||
|
||||
class AnimatedImagePage extends StatelessWidget {
|
||||
const AnimatedImagePage({Key key, this.onFrame}) : super(key: key);
|
||||
|
||||
final ValueChanged<int> onFrame;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: const Text('Animated Image'),
|
||||
),
|
||||
body: Image.asset(
|
||||
'animated_images/animated_flutter_lgtm.gif',
|
||||
package: 'flutter_gallery_assets',
|
||||
frameBuilder: (BuildContext context, Widget child, int/*?*/ frame, bool syncCall) {
|
||||
if (onFrame != null && frame != null) {
|
||||
onFrame(frame);
|
||||
}
|
||||
return child;
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
@ -81,6 +81,7 @@ dev_dependencies:
|
||||
flutter:
|
||||
uses-material-design: true
|
||||
assets:
|
||||
- packages/flutter_gallery_assets/animated_images/animated_flutter_lgtm.gif
|
||||
- packages/flutter_gallery_assets/food/butternut_squash_soup.png
|
||||
- packages/flutter_gallery_assets/food/cherry_pie.png
|
||||
- assets/999x1000.png
|
||||
|
@ -0,0 +1,35 @@
|
||||
// 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/material.dart';
|
||||
import 'package:flutter_driver/driver_extension.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
|
||||
import 'package:macrobenchmarks/src/animated_image.dart';
|
||||
|
||||
/// This test is slightly different than most of the other tests in this
|
||||
/// application, in that it directly instantiates the page we care about and
|
||||
/// passes a callback. This way, we can make sure to consistently wait for a
|
||||
/// set number of image frames to render.
|
||||
Future<void> main() async {
|
||||
final Completer<void> waiter = Completer<void>();
|
||||
enableFlutterDriverExtension(handler: (String request) async {
|
||||
if (request != 'waitForAnimation') {
|
||||
throw UnsupportedError('Unrecognized request $request');
|
||||
}
|
||||
await waiter.future;
|
||||
return 'done';
|
||||
});
|
||||
runApp(MaterialApp(
|
||||
home: AnimatedImagePage(
|
||||
onFrame: (int frameNumber) {
|
||||
if (frameNumber == 250) {
|
||||
waiter.complete();
|
||||
}
|
||||
},
|
||||
),
|
||||
));
|
||||
}
|
@ -0,0 +1,24 @@
|
||||
// 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;
|
||||
|
||||
Future<void> main() async {
|
||||
const String fileName = 'large_image_changer';
|
||||
|
||||
test('Animate for 250 frames', () async {
|
||||
final FlutterDriver driver = await FlutterDriver.connect();
|
||||
await driver.forceGC();
|
||||
|
||||
|
||||
final Timeline timeline = await driver.traceAction(() async {
|
||||
await driver.requestData('waitForAnimation');
|
||||
});
|
||||
final TimelineSummary summary = TimelineSummary.summarize(timeline);
|
||||
await summary.writeTimelineToFile(fileName, pretty: true);
|
||||
|
||||
await driver.close();
|
||||
});
|
||||
}
|
16
dev/devicelab/bin/tasks/animated_image_gc_perf.dart
Normal file
16
dev/devicelab/bin/tasks/animated_image_gc_perf.dart
Normal file
@ -0,0 +1,16 @@
|
||||
// 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/adb.dart';
|
||||
import 'package:flutter_devicelab/framework/framework.dart';
|
||||
import 'package:flutter_devicelab/framework/utils.dart';
|
||||
import 'package:flutter_devicelab/tasks/perf_tests.dart';
|
||||
|
||||
Future<void> main() async {
|
||||
deviceOperatingSystem = DeviceOperatingSystem.android;
|
||||
await task(DevToolsMemoryTest(
|
||||
'${flutterDirectory.path}/dev/benchmarks/macrobenchmarks',
|
||||
'test_driver/animated_image.dart',
|
||||
).run);
|
||||
}
|
@ -34,7 +34,7 @@ class ImagesDemo extends StatelessWidget {
|
||||
exampleCodeTag: 'animated_image',
|
||||
demoWidget: Semantics(
|
||||
label: 'Example of animated GIF',
|
||||
child:Image.asset(
|
||||
child: Image.asset(
|
||||
'animated_images/animated_flutter_lgtm.gif',
|
||||
package: 'flutter_gallery_assets',
|
||||
),
|
||||
|
@ -324,6 +324,12 @@
|
||||
"task_name": "linux_large_image_changer_perf_android",
|
||||
"flaky": false
|
||||
},
|
||||
{
|
||||
"name": "Linux animated_image_gc_perf",
|
||||
"repo": "flutter",
|
||||
"task_name": "animated_image_gc_perf",
|
||||
"flaky": true
|
||||
},
|
||||
{
|
||||
"name": "Linux linux_chrome_dev_mode",
|
||||
"repo": "flutter",
|
||||
|
@ -95,6 +95,20 @@ class TimelineSummary {
|
||||
/// The total number of rasterizer cycles recorded in the timeline.
|
||||
int countRasterizations() => _extractGpuRasterizerDrawDurations().length;
|
||||
|
||||
/// The total number of old generation garbage collections recorded in the timeline.
|
||||
int oldGenerationGarbageCollections() {
|
||||
return _timeline.events!.where((TimelineEvent event) {
|
||||
return event.category == 'GC' && event.name == 'CollectOldGeneration';
|
||||
}).length;
|
||||
}
|
||||
|
||||
/// The total number of new generation garbage collections recorded in the timeline.
|
||||
int newGenerationGarbageCollections() {
|
||||
return _timeline.events!.where((TimelineEvent event) {
|
||||
return event.category == 'GC' && event.name == 'CollectNewGeneration';
|
||||
}).length;
|
||||
}
|
||||
|
||||
/// Encodes this summary as JSON.
|
||||
///
|
||||
/// Data ends with "_time_millis" means time in milliseconds and numbers in
|
||||
@ -176,6 +190,8 @@ class TimelineSummary {
|
||||
'missed_frame_rasterizer_budget_count': computeMissedFrameRasterizerBudgetCount(),
|
||||
'frame_count': countFrames(),
|
||||
'frame_rasterizer_count': countRasterizations(),
|
||||
'new_gen_gc_count': newGenerationGarbageCollections(),
|
||||
'old_gen_gc_count': oldGenerationGarbageCollections(),
|
||||
'frame_build_times': _extractFrameDurations()
|
||||
.map<int>((Duration duration) => duration.inMicroseconds)
|
||||
.toList(),
|
||||
|
@ -95,6 +95,38 @@ void main() {
|
||||
'ts': timeStamp,
|
||||
};
|
||||
|
||||
List<Map<String, dynamic>> newGenGC(int count) => List<Map<String, dynamic>>.filled(
|
||||
count,
|
||||
<String, dynamic>{
|
||||
'name': 'CollectNewGeneration',
|
||||
'cat': 'GC',
|
||||
'tid': 19695,
|
||||
'pid': 19650,
|
||||
'ts': 358849612473,
|
||||
'tts': 476761,
|
||||
'ph': 'B',
|
||||
'args': <String, dynamic>{
|
||||
'isolateGroupId': 'isolateGroups/10824099774666259225',
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
List<Map<String, dynamic>> oldGenGC(int count) => List<Map<String, dynamic>>.filled(
|
||||
count,
|
||||
<String, dynamic>{
|
||||
'name': 'CollectOldGeneration',
|
||||
'cat': 'GC',
|
||||
'tid': 19695,
|
||||
'pid': 19650,
|
||||
'ts': 358849612473,
|
||||
'tts': 476761,
|
||||
'ph': 'B',
|
||||
'args': <String, dynamic>{
|
||||
'isolateGroupId': 'isolateGroups/10824099774666259225',
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
List<Map<String, dynamic>> rasterizeTimeSequenceInMillis(List<int> sequence) {
|
||||
final List<Map<String, dynamic>> result = <Map<String, dynamic>>[];
|
||||
int t = 0;
|
||||
@ -388,6 +420,8 @@ void main() {
|
||||
begin(1000), end(19000),
|
||||
begin(19000), end(29000),
|
||||
begin(29000), end(49000),
|
||||
...newGenGC(4),
|
||||
...oldGenGC(5),
|
||||
frameBegin(1000), frameEnd(18000),
|
||||
frameBegin(19000), frameEnd(28000),
|
||||
frameBegin(29000), frameEnd(48000),
|
||||
@ -405,6 +439,8 @@ void main() {
|
||||
'missed_frame_rasterizer_budget_count': 2,
|
||||
'frame_count': 3,
|
||||
'frame_rasterizer_count': 3,
|
||||
'new_gen_gc_count': 4,
|
||||
'old_gen_gc_count': 5,
|
||||
'frame_build_times': <int>[17000, 9000, 19000],
|
||||
'frame_rasterizer_times': <int>[18000, 10000, 20000],
|
||||
'frame_begin_times': <int>[0, 18000, 28000],
|
||||
@ -475,6 +511,8 @@ void main() {
|
||||
lagBegin(1000, 4), lagEnd(2000, 4),
|
||||
lagBegin(1200, 12), lagEnd(2400, 12),
|
||||
lagBegin(4200, 8), lagEnd(9400, 8),
|
||||
...newGenGC(4),
|
||||
...oldGenGC(5),
|
||||
cpuUsage(5000, 20), cpuUsage(5010, 60),
|
||||
memoryUsage(6000, 20, 40), memoryUsage(6100, 30, 45),
|
||||
platformVsync(7000), vsyncCallback(7500),
|
||||
@ -494,6 +532,8 @@ void main() {
|
||||
'missed_frame_rasterizer_budget_count': 2,
|
||||
'frame_count': 3,
|
||||
'frame_rasterizer_count': 3,
|
||||
'new_gen_gc_count': 4,
|
||||
'old_gen_gc_count': 5,
|
||||
'frame_build_times': <int>[17000, 9000, 19000],
|
||||
'frame_rasterizer_times': <int>[18000, 10000, 20000],
|
||||
'frame_begin_times': <int>[0, 18000, 28000],
|
||||
|
Loading…
x
Reference in New Issue
Block a user