From 9ee6763a66e8c10415b57350c802a07e5ef3adfa Mon Sep 17 00:00:00 2001 From: liyuqian Date: Tue, 5 May 2020 15:12:01 -0700 Subject: [PATCH] Add DevTools memory test (#55486) --- ...x_layout_scroll_perf__devtools_memory.dart | 18 +++ dev/devicelab/lib/tasks/perf_tests.dart | 126 +++++++++++++++++- dev/devicelab/manifest.yaml | 6 + 3 files changed, 149 insertions(+), 1 deletion(-) create mode 100644 dev/devicelab/bin/tasks/complex_layout_scroll_perf__devtools_memory.dart diff --git a/dev/devicelab/bin/tasks/complex_layout_scroll_perf__devtools_memory.dart b/dev/devicelab/bin/tasks/complex_layout_scroll_perf__devtools_memory.dart new file mode 100644 index 00000000000..91834529ee6 --- /dev/null +++ b/dev/devicelab/bin/tasks/complex_layout_scroll_perf__devtools_memory.dart @@ -0,0 +1,18 @@ +// 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_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 main() async { + deviceOperatingSystem = DeviceOperatingSystem.android; + await task(DevToolsMemoryTest( + '${flutterDirectory.path}/dev/benchmarks/complex_layout', + 'test_driver/scroll_perf.dart', + ).run); +} diff --git a/dev/devicelab/lib/tasks/perf_tests.dart b/dev/devicelab/lib/tasks/perf_tests.dart index ddb6a35f2dd..890bfd7acc6 100644 --- a/dev/devicelab/lib/tasks/perf_tests.dart +++ b/dev/devicelab/lib/tasks/perf_tests.dart @@ -3,8 +3,9 @@ // found in the LICENSE file. import 'dart:async'; -import 'dart:convert' show json; +import 'dart:convert' show LineSplitter, json, utf8; import 'dart:io'; +import 'dart:math' as math; import 'package:meta/meta.dart'; import 'package:path/path.dart' as path; @@ -692,6 +693,129 @@ class MemoryTest { } } +class DevToolsMemoryTest { + DevToolsMemoryTest(this.project, this.driverTest); + + final String project; + final String driverTest; + + Future run() { + return inDirectory(project, () async { + _device = await devices.workingDevice; + await _device.unlock(); + await flutter('packages', options: ['get']); + + await _launchApp(); + if (_observatoryUri == null) { + return TaskResult.failure('Observatory URI not found.'); + } + + await _launchDevTools(); + + await flutter( + 'drive', + options: [ + '--use-existing-app', _observatoryUri, + '-d', _device.deviceId, + '--profile', + driverTest, + ], + ); + + _devToolsProcess.kill(); + await _devToolsProcess.exitCode; + + _runProcess.kill(); + await _runProcess.exitCode; + + final Map data = json.decode( + file('$project/$_kJsonFileName').readAsStringSync(), + ) as Map; + final List samples = data['samples']['data'] as List; + int maxRss = 0; + int maxAdbTotal = 0; + for (final dynamic sample in samples) { + maxRss = math.max(maxRss, sample['rss'] as int); + if (sample['adb_memoryInfo'] != null) { + maxAdbTotal = math.max(maxAdbTotal, sample['adb_memoryInfo']['Total'] as int); + } + } + return TaskResult.success( + {'maxRss': maxRss, 'maxAdbTotal': maxAdbTotal}, + benchmarkScoreKeys: ['maxRss', 'maxAdbTotal'], + ); + }); + } + + Future _launchApp() async { + print('launching $project$driverTest on device...'); + final String flutterPath = path.join(flutterDirectory.path, 'bin', 'flutter'); + _runProcess = await startProcess( + flutterPath, + [ + 'run', + '--verbose', + '--profile', + '-d', _device.deviceId, + driverTest, + ], + ); + + // Listen for Observatory URI and forward stdout/stderr + final Completer observatoryUri = Completer(); + _runProcess.stdout + .transform(utf8.decoder) + .transform(const LineSplitter()) + .listen((String line) { + print('run stdout: $line'); + final RegExpMatch match = RegExp(r'An Observatory debugger and profiler on .+ is available at: ((http|//)[a-zA-Z0-9:/=_\-\.\[\]]+)').firstMatch(line); + if (match != null) { + observatoryUri.complete(match[1]); + _observatoryUri = match[1]; + } + }, onDone: () { observatoryUri.complete(null); }); + _forwardStream(_runProcess.stderr, 'run stderr'); + + _observatoryUri = await observatoryUri.future; + } + + Future _launchDevTools() async { + await exec('pub', [ + 'global', + 'activate', + 'devtools', + ]); + _devToolsProcess = await startProcess( + 'pub', + [ + 'global', + 'run', + 'devtools', + '--vm-uri', _observatoryUri, + '--profile-memory', _kJsonFileName, + ], + ); + _forwardStream(_devToolsProcess.stdout, 'devtools stdout'); + _forwardStream(_devToolsProcess.stderr, 'devtools stderr'); + } + + void _forwardStream(Stream> stream, String label) { + stream + .transform(utf8.decoder) + .transform(const LineSplitter()) + .listen((String line) { + print('$label: $line'); + }); + } + + Device _device; + String _observatoryUri; + Process _runProcess; + Process _devToolsProcess; + + static const String _kJsonFileName = 'devtools_memory.json'; +} + enum ReportedDurationTestFlavor { debug, profile, release } diff --git a/dev/devicelab/manifest.yaml b/dev/devicelab/manifest.yaml index e89c8888b1e..aacc1c521c6 100644 --- a/dev/devicelab/manifest.yaml +++ b/dev/devicelab/manifest.yaml @@ -285,6 +285,12 @@ tasks: stage: devicelab required_agent_capabilities: ["mac/android"] + complex_layout_scroll_perf__devtools_memory: + description: > + Measures memory usage of the scroll performance test using DevTools. + stage: devicelab + required_agent_capabilities: ["linux/android"] + hello_world_android__compile: description: > Measures the APK size of Hello World.