[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); }