[H] Move the splitting of licenses to an isolate (#14160)
* Move the splitting of licenses to an isolate
This improves (from horrific to terrible) the performance of the
license screen. It also introduces a feature in the foundation layer
to make using isolates for one-off computations easier.
The real problem that remains with this, though, is that transfering
data between isolates is a stop-the-world operation and can take an
absurd amount of time (far more than a few milliseconds), so we still
skip frames.
More work thus remains to be done.
* - Add profile instrumentation to the isolate compute() method
- Add profile instrumentation to the LicensePage
- Add profile instrumentation to the scheduleTask method
- Make scheduleTask support returning a value
- Make the license page builder logic use scheduled tasks so that it doesn't blow the frame budget
diff --git a/dev/bots/analyze-sample-code.dart b/dev/bots/analyze-sample-code.dart
index 4ff9210..a82c44c 100644
--- a/dev/bots/analyze-sample-code.dart
+++ b/dev/bots/analyze-sample-code.dart
@@ -37,11 +37,16 @@
final List<String> code;
final String postamble;
Iterable<String> get strings sync* {
- if (preamble != null)
+ if (preamble != null) {
+ assert(!preamble.contains('\n'));
yield preamble;
+ }
+ assert(!code.any((String line) => line.contains('\n')));
yield* code;
- if (postamble != null)
+ if (postamble != null) {
+ assert(!postamble.contains('\n'));
yield postamble;
+ }
}
List<Line> get lines {
final List<Line> result = new List<Line>.generate(code.length, (int index) => start + index);
@@ -61,6 +66,7 @@
final Directory temp = Directory.systemTemp.createTempSync('analyze_sample_code_');
int exitCode = 1;
bool keepMain = false;
+ final List<String> buffer = <String>[];
try {
final File mainDart = new File(path.join(temp.path, 'main.dart'));
final File pubSpec = new File(path.join(temp.path, 'pubspec.yaml'));
@@ -128,7 +134,6 @@
}
}
}
- final List<String> buffer = <String>[];
buffer.add('// generated code');
buffer.add('import \'dart:async\';');
buffer.add('import \'dart:math\' as math;');
@@ -146,6 +151,7 @@
buffer.addAll(section.strings);
lines.addAll(section.lines);
}
+ assert(buffer.length == lines.length);
mainDart.writeAsStringSync(buffer.join('\n'));
pubSpec.writeAsStringSync('''
name: analyze_sample_code
@@ -180,17 +186,23 @@
final String message = error.substring(start + kBullet.length, end);
final String atMatch = atRegExp.firstMatch(error)[0];
final int colon2 = error.indexOf(kColon, end + atMatch.length);
- if (colon2 < 0)
+ if (colon2 < 0) {
+ keepMain = true;
throw 'failed to parse error message: $error';
+ }
final String line = error.substring(end + atMatch.length, colon2);
final int bullet2 = error.indexOf(kBullet, colon2);
- if (bullet2 < 0)
+ if (bullet2 < 0) {
+ keepMain = true;
throw 'failed to parse error message: $error';
+ }
final String column = error.substring(colon2 + kColon.length, bullet2);
final int lineNumber = int.parse(line, radix: 10, onError: (String source) => throw 'failed to parse error message: $error');
final int columnNumber = int.parse(column, radix: 10, onError: (String source) => throw 'failed to parse error message: $error');
- if (lineNumber < 0 || lineNumber >= lines.length)
- throw 'failed to parse error message: $error';
+ if (lineNumber < 1 || lineNumber > lines.length) {
+ keepMain = true;
+ throw 'failed to parse error message (read line number as $lineNumber; total number of lines is ${lines.length}): $error';
+ }
final Line actualLine = lines[lineNumber - 1];
final String errorCode = error.substring(bullet2 + kBullet.length);
if (errorCode == 'unused_element') {
@@ -211,6 +223,7 @@
}
} else {
print('?? $error');
+ keepMain = true;
errorCount += 1;
}
}
@@ -222,6 +235,13 @@
} finally {
if (keepMain) {
print('Kept ${temp.path} because it had errors (see above).');
+ print('-------8<-------');
+ int number = 1;
+ for (String line in buffer) {
+ print('${number.toString().padLeft(6, " ")}: $line');
+ number += 1;
+ }
+ print('-------8<-------');
} else {
temp.deleteSync(recursive: true);
}