Adding first semantics perf test (#10649)
* Adding first semantics perf test * review commnts and analyzer fixes * fix analyzer warning
This commit is contained in:
parent
0774c5194b
commit
8bf17192f6
@ -0,0 +1,11 @@
|
||||
// Copyright 2017 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:complex_layout/main.dart' as app;
|
||||
|
||||
void main() {
|
||||
enableFlutterDriverExtension();
|
||||
app.main();
|
||||
}
|
@ -0,0 +1,43 @@
|
||||
// Copyright 2017 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:async';
|
||||
import 'dart:convert';
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:flutter_driver/flutter_driver.dart';
|
||||
import 'package:path/path.dart' as p;
|
||||
import 'package:test/test.dart';
|
||||
|
||||
void main() {
|
||||
group('semantics performance test', () {
|
||||
FlutterDriver driver;
|
||||
|
||||
setUpAll(() async {
|
||||
driver = await FlutterDriver.connect(printCommunication: true);
|
||||
});
|
||||
|
||||
tearDownAll(() async {
|
||||
if (driver != null)
|
||||
driver.close();
|
||||
});
|
||||
|
||||
test('inital tree creation', () async {
|
||||
// Let app become fully idle.
|
||||
await new Future<Null>.delayed(const Duration(seconds: 1));
|
||||
|
||||
final Timeline timeline = await driver.traceAction(() async {
|
||||
expect(await driver.setSemantics(true), isTrue);
|
||||
});
|
||||
|
||||
final Iterable<TimelineEvent> semanticsEvents = timeline.events.where((TimelineEvent event) => event.name == "Semantics");
|
||||
if (semanticsEvents.length != 1)
|
||||
fail('Expected exactly one semantics event, got ${semanticsEvents.length}');
|
||||
final Duration semanticsTreeCreation = semanticsEvents.first.duration;
|
||||
|
||||
final String json = JSON.encode(<String, dynamic>{'initialSemanticsTreeCreation': semanticsTreeCreation.inMilliseconds});
|
||||
new File(p.join(testOutputsDirectory, 'complex_layout_semantics_perf.json')).writeAsStringSync(json);
|
||||
});
|
||||
});
|
||||
}
|
38
dev/devicelab/bin/tasks/complex_layout_semantics_perf.dart
Normal file
38
dev/devicelab/bin/tasks/complex_layout_semantics_perf.dart
Normal file
@ -0,0 +1,38 @@
|
||||
// Copyright (c) 2017 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/framework/utils.dart';
|
||||
import 'package:path/path.dart' as p;
|
||||
|
||||
void main() {
|
||||
task(() async {
|
||||
deviceOperatingSystem = DeviceOperatingSystem.android;
|
||||
|
||||
final Device device = await devices.workingDevice;
|
||||
await device.unlock();
|
||||
final String deviceId = device.deviceId;
|
||||
await flutter('packages', options: <String>['get']);
|
||||
|
||||
final String complexLayoutPath = p.join(flutterDirectory.path, 'dev', 'benchmarks', 'complex_layout');
|
||||
|
||||
await inDirectory(complexLayoutPath, () async {
|
||||
await flutter('drive', options: <String>[
|
||||
'-v',
|
||||
'--profile',
|
||||
'--trace-startup', // Enables "endless" timeline event buffering.
|
||||
'-t',
|
||||
p.join(complexLayoutPath, 'test_driver', 'semantics_perf.dart'),
|
||||
'-d',
|
||||
deviceId,
|
||||
]);
|
||||
});
|
||||
|
||||
final String dataPath = p.join(complexLayoutPath, 'build', 'complex_layout_semantics_perf.json');
|
||||
return new TaskResult.successFromFile(file(dataPath), benchmarkScoreKeys: <String>[
|
||||
'initialSemanticsTreeCreation',
|
||||
]);
|
||||
});
|
||||
}
|
@ -133,6 +133,13 @@ tasks:
|
||||
required_agent_capabilities: ["linux/android"]
|
||||
flaky: true
|
||||
|
||||
complex_layout_semantics_perf:
|
||||
description: >
|
||||
Measures duration of building the initial semantics tree.
|
||||
stage: devicelab
|
||||
required_agent_capabilities: ["linux/android"]
|
||||
flaky: true
|
||||
|
||||
# iOS on-device tests
|
||||
|
||||
channels_integration_test_ios:
|
||||
|
@ -21,6 +21,7 @@ import 'gesture.dart';
|
||||
import 'health.dart';
|
||||
import 'message.dart';
|
||||
import 'render_tree.dart';
|
||||
import 'semantics.dart';
|
||||
import 'timeline.dart';
|
||||
|
||||
/// Timeline stream identifier.
|
||||
@ -383,6 +384,15 @@ class FlutterDriver {
|
||||
return GetTextResult.fromJson(await _sendCommand(new GetText(finder, timeout: timeout))).text;
|
||||
}
|
||||
|
||||
/// Turns semantics on or off in the Flutter app under test.
|
||||
///
|
||||
/// Returns `true` when the call actually changed the state from on to off or
|
||||
/// vice versa.
|
||||
Future<bool> setSemantics(bool enabled, { Duration timeout: _kShortTimeout }) async {
|
||||
final SetSemanticsResult result = SetSemanticsResult.fromJson(await _sendCommand(new SetSemantics(enabled, timeout: timeout)));
|
||||
return result.changedState;
|
||||
}
|
||||
|
||||
/// Take a screenshot. The image will be returned as a PNG.
|
||||
Future<List<int>> screenshot({ Duration timeout }) async {
|
||||
timeout ??= _kLongTimeout;
|
||||
|
@ -8,7 +8,7 @@ import 'package:meta/meta.dart';
|
||||
|
||||
import 'package:flutter/gestures.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/rendering.dart' show RendererBinding;
|
||||
import 'package:flutter/rendering.dart' show RendererBinding, SemanticsHandle;
|
||||
import 'package:flutter/scheduler.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
@ -20,6 +20,7 @@ import 'gesture.dart';
|
||||
import 'health.dart';
|
||||
import 'message.dart';
|
||||
import 'render_tree.dart';
|
||||
import 'semantics.dart';
|
||||
|
||||
const String _extensionMethodName = 'driver';
|
||||
const String _extensionMethod = 'ext.flutter.$_extensionMethodName';
|
||||
@ -70,6 +71,7 @@ class FlutterDriverExtension {
|
||||
'tap': _tap,
|
||||
'get_text': _getText,
|
||||
'set_frame_sync': _setFrameSync,
|
||||
'set_semantics': _setSemantics,
|
||||
'scroll': _scroll,
|
||||
'scrollIntoView': _scrollIntoView,
|
||||
'waitFor': _waitFor,
|
||||
@ -82,6 +84,7 @@ class FlutterDriverExtension {
|
||||
'tap': (Map<String, String> params) => new Tap.deserialize(params),
|
||||
'get_text': (Map<String, String> params) => new GetText.deserialize(params),
|
||||
'set_frame_sync': (Map<String, String> params) => new SetFrameSync.deserialize(params),
|
||||
'set_semantics': (Map<String, String> params) => new SetSemantics.deserialize(params),
|
||||
'scroll': (Map<String, String> params) => new Scroll.deserialize(params),
|
||||
'scrollIntoView': (Map<String, String> params) => new ScrollIntoView.deserialize(params),
|
||||
'waitFor': (Map<String, String> params) => new WaitFor.deserialize(params),
|
||||
@ -271,4 +274,27 @@ class FlutterDriverExtension {
|
||||
_frameSync = setFrameSyncCommand.enabled;
|
||||
return new SetFrameSyncResult();
|
||||
}
|
||||
|
||||
SemanticsHandle _semantics;
|
||||
bool get _semanticsIsEnabled => RendererBinding.instance.pipelineOwner.semanticsOwner != null;
|
||||
|
||||
Future<SetSemanticsResult> _setSemantics(Command command) async {
|
||||
final SetSemantics setSemanticsCommand = command;
|
||||
final bool semanticsWasEnabled = _semanticsIsEnabled;
|
||||
if (setSemanticsCommand.enabled && _semantics == null) {
|
||||
_semantics = RendererBinding.instance.pipelineOwner.ensureSemantics();
|
||||
if (!semanticsWasEnabled) {
|
||||
// wait for the first frame where semantics is enabled.
|
||||
final Completer<Null> completer = new Completer<Null>();
|
||||
SchedulerBinding.instance.addPostFrameCallback((Duration d) {
|
||||
completer.complete();
|
||||
});
|
||||
await completer.future;
|
||||
}
|
||||
} else if (!setSemanticsCommand.enabled && _semantics != null) {
|
||||
_semantics.dispose();
|
||||
_semantics = null;
|
||||
}
|
||||
return new SetSemanticsResult(semanticsWasEnabled != _semanticsIsEnabled);
|
||||
}
|
||||
}
|
||||
|
@ -2,6 +2,8 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
import 'package:meta/meta.dart';
|
||||
|
||||
/// An object sent from the Flutter Driver to a Flutter application to instruct
|
||||
/// the application to perform a task.
|
||||
abstract class Command {
|
||||
@ -20,6 +22,7 @@ abstract class Command {
|
||||
String get kind;
|
||||
|
||||
/// Serializes this command to parameter name/value pairs.
|
||||
@mustCallSuper
|
||||
Map<String, String> serialize() => <String, String>{
|
||||
'command': kind,
|
||||
'timeout': '${timeout.inMilliseconds}',
|
||||
|
43
packages/flutter_driver/lib/src/semantics.dart
Normal file
43
packages/flutter_driver/lib/src/semantics.dart
Normal file
@ -0,0 +1,43 @@
|
||||
// Copyright 2017 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 'message.dart';
|
||||
|
||||
/// Enables or disables semantics.
|
||||
class SetSemantics extends Command {
|
||||
@override
|
||||
final String kind = 'set_semantics';
|
||||
|
||||
/// Whether semantics should be enabled or disabled.
|
||||
final bool enabled;
|
||||
|
||||
SetSemantics(this.enabled, { Duration timeout }) : super(timeout: timeout);
|
||||
|
||||
/// Deserializes this command from the value generated by [serialize].
|
||||
SetSemantics.deserialize(Map<String, String> params)
|
||||
: this.enabled = params['enabled'].toLowerCase() == 'true',
|
||||
super.deserialize(params);
|
||||
|
||||
@override
|
||||
Map<String, String> serialize() => super.serialize()..addAll(<String, String>{
|
||||
'enabled': '$enabled',
|
||||
});
|
||||
}
|
||||
|
||||
/// The result of a [SetSemantics] command.
|
||||
class SetSemanticsResult extends Result {
|
||||
SetSemanticsResult(this.changedState);
|
||||
|
||||
final bool changedState;
|
||||
|
||||
/// Deserializes this result from JSON.
|
||||
static SetSemanticsResult fromJson(Map<String, dynamic> json) {
|
||||
return new SetSemanticsResult(json['changedState']);
|
||||
}
|
||||
|
||||
@override
|
||||
Map<String, dynamic> toJson() => <String, dynamic>{
|
||||
'changedState': changedState,
|
||||
};
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user