Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(553)

Side by Side Diff: pkg/analyzer/lib/src/task/driver.dart

Issue 1131673004: Use WorkManager(s) in AnalysisDriver. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 5 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2015, 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 library analyzer.src.task.driver; 5 library analyzer.src.task.driver;
6 6
7 import 'dart:async'; 7 import 'dart:async';
8 import 'dart:collection'; 8 import 'dart:collection';
9 9
10 import 'package:analyzer/src/context/cache.dart'; 10 import 'package:analyzer/src/context/cache.dart';
11 import 'package:analyzer/src/generated/engine.dart' hide AnalysisTask; 11 import 'package:analyzer/src/generated/engine.dart' hide AnalysisTask;
12 import 'package:analyzer/src/generated/java_engine.dart'; 12 import 'package:analyzer/src/generated/java_engine.dart';
13 import 'package:analyzer/src/generated/resolver.dart'; 13 import 'package:analyzer/src/generated/resolver.dart';
14 import 'package:analyzer/src/task/inputs.dart'; 14 import 'package:analyzer/src/task/inputs.dart';
15 import 'package:analyzer/src/task/manager.dart'; 15 import 'package:analyzer/src/task/manager.dart';
16 import 'package:analyzer/task/model.dart'; 16 import 'package:analyzer/task/model.dart';
17 17
18 /** 18 /**
19 * An object that is used to cause analysis to be performed until all of the 19 * An object that is used to cause analysis to be performed until all of the
20 * required analysis information has been computed. 20 * required analysis information has been computed.
21 */ 21 */
22 class AnalysisDriver { 22 class AnalysisDriver {
23 /** 23 /**
24 * The task manager used to figure out how to compute analysis results. 24 * The task manager used to figure out how to compute analysis results.
25 */ 25 */
26 final TaskManager taskManager; 26 final TaskManager taskManager;
27 27
28 // /** 28 /**
29 // * The list of [WorkManager] used to figure out which analysis results to 29 * The list of [WorkManager] used to figure out which analysis results to
30 // * compute. 30 * compute.
31 // */ 31 */
32 // final List<WorkManager> workManagers; 32 final List<WorkManager> workManagers;
33 33
34 /** 34 /**
35 * The context in which analysis is to be performed. 35 * The context in which analysis is to be performed.
36 */ 36 */
37 final InternalAnalysisContext context; 37 final InternalAnalysisContext context;
38 38
39 /** 39 /**
40 * The work order that was previously computed but that has not yet been 40 * The work order that was previously computed but that has not yet been
41 * completed. 41 * completed.
42 */ 42 */
43 WorkOrder currentWorkOrder; 43 WorkOrder currentWorkOrder;
44 44
45 /** 45 /**
46 * The controller that is notified when a task is started. 46 * The controller that is notified when a task is started.
47 */ 47 */
48 StreamController<AnalysisTask> _onTaskStartedController; 48 StreamController<AnalysisTask> _onTaskStartedController;
49 49
50 /** 50 /**
51 * The controller that is notified when a task is complete. 51 * The controller that is notified when a task is complete.
52 */ 52 */
53 StreamController<AnalysisTask> _onTaskCompletedController; 53 StreamController<AnalysisTask> _onTaskCompletedController;
54 54
55 /** 55 /**
56 * Initialize a newly created driver to use the tasks know to the given 56 * Initialize a newly created driver to use the tasks know to the given
57 * [taskManager] to perform analysis in the given [context]. 57 * [taskManager] to perform analysis in the given [context].
58 */ 58 */
59 AnalysisDriver(this.taskManager, this.context) { 59 AnalysisDriver(this.taskManager, this.workManagers, this.context) {
60 _onTaskStartedController = new StreamController.broadcast(); 60 _onTaskStartedController = new StreamController.broadcast();
61 _onTaskCompletedController = new StreamController.broadcast(); 61 _onTaskCompletedController = new StreamController.broadcast();
62 } 62 }
63 63
64 /** 64 /**
65 * The stream that is notified when a task is complete. 65 * The stream that is notified when a task is complete.
66 */ 66 */
67 Stream<AnalysisTask> get onTaskCompleted => _onTaskCompletedController.stream; 67 Stream<AnalysisTask> get onTaskCompleted => _onTaskCompletedController.stream;
68 68
69 /** 69 /**
(...skipping 14 matching lines...) Expand all
84 } 84 }
85 } 85 }
86 return task; 86 return task;
87 } 87 }
88 88
89 /** 89 /**
90 * Return the work order describing the work that should be getting worked on, 90 * Return the work order describing the work that should be getting worked on,
91 * or `null` if there is currently no work to be done. 91 * or `null` if there is currently no work to be done.
92 */ 92 */
93 WorkOrder createNextWorkOrder() { 93 WorkOrder createNextWorkOrder() {
94 // 94 while (true) {
95 // TODO(brianwilkerson) This is an inefficient implementation. We need to 95 // Find the WorkManager with the highest priority.
96 // port over the concept of the WorkManager to manage the list of sources 96 WorkOrderPriority highestPriority = null;
97 // for which some work needs to be performed so that we do not waste time 97 WorkManager highestManager = null;
98 // repeatedly looking at the same completed sources to see whether there is 98 for (WorkManager manager in workManagers) {
99 // work that needs to be done. 99 WorkOrderPriority priority = manager.getNextResultPriority();
100 // 100 if (highestPriority == null || highestPriority.index > priority.index) {
101 for (AnalysisTarget target in context.priorityTargets) { 101 highestPriority = priority;
102 WorkOrder workOrder = createWorkOrderForTarget(target, true); 102 highestManager = manager;
103 if (workOrder != null) { 103 }
104 return workOrder; 104 }
105 // Nothing to do.
106 if (highestPriority == WorkOrderPriority.NONE) {
107 return null;
108 }
109 // Create a new WorkOrder.
110 TargetedResult request = highestManager.getNextResult();
111 if (request != null) {
112 WorkOrder workOrder =
113 createWorkOrderForResult(request.target, request.result);
114 if (workOrder != null) {
115 return workOrder;
116 }
105 } 117 }
106 } 118 }
107 // TODO(brianwilkerson) Add a third priority, corresponding to
108 // AnalysisContextImpl._pendingFutureSources to support code completion.
109 for (AnalysisTarget target in context.explicitTargets) {
110 WorkOrder workOrder = createWorkOrderForTarget(target, false);
111 if (workOrder != null) {
112 return workOrder;
113 }
114 }
115 return null;
116 } 119 }
117 120
118 /** 121 /**
119 * Create a work order that will produce the given [result] for the given 122 * Create a work order that will produce the given [result] for the given
120 * [target]. Return the work order that was created, or `null` if the result 123 * [target]. Return the work order that was created, or `null` if the result
121 * has already been computed. 124 * has already been computed.
122 */ 125 */
123 WorkOrder createWorkOrderForResult( 126 WorkOrder createWorkOrderForResult(
124 AnalysisTarget target, ResultDescriptor result) { 127 AnalysisTarget target, ResultDescriptor result) {
125 CacheEntry entry = context.getCacheEntry(target); 128 CacheEntry entry = context.getCacheEntry(target);
(...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after
217 task.perform(); 220 task.perform();
218 CacheEntry entry = context.getCacheEntry(task.target); 221 CacheEntry entry = context.getCacheEntry(task.target);
219 if (task.caughtException == null) { 222 if (task.caughtException == null) {
220 List<TargetedResult> dependedOn = item.inputTargetedResults.toList(); 223 List<TargetedResult> dependedOn = item.inputTargetedResults.toList();
221 Map<ResultDescriptor, dynamic> outputs = task.outputs; 224 Map<ResultDescriptor, dynamic> outputs = task.outputs;
222 for (ResultDescriptor result in task.descriptor.results) { 225 for (ResultDescriptor result in task.descriptor.results) {
223 // TODO(brianwilkerson) We could check here that a value was produced 226 // TODO(brianwilkerson) We could check here that a value was produced
224 // and throw an exception if not (unless we want to allow null values). 227 // and throw an exception if not (unless we want to allow null values).
225 entry.setValue(result, outputs[result], dependedOn); 228 entry.setValue(result, outputs[result], dependedOn);
226 } 229 }
230 for (WorkManager manager in workManagers) {
231 manager.resultsComputed(task.target, outputs);
232 }
227 } else { 233 } else {
228 entry.setErrorState(task.caughtException, item.descriptor.results); 234 entry.setErrorState(task.caughtException, item.descriptor.results);
229 } 235 }
230 _onTaskCompletedController.add(task); 236 _onTaskCompletedController.add(task);
231 return task; 237 return task;
232 } 238 }
233 239
234 /** 240 /**
235 * Reset the state of the driver in response to a change in the state of one 241 * Reset the state of the driver in response to a change in the state of one
236 * or more analysis targets. This will cause any analysis that was currently 242 * or more analysis targets. This will cause any analysis that was currently
(...skipping 158 matching lines...) Expand 10 before | Expand all | Expand 10 after
395 } 401 }
396 } 402 }
397 return null; 403 return null;
398 } 404 }
399 405
400 @override 406 @override
401 String toString() => 'Run $descriptor on $target'; 407 String toString() => 'Run $descriptor on $target';
402 } 408 }
403 409
404 /** 410 /**
411 * [AnalysisDriver] uses [WorkManager]s to select results to compute.
412 *
413 * They know specific of the targets and results they care about,
414 * so they can request analysis results in optimal order.
415 */
416 abstract class WorkManager {
417 /**
418 * Return the next [TargetedResult] that this work manager wants to be
419 * computed, or `null` if this manager doesn't need any new results.
420 */
421 TargetedResult getNextResult();
422
423 /**
424 * Return the priority if the next work order this work manager want to be
425 * computed. The [AnalysisDriver] will perform the work order with
426 * the highest priority.
427 *
428 * Even if the returned value is [WorkOrderPriority.NONE], it still does not
429 * guarantee that [getNextResult] will return not `null`.
430 */
431 WorkOrderPriority getNextResultPriority();
432
433 /**
434 * Notifies the manager that the given [outputs] were produced for
435 * the given [target].
436 */
437 void resultsComputed(
438 AnalysisTarget target, Map<ResultDescriptor, dynamic> outputs);
439 }
440
441 /**
442 * The priorities of work orders returned by [WorkManager]s.
443 */
444 enum WorkOrderPriority {
445 /**
446 * Responding to an user's action.
447 */
448 INTERACTIVE,
449
450 /**
451 * Computing information for priority sources.
452 */
453 PRIORITY,
454
455 /**
456 * A work should be done, but without any special urgency.
457 */
458 NORMAL,
459
460 /**
461 * Nothing to do.
462 */
463 NONE
464 }
465
466 /**
405 * A description of the work to be done to compute a desired analysis result. 467 * A description of the work to be done to compute a desired analysis result.
406 * The class implements a lazy depth-first traversal of the work item's input. 468 * The class implements a lazy depth-first traversal of the work item's input.
407 */ 469 */
408 class WorkOrder implements Iterator<WorkItem> { 470 class WorkOrder implements Iterator<WorkItem> {
409 /** 471 /**
410 * The task manager used to build work items. 472 * The task manager used to build work items.
411 */ 473 */
412 final TaskManager taskManager; 474 final TaskManager taskManager;
413 475
414 /** 476 /**
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after
468 TaskDescriptor descriptor = currentItem.descriptor; 530 TaskDescriptor descriptor = currentItem.descriptor;
469 AnalysisTarget target = currentItem.target; 531 AnalysisTarget target = currentItem.target;
470 for (WorkItem item in pendingItems) { 532 for (WorkItem item in pendingItems) {
471 if (item.descriptor == descriptor && item.target == target) { 533 if (item.descriptor == descriptor && item.target == target) {
472 return true; 534 return true;
473 } 535 }
474 } 536 }
475 return false; 537 return false;
476 } 538 }
477 } 539 }
478
479 /**
480 * [AnalysisDriver] uses [WorkManager]s to select results to compute.
481 *
482 * They know specific of the targets and results they care about,
483 * so they can request analysis results in optimal order.
484 */
485 abstract class WorkManager {
486 /**
487 * Return the next [TargetedResult] that this work manager wants to be
488 * computed, or `null` if this manager doesn't need any new results.
489 */
490 TargetedResult getNextResult();
491
492 /**
493 * Notifies the manager that the given [outputs] were produced for
494 * the given [target].
495 */
496 void resultsComputed(
497 AnalysisTarget target, Map<ResultDescriptor, dynamic> outputs);
498 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698