Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 import 'dart:async'; | 5 import 'dart:async'; |
| 6 import 'dart:collection'; | 6 import 'dart:collection'; |
| 7 import 'dart:typed_data'; | 7 import 'dart:typed_data'; |
| 8 | 8 |
| 9 import 'package:analyzer/dart/ast/ast.dart'; | 9 import 'package:analyzer/dart/ast/ast.dart'; |
| 10 import 'package:analyzer/dart/element/element.dart' show CompilationUnitElement; | 10 import 'package:analyzer/dart/element/element.dart' show CompilationUnitElement; |
| (...skipping 900 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 911 referencingName, | 911 referencingName, |
| 912 getIndex, | 912 getIndex, |
| 913 interactive | 913 interactive |
| 914 } | 914 } |
| 915 | 915 |
| 916 /** | 916 /** |
| 917 * Instances of this class schedule work in multiple [AnalysisDriver]s so that | 917 * Instances of this class schedule work in multiple [AnalysisDriver]s so that |
| 918 * work with the highest priority is performed first. | 918 * work with the highest priority is performed first. |
| 919 */ | 919 */ |
| 920 class AnalysisDriverScheduler { | 920 class AnalysisDriverScheduler { |
| 921 /** | |
| 922 * Time interval in milliseconds before pumping the event queue. | |
| 923 * | |
| 924 * Relinquishing execution flow and running event loop after every task has | |
|
Brian Wilkerson
2016/12/01 17:12:27
"running event" --> "running the event"
| |
| 925 * too much overhead. Instead we use a fixed length of time, so we can spend | |
| 926 * less time overall and still respond quick enough. | |
| 927 */ | |
| 928 static const int _MS_BEFORE_PUMPING_EVENT_QUEUE = 2; | |
| 929 | |
| 930 /** | |
| 931 * Event queue pumping is required to allow IO and other asynchronous data | |
| 932 * processing while analysis is active. For example Analysis Server needs to | |
| 933 * be able to process `updateContent` or `setPriorityFiles` requests while | |
| 934 * background analysis is in progress. | |
| 935 * | |
| 936 * The number of pumpings is arbitrary, might be changed if we see that | |
| 937 * analysis or other data processing tasks are starving. Ideally we would | |
| 938 * need to run all asynchronous operations using a single global scheduler. | |
| 939 */ | |
| 940 static const int _NUMBER_OF_EVENT_QUEUE_PUMPINGS = 128; | |
| 941 | |
| 921 final PerformanceLog _logger; | 942 final PerformanceLog _logger; |
| 922 final List<AnalysisDriver> _drivers = []; | 943 final List<AnalysisDriver> _drivers = []; |
| 923 final Monitor _hasWork = new Monitor(); | 944 final Monitor _hasWork = new Monitor(); |
| 924 final StatusSupport _statusSupport = new StatusSupport(); | 945 final StatusSupport _statusSupport = new StatusSupport(); |
| 925 | 946 |
| 926 bool _started = false; | 947 bool _started = false; |
| 927 | 948 |
| 928 AnalysisDriverScheduler(this._logger); | 949 AnalysisDriverScheduler(this._logger); |
| 929 | 950 |
| 930 /** | 951 /** |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 970 _drivers.remove(driver); | 991 _drivers.remove(driver); |
| 971 _statusSupport.transitionToAnalyzing(); | 992 _statusSupport.transitionToAnalyzing(); |
| 972 _hasWork.notify(); | 993 _hasWork.notify(); |
| 973 } | 994 } |
| 974 | 995 |
| 975 /** | 996 /** |
| 976 * Run infinitely analysis cycle, selecting the drivers with the highest | 997 * Run infinitely analysis cycle, selecting the drivers with the highest |
| 977 * priority first. | 998 * priority first. |
| 978 */ | 999 */ |
| 979 Future<Null> _run() async { | 1000 Future<Null> _run() async { |
| 1001 Stopwatch timer = new Stopwatch()..start(); | |
| 980 PerformanceLogSection analysisSection; | 1002 PerformanceLogSection analysisSection; |
| 981 while (true) { | 1003 while (true) { |
| 982 // Pump the event queue to allow IO and other asynchronous data | 1004 // Pump the event queue. |
| 983 // processing while analysis is active. For example Analysis Server | 1005 if (timer.elapsedMilliseconds > _MS_BEFORE_PUMPING_EVENT_QUEUE) { |
| 984 // needs to be able to process `updateContent` or `setPriorityFiles` | 1006 await _pumpEventQueue(_NUMBER_OF_EVENT_QUEUE_PUMPINGS); |
| 985 // requests while background analysis is in progress. | 1007 timer.reset(); |
| 986 // | 1008 } |
| 987 // The number of pumpings is arbitrary, might be changed if we see that | |
| 988 // analysis or other data processing tasks are starving. Ideally we | |
| 989 // would need to be able to set priority of (continuous) asynchronous | |
| 990 // tasks. | |
| 991 await _pumpEventQueue(128); | |
| 992 | 1009 |
| 993 await _hasWork.signal; | 1010 await _hasWork.signal; |
| 994 | 1011 |
| 995 if (analysisSection == null) { | 1012 if (analysisSection == null) { |
| 996 analysisSection = _logger.enter('Analyzing'); | 1013 analysisSection = _logger.enter('Analyzing'); |
| 997 } | 1014 } |
| 998 | 1015 |
| 999 // Find the driver with the highest priority. | 1016 // Find the driver with the highest priority. |
| 1000 AnalysisDriver bestDriver; | 1017 AnalysisDriver bestDriver; |
| 1001 AnalysisDriverPriority bestPriority = AnalysisDriverPriority.nothing; | 1018 AnalysisDriverPriority bestPriority = AnalysisDriverPriority.nothing; |
| (...skipping 257 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1259 final String name; | 1276 final String name; |
| 1260 final Completer<List<String>> completer = new Completer<List<String>>(); | 1277 final Completer<List<String>> completer = new Completer<List<String>>(); |
| 1261 | 1278 |
| 1262 final List<String> referencingFiles = <String>[]; | 1279 final List<String> referencingFiles = <String>[]; |
| 1263 final Set<String> checkedFiles = new Set<String>(); | 1280 final Set<String> checkedFiles = new Set<String>(); |
| 1264 final List<String> filesToCheck = <String>[]; | 1281 final List<String> filesToCheck = <String>[]; |
| 1265 | 1282 |
| 1266 _FilesReferencingNameTask(this.driver, this.name); | 1283 _FilesReferencingNameTask(this.driver, this.name); |
| 1267 | 1284 |
| 1268 /** | 1285 /** |
| 1269 * Perform work for a fixed length of time, and either complete the | 1286 * Perform a single piece of work, and either complete the [completer] and |
| 1270 * [completer] and return `true` to indicate that the task is done, return | 1287 * return `true` to indicate that the task is done, return `false` to indicate |
| 1271 * `false` to indicate that the task should continue to be run. | 1288 * that the task should continue to be run. |
| 1272 * | |
| 1273 * Relinquishing execution flow and running event loop after every file | |
| 1274 * works, but has too much overhead. Instead we use a fixed length of time, | |
| 1275 * so we can spend less time overall and keep quick enough response time. | |
| 1276 */ | 1289 */ |
| 1277 Future<bool> perform() async { | 1290 Future<bool> perform() async { |
| 1278 Stopwatch timer = new Stopwatch()..start(); | 1291 // Prepare files to check. |
| 1279 while (timer.elapsedMilliseconds < 5) { | 1292 if (filesToCheck.isEmpty) { |
| 1280 // Prepare files to check. | 1293 Set<String> newFiles = driver.addedFiles.difference(checkedFiles); |
| 1281 if (filesToCheck.isEmpty) { | 1294 filesToCheck.addAll(newFiles); |
| 1282 Set<String> newFiles = driver.addedFiles.difference(checkedFiles); | 1295 } |
| 1283 filesToCheck.addAll(newFiles); | |
| 1284 } | |
| 1285 | 1296 |
| 1286 // If no more files to check, complete and done. | 1297 // If no more files to check, complete and done. |
| 1287 if (filesToCheck.isEmpty) { | 1298 if (filesToCheck.isEmpty) { |
| 1288 completer.complete(referencingFiles); | 1299 completer.complete(referencingFiles); |
| 1289 return true; | 1300 return true; |
| 1290 } | 1301 } |
| 1291 | 1302 |
| 1292 // Check the next file. | 1303 // Check the next file. |
| 1293 String path = filesToCheck.removeLast(); | 1304 String path = filesToCheck.removeLast(); |
| 1294 FileState file = driver._fsState.getFileForPath(path); | 1305 FileState file = driver._fsState.getFileForPath(path); |
| 1295 if (file.referencedNames.contains(name)) { | 1306 if (file.referencedNames.contains(name)) { |
| 1296 referencingFiles.add(path); | 1307 referencingFiles.add(path); |
| 1297 } | |
| 1298 checkedFiles.add(path); | |
| 1299 } | 1308 } |
| 1309 checkedFiles.add(path); | |
| 1300 | 1310 |
| 1301 // We're not done yet. | 1311 // We're not done yet. |
| 1302 return false; | 1312 return false; |
| 1303 } | 1313 } |
| 1304 } | 1314 } |
| 1305 | 1315 |
| 1306 /** | 1316 /** |
| 1307 * TODO(scheglov) document | 1317 * TODO(scheglov) document |
| 1308 */ | 1318 */ |
| 1309 class _LibraryContext { | 1319 class _LibraryContext { |
| 1310 final FileState file; | 1320 final FileState file; |
| 1311 final SummaryDataStore store; | 1321 final SummaryDataStore store; |
| 1312 _LibraryContext(this.file, this.store); | 1322 _LibraryContext(this.file, this.store); |
| 1313 } | 1323 } |
| OLD | NEW |