Unverified Commit 52bd2ccb authored by Alexander Aprelev's avatar Alexander Aprelev Committed by GitHub

Report devfs stats (#25586)

* Collect devfs stats for better analytics

* Fix fields initialization

* Fix lints
parent 50f9b883
......@@ -350,6 +350,32 @@ class _DevFSHttpWriter {
}
}
// Basic statistics for DevFS update operation.
class UpdateFSReport {
UpdateFSReport({bool success = false,
int invalidatedSourcesCount = 0, int syncedBytes = 0}) {
_success = success;
_invalidatedSourcesCount = invalidatedSourcesCount;
_syncedBytes = syncedBytes;
}
bool get success => _success;
int get invalidatedSourcesCount => _invalidatedSourcesCount;
int get syncedBytes => _syncedBytes;
void incorporateResults(UpdateFSReport report) {
if (!report._success) {
_success = false;
}
_invalidatedSourcesCount += report._invalidatedSourcesCount;
_syncedBytes += report._syncedBytes;
}
bool _success;
int _invalidatedSourcesCount;
int _syncedBytes;
}
class DevFS {
/// Create a [DevFS] named [fsName] for the local files in [rootDirectory].
DevFS(VMService serviceProtocol,
......@@ -422,7 +448,7 @@ class DevFS {
/// Updates files on the device.
///
/// Returns the number of bytes synced.
Future<int> update({
Future<UpdateFSReport> update({
@required String mainPath,
String target,
AssetBundle bundle,
......@@ -487,7 +513,7 @@ class DevFS {
}
// Update modified files
int numBytes = 0;
int syncedBytes = 0;
final Map<Uri, DevFSContent> dirtyEntries = <Uri, DevFSContent>{};
_entries.forEach((Uri deviceUri, DevFSContent content) {
String archivePath;
......@@ -498,7 +524,7 @@ class DevFS {
// files to incremental compiler next time user does hot reload.
if (content.isModified || ((bundleDirty || bundleFirstUpload) && archivePath != null)) {
dirtyEntries[deviceUri] = content;
numBytes += content.size;
syncedBytes += content.size;
if (archivePath != null && (!bundleFirstUpload || content.isModifiedAfter(firstBuildTime)))
assetPathsToEvict.add(archivePath);
}
......@@ -516,7 +542,7 @@ class DevFS {
if (content is DevFSFileContent) {
filesUris.add(uri);
invalidatedFiles.add(content.file.uri.toString());
numBytes -= content.size;
syncedBytes -= content.size;
}
}
}
......@@ -545,7 +571,7 @@ class DevFS {
if (!dirtyEntries.containsKey(entryUri)) {
final DevFSFileContent content = DevFSFileContent(fs.file(compiledBinary));
dirtyEntries[entryUri] = content;
numBytes += content.size;
syncedBytes += content.size;
}
}
}
......@@ -576,7 +602,8 @@ class DevFS {
}
printTrace('DevFS: Sync finished');
return numBytes;
return UpdateFSReport(success: true, syncedBytes: syncedBytes,
invalidatedSourcesCount: invalidatedFiles.length);
}
void _scanFile(Uri deviceUri, FileSystemEntity file) {
......
......@@ -368,7 +368,7 @@ class FlutterDevice {
return 0;
}
Future<bool> updateDevFS({
Future<UpdateFSReport> updateDevFS({
String mainPath,
String target,
AssetBundle bundle,
......@@ -384,9 +384,9 @@ class FlutterDevice {
'Syncing files to device ${device.name}...',
expectSlowOperation: true,
);
int bytes = 0;
UpdateFSReport report;
try {
bytes = await devFS.update(
report = await devFS.update(
mainPath: mainPath,
target: target,
bundle: bundle,
......@@ -403,11 +403,11 @@ class FlutterDevice {
);
} on DevFSException {
devFSStatus.cancel();
return false;
return UpdateFSReport(success: false);
}
devFSStatus.stop();
printTrace('Synced ${getSizeAsMB(bytes)}.');
return true;
printTrace('Synced ${getSizeAsMB(report.syncedBytes)}.');
return report;
}
void updateReloadStatus(bool wasReloadSuccessful) {
......
......@@ -19,6 +19,7 @@ import 'build_info.dart';
import 'compile.dart';
import 'dart/dependencies.dart';
import 'dart/pub.dart';
import 'devfs.dart';
import 'device.dart';
import 'globals.dart';
import 'resident_runner.dart';
......@@ -193,12 +194,12 @@ class HotRunner extends ResidentRunner {
return 3;
}
final Stopwatch initialUpdateDevFSsTimer = Stopwatch()..start();
final bool devfsResult = await _updateDevFS(fullRestart: true);
final UpdateFSReport devfsResult = await _updateDevFS(fullRestart: true);
_addBenchmarkData(
'hotReloadInitialDevFSSyncMilliseconds',
initialUpdateDevFSsTimer.elapsed.inMilliseconds,
);
if (!devfsResult)
if (!devfsResult.success)
return 3;
await refreshViews();
......@@ -329,10 +330,10 @@ class HotRunner extends ResidentRunner {
return devFSUris;
}
Future<bool> _updateDevFS({ bool fullRestart = false }) async {
Future<UpdateFSReport> _updateDevFS({ bool fullRestart = false }) async {
if (!await _refreshDartDependencies()) {
// Did not update DevFS because of a Dart source error.
return false;
return UpdateFSReport(success: false);
}
final bool isFirstUpload = assetBundle.wasBuiltOnce() == false;
final bool rebuildBundle = assetBundle.needsBuild();
......@@ -340,12 +341,12 @@ class HotRunner extends ResidentRunner {
printTrace('Updating assets');
final int result = await assetBundle.build();
if (result != 0)
return false;
return UpdateFSReport(success: false);
}
final List<bool> results = <bool>[];
final UpdateFSReport results = UpdateFSReport(success: true);
for (FlutterDevice device in flutterDevices) {
results.add(await device.updateDevFS(
results.incorporateResults(await device.updateDevFS(
mainPath: mainPath,
target: target,
bundle: assetBundle,
......@@ -358,16 +359,15 @@ class HotRunner extends ResidentRunner {
pathToReload: getReloadPath(fullRestart: fullRestart),
));
}
// If there any failures reported, bail out.
if (results.any((bool result) => !result)) {
return false;
if (!results.success) {
return results;
}
if (!hotRunnerConfig.stableDartDependencies) {
// Clear the set after the sync so they are recomputed next time.
_dartDependencies = null;
}
return true;
return results;
}
Future<void> _evictDirtyAssets() {
......@@ -460,8 +460,8 @@ class HotRunner extends ResidentRunner {
final Stopwatch restartTimer = Stopwatch()..start();
// TODO(aam): Add generator reset logic once we switch to using incremental
// compiler for full application recompilation on restart.
final bool updatedDevFS = await _updateDevFS(fullRestart: true);
if (!updatedDevFS) {
final UpdateFSReport updatedDevFS = await _updateDevFS(fullRestart: true);
if (!updatedDevFS.success) {
for (FlutterDevice device in flutterDevices) {
if (device.generator != null)
device.generator.reject();
......@@ -618,11 +618,11 @@ class HotRunner extends ResidentRunner {
final Stopwatch reloadTimer = Stopwatch()..start();
final Stopwatch devFSTimer = Stopwatch()..start();
final bool updatedDevFS = await _updateDevFS();
final UpdateFSReport updatedDevFS = await _updateDevFS();
// Record time it took to synchronize to DevFS.
_addBenchmarkData('hotReloadDevFSSyncMilliseconds',
devFSTimer.elapsed.inMilliseconds);
if (!updatedDevFS)
if (!updatedDevFS.success)
return OperationResult(1, 'DevFS synchronization failed');
String reloadMessage;
final Stopwatch vmReloadTimer = Stopwatch()..start();
......
This diff is collapsed.
......@@ -112,7 +112,8 @@ void main() {
trackWidgetCreation: anyNamed('trackWidgetCreation'),
projectRootPath: anyNamed('projectRootPath'),
pathToReload: anyNamed('pathToReload'),
)).thenAnswer((Invocation _) => Future<int>.value(1000));
)).thenAnswer((Invocation _) => Future<UpdateFSReport>.value(
UpdateFSReport(success: true, syncedBytes: 1000, invalidatedSourcesCount: 1)));
when(mockDevFs.assetPathsToEvict).thenReturn(Set<String>());
when(mockDevFs.baseUri).thenReturn(Uri.file('test'));
......
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