Unverified Commit 9cc29c61 authored by liyuqian's avatar liyuqian Committed by GitHub

Reland "Measure iOS CPU/GPU percentage #41426" (#41578)

This reverts commit baea9bf7.

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.
parent baea9bf7
......@@ -5,3 +5,4 @@
const String kCullOpacityRouteName = '/cull_opacity';
const String kCubicBezierRouteName = '/cubic_bezier';
const String kBackdropFilterRouteName = '/backdrop_filter';
const String kSimpleAnimationRouteName = '/simple_animation';
......@@ -8,6 +8,7 @@ import 'common.dart';
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 @@ class MacrobenchmarksApp extends StatelessWidget {
kCullOpacityRouteName: (BuildContext context) => CullOpacityPage(),
kCubicBezierRouteName: (BuildContext context) => CubicBezierPage(),
kBackdropFilterRouteName: (BuildContext context) => BackdropFilterPage(),
kSimpleAnimationRouteName: (BuildContext conttext) => SimpleAnimationPage(),
},
);
}
......@@ -39,24 +41,31 @@ class HomePage extends StatelessWidget {
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);
},
),
],
),
);
......
// 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';
......
// 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());
}
}
// 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();
}
// 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,
);
}
......@@ -10,5 +10,5 @@ import 'package:flutter_devicelab/framework/framework.dart';
Future<void> main() async {
deviceOperatingSystem = DeviceOperatingSystem.ios;
await task(createBackdropFilterPerfTest());
await task(createBackdropFilterPerfTest(needsMeasureCpuGpu: true));
}
// 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));
}
......@@ -622,3 +622,46 @@ void checkFileExists(String file) {
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());
}
......@@ -54,11 +54,21 @@ TaskFunction createCubicBezierPerfTest() {
).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 @@ class StartupTest {
/// 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 @@ class PerfTest {
);
}
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 @@ class PerfTest {
'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',
]);
});
}
......
......@@ -535,6 +535,12 @@ tasks:
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.
......
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