mirror of
https://github.com/dart-lang/sdk
synced 2024-10-06 13:18:01 +00:00
Move running tasks for fixed time to the scheduler.
This improves recovery time for change/undo from 300 ms to 200 ms for analyzer + analysis_server + front_end. _FilesReferencingNameTask does not degrade in any noticeble way, it is still about 0-1 ms for this code base, as compared to 60 ms without fixing runing time in the task or the scheduler. R=brianwilkerson@google.com, paulberry@google.com BUG= Review URL: https://codereview.chromium.org/2540403002 .
This commit is contained in:
parent
aaaeee5bc4
commit
53b04631bc
|
@ -918,6 +918,27 @@ enum AnalysisDriverPriority {
|
|||
* work with the highest priority is performed first.
|
||||
*/
|
||||
class AnalysisDriverScheduler {
|
||||
/**
|
||||
* Time interval in milliseconds before pumping the event queue.
|
||||
*
|
||||
* Relinquishing execution flow and running the event loop after every task
|
||||
* has too much overhead. Instead we use a fixed length of time, so we can
|
||||
* spend less time overall and still respond quickly enough.
|
||||
*/
|
||||
static const int _MS_BEFORE_PUMPING_EVENT_QUEUE = 2;
|
||||
|
||||
/**
|
||||
* Event queue pumping is required to allow IO and other asynchronous data
|
||||
* processing while analysis is active. For example Analysis Server needs to
|
||||
* be able to process `updateContent` or `setPriorityFiles` requests while
|
||||
* background analysis is in progress.
|
||||
*
|
||||
* The number of pumpings is arbitrary, might be changed if we see that
|
||||
* analysis or other data processing tasks are starving. Ideally we would
|
||||
* need to run all asynchronous operations using a single global scheduler.
|
||||
*/
|
||||
static const int _NUMBER_OF_EVENT_QUEUE_PUMPINGS = 128;
|
||||
|
||||
final PerformanceLog _logger;
|
||||
final List<AnalysisDriver> _drivers = [];
|
||||
final Monitor _hasWork = new Monitor();
|
||||
|
@ -977,18 +998,14 @@ class AnalysisDriverScheduler {
|
|||
* priority first.
|
||||
*/
|
||||
Future<Null> _run() async {
|
||||
Stopwatch timer = new Stopwatch()..start();
|
||||
PerformanceLogSection analysisSection;
|
||||
while (true) {
|
||||
// Pump the event queue to allow IO and other asynchronous data
|
||||
// processing while analysis is active. For example Analysis Server
|
||||
// needs to be able to process `updateContent` or `setPriorityFiles`
|
||||
// requests while background analysis is in progress.
|
||||
//
|
||||
// The number of pumpings is arbitrary, might be changed if we see that
|
||||
// analysis or other data processing tasks are starving. Ideally we
|
||||
// would need to be able to set priority of (continuous) asynchronous
|
||||
// tasks.
|
||||
await _pumpEventQueue(128);
|
||||
// Pump the event queue.
|
||||
if (timer.elapsedMilliseconds > _MS_BEFORE_PUMPING_EVENT_QUEUE) {
|
||||
await _pumpEventQueue(_NUMBER_OF_EVENT_QUEUE_PUMPINGS);
|
||||
timer.reset();
|
||||
}
|
||||
|
||||
await _hasWork.signal;
|
||||
|
||||
|
@ -1266,38 +1283,31 @@ class _FilesReferencingNameTask {
|
|||
_FilesReferencingNameTask(this.driver, this.name);
|
||||
|
||||
/**
|
||||
* Perform work for a fixed length of time, and either complete the
|
||||
* [completer] and return `true` to indicate that the task is done, return
|
||||
* `false` to indicate that the task should continue to be run.
|
||||
*
|
||||
* Relinquishing execution flow and running event loop after every file
|
||||
* works, but has too much overhead. Instead we use a fixed length of time,
|
||||
* so we can spend less time overall and keep quick enough response time.
|
||||
* Perform a single piece of work, and either complete the [completer] and
|
||||
* return `true` to indicate that the task is done, return `false` to indicate
|
||||
* that the task should continue to be run.
|
||||
*/
|
||||
Future<bool> perform() async {
|
||||
Stopwatch timer = new Stopwatch()..start();
|
||||
while (timer.elapsedMilliseconds < 5) {
|
||||
// Prepare files to check.
|
||||
if (filesToCheck.isEmpty) {
|
||||
Set<String> newFiles = driver.addedFiles.difference(checkedFiles);
|
||||
filesToCheck.addAll(newFiles);
|
||||
}
|
||||
|
||||
// If no more files to check, complete and done.
|
||||
if (filesToCheck.isEmpty) {
|
||||
completer.complete(referencingFiles);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Check the next file.
|
||||
String path = filesToCheck.removeLast();
|
||||
FileState file = driver._fsState.getFileForPath(path);
|
||||
if (file.referencedNames.contains(name)) {
|
||||
referencingFiles.add(path);
|
||||
}
|
||||
checkedFiles.add(path);
|
||||
// Prepare files to check.
|
||||
if (filesToCheck.isEmpty) {
|
||||
Set<String> newFiles = driver.addedFiles.difference(checkedFiles);
|
||||
filesToCheck.addAll(newFiles);
|
||||
}
|
||||
|
||||
// If no more files to check, complete and done.
|
||||
if (filesToCheck.isEmpty) {
|
||||
completer.complete(referencingFiles);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Check the next file.
|
||||
String path = filesToCheck.removeLast();
|
||||
FileState file = driver._fsState.getFileForPath(path);
|
||||
if (file.referencedNames.contains(name)) {
|
||||
referencingFiles.add(path);
|
||||
}
|
||||
checkedFiles.add(path);
|
||||
|
||||
// We're not done yet.
|
||||
return false;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue