Unverified Commit b847ba5a authored by Zachary Anderson's avatar Zachary Anderson Committed by GitHub

[flutter_tool] Send build timing to analytics (#34049)

parent bd413bff
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
import 'dart:async'; import 'dart:async';
import 'package:crypto/crypto.dart';
import 'package:meta/meta.dart'; import 'package:meta/meta.dart';
import '../android/android_sdk.dart'; import '../android/android_sdk.dart';
...@@ -352,6 +353,7 @@ Future<void> _buildGradleProjectV1(FlutterProject project, String gradle) async ...@@ -352,6 +353,7 @@ Future<void> _buildGradleProjectV1(FlutterProject project, String gradle) async
timeout: timeoutConfiguration.slowOperation, timeout: timeoutConfiguration.slowOperation,
multilineOutput: true, multilineOutput: true,
); );
final Stopwatch sw = Stopwatch()..start();
final int exitCode = await runCommandAndStreamOutput( final int exitCode = await runCommandAndStreamOutput(
<String>[fs.file(gradle).absolute.path, 'build'], <String>[fs.file(gradle).absolute.path, 'build'],
workingDirectory: project.android.hostAppGradleRoot.path, workingDirectory: project.android.hostAppGradleRoot.path,
...@@ -359,6 +361,7 @@ Future<void> _buildGradleProjectV1(FlutterProject project, String gradle) async ...@@ -359,6 +361,7 @@ Future<void> _buildGradleProjectV1(FlutterProject project, String gradle) async
environment: _gradleEnv, environment: _gradleEnv,
); );
status.stop(); status.stop();
flutterUsage.sendTiming('build', 'gradle-v1', Duration(milliseconds: sw.elapsedMilliseconds));
if (exitCode != 0) if (exitCode != 0)
throwToolExit('Gradle build failed: $exitCode', exitCode: exitCode); throwToolExit('Gradle build failed: $exitCode', exitCode: exitCode);
...@@ -366,6 +369,25 @@ Future<void> _buildGradleProjectV1(FlutterProject project, String gradle) async ...@@ -366,6 +369,25 @@ Future<void> _buildGradleProjectV1(FlutterProject project, String gradle) async
printStatus('Built ${fs.path.relative(project.android.gradleAppOutV1File.path)}.'); printStatus('Built ${fs.path.relative(project.android.gradleAppOutV1File.path)}.');
} }
String _hex(List<int> bytes) {
final StringBuffer result = StringBuffer();
for (int part in bytes)
result.write('${part < 16 ? '0' : ''}${part.toRadixString(16)}');
return result.toString();
}
String _calculateSha(File file) {
final Stopwatch sw = Stopwatch()..start();
final List<int> bytes = file.readAsBytesSync();
printTrace('calculateSha: reading file took ${sw.elapsedMilliseconds}us');
flutterUsage.sendTiming('build', 'apk-sha-read', Duration(milliseconds: sw.elapsedMilliseconds));
sw.reset();
final String sha = _hex(sha1.convert(bytes).bytes);
printTrace('calculateSha: computing sha took ${sw.elapsedMilliseconds}us');
flutterUsage.sendTiming('build', 'apk-sha-calc', Duration(milliseconds: sw.elapsedMilliseconds));
return sha;
}
Future<void> _buildGradleProjectV2( Future<void> _buildGradleProjectV2(
FlutterProject flutterProject, FlutterProject flutterProject,
String gradle, String gradle,
...@@ -439,7 +461,10 @@ Future<void> _buildGradleProjectV2( ...@@ -439,7 +461,10 @@ Future<void> _buildGradleProjectV2(
command.add(assembleTask); command.add(assembleTask);
bool potentialAndroidXFailure = false; bool potentialAndroidXFailure = false;
final int exitCode = await runCommandAndStreamOutput( final Stopwatch sw = Stopwatch()..start();
int exitCode = 1;
try {
exitCode = await runCommandAndStreamOutput(
command, command,
workingDirectory: flutterProject.android.hostAppGradleRoot.path, workingDirectory: flutterProject.android.hostAppGradleRoot.path,
allowReentrantFlutter: true, allowReentrantFlutter: true,
...@@ -462,7 +487,9 @@ Future<void> _buildGradleProjectV2( ...@@ -462,7 +487,9 @@ Future<void> _buildGradleProjectV2(
return line; return line;
}, },
); );
} finally {
status.stop(); status.stop();
}
if (exitCode != 0) { if (exitCode != 0) {
if (potentialAndroidXFailure) { if (potentialAndroidXFailure) {
...@@ -478,6 +505,7 @@ Future<void> _buildGradleProjectV2( ...@@ -478,6 +505,7 @@ Future<void> _buildGradleProjectV2(
} }
throwToolExit('Gradle task $assembleTask failed with exit code $exitCode', exitCode: exitCode); throwToolExit('Gradle task $assembleTask failed with exit code $exitCode', exitCode: exitCode);
} }
flutterUsage.sendTiming('build', 'gradle-v2', Duration(milliseconds: sw.elapsedMilliseconds));
if (!isBuildingBundle) { if (!isBuildingBundle) {
final File apkFile = _findApkFile(project, buildInfo); final File apkFile = _findApkFile(project, buildInfo);
...@@ -488,7 +516,7 @@ Future<void> _buildGradleProjectV2( ...@@ -488,7 +516,7 @@ Future<void> _buildGradleProjectV2(
printTrace('calculateSha: ${project.apkDirectory}/app.apk'); printTrace('calculateSha: ${project.apkDirectory}/app.apk');
final File apkShaFile = project.apkDirectory.childFile('app.apk.sha1'); final File apkShaFile = project.apkDirectory.childFile('app.apk.sha1');
apkShaFile.writeAsStringSync(calculateSha(apkFile)); apkShaFile.writeAsStringSync(_calculateSha(apkFile));
String appSize; String appSize;
if (buildInfo.mode == BuildMode.debug) { if (buildInfo.mode == BuildMode.debug) {
......
...@@ -15,6 +15,7 @@ import '../dart/package_map.dart'; ...@@ -15,6 +15,7 @@ import '../dart/package_map.dart';
import '../globals.dart'; import '../globals.dart';
import '../macos/xcode.dart'; import '../macos/xcode.dart';
import '../project.dart'; import '../project.dart';
import '../usage.dart';
import 'context.dart'; import 'context.dart';
import 'file_system.dart'; import 'file_system.dart';
import 'fingerprint.dart'; import 'fingerprint.dart';
...@@ -194,7 +195,9 @@ class AOTSnapshotter { ...@@ -194,7 +195,9 @@ class AOTSnapshotter {
// } // }
final SnapshotType snapshotType = SnapshotType(platform, buildMode); final SnapshotType snapshotType = SnapshotType(platform, buildMode);
final int genSnapshotExitCode = await _timedStep('snapshot(CompileTime)', () => genSnapshot.run( final int genSnapshotExitCode =
await _timedStep('snapshot(CompileTime)', 'aot-snapshot',
() => genSnapshot.run(
snapshotType: snapshotType, snapshotType: snapshotType,
additionalArgs: genSnapshotArgs, additionalArgs: genSnapshotArgs,
iosArch: iosArch, iosArch: iosArch,
...@@ -281,7 +284,9 @@ class AOTSnapshotter { ...@@ -281,7 +284,9 @@ class AOTSnapshotter {
final String depfilePath = fs.path.join(outputPath, 'kernel_compile.d'); final String depfilePath = fs.path.join(outputPath, 'kernel_compile.d');
final KernelCompiler kernelCompiler = await kernelCompilerFactory.create(flutterProject); final KernelCompiler kernelCompiler = await kernelCompilerFactory.create(flutterProject);
final CompilerOutput compilerOutput = await _timedStep('frontend(CompileTime)', () => kernelCompiler.compile( final CompilerOutput compilerOutput =
await _timedStep('frontend(CompileTime)', 'aot-kernel',
() => kernelCompiler.compile(
sdkRoot: artifacts.getArtifactPath(Artifact.flutterPatchedSdkPath, mode: buildMode), sdkRoot: artifacts.getArtifactPath(Artifact.flutterPatchedSdkPath, mode: buildMode),
mainPath: mainPath, mainPath: mainPath,
packagesPath: packagesPath, packagesPath: packagesPath,
...@@ -323,12 +328,13 @@ class AOTSnapshotter { ...@@ -323,12 +328,13 @@ class AOTSnapshotter {
/// to find. /// to find.
/// Important: external performance tracking tools expect format of this /// Important: external performance tracking tools expect format of this
/// output to be stable. /// output to be stable.
Future<T> _timedStep<T>(String marker, FutureOr<T> Function() action) async { Future<T> _timedStep<T>(String marker, String analyticsVar, FutureOr<T> Function() action) async {
final Stopwatch sw = Stopwatch()..start(); final Stopwatch sw = Stopwatch()..start();
final T value = await action(); final T value = await action();
if (reportTimings) { if (reportTimings) {
printStatus('$marker: ${sw.elapsedMilliseconds} ms.'); printStatus('$marker: ${sw.elapsedMilliseconds} ms.');
} }
flutterUsage.sendTiming('build', analyticsVar, Duration(milliseconds: sw.elapsedMilliseconds));
return value; return value;
} }
} }
......
...@@ -5,7 +5,6 @@ ...@@ -5,7 +5,6 @@
import 'dart:async'; import 'dart:async';
import 'dart:math' show Random, max; import 'dart:math' show Random, max;
import 'package:crypto/crypto.dart';
import 'package:intl/intl.dart'; import 'package:intl/intl.dart';
import '../convert.dart'; import '../convert.dart';
...@@ -53,24 +52,6 @@ bool get isRunningOnBot { ...@@ -53,24 +52,6 @@ bool get isRunningOnBot {
return botDetector.isRunningOnBot; return botDetector.isRunningOnBot;
} }
String hex(List<int> bytes) {
final StringBuffer result = StringBuffer();
for (int part in bytes)
result.write('${part < 16 ? '0' : ''}${part.toRadixString(16)}');
return result.toString();
}
String calculateSha(File file) {
final Stopwatch stopwatch = Stopwatch()..start();
final List<int> bytes = file.readAsBytesSync();
printTrace('calculateSha: reading file took ${stopwatch.elapsedMicroseconds}us');
stopwatch.reset();
final String sha = hex(sha1.convert(bytes).bytes);
stopwatch.stop();
printTrace('calculateSha: computing sha took ${stopwatch.elapsedMicroseconds}us');
return sha;
}
/// Convert `foo_bar` to `fooBar`. /// Convert `foo_bar` to `fooBar`.
String camelCase(String str) { String camelCase(String str) {
int index = str.indexOf('_'); int index = str.indexOf('_');
......
...@@ -2,6 +2,8 @@ ...@@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
import 'dart:async';
import 'package:meta/meta.dart'; import 'package:meta/meta.dart';
import '../asset.dart'; import '../asset.dart';
...@@ -12,11 +14,20 @@ import '../build_info.dart'; ...@@ -12,11 +14,20 @@ import '../build_info.dart';
import '../bundle.dart'; import '../bundle.dart';
import '../convert.dart'; import '../convert.dart';
import '../devfs.dart'; import '../devfs.dart';
import '../globals.dart';
import '../project.dart'; import '../project.dart';
import '../usage.dart';
import 'fuchsia_pm.dart'; import 'fuchsia_pm.dart';
import 'fuchsia_sdk.dart'; import 'fuchsia_sdk.dart';
Future<void> _timedBuildStep(String name, Future<void> Function() action) async {
final Stopwatch sw = Stopwatch()..start();
await action();
printTrace('$name: ${sw.elapsedMilliseconds} ms.');
flutterUsage.sendTiming('build', name, Duration(milliseconds: sw.elapsedMilliseconds));
}
// Building a Fuchsia package has a few steps: // Building a Fuchsia package has a few steps:
// 1. Do the custom kernel compile using the kernel compiler from the Fuchsia // 1. Do the custom kernel compile using the kernel compiler from the Fuchsia
// SDK. This produces .dilp files (among others) and a manifest file. // SDK. This produces .dilp files (among others) and a manifest file.
...@@ -32,10 +43,13 @@ Future<void> buildFuchsia( ...@@ -32,10 +43,13 @@ Future<void> buildFuchsia(
outDir.createSync(recursive: true); outDir.createSync(recursive: true);
} }
await fuchsiaSdk.fuchsiaKernelCompiler.build( await _timedBuildStep('fuchsia-kernel-compile',
fuchsiaProject: fuchsiaProject, target: target, buildInfo: buildInfo); () => fuchsiaSdk.fuchsiaKernelCompiler.build(
await _buildAssets(fuchsiaProject, target, buildInfo); fuchsiaProject: fuchsiaProject, target: target, buildInfo: buildInfo));
await _buildPackage(fuchsiaProject, target, buildInfo); await _timedBuildStep('fuchsia-build-assets',
() => _buildAssets(fuchsiaProject, target, buildInfo));
await _timedBuildStep('fuchsia-build-package',
() => _buildPackage(fuchsiaProject, target, buildInfo));
} }
Future<void> _buildAssets( Future<void> _buildAssets(
......
...@@ -24,6 +24,7 @@ import '../macos/cocoapod_utils.dart'; ...@@ -24,6 +24,7 @@ import '../macos/cocoapod_utils.dart';
import '../macos/xcode.dart'; import '../macos/xcode.dart';
import '../project.dart'; import '../project.dart';
import '../services.dart'; import '../services.dart';
import '../usage.dart';
import 'code_signing.dart'; import 'code_signing.dart';
import 'xcodeproj.dart'; import 'xcodeproj.dart';
...@@ -374,7 +375,7 @@ Future<XcodeBuildResult> buildXcodeProject({ ...@@ -374,7 +375,7 @@ Future<XcodeBuildResult> buildXcodeProject({
buildCommands.add('SCRIPT_OUTPUT_STREAM_FILE=${scriptOutputPipeFile.absolute.path}'); buildCommands.add('SCRIPT_OUTPUT_STREAM_FILE=${scriptOutputPipeFile.absolute.path}');
} }
final Stopwatch buildStopwatch = Stopwatch()..start(); final Stopwatch sw = Stopwatch()..start();
initialBuildStatus = logger.startProgress('Running Xcode build...', timeout: timeoutConfiguration.fastOperation); initialBuildStatus = logger.startProgress('Running Xcode build...', timeout: timeoutConfiguration.fastOperation);
final RunResult buildResult = await runAsync( final RunResult buildResult = await runAsync(
buildCommands, buildCommands,
...@@ -387,11 +388,11 @@ Future<XcodeBuildResult> buildXcodeProject({ ...@@ -387,11 +388,11 @@ Future<XcodeBuildResult> buildXcodeProject({
buildSubStatus = null; buildSubStatus = null;
initialBuildStatus?.cancel(); initialBuildStatus?.cancel();
initialBuildStatus = null; initialBuildStatus = null;
buildStopwatch.stop();
printStatus( printStatus(
'Xcode build done.'.padRight(kDefaultStatusPadding + 1) 'Xcode build done.'.padRight(kDefaultStatusPadding + 1)
+ '${getElapsedAsSeconds(buildStopwatch.elapsed).padLeft(5)}', + '${getElapsedAsSeconds(sw.elapsed).padLeft(5)}',
); );
flutterUsage.sendTiming('build', 'xcode-ios', Duration(milliseconds: sw.elapsedMilliseconds));
// Run -showBuildSettings again but with the exact same parameters as the build. // Run -showBuildSettings again but with the exact same parameters as the build.
final Map<String, String> buildSettings = parseXcodeBuildSettings(runCheckedSync( final Map<String, String> buildSettings = parseXcodeBuildSettings(runCheckedSync(
......
...@@ -13,6 +13,7 @@ import '../cache.dart'; ...@@ -13,6 +13,7 @@ import '../cache.dart';
import '../convert.dart'; import '../convert.dart';
import '../globals.dart'; import '../globals.dart';
import '../project.dart'; import '../project.dart';
import '../usage.dart';
/// Builds the Linux project through the Makefile. /// Builds the Linux project through the Makefile.
Future<void> buildLinux(LinuxProject linuxProject, BuildInfo buildInfo, {String target = 'lib/main.dart'}) async { Future<void> buildLinux(LinuxProject linuxProject, BuildInfo buildInfo, {String target = 'lib/main.dart'}) async {
...@@ -37,6 +38,8 @@ export PROJECT_DIR=${linuxProject.project.directory.path} ...@@ -37,6 +38,8 @@ export PROJECT_DIR=${linuxProject.project.directory.path}
..createSync(recursive: true) ..createSync(recursive: true)
..writeAsStringSync(buffer.toString()); ..writeAsStringSync(buffer.toString());
// Invoke make.
final Stopwatch sw = Stopwatch()..start();
final Process process = await processManager.start(<String>[ final Process process = await processManager.start(<String>[
'make', 'make',
'-C', '-C',
...@@ -63,4 +66,5 @@ export PROJECT_DIR=${linuxProject.project.directory.path} ...@@ -63,4 +66,5 @@ export PROJECT_DIR=${linuxProject.project.directory.path}
if (result != 0) { if (result != 0) {
throwToolExit('Build process failed'); throwToolExit('Build process failed');
} }
flutterUsage.sendTiming('build', 'make-linux', Duration(milliseconds: sw.elapsedMilliseconds));
} }
...@@ -12,6 +12,7 @@ import '../convert.dart'; ...@@ -12,6 +12,7 @@ import '../convert.dart';
import '../globals.dart'; import '../globals.dart';
import '../ios/xcodeproj.dart'; import '../ios/xcodeproj.dart';
import '../project.dart'; import '../project.dart';
import '../usage.dart';
import 'cocoapod_utils.dart'; import 'cocoapod_utils.dart';
/// Builds the macOS project through xcode build. /// Builds the macOS project through xcode build.
...@@ -37,6 +38,7 @@ Future<void> buildMacOS(FlutterProject flutterProject, BuildInfo buildInfo) asyn ...@@ -37,6 +38,7 @@ Future<void> buildMacOS(FlutterProject flutterProject, BuildInfo buildInfo) asyn
config = 'Release'; config = 'Release';
} }
// Run build script provided by application. // Run build script provided by application.
final Stopwatch sw = Stopwatch()..start();
final Process process = await processManager.start(<String>[ final Process process = await processManager.start(<String>[
'/usr/bin/env', '/usr/bin/env',
'xcrun', 'xcrun',
...@@ -69,4 +71,5 @@ Future<void> buildMacOS(FlutterProject flutterProject, BuildInfo buildInfo) asyn ...@@ -69,4 +71,5 @@ Future<void> buildMacOS(FlutterProject flutterProject, BuildInfo buildInfo) asyn
if (result != 0) { if (result != 0) {
throwToolExit('Build process failed'); throwToolExit('Build process failed');
} }
flutterUsage.sendTiming('build', 'xcode-macos', Duration(milliseconds: sw.elapsedMilliseconds));
} }
...@@ -13,12 +13,14 @@ import '../build_info.dart'; ...@@ -13,12 +13,14 @@ import '../build_info.dart';
import '../bundle.dart'; import '../bundle.dart';
import '../globals.dart'; import '../globals.dart';
import '../project.dart'; import '../project.dart';
import '../usage.dart';
/// The [WebCompilationProxy] instance. /// The [WebCompilationProxy] instance.
WebCompilationProxy get webCompilationProxy => context.get<WebCompilationProxy>(); WebCompilationProxy get webCompilationProxy => context.get<WebCompilationProxy>();
Future<void> buildWeb(FlutterProject flutterProject, String target, BuildInfo buildInfo) async { Future<void> buildWeb(FlutterProject flutterProject, String target, BuildInfo buildInfo) async {
final Status status = logger.startProgress('Compiling $target for the Web...', timeout: null); final Status status = logger.startProgress('Compiling $target for the Web...', timeout: null);
final Stopwatch sw = Stopwatch()..start();
final Directory outputDir = fs.directory(getWebBuildDirectory()) final Directory outputDir = fs.directory(getWebBuildDirectory())
..createSync(recursive: true); ..createSync(recursive: true);
bool result; bool result;
...@@ -55,6 +57,11 @@ Future<void> buildWeb(FlutterProject flutterProject, String target, BuildInfo bu ...@@ -55,6 +57,11 @@ Future<void> buildWeb(FlutterProject flutterProject, String target, BuildInfo bu
if (result == false) { if (result == false) {
throwToolExit('Failed to compile $target for the Web.'); throwToolExit('Failed to compile $target for the Web.');
} }
String buildName = 'ddc';
if (buildInfo.isRelease) {
buildName = 'dart2js';
}
flutterUsage.sendTiming('build', buildName, Duration(milliseconds: sw.elapsedMilliseconds));
} }
/// An indirection on web compilation. /// An indirection on web compilation.
......
...@@ -13,6 +13,7 @@ import '../cache.dart'; ...@@ -13,6 +13,7 @@ import '../cache.dart';
import '../convert.dart'; import '../convert.dart';
import '../globals.dart'; import '../globals.dart';
import '../project.dart'; import '../project.dart';
import '../usage.dart';
import 'msbuild_utils.dart'; import 'msbuild_utils.dart';
import 'visual_studio.dart'; import 'visual_studio.dart';
...@@ -48,6 +49,7 @@ Future<void> buildWindows(WindowsProject windowsProject, BuildInfo buildInfo, {S ...@@ -48,6 +49,7 @@ Future<void> buildWindows(WindowsProject windowsProject, BuildInfo buildInfo, {S
final String configuration = buildInfo.isDebug ? 'Debug' : 'Release'; final String configuration = buildInfo.isDebug ? 'Debug' : 'Release';
final String solutionPath = windowsProject.solutionFile.path; final String solutionPath = windowsProject.solutionFile.path;
final Stopwatch sw = Stopwatch()..start();
// Run the script with a relative path to the project using the enclosing // Run the script with a relative path to the project using the enclosing
// directory as the workingDirectory, to avoid hitting the limit on command // directory as the workingDirectory, to avoid hitting the limit on command
// lengths in batch scripts if the absolute path to the project is long. // lengths in batch scripts if the absolute path to the project is long.
...@@ -78,4 +80,5 @@ Future<void> buildWindows(WindowsProject windowsProject, BuildInfo buildInfo, {S ...@@ -78,4 +80,5 @@ Future<void> buildWindows(WindowsProject windowsProject, BuildInfo buildInfo, {S
if (result != 0) { if (result != 0) {
throwToolExit('Build process failed'); throwToolExit('Build process failed');
} }
flutterUsage.sendTiming('build', 'vs_build', Duration(milliseconds: sw.elapsedMilliseconds));
} }
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