Reland "Measure iOS CPU/GPU percentage #41426" (#41578)
This reverts commit baea9bf7cc7447b5ec6e6d377a68b17e79cb9ccf.
Additionally, we let the test run on mac8 with iphonexs because the test won't run on Xcode 10.1 (mac3-7). Hence we force it to run on mac8 which currently has Xcode 10.2.
diff --git a/dev/benchmarks/macrobenchmarks/lib/common.dart b/dev/benchmarks/macrobenchmarks/lib/common.dart
index 746d824..7695b53 100644
--- a/dev/benchmarks/macrobenchmarks/lib/common.dart
+++ b/dev/benchmarks/macrobenchmarks/lib/common.dart
@@ -5,3 +5,4 @@
const String kCullOpacityRouteName = '/cull_opacity';
const String kCubicBezierRouteName = '/cubic_bezier';
const String kBackdropFilterRouteName = '/backdrop_filter';
+const String kSimpleAnimationRouteName = '/simple_animation';
diff --git a/dev/benchmarks/macrobenchmarks/lib/main.dart b/dev/benchmarks/macrobenchmarks/lib/main.dart
index 5f87dfd..267b0f2 100644
--- a/dev/benchmarks/macrobenchmarks/lib/main.dart
+++ b/dev/benchmarks/macrobenchmarks/lib/main.dart
@@ -8,6 +8,7 @@
import 'src/backdrop_filter.dart';
import 'src/cubic_bezier.dart';
import 'src/cull_opacity.dart';
+import 'src/simple_animation.dart';
const String kMacrobenchmarks ='Macrobenchmarks';
@@ -24,6 +25,7 @@
kCullOpacityRouteName: (BuildContext context) => CullOpacityPage(),
kCubicBezierRouteName: (BuildContext context) => CubicBezierPage(),
kBackdropFilterRouteName: (BuildContext context) => BackdropFilterPage(),
+ kSimpleAnimationRouteName: (BuildContext conttext) => SimpleAnimationPage(),
},
);
}
@@ -39,24 +41,31 @@
RaisedButton(
key: const Key(kCullOpacityRouteName),
child: const Text('Cull opacity'),
- onPressed: (){
+ onPressed: () {
Navigator.pushNamed(context, kCullOpacityRouteName);
},
),
RaisedButton(
key: const Key(kCubicBezierRouteName),
child: const Text('Cubic Bezier'),
- onPressed: (){
+ onPressed: () {
Navigator.pushNamed(context, kCubicBezierRouteName);
},
),
RaisedButton(
key: const Key(kBackdropFilterRouteName),
child: const Text('Backdrop Filter'),
- onPressed: (){
+ onPressed: () {
Navigator.pushNamed(context, kBackdropFilterRouteName);
},
),
+ RaisedButton(
+ key: const Key(kSimpleAnimationRouteName),
+ child: const Text('Simple Animation'),
+ onPressed: () {
+ Navigator.pushNamed(context, kSimpleAnimationRouteName);
+ },
+ ),
],
),
);
diff --git a/dev/benchmarks/macrobenchmarks/lib/src/backdrop_filter.dart b/dev/benchmarks/macrobenchmarks/lib/src/backdrop_filter.dart
index 5e93117..57ceb41 100644
--- a/dev/benchmarks/macrobenchmarks/lib/src/backdrop_filter.dart
+++ b/dev/benchmarks/macrobenchmarks/lib/src/backdrop_filter.dart
@@ -1,3 +1,7 @@
+// Copyright 2019 The Chromium 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:ui';
import 'package:flutter/material.dart';
diff --git a/dev/benchmarks/macrobenchmarks/lib/src/simple_animation.dart b/dev/benchmarks/macrobenchmarks/lib/src/simple_animation.dart
new file mode 100644
index 0000000..7182bed
--- /dev/null
+++ b/dev/benchmarks/macrobenchmarks/lib/src/simple_animation.dart
@@ -0,0 +1,12 @@
+// Copyright 2019 The Chromium 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 SimpleAnimationPage extends StatelessWidget {
+ @override
+ Widget build(BuildContext context) {
+ return const Center(child: LinearProgressIndicator());
+ }
+}
diff --git a/dev/benchmarks/macrobenchmarks/test_driver/simple_animation_perf.dart b/dev/benchmarks/macrobenchmarks/test_driver/simple_animation_perf.dart
new file mode 100644
index 0000000..80361f3
--- /dev/null
+++ b/dev/benchmarks/macrobenchmarks/test_driver/simple_animation_perf.dart
@@ -0,0 +1,11 @@
+// Copyright 2019 The Chromium 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/driver_extension.dart';
+import 'package:macrobenchmarks/main.dart' as app;
+
+void main() {
+ enableFlutterDriverExtension();
+ app.main();
+}
diff --git a/dev/benchmarks/macrobenchmarks/test_driver/simple_animation_perf_test.dart b/dev/benchmarks/macrobenchmarks/test_driver/simple_animation_perf_test.dart
new file mode 100644
index 0000000..494f2c6
--- /dev/null
+++ b/dev/benchmarks/macrobenchmarks/test_driver/simple_animation_perf_test.dart
@@ -0,0 +1,14 @@
+// Copyright 2019 The Chromium 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:macrobenchmarks/common.dart';
+
+import 'util.dart';
+
+void main() {
+ macroPerfTest(
+ 'simple_animation_perf',
+ kSimpleAnimationRouteName,
+ );
+}
diff --git a/dev/devicelab/bin/tasks/backdrop_filter_perf_ios__timeline_summary.dart b/dev/devicelab/bin/tasks/backdrop_filter_perf_ios__timeline_summary.dart
index 840c775..20dc420 100644
--- a/dev/devicelab/bin/tasks/backdrop_filter_perf_ios__timeline_summary.dart
+++ b/dev/devicelab/bin/tasks/backdrop_filter_perf_ios__timeline_summary.dart
@@ -10,5 +10,5 @@
Future<void> main() async {
deviceOperatingSystem = DeviceOperatingSystem.ios;
- await task(createBackdropFilterPerfTest());
+ await task(createBackdropFilterPerfTest(needsMeasureCpuGpu: true));
}
diff --git a/dev/devicelab/bin/tasks/simple_animation_perf_ios.dart b/dev/devicelab/bin/tasks/simple_animation_perf_ios.dart
new file mode 100644
index 0000000..3982569
--- /dev/null
+++ b/dev/devicelab/bin/tasks/simple_animation_perf_ios.dart
@@ -0,0 +1,13 @@
+// Copyright 2019 The Chromium 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/tasks/perf_tests.dart';
+
+Future<void> main() async {
+ deviceOperatingSystem = DeviceOperatingSystem.ios;
+ await task(createSimpleAnimationPerfTest(needsMeasureCpuGpu: true));
+}
diff --git a/dev/devicelab/lib/framework/utils.dart b/dev/devicelab/lib/framework/utils.dart
index e5f3d34..307de3b 100644
--- a/dev/devicelab/lib/framework/utils.dart
+++ b/dev/devicelab/lib/framework/utils.dart
@@ -622,3 +622,46 @@
throw FileSystemException('Expected file to exit.', file);
}
}
+
+void _checkExitCode(int code) {
+ if (code != 0) {
+ throw Exception(
+ 'Unexpected exit code = $code!',
+ );
+ }
+}
+
+Future<void> _execAndCheck(String executable, List<String> args) async {
+ _checkExitCode(await exec(executable, args));
+}
+
+// Measure the CPU/GPU percentage for [duration] while a Flutter app is running
+// on an iOS device (e.g., right after a Flutter driver test has finished, which
+// doesn't close the Flutter app, and the Flutter app has an indefinite
+// animation). The return should have a format like the following json
+// ```
+// {"gpu_percentage":12.6,"cpu_percentage":18.15}
+// ```
+Future<Map<String, dynamic>> measureIosCpuGpu({
+ Duration duration = const Duration(seconds: 10),
+ String deviceId,
+}) async {
+ await _execAndCheck('pub', <String>[
+ 'global',
+ 'activate',
+ 'gauge',
+ '0.1.4',
+ ]);
+
+ await _execAndCheck('pub', <String>[
+ 'global',
+ 'run',
+ 'gauge',
+ 'ioscpugpu',
+ 'new',
+ if (deviceId != null) ...<String>['-w', deviceId],
+ '-l',
+ '${duration.inMilliseconds}',
+ ]);
+ return json.decode(file('$cwd/result.json').readAsStringSync());
+}
diff --git a/dev/devicelab/lib/tasks/perf_tests.dart b/dev/devicelab/lib/tasks/perf_tests.dart
index 88c6f81..9aa2bf5 100644
--- a/dev/devicelab/lib/tasks/perf_tests.dart
+++ b/dev/devicelab/lib/tasks/perf_tests.dart
@@ -54,11 +54,21 @@
).run;
}
-TaskFunction createBackdropFilterPerfTest() {
+TaskFunction createBackdropFilterPerfTest({bool needsMeasureCpuGpu = false}) {
return PerfTest(
'${flutterDirectory.path}/dev/benchmarks/macrobenchmarks',
'test_driver/backdrop_filter_perf.dart',
'backdrop_filter_perf',
+ needsMeasureCpuGPu: needsMeasureCpuGpu,
+ ).run;
+}
+
+TaskFunction createSimpleAnimationPerfTest({bool needsMeasureCpuGpu = false}) {
+ return PerfTest(
+ '${flutterDirectory.path}/dev/benchmarks/macrobenchmarks',
+ 'test_driver/simple_animation_perf.dart',
+ 'simple_animation_perf',
+ needsMeasureCpuGPu: needsMeasureCpuGpu,
).run;
}
@@ -168,12 +178,18 @@
/// Measures application runtime performance, specifically per-frame
/// performance.
class PerfTest {
- const PerfTest(this.testDirectory, this.testTarget, this.timelineFileName);
+ const PerfTest(
+ this.testDirectory,
+ this.testTarget,
+ this.timelineFileName,
+ {this.needsMeasureCpuGPu = false});
final String testDirectory;
final String testTarget;
final String timelineFileName;
+ final bool needsMeasureCpuGPu;
+
Future<TaskResult> run() {
return inDirectory<TaskResult>(testDirectory, () async {
final Device device = await devices.workingDevice;
@@ -202,6 +218,12 @@
);
}
+ if (needsMeasureCpuGPu) {
+ await inDirectory<void>('$testDirectory/build', () async {
+ data.addAll(await measureIosCpuGpu(deviceId: deviceId));
+ });
+ }
+
return TaskResult.success(data, benchmarkScoreKeys: <String>[
'average_frame_build_time_millis',
'worst_frame_build_time_millis',
@@ -213,6 +235,8 @@
'missed_frame_rasterizer_budget_count',
'90th_percentile_frame_rasterizer_time_millis',
'99th_percentile_frame_rasterizer_time_millis',
+ if (needsMeasureCpuGPu) 'cpu_percentage',
+ if (needsMeasureCpuGPu) 'gpu_percentage',
]);
});
}
diff --git a/dev/devicelab/manifest.yaml b/dev/devicelab/manifest.yaml
index 46e63df..9f75f2d 100644
--- a/dev/devicelab/manifest.yaml
+++ b/dev/devicelab/manifest.yaml
@@ -535,6 +535,12 @@
stage: devicelab_ios
required_agent_capabilities: ["mac/ios"]
+ simple_animation_perf_iphonexs:
+ description: >
+ Measure CPU/GPU usage percentages of a simple animation.
+ stage: devicelab_ios
+ required_agent_capabilities: ["mac/iphonexs"]
+
smoke_catalina_start_up_ios:
description: >
A smoke test that runs on macOS Catalina, which is a clone of the Gallery startup latency test.