mirror of
https://github.com/flutter/flutter.git
synced 2025-06-03 00:51:18 +00:00
[flutter_tool] Send build timing to analytics (#34049)
This commit is contained in:
parent
bd413bff1b
commit
b847ba5a63
@ -4,6 +4,7 @@
|
||||
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:crypto/crypto.dart';
|
||||
import 'package:meta/meta.dart';
|
||||
|
||||
import '../android/android_sdk.dart';
|
||||
@ -352,6 +353,7 @@ Future<void> _buildGradleProjectV1(FlutterProject project, String gradle) async
|
||||
timeout: timeoutConfiguration.slowOperation,
|
||||
multilineOutput: true,
|
||||
);
|
||||
final Stopwatch sw = Stopwatch()..start();
|
||||
final int exitCode = await runCommandAndStreamOutput(
|
||||
<String>[fs.file(gradle).absolute.path, 'build'],
|
||||
workingDirectory: project.android.hostAppGradleRoot.path,
|
||||
@ -359,6 +361,7 @@ Future<void> _buildGradleProjectV1(FlutterProject project, String gradle) async
|
||||
environment: _gradleEnv,
|
||||
);
|
||||
status.stop();
|
||||
flutterUsage.sendTiming('build', 'gradle-v1', Duration(milliseconds: sw.elapsedMilliseconds));
|
||||
|
||||
if (exitCode != 0)
|
||||
throwToolExit('Gradle build failed: $exitCode', exitCode: exitCode);
|
||||
@ -366,6 +369,25 @@ Future<void> _buildGradleProjectV1(FlutterProject project, String gradle) async
|
||||
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(
|
||||
FlutterProject flutterProject,
|
||||
String gradle,
|
||||
@ -439,30 +461,35 @@ Future<void> _buildGradleProjectV2(
|
||||
|
||||
command.add(assembleTask);
|
||||
bool potentialAndroidXFailure = false;
|
||||
final int exitCode = await runCommandAndStreamOutput(
|
||||
command,
|
||||
workingDirectory: flutterProject.android.hostAppGradleRoot.path,
|
||||
allowReentrantFlutter: true,
|
||||
environment: _gradleEnv,
|
||||
// TODO(mklim): if AndroidX warnings are no longer required, this
|
||||
// mapFunction and all its associated variabled can be replaced with just
|
||||
// `filter: ndkMessagefilter`.
|
||||
mapFunction: (String line) {
|
||||
final bool isAndroidXPluginWarning = androidXPluginWarningRegex.hasMatch(line);
|
||||
if (!isAndroidXPluginWarning && androidXFailureRegex.hasMatch(line)) {
|
||||
potentialAndroidXFailure = true;
|
||||
}
|
||||
// Always print the full line in verbose mode.
|
||||
if (logger.isVerbose) {
|
||||
return line;
|
||||
} else if (isAndroidXPluginWarning || !ndkMessageFilter.hasMatch(line)) {
|
||||
return null;
|
||||
}
|
||||
final Stopwatch sw = Stopwatch()..start();
|
||||
int exitCode = 1;
|
||||
try {
|
||||
exitCode = await runCommandAndStreamOutput(
|
||||
command,
|
||||
workingDirectory: flutterProject.android.hostAppGradleRoot.path,
|
||||
allowReentrantFlutter: true,
|
||||
environment: _gradleEnv,
|
||||
// TODO(mklim): if AndroidX warnings are no longer required, this
|
||||
// mapFunction and all its associated variabled can be replaced with just
|
||||
// `filter: ndkMessagefilter`.
|
||||
mapFunction: (String line) {
|
||||
final bool isAndroidXPluginWarning = androidXPluginWarningRegex.hasMatch(line);
|
||||
if (!isAndroidXPluginWarning && androidXFailureRegex.hasMatch(line)) {
|
||||
potentialAndroidXFailure = true;
|
||||
}
|
||||
// Always print the full line in verbose mode.
|
||||
if (logger.isVerbose) {
|
||||
return line;
|
||||
} else if (isAndroidXPluginWarning || !ndkMessageFilter.hasMatch(line)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return line;
|
||||
},
|
||||
);
|
||||
status.stop();
|
||||
return line;
|
||||
},
|
||||
);
|
||||
} finally {
|
||||
status.stop();
|
||||
}
|
||||
|
||||
if (exitCode != 0) {
|
||||
if (potentialAndroidXFailure) {
|
||||
@ -478,6 +505,7 @@ Future<void> _buildGradleProjectV2(
|
||||
}
|
||||
throwToolExit('Gradle task $assembleTask failed with exit code $exitCode', exitCode: exitCode);
|
||||
}
|
||||
flutterUsage.sendTiming('build', 'gradle-v2', Duration(milliseconds: sw.elapsedMilliseconds));
|
||||
|
||||
if (!isBuildingBundle) {
|
||||
final File apkFile = _findApkFile(project, buildInfo);
|
||||
@ -488,7 +516,7 @@ Future<void> _buildGradleProjectV2(
|
||||
|
||||
printTrace('calculateSha: ${project.apkDirectory}/app.apk');
|
||||
final File apkShaFile = project.apkDirectory.childFile('app.apk.sha1');
|
||||
apkShaFile.writeAsStringSync(calculateSha(apkFile));
|
||||
apkShaFile.writeAsStringSync(_calculateSha(apkFile));
|
||||
|
||||
String appSize;
|
||||
if (buildInfo.mode == BuildMode.debug) {
|
||||
|
@ -15,6 +15,7 @@ import '../dart/package_map.dart';
|
||||
import '../globals.dart';
|
||||
import '../macos/xcode.dart';
|
||||
import '../project.dart';
|
||||
import '../usage.dart';
|
||||
import 'context.dart';
|
||||
import 'file_system.dart';
|
||||
import 'fingerprint.dart';
|
||||
@ -194,7 +195,9 @@ class AOTSnapshotter {
|
||||
// }
|
||||
|
||||
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,
|
||||
additionalArgs: genSnapshotArgs,
|
||||
iosArch: iosArch,
|
||||
@ -281,7 +284,9 @@ class AOTSnapshotter {
|
||||
|
||||
final String depfilePath = fs.path.join(outputPath, 'kernel_compile.d');
|
||||
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),
|
||||
mainPath: mainPath,
|
||||
packagesPath: packagesPath,
|
||||
@ -323,12 +328,13 @@ class AOTSnapshotter {
|
||||
/// to find.
|
||||
/// Important: external performance tracking tools expect format of this
|
||||
/// 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 T value = await action();
|
||||
if (reportTimings) {
|
||||
printStatus('$marker: ${sw.elapsedMilliseconds} ms.');
|
||||
}
|
||||
flutterUsage.sendTiming('build', analyticsVar, Duration(milliseconds: sw.elapsedMilliseconds));
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
@ -5,7 +5,6 @@
|
||||
import 'dart:async';
|
||||
import 'dart:math' show Random, max;
|
||||
|
||||
import 'package:crypto/crypto.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
|
||||
import '../convert.dart';
|
||||
@ -53,24 +52,6 @@ bool get 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`.
|
||||
String camelCase(String str) {
|
||||
int index = str.indexOf('_');
|
||||
|
@ -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 'dart:async';
|
||||
|
||||
import 'package:meta/meta.dart';
|
||||
|
||||
import '../asset.dart';
|
||||
@ -12,11 +14,20 @@ import '../build_info.dart';
|
||||
import '../bundle.dart';
|
||||
import '../convert.dart';
|
||||
import '../devfs.dart';
|
||||
import '../globals.dart';
|
||||
import '../project.dart';
|
||||
import '../usage.dart';
|
||||
|
||||
import 'fuchsia_pm.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:
|
||||
// 1. Do the custom kernel compile using the kernel compiler from the Fuchsia
|
||||
// SDK. This produces .dilp files (among others) and a manifest file.
|
||||
@ -32,10 +43,13 @@ Future<void> buildFuchsia(
|
||||
outDir.createSync(recursive: true);
|
||||
}
|
||||
|
||||
await fuchsiaSdk.fuchsiaKernelCompiler.build(
|
||||
fuchsiaProject: fuchsiaProject, target: target, buildInfo: buildInfo);
|
||||
await _buildAssets(fuchsiaProject, target, buildInfo);
|
||||
await _buildPackage(fuchsiaProject, target, buildInfo);
|
||||
await _timedBuildStep('fuchsia-kernel-compile',
|
||||
() => fuchsiaSdk.fuchsiaKernelCompiler.build(
|
||||
fuchsiaProject: fuchsiaProject, target: target, buildInfo: buildInfo));
|
||||
await _timedBuildStep('fuchsia-build-assets',
|
||||
() => _buildAssets(fuchsiaProject, target, buildInfo));
|
||||
await _timedBuildStep('fuchsia-build-package',
|
||||
() => _buildPackage(fuchsiaProject, target, buildInfo));
|
||||
}
|
||||
|
||||
Future<void> _buildAssets(
|
||||
|
@ -24,6 +24,7 @@ import '../macos/cocoapod_utils.dart';
|
||||
import '../macos/xcode.dart';
|
||||
import '../project.dart';
|
||||
import '../services.dart';
|
||||
import '../usage.dart';
|
||||
import 'code_signing.dart';
|
||||
import 'xcodeproj.dart';
|
||||
|
||||
@ -374,7 +375,7 @@ Future<XcodeBuildResult> buildXcodeProject({
|
||||
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);
|
||||
final RunResult buildResult = await runAsync(
|
||||
buildCommands,
|
||||
@ -387,11 +388,11 @@ Future<XcodeBuildResult> buildXcodeProject({
|
||||
buildSubStatus = null;
|
||||
initialBuildStatus?.cancel();
|
||||
initialBuildStatus = null;
|
||||
buildStopwatch.stop();
|
||||
printStatus(
|
||||
'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.
|
||||
final Map<String, String> buildSettings = parseXcodeBuildSettings(runCheckedSync(
|
||||
|
@ -13,6 +13,7 @@ import '../cache.dart';
|
||||
import '../convert.dart';
|
||||
import '../globals.dart';
|
||||
import '../project.dart';
|
||||
import '../usage.dart';
|
||||
|
||||
/// Builds the Linux project through the Makefile.
|
||||
Future<void> buildLinux(LinuxProject linuxProject, BuildInfo buildInfo, {String target = 'lib/main.dart'}) async {
|
||||
@ -37,6 +38,8 @@ export PROJECT_DIR=${linuxProject.project.directory.path}
|
||||
..createSync(recursive: true)
|
||||
..writeAsStringSync(buffer.toString());
|
||||
|
||||
// Invoke make.
|
||||
final Stopwatch sw = Stopwatch()..start();
|
||||
final Process process = await processManager.start(<String>[
|
||||
'make',
|
||||
'-C',
|
||||
@ -63,4 +66,5 @@ export PROJECT_DIR=${linuxProject.project.directory.path}
|
||||
if (result != 0) {
|
||||
throwToolExit('Build process failed');
|
||||
}
|
||||
flutterUsage.sendTiming('build', 'make-linux', Duration(milliseconds: sw.elapsedMilliseconds));
|
||||
}
|
||||
|
@ -12,6 +12,7 @@ import '../convert.dart';
|
||||
import '../globals.dart';
|
||||
import '../ios/xcodeproj.dart';
|
||||
import '../project.dart';
|
||||
import '../usage.dart';
|
||||
import 'cocoapod_utils.dart';
|
||||
|
||||
/// Builds the macOS project through xcode build.
|
||||
@ -37,6 +38,7 @@ Future<void> buildMacOS(FlutterProject flutterProject, BuildInfo buildInfo) asyn
|
||||
config = 'Release';
|
||||
}
|
||||
// Run build script provided by application.
|
||||
final Stopwatch sw = Stopwatch()..start();
|
||||
final Process process = await processManager.start(<String>[
|
||||
'/usr/bin/env',
|
||||
'xcrun',
|
||||
@ -69,4 +71,5 @@ Future<void> buildMacOS(FlutterProject flutterProject, BuildInfo buildInfo) asyn
|
||||
if (result != 0) {
|
||||
throwToolExit('Build process failed');
|
||||
}
|
||||
flutterUsage.sendTiming('build', 'xcode-macos', Duration(milliseconds: sw.elapsedMilliseconds));
|
||||
}
|
||||
|
@ -13,12 +13,14 @@ import '../build_info.dart';
|
||||
import '../bundle.dart';
|
||||
import '../globals.dart';
|
||||
import '../project.dart';
|
||||
import '../usage.dart';
|
||||
|
||||
/// The [WebCompilationProxy] instance.
|
||||
WebCompilationProxy get webCompilationProxy => context.get<WebCompilationProxy>();
|
||||
|
||||
Future<void> buildWeb(FlutterProject flutterProject, String target, BuildInfo buildInfo) async {
|
||||
final Status status = logger.startProgress('Compiling $target for the Web...', timeout: null);
|
||||
final Stopwatch sw = Stopwatch()..start();
|
||||
final Directory outputDir = fs.directory(getWebBuildDirectory())
|
||||
..createSync(recursive: true);
|
||||
bool result;
|
||||
@ -55,6 +57,11 @@ Future<void> buildWeb(FlutterProject flutterProject, String target, BuildInfo bu
|
||||
if (result == false) {
|
||||
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.
|
||||
|
@ -13,6 +13,7 @@ import '../cache.dart';
|
||||
import '../convert.dart';
|
||||
import '../globals.dart';
|
||||
import '../project.dart';
|
||||
import '../usage.dart';
|
||||
import 'msbuild_utils.dart';
|
||||
import 'visual_studio.dart';
|
||||
|
||||
@ -48,6 +49,7 @@ Future<void> buildWindows(WindowsProject windowsProject, BuildInfo buildInfo, {S
|
||||
|
||||
final String configuration = buildInfo.isDebug ? 'Debug' : 'Release';
|
||||
final String solutionPath = windowsProject.solutionFile.path;
|
||||
final Stopwatch sw = Stopwatch()..start();
|
||||
// Run the script with a relative path to the project using the enclosing
|
||||
// directory as the workingDirectory, to avoid hitting the limit on command
|
||||
// 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
|
||||
if (result != 0) {
|
||||
throwToolExit('Build process failed');
|
||||
}
|
||||
flutterUsage.sendTiming('build', 'vs_build', Duration(milliseconds: sw.elapsedMilliseconds));
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user