blob: 4770141c2f52b9b0a6125ea3825255d19113b354 [file] [log] [blame]
// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
library dart2js.serialization_helper;
import 'dart:async';
import 'dart:io';
import 'package:compiler/compiler_new.dart';
import 'package:compiler/src/commandline_options.dart';
import 'package:compiler/src/common/names.dart';
import 'package:compiler/src/compiler.dart';
import 'package:compiler/src/elements/elements.dart';
import 'package:compiler/src/filenames.dart';
import '../memory_compiler.dart';
import 'test_data.dart';
const String DEFAULT_DATA_FILE_NAME = 'out.data';
class Arguments {
final String filename;
final int start;
final int end;
final bool loadSerializedData;
final bool saveSerializedData;
final String serializedDataFileName;
final bool verbose;
const Arguments(
{this.filename,
this.start,
this.end,
this.loadSerializedData: false,
this.saveSerializedData: false,
this.serializedDataFileName: DEFAULT_DATA_FILE_NAME,
this.verbose: false});
factory Arguments.from(List<String> arguments) {
String filename;
int start;
int end;
for (String arg in arguments) {
if (!arg.startsWith('-')) {
int index = int.parse(arg, onError: (_) => null);
if (index == null) {
filename = arg;
} else if (start == null) {
start = index;
} else {
end = index;
}
}
}
bool verbose = arguments.contains('-v');
bool loadSerializedData = arguments.contains('-l');
bool saveSerializedData = arguments.contains('-s');
if (arguments.contains('--auto')) {
File file = new File(DEFAULT_DATA_FILE_NAME);
if (file.existsSync()) {
loadSerializedData = true;
} else {
saveSerializedData = true;
}
}
return new Arguments(
filename: filename,
start: start,
end: end,
verbose: verbose,
loadSerializedData: loadSerializedData,
saveSerializedData: saveSerializedData);
}
Uri get uri {
if (filename != null) {
return Uri.base.resolve(nativeToUriPath(filename));
}
return null;
}
Future forEachTest(SerializedData serializedData, List<Test> tests,
TestFunction testFunction) async {
Uri entryPoint = Uri.parse('memory:main.dart');
int first = start ?? 0;
int last = end ?? tests.length;
for (int index = first; index < last; index++) {
Test test = TESTS[index];
List<SerializedData> dataList =
await preserializeData(serializedData, test);
Map<String, String> sourceFiles = <String, String>{};
sourceFiles.addAll(test.sourceFiles);
if (test.preserializedSourceFiles != null) {
sourceFiles.addAll(test.preserializedSourceFiles);
}
if (test.unserializedSourceFiles != null) {
sourceFiles.addAll(test.unserializedSourceFiles);
}
List<Uri> resolutionInputs = <Uri>[];
for (SerializedData data in dataList) {
data.expandMemorySourceFiles(sourceFiles);
data.expandUris(resolutionInputs);
}
await testFunction(entryPoint,
sourceFiles: sourceFiles,
resolutionInputs: resolutionInputs,
index: index,
test: test,
verbose: verbose);
}
}
}
typedef Future TestFunction(Uri entryPoint,
{Map<String, String> sourceFiles,
List<Uri> resolutionInputs,
int index,
Test test,
bool verbose});
Future<SerializedData> serializeDartCore(
{Arguments arguments: const Arguments()}) {
return measure('dart:core', 'serialize', () async {
Uri uri = Uri.parse('memory:${arguments.serializedDataFileName}');
SerializedData serializedData;
if (arguments.loadSerializedData) {
File file = new File(arguments.serializedDataFileName);
if (file.existsSync()) {
print('Loading data from $file');
serializedData = new SerializedData(uri, file.readAsStringSync());
}
} else {
SerializationResult result =
await serialize(Uris.dart_core, dataUri: uri);
serializedData = result.serializedData;
}
if (arguments.saveSerializedData) {
File file = new File(arguments.serializedDataFileName);
print('Saving data to $file');
file.writeAsStringSync(serializedData.data);
}
return serializedData;
});
}
class SerializationResult {
final Compiler compiler;
final SerializedData serializedData;
SerializationResult(this.compiler, this.serializedData);
}
Future<SerializationResult> serialize(Uri entryPoint,
{Map<String, String> memorySourceFiles: const <String, String>{},
List<Uri> resolutionInputs: const <Uri>[],
Uri dataUri,
bool deserializeCompilationDataForTesting: false}) async {
if (dataUri == null) {
dataUri = Uri.parse('memory:${DEFAULT_DATA_FILE_NAME}');
}
OutputCollector outputCollector = new OutputCollector();
Compiler compiler = compilerFor(
options: [Flags.resolveOnly, Flags.useOldFrontend],
memorySourceFiles: memorySourceFiles,
resolutionInputs: resolutionInputs,
outputProvider: outputCollector);
compiler.serialization.deserializeCompilationDataForTesting =
deserializeCompilationDataForTesting;
await compiler.run(entryPoint);
SerializedData serializedData = new SerializedData(
dataUri, outputCollector.getOutput('', OutputType.serializationData));
return new SerializationResult(compiler, serializedData);
}
class SerializedData {
final Uri uri;
final String data;
SerializedData(this.uri, this.data) {
assert(uri != null);
assert(data != null);
}
Map<String, String> toMemorySourceFiles([Map<String, String> input]) {
Map<String, String> sourceFiles = <String, String>{};
if (input != null) {
sourceFiles.addAll(input);
}
expandMemorySourceFiles(sourceFiles);
return sourceFiles;
}
void expandMemorySourceFiles(Map<String, String> sourceFiles) {
if (uri.scheme == 'memory') {
sourceFiles[uri.path] = data;
}
}
List<Uri> toUris([List<Uri> input]) {
List<Uri> uris = <Uri>[];
if (input != null) {
uris.addAll(input);
}
expandUris(uris);
return uris;
}
void expandUris(List<Uri> uris) {
uris.add(uri);
}
}
Future<List<SerializedData>> preserializeData(
SerializedData serializedData, Test test) async {
if (test == null ||
test.preserializedSourceFiles == null ||
test.preserializedSourceFiles.isEmpty) {
return <SerializedData>[serializedData];
}
List<Uri> uriList = <Uri>[];
for (String key in test.preserializedSourceFiles.keys) {
uriList.add(Uri.parse('memory:$key'));
}
Map<String, String> sourceFiles = serializedData.toMemorySourceFiles();
sourceFiles.addAll(test.preserializedSourceFiles);
if (test.unserializedSourceFiles != null) {
sourceFiles.addAll(test.unserializedSourceFiles);
}
Uri additionalDataUri = Uri.parse('memory:additional.data');
SerializedData additionalSerializedData;
if (test.sourceFiles.isEmpty) {
SerializationResult result = await serialize(uriList.first,
memorySourceFiles: sourceFiles,
resolutionInputs: serializedData.toUris(),
dataUri: additionalDataUri);
additionalSerializedData = result.serializedData;
} else {
OutputCollector outputCollector = new OutputCollector();
Compiler compiler = compilerFor(
entryPoint: test.sourceFiles.isEmpty ? uriList.first : null,
memorySourceFiles: sourceFiles,
resolutionInputs: serializedData.toUris(),
options: [Flags.resolveOnly, Flags.useOldFrontend],
outputProvider: outputCollector);
compiler.librariesToAnalyzeWhenRun = uriList;
await compiler.run(null);
List<LibraryElement> libraries = <LibraryElement>[];
for (Uri uri in uriList) {
libraries.add(compiler.libraryLoader.lookupLibrary(uri));
}
additionalSerializedData = new SerializedData(additionalDataUri,
outputCollector.getOutput('', OutputType.serializationData));
}
return <SerializedData>[serializedData, additionalSerializedData];
}
class MeasurementResult {
final String title;
final String taskTitle;
final int elapsedMilliseconds;
MeasurementResult(this.title, this.taskTitle, this.elapsedMilliseconds);
}
final List<MeasurementResult> measurementResults = <MeasurementResult>[];
/// Print all store [measurementResults] grouped by title and sorted by
/// decreasing execution time.
void printMeasurementResults() {
Map<String, int> totals = <String, int>{};
for (MeasurementResult result in measurementResults) {
totals.putIfAbsent(result.title, () => 0);
totals[result.title] += result.elapsedMilliseconds;
}
List<String> sorted = totals.keys.toList();
sorted.sort((a, b) => -totals[a].compareTo(totals[b]));
int paddingLength = '${totals[sorted.first]}'.length;
String pad(int value) {
String text = '$value';
return '${' ' * (paddingLength - text.length)}$text';
}
print('================================================================');
print('Summary:');
for (String task in sorted) {
int time = totals[task];
print('${pad(time)}ms $task');
}
measurementResults.clear();
}
/// Measure execution of [task], print the result and store it in
/// [measurementResults] for a summary.
Future measure(String title, String taskTitle, Future task()) async {
Stopwatch stopwatch = new Stopwatch()..start();
print('================================================================');
print('$taskTitle: $title');
print('----------------------------------------------------------------');
var result = await task();
stopwatch.stop();
int elapsedMilliseconds = stopwatch.elapsedMilliseconds;
print('$taskTitle: $title: ${elapsedMilliseconds}ms');
measurementResults
.add(new MeasurementResult(title, taskTitle, elapsedMilliseconds));
return result;
}