Unverified Commit a58d50de authored by Jonah Williams's avatar Jonah Williams Committed by GitHub

[flutter_tools] allow pulling performance data from assemble (#55699)

parent 46a5c550
......@@ -666,7 +666,7 @@ class _BuildInstance {
Future<bool> _invokeInternal(Node node) async {
final PoolResource resource = await resourcePool.request();
final Stopwatch stopwatch = Stopwatch()..start();
bool passed = true;
bool succeeded = true;
bool skipped = false;
// The build system produces a list of aggregate input and output
......@@ -702,7 +702,7 @@ class _BuildInstance {
skipped = true;
logger.printTrace('Skipping target: ${node.target.name}');
updateGraph();
return passed;
return succeeded;
}
logger.printTrace('${node.target.name}: Starting due to ${node.invalidatedReasons}');
await node.target.build(environment);
......@@ -741,7 +741,7 @@ class _BuildInstance {
// TODO(jonahwilliams): throw specific exception for expected errors to mark
// as non-fatal. All others should be fatal.
node.target.clearStamp(environment);
passed = false;
succeeded = false;
skipped = false;
exceptionMeasurements[node.target.name] = ExceptionMeasurement(
node.target.name, exception, stackTrace);
......@@ -752,11 +752,11 @@ class _BuildInstance {
target: node.target.name,
elapsedMilliseconds: stopwatch.elapsedMilliseconds,
skipped: skipped,
passed: passed,
succeeded: succeeded,
analyicsName: node.target.analyticsName,
);
}
return passed;
return succeeded;
}
}
......@@ -781,14 +781,14 @@ class PerformanceMeasurement {
@required this.target,
@required this.elapsedMilliseconds,
@required this.skipped,
@required this.passed,
@required this.succeeded,
@required this.analyicsName,
});
final int elapsedMilliseconds;
final String target;
final bool skipped;
final bool passed;
final bool succeeded;
final String analyicsName;
}
......
......@@ -17,6 +17,7 @@ import '../build_system/targets/macos.dart';
import '../build_system/targets/web.dart';
import '../build_system/targets/windows.dart';
import '../cache.dart';
import '../convert.dart';
import '../globals.dart' as globals;
import '../project.dart';
import '../reporting/reporting.dart';
......@@ -72,6 +73,10 @@ class AssembleCommand extends FlutterCommand {
abbr: 'd',
help: 'Allows passing configuration to a target with --define=target=key=value.',
);
argParser.addOption(
'performance-measurement-file',
help: 'Output individual target performance to a JSON file.'
);
argParser.addMultiOption(
'input',
abbr: 'i',
......@@ -231,6 +236,10 @@ class AssembleCommand extends FlutterCommand {
if (argResults.wasParsed('build-outputs')) {
writeListIfChanged(result.outputFiles, stringArg('build-outputs'));
}
if (argResults.wasParsed('performance-measurement-file')) {
final File outFile = globals.fs.file(argResults['performance-measurement-file']);
writePerformanceData(result.performance.values, outFile);
}
if (argResults.wasParsed('depfile')) {
final File depfileFile = globals.fs.file(stringArg('depfile'));
final Depfile depfile = Depfile(result.inputFiles, result.outputFiles);
......@@ -262,6 +271,26 @@ void writeListIfChanged(List<File> files, String path) {
}
}
/// Output performance measurement data in [outFile].
@visibleForTesting
void writePerformanceData(Iterable<PerformanceMeasurement> measurements, File outFile) {
final Map<String, Object> jsonData = <String, Object>{
'targets': <Object>[
for (final PerformanceMeasurement measurement in measurements)
<String, Object>{
'name': measurement.analyicsName,
'skipped': measurement.skipped,
'succeeded': measurement.succeeded,
'elapsedMilliseconds': measurement.elapsedMilliseconds,
}
]
};
if (!outFile.parent.existsSync()) {
outFile.parent.createSync(recursive: true);
}
outFile.writeAsStringSync(json.encode(jsonData));
}
class _CompositeTarget extends Target {
_CompositeTarget(this.dependencies);
......
......@@ -3,11 +3,14 @@
// found in the LICENSE file.
import 'package:args/command_runner.dart';
import 'package:file/memory.dart';
import 'package:file_testing/file_testing.dart';
import 'package:flutter_tools/src/artifacts.dart';
import 'package:flutter_tools/src/base/file_system.dart';
import 'package:flutter_tools/src/build_system/build_system.dart';
import 'package:flutter_tools/src/cache.dart';
import 'package:flutter_tools/src/commands/assemble.dart';
import 'package:flutter_tools/src/convert.dart';
import 'package:flutter_tools/src/runner/flutter_command_runner.dart';
import 'package:mockito/mockito.dart';
import 'package:flutter_tools/src/globals.dart' as globals;
......@@ -97,6 +100,37 @@ void main() {
expect(testLogger.errorText, isNot(contains(testStackTrace.toString())));
});
testbed.test('flutter assemble outputs JSON performance data to provided file', () async {
when(globals.buildSystem.build(any, any, buildSystemConfig: anyNamed('buildSystemConfig')))
.thenAnswer((Invocation invocation) async {
return BuildResult(success: true, performance: <String, PerformanceMeasurement>{
'hello': PerformanceMeasurement(
target: 'hello',
analyicsName: 'bar',
elapsedMilliseconds: 123,
skipped: false,
succeeded: true,
),
});
});
final CommandRunner<void> commandRunner = createTestCommandRunner(AssembleCommand());
await commandRunner.run(<String>[
'assemble',
'-o Output',
'--performance-measurement-file=out.json',
'debug_macos_bundle_flutter_assets',
]);
expect(globals.fs.file('out.json'), exists);
expect(
json.decode(globals.fs.file('out.json').readAsStringSync()),
containsPair('targets', contains(
containsPair('name', 'bar'),
)),
);
});
testbed.test('flutter assemble does not inject engine revision with local-engine', () async {
Environment environment;
when(globals.artifacts.isLocalEngine).thenReturn(true);
......@@ -170,6 +204,36 @@ void main() {
expect(inputs.readAsStringSync(), contains('fizz'));
expect(inputs.lastModifiedSync(), isNot(theDistantPast));
});
testWithoutContext('writePerformanceData outputs performance data in JSON form', () {
final List<PerformanceMeasurement> performanceMeasurement = <PerformanceMeasurement>[
PerformanceMeasurement(
analyicsName: 'foo',
target: 'hidden',
skipped: false,
succeeded: true,
elapsedMilliseconds: 123,
)
];
final FileSystem fileSystem = MemoryFileSystem.test();
final File outFile = fileSystem.currentDirectory
.childDirectory('foo')
.childFile('out.json');
writePerformanceData(performanceMeasurement, outFile);
expect(outFile, exists);
expect(json.decode(outFile.readAsStringSync()), <String, Object>{
'targets': <Object>[
<String, Object>{
'name': 'foo',
'skipped': false,
'succeeded': true,
'elapsedMilliseconds': 123,
},
],
});
});
}
class MockBuildSystem extends Mock implements BuildSystem {}
......
......@@ -119,14 +119,14 @@ void main() {
analyicsName: 'kernel_snapshot',
target: 'kernel_snapshot',
elapsedMilliseconds: 1000,
passed: true,
succeeded: true,
skipped: false,
),
'anything': PerformanceMeasurement(
analyicsName: 'android_aot',
target: 'anything',
elapsedMilliseconds: 1000,
passed: true,
succeeded: true,
skipped: false,
),
});
......
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