 Chromium Code Reviews
 Chromium Code Reviews Issue 2540403002:
  Move running tasks for fixed time to the scheduler.  (Closed)
    
  
    Issue 2540403002:
  Move running tasks for fixed time to the scheduler.  (Closed) 
  | 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 |