Restructure hot mode test so it runs interactively. (#12519)
* Restructure hot mode test so it runs interactively. This allows to add a benchmark for hot reload after actual source code change. * Add curly braces, refactory copyRecursive
This commit is contained in:
parent
0999fca99d
commit
be1467e0cd
@ -98,6 +98,21 @@ void copy(File sourceFile, Directory targetDirectory, {String name}) {
|
|||||||
target.writeAsBytesSync(sourceFile.readAsBytesSync());
|
target.writeAsBytesSync(sourceFile.readAsBytesSync());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void recursiveCopy(Directory source, Directory target) {
|
||||||
|
if (!target.existsSync())
|
||||||
|
target.createSync();
|
||||||
|
|
||||||
|
for (FileSystemEntity entity in source.listSync(followLinks: false)) {
|
||||||
|
final String name = path.basename(entity.path);
|
||||||
|
if (entity is Directory)
|
||||||
|
recursiveCopy(entity, new Directory(path.join(target.path, name)));
|
||||||
|
else if (entity is File) {
|
||||||
|
final File dest = new File(path.join(target.path, name));
|
||||||
|
dest.writeAsBytesSync(entity.readAsBytesSync());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
FileSystemEntity move(FileSystemEntity whatToMove,
|
FileSystemEntity move(FileSystemEntity whatToMove,
|
||||||
{Directory to, String name}) {
|
{Directory to, String name}) {
|
||||||
return whatToMove
|
return whatToMove
|
||||||
|
@ -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 'dart:convert';
|
||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
|
|
||||||
import 'package:path/path.dart' as path;
|
import 'package:path/path.dart' as path;
|
||||||
@ -10,30 +12,81 @@ import '../framework/adb.dart';
|
|||||||
import '../framework/framework.dart';
|
import '../framework/framework.dart';
|
||||||
import '../framework/utils.dart';
|
import '../framework/utils.dart';
|
||||||
|
|
||||||
|
final Directory _editedFlutterGalleryDir = dir(path.join(Directory.systemTemp.path, 'edited_flutter_gallery'));
|
||||||
|
final Directory flutterGalleryDir = dir(path.join(flutterDirectory.path, 'examples/flutter_gallery'));
|
||||||
|
|
||||||
TaskFunction createHotModeTest({ bool isPreviewDart2: false }) {
|
TaskFunction createHotModeTest({ bool isPreviewDart2: false }) {
|
||||||
return () async {
|
return () async {
|
||||||
final Device device = await devices.workingDevice;
|
final Device device = await devices.workingDevice;
|
||||||
await device.unlock();
|
await device.unlock();
|
||||||
final Directory appDir =
|
final File benchmarkFile = file(path.join(_editedFlutterGalleryDir.path, 'hot_benchmark.json'));
|
||||||
dir(path.join(flutterDirectory.path, 'examples/flutter_gallery'));
|
|
||||||
final File benchmarkFile = file(path.join(appDir.path, 'hot_benchmark.json'));
|
|
||||||
rm(benchmarkFile);
|
rm(benchmarkFile);
|
||||||
final List<String> options = <String>[
|
final List<String> options = <String>[
|
||||||
'--hot', '-d', device.deviceId, '--benchmark', '--verbose'
|
'--hot', '-d', device.deviceId, '--benchmark', '--verbose', '--resident'
|
||||||
];
|
];
|
||||||
if (isPreviewDart2)
|
if (isPreviewDart2)
|
||||||
options.add('--preview-dart-2');
|
options.add('--preview-dart-2');
|
||||||
await inDirectory(appDir, () async {
|
int hotReloadCount = 0;
|
||||||
return await flutter('run', options: options, canFail: false);
|
await inDirectory(flutterDirectory, () async {
|
||||||
|
rmTree(_editedFlutterGalleryDir);
|
||||||
|
mkdirs(_editedFlutterGalleryDir);
|
||||||
|
recursiveCopy(flutterGalleryDir, _editedFlutterGalleryDir);
|
||||||
|
await inDirectory(_editedFlutterGalleryDir, () async {
|
||||||
|
final Process process = await startProcess(
|
||||||
|
path.join(flutterDirectory.path, 'bin', 'flutter'),
|
||||||
|
<String>['run']..addAll(options),
|
||||||
|
environment: null
|
||||||
|
);
|
||||||
|
|
||||||
|
final Completer<Null> stdoutDone = new Completer<Null>();
|
||||||
|
final Completer<Null> stderrDone = new Completer<Null>();
|
||||||
|
process.stdout
|
||||||
|
.transform(UTF8.decoder)
|
||||||
|
.transform(const LineSplitter())
|
||||||
|
.listen((String line) {
|
||||||
|
if (line.contains('\] Hot reload performed in')) {
|
||||||
|
if (hotReloadCount == 0) {
|
||||||
|
// Update the file and reload again.
|
||||||
|
final File appDartSource = file(path.join(
|
||||||
|
_editedFlutterGalleryDir.path, 'lib/gallery/app.dart'
|
||||||
|
));
|
||||||
|
appDartSource.writeAsStringSync(
|
||||||
|
appDartSource.readAsStringSync().replaceFirst(
|
||||||
|
"'Flutter Gallery'", "'Updated Flutter Gallery'"
|
||||||
|
)
|
||||||
|
);
|
||||||
|
process.stdin.writeln('r');
|
||||||
|
++hotReloadCount;
|
||||||
|
} else {
|
||||||
|
// Quit after second hot reload.
|
||||||
|
process.stdin.writeln('q');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
print('stdout: $line');
|
||||||
|
}, onDone: () { stdoutDone.complete(); });
|
||||||
|
process.stderr
|
||||||
|
.transform(UTF8.decoder)
|
||||||
|
.transform(const LineSplitter())
|
||||||
|
.listen((String line) {
|
||||||
|
print('stderr: $line');
|
||||||
|
}, onDone: () { stderrDone.complete(); });
|
||||||
|
|
||||||
|
await Future.wait<Null>(<Future<Null>>[stdoutDone.future, stderrDone.future]);
|
||||||
|
return await process.exitCode;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
final Map<String, dynamic> twoReloadsData = JSON.decode(
|
||||||
|
benchmarkFile.readAsStringSync());
|
||||||
|
return new TaskResult.success(<String, dynamic> {
|
||||||
|
'hotReloadInitialDevFSSyncMilliseconds': twoReloadsData['hotReloadInitialDevFSSyncMilliseconds'][0],
|
||||||
|
'hotRestartMillisecondsToFrame': twoReloadsData['hotRestartMillisecondsToFrame'][0],
|
||||||
|
'hotReloadMillisecondsToFrame' : twoReloadsData['hotReloadMillisecondsToFrame'][0],
|
||||||
|
'hotReloadDevFSSyncMilliseconds': twoReloadsData['hotReloadDevFSSyncMilliseconds'][0],
|
||||||
|
'hotReloadFlutterReassembleMilliseconds': twoReloadsData['hotReloadFlutterReassembleMilliseconds'][0],
|
||||||
|
'hotReloadVMReloadMilliseconds': twoReloadsData['hotReloadVMReloadMilliseconds'][0],
|
||||||
|
'hotReloadDevFSSyncMillisecondsAfterChange': twoReloadsData['hotReloadDevFSSyncMilliseconds'][1],
|
||||||
|
'hotReloadFlutterReassembleMillisecondsAfterChange': twoReloadsData['hotReloadFlutterReassembleMilliseconds'][1],
|
||||||
|
'hotReloadVMReloadMillisecondsAfterChange': twoReloadsData['hotReloadVMReloadMilliseconds'][1]
|
||||||
});
|
});
|
||||||
return new TaskResult.successFromFile(benchmarkFile,
|
|
||||||
benchmarkScoreKeys: <String>[
|
|
||||||
'hotReloadInitialDevFSSyncMilliseconds',
|
|
||||||
'hotReloadMillisecondsToFrame',
|
|
||||||
'hotRestartMillisecondsToFrame',
|
|
||||||
'hotReloadDevFSSyncMilliseconds',
|
|
||||||
'hotReloadFlutterReassembleMilliseconds',
|
|
||||||
'hotReloadVMReloadMilliseconds',
|
|
||||||
]);
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -57,11 +57,16 @@ class HotRunner extends ResidentRunner {
|
|||||||
Set<String> _dartDependencies;
|
Set<String> _dartDependencies;
|
||||||
|
|
||||||
final bool benchmarkMode;
|
final bool benchmarkMode;
|
||||||
final Map<String, int> benchmarkData = <String, int>{};
|
final Map<String, List<int>> benchmarkData = <String, List<int>>{};
|
||||||
// The initial launch is from a snapshot.
|
// The initial launch is from a snapshot.
|
||||||
bool _runningFromSnapshot = true;
|
bool _runningFromSnapshot = true;
|
||||||
bool previewDart2 = false;
|
bool previewDart2 = false;
|
||||||
|
|
||||||
|
void _addBenchmarkData(String name, int value) {
|
||||||
|
benchmarkData[name] ??= <int>[];
|
||||||
|
benchmarkData[name].add(value);
|
||||||
|
}
|
||||||
|
|
||||||
bool _refreshDartDependencies() {
|
bool _refreshDartDependencies() {
|
||||||
if (!hotRunnerConfig.computeDartDependencies) {
|
if (!hotRunnerConfig.computeDartDependencies) {
|
||||||
// Disabled.
|
// Disabled.
|
||||||
@ -130,8 +135,8 @@ class HotRunner extends ResidentRunner {
|
|||||||
}
|
}
|
||||||
final Stopwatch initialUpdateDevFSsTimer = new Stopwatch()..start();
|
final Stopwatch initialUpdateDevFSsTimer = new Stopwatch()..start();
|
||||||
final bool devfsResult = await _updateDevFS();
|
final bool devfsResult = await _updateDevFS();
|
||||||
benchmarkData['hotReloadInitialDevFSSyncMilliseconds'] =
|
_addBenchmarkData('hotReloadInitialDevFSSyncMilliseconds',
|
||||||
initialUpdateDevFSsTimer.elapsed.inMilliseconds;
|
initialUpdateDevFSsTimer.elapsed.inMilliseconds);
|
||||||
if (!devfsResult)
|
if (!devfsResult)
|
||||||
return 3;
|
return 3;
|
||||||
|
|
||||||
@ -162,12 +167,17 @@ class HotRunner extends ResidentRunner {
|
|||||||
printStatus('Benchmarking hot reload');
|
printStatus('Benchmarking hot reload');
|
||||||
// Measure time to perform a hot reload.
|
// Measure time to perform a hot reload.
|
||||||
await restart(fullRestart: false);
|
await restart(fullRestart: false);
|
||||||
printStatus('Benchmark completed. Exiting application.');
|
if (stayResident) {
|
||||||
await _cleanupDevFS();
|
await waitForAppToFinish();
|
||||||
await stopEchoingDeviceLog();
|
} else {
|
||||||
await stopApp();
|
printStatus('Benchmark completed. Exiting application.');
|
||||||
|
await _cleanupDevFS();
|
||||||
|
await stopEchoingDeviceLog();
|
||||||
|
await stopApp();
|
||||||
|
}
|
||||||
final File benchmarkOutput = fs.file('hot_benchmark.json');
|
final File benchmarkOutput = fs.file('hot_benchmark.json');
|
||||||
benchmarkOutput.writeAsStringSync(toPrettyJson(benchmarkData));
|
benchmarkOutput.writeAsStringSync(toPrettyJson(benchmarkData));
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (stayResident)
|
if (stayResident)
|
||||||
@ -362,8 +372,8 @@ class HotRunner extends ResidentRunner {
|
|||||||
'${getElapsedAsMilliseconds(restartTimer.elapsed)}.');
|
'${getElapsedAsMilliseconds(restartTimer.elapsed)}.');
|
||||||
// We are now running from sources.
|
// We are now running from sources.
|
||||||
_runningFromSnapshot = false;
|
_runningFromSnapshot = false;
|
||||||
benchmarkData['hotRestartMillisecondsToFrame'] =
|
_addBenchmarkData('hotRestartMillisecondsToFrame',
|
||||||
restartTimer.elapsed.inMilliseconds;
|
restartTimer.elapsed.inMilliseconds);
|
||||||
flutterUsage.sendEvent('hot', 'restart');
|
flutterUsage.sendEvent('hot', 'restart');
|
||||||
flutterUsage.sendTiming('hot', 'restart', restartTimer.elapsed);
|
flutterUsage.sendTiming('hot', 'restart', restartTimer.elapsed);
|
||||||
return OperationResult.ok;
|
return OperationResult.ok;
|
||||||
@ -467,11 +477,10 @@ class HotRunner extends ResidentRunner {
|
|||||||
final Stopwatch devFSTimer = new Stopwatch()..start();
|
final Stopwatch devFSTimer = new Stopwatch()..start();
|
||||||
final bool updatedDevFS = await _updateDevFS();
|
final bool updatedDevFS = await _updateDevFS();
|
||||||
// Record time it took to synchronize to DevFS.
|
// Record time it took to synchronize to DevFS.
|
||||||
benchmarkData['hotReloadDevFSSyncMilliseconds'] =
|
_addBenchmarkData('hotReloadDevFSSyncMilliseconds',
|
||||||
devFSTimer.elapsed.inMilliseconds;
|
devFSTimer.elapsed.inMilliseconds);
|
||||||
if (!updatedDevFS)
|
if (!updatedDevFS)
|
||||||
return new OperationResult(1, 'DevFS synchronization failed');
|
return new OperationResult(1, 'DevFS synchronization failed');
|
||||||
|
|
||||||
String reloadMessage;
|
String reloadMessage;
|
||||||
final Stopwatch vmReloadTimer = new Stopwatch()..start();
|
final Stopwatch vmReloadTimer = new Stopwatch()..start();
|
||||||
try {
|
try {
|
||||||
@ -536,8 +545,8 @@ class HotRunner extends ResidentRunner {
|
|||||||
return new OperationResult(errorCode, errorMessage);
|
return new OperationResult(errorCode, errorMessage);
|
||||||
}
|
}
|
||||||
// Record time it took for the VM to reload the sources.
|
// Record time it took for the VM to reload the sources.
|
||||||
benchmarkData['hotReloadVMReloadMilliseconds'] =
|
_addBenchmarkData('hotReloadVMReloadMilliseconds',
|
||||||
vmReloadTimer.elapsed.inMilliseconds;
|
vmReloadTimer.elapsed.inMilliseconds);
|
||||||
final Stopwatch reassembleTimer = new Stopwatch()..start();
|
final Stopwatch reassembleTimer = new Stopwatch()..start();
|
||||||
// Reload the isolate.
|
// Reload the isolate.
|
||||||
for (FlutterDevice device in flutterDevices) {
|
for (FlutterDevice device in flutterDevices) {
|
||||||
@ -595,15 +604,15 @@ class HotRunner extends ResidentRunner {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Record time it took for Flutter to reassemble the application.
|
// Record time it took for Flutter to reassemble the application.
|
||||||
benchmarkData['hotReloadFlutterReassembleMilliseconds'] =
|
_addBenchmarkData('hotReloadFlutterReassembleMilliseconds',
|
||||||
reassembleTimer.elapsed.inMilliseconds;
|
reassembleTimer.elapsed.inMilliseconds);
|
||||||
|
|
||||||
reloadTimer.stop();
|
reloadTimer.stop();
|
||||||
printTrace('Hot reload performed in '
|
printTrace('Hot reload performed in '
|
||||||
'${getElapsedAsMilliseconds(reloadTimer.elapsed)}.');
|
'${getElapsedAsMilliseconds(reloadTimer.elapsed)}.');
|
||||||
// Record complete time it took for the reload.
|
// Record complete time it took for the reload.
|
||||||
benchmarkData['hotReloadMillisecondsToFrame'] =
|
_addBenchmarkData('hotReloadMillisecondsToFrame',
|
||||||
reloadTimer.elapsed.inMilliseconds;
|
reloadTimer.elapsed.inMilliseconds);
|
||||||
// Only report timings if we reloaded a single view without any
|
// Only report timings if we reloaded a single view without any
|
||||||
// errors or timeouts.
|
// errors or timeouts.
|
||||||
if ((reassembleViews.length == 1) &&
|
if ((reassembleViews.length == 1) &&
|
||||||
|
Loading…
x
Reference in New Issue
Block a user