Skip to content

Commit

Permalink
Reland "Measure iOS CPU/GPU percentage (flutter#41234)" (flutter#41426)
Browse files Browse the repository at this point in the history
This reverts commit f1e7fe8.

This fix is in flutter/packages#39
  • Loading branch information
liyuqian committed Sep 28, 2019
1 parent 0223565 commit 67b5bdf
Show file tree
Hide file tree
Showing 11 changed files with 143 additions and 6 deletions.
1 change: 1 addition & 0 deletions dev/benchmarks/macrobenchmarks/lib/common.dart
Expand Up @@ -5,3 +5,4 @@
const String kCullOpacityRouteName = '/cull_opacity';
const String kCubicBezierRouteName = '/cubic_bezier';
const String kBackdropFilterRouteName = '/backdrop_filter';
const String kSimpleAnimationRouteName = '/simple_animation';
15 changes: 12 additions & 3 deletions dev/benchmarks/macrobenchmarks/lib/main.dart
Expand Up @@ -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';

Expand All @@ -24,6 +25,7 @@ class MacrobenchmarksApp extends StatelessWidget {
kCullOpacityRouteName: (BuildContext context) => CullOpacityPage(),
kCubicBezierRouteName: (BuildContext context) => CubicBezierPage(),
kBackdropFilterRouteName: (BuildContext context) => BackdropFilterPage(),
kSimpleAnimationRouteName: (BuildContext conttext) => SimpleAnimationPage(),
},
);
}
Expand All @@ -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);
},
),
],
),
);
Expand Down
4 changes: 4 additions & 0 deletions 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';
Expand Down
12 changes: 12 additions & 0 deletions 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());
}
}
@@ -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();
}
@@ -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,
);
}
Expand Up @@ -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));
}
13 changes: 13 additions & 0 deletions 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));
}
43 changes: 43 additions & 0 deletions dev/devicelab/lib/framework/utils.dart
Expand Up @@ -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());
}
28 changes: 26 additions & 2 deletions dev/devicelab/lib/tasks/perf_tests.dart
Expand Up @@ -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;
}

Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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',
Expand All @@ -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',
]);
});
}
Expand Down
6 changes: 6 additions & 0 deletions dev/devicelab/manifest.yaml
Expand Up @@ -535,6 +535,12 @@ tasks:
stage: devicelab_ios
required_agent_capabilities: ["mac/ios"]

simple_animation_perf_ios:
description: >
Measure CPU/GPU usage percentages of a simple animation.
stage: devicelab_ios
required_agent_capabilities: ["mac/ios"]

smoke_catalina_start_up_ios:
description: >
A smoke test that runs on macOS Catalina, which is a clone of the Gallery startup latency test.
Expand Down

0 comments on commit 67b5bdf

Please sign in to comment.