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

Side by Side Diff: pkg/compiler/lib/src/common/tasks.dart

Issue 2000323006: Make CompilerTask independent of compiler. (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: Created 4 years, 6 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
OLDNEW
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2012, 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 dart2js.common.tasks; 5 library dart2js.common.tasks;
6 6
7 import 'dart:async' 7 import 'dart:async'
8 show Future, Zone, ZoneDelegate, ZoneSpecification, runZoned; 8 show Future, Zone, ZoneDelegate, ZoneSpecification, runZoned;
9 9
10 import '../common.dart'; 10 /// Used to measure where time is spent in the compiler.
11 import '../compiler.dart' show Compiler; 11 ///
12 import '../elements/elements.dart' show Element; 12 /// This exposes [measure] and [measureIo], which wrap an action and assotiate
Harry Terkelsen 2016/05/25 15:51:36 assotiate -> associate
Siggi Cherem (dart-lang) 2016/05/25 16:11:18 Done.
13 13 /// the time spend during that action with this task. Nested measurements can be
Harry Terkelsen 2016/05/25 15:51:36 spend -> spent
Siggi Cherem (dart-lang) 2016/05/25 16:11:17 Done.
14 typedef void DeferredAction(); 14 /// introduced by using [measureSubtask].
15 15 // TODO(sigmund): rename to MeasurableTask
16 class DeferredTask { 16 abstract class CompilerTask {
Siggi Cherem (dart-lang) 2016/05/25 01:45:17 this is unrelated to the other kind of task, I mov
Johnni Winther 2016/05/25 09:02:00 Acknowledged.
17 final Element element; 17 final Measurer measurer;
18 final DeferredAction action; 18 final Stopwatch _watch;
19
20 DeferredTask(this.element, this.action);
21 }
22
23 /// A [CompilerTask] is used to measure where time is spent in the compiler.
24 /// The main entry points are [measure] and [measureIo].
25 class CompilerTask {
26 final Compiler compiler;
27 final Stopwatch watch;
28 final Map<String, GenericTask> _subtasks = <String, GenericTask>{}; 19 final Map<String, GenericTask> _subtasks = <String, GenericTask>{};
29 20
30 int asyncCount = 0; 21 int asyncCount = 0;
31 22
32 CompilerTask(Compiler compiler) 23 CompilerTask(Measurer measurer)
33 : this.compiler = compiler, 24 : measurer = measurer,
34 watch = (compiler.options.verbose) ? new Stopwatch() : null; 25 _watch = measurer.enableTaskMeasurements ? new Stopwatch() : null;
35 26
36 DiagnosticReporter get reporter => compiler.reporter; 27 /// Whether measurement is disabled. The functions [measure] and [measureIo]
28 /// only measure time if measurements are enabled.
29 bool get _isDisabled => _watch == null;
37 30
38 Measurer get measurer => compiler.measurer; 31 /// Name to use for reporting timing information.
39 32 // Note: it would be sufficient to mark this getter abstract if we had enough
Harry Terkelsen 2016/05/25 15:51:36 this note seems more like a TODO
Siggi Cherem (dart-lang) 2016/05/25 16:11:17 Yeah, not sure if it's worth deleting. Rephrase th
33 // static checking to ensure that all subclasses override it.
40 String get name => "Unknown task '${this.runtimeType}'"; 34 String get name => "Unknown task '${this.runtimeType}'";
41 35
42 bool get isRunning => watch?.isRunning == true; 36 bool get isRunning => _watch?.isRunning == true;
43 37
44 int get timing { 38 int get timing {
45 if (watch == null) return 0; 39 if (_isDisabled) return 0;
46 int total = watch.elapsedMilliseconds; 40 int total = _watch.elapsedMilliseconds;
47 for (GenericTask subtask in _subtasks.values) { 41 for (GenericTask subtask in _subtasks.values) {
48 total += subtask.timing; 42 total += subtask.timing;
49 } 43 }
50 return total; 44 return total;
51 } 45 }
52 46
53 Duration get duration { 47 Duration get duration {
54 if (watch == null) return Duration.ZERO; 48 if (_isDisabled) return Duration.ZERO;
55 Duration total = watch.elapsed; 49 Duration total = _watch.elapsed;
56 for (GenericTask subtask in _subtasks.values) { 50 for (GenericTask subtask in _subtasks.values) {
57 total += subtask.duration; 51 total += subtask.duration;
58 } 52 }
59 return total; 53 return total;
60 } 54 }
61 55
62 /// Perform [action] and use [watch] to measure its runtime (including any 56 /// Perform [action] and use [_watch] to measure its runtime (including any
Harry Terkelsen 2016/05/25 15:51:36 maybe remove the part about _watch in the docs sin
Siggi Cherem (dart-lang) 2016/05/25 16:11:18 good point, done.
63 /// asynchronous callbacks, such as, [Future.then], but excluding code 57 /// asynchronous callbacks, such as, [Future.then], but excluding code
64 /// measured by other tasks). 58 /// measured by other tasks).
65 measure(action()) => watch == null ? action() : measureZoned(action); 59 measure(action()) => _isDisabled ? action() : _measureZoned(action);
66 60
67 /// Helper method that starts measuring with this [CompilerTask], that is, 61 /// Helper method that starts measuring with this [CompilerTask], that is,
68 /// make this task the currently measured task. 62 /// make this task the currently measured task.
69 CompilerTask start() { 63 CompilerTask _start() {
70 if (watch == null) return null; 64 if (_isDisabled) return null;
71 CompilerTask previous = measurer.currentTask; 65 CompilerTask previous = measurer.currentTask;
72 measurer.currentTask = this; 66 measurer.currentTask = this;
73 if (previous != null) previous.watch.stop(); 67 if (previous != null) previous._watch.stop();
74 // Regardless of whether [previous] is `null` we've returned from the 68 // Regardless of whether [previous] is `null` we've returned from the
75 // eventloop. 69 // eventloop.
76 measurer.stopAsyncWallClock(); 70 measurer.stopAsyncWallClock();
77 watch.start(); 71 _watch.start();
78 return previous; 72 return previous;
79 } 73 }
80 74
81 /// Helper method that stops measuring with this [CompilerTask], that is, 75 /// Helper method that stops measuring with this [CompilerTask], that is,
82 /// make [previous] the currently measured task. 76 /// make [previous] the currently measured task.
83 void stop(CompilerTask previous) { 77 void _stop(CompilerTask previous) {
84 if (watch == null) return; 78 if (_isDisabled) return;
85 watch.stop(); 79 _watch.stop();
86 if (previous != null) { 80 if (previous != null) {
87 previous.watch.start(); 81 previous._watch.start();
88 } else { 82 } else {
89 // If there's no previous task, we're about to return control to the 83 // If there's no previous task, we're about to return control to the
90 // event loop. Start counting that as waiting asynchronous I/O. 84 // event loop. Start counting that as waiting asynchronous I/O.
91 measurer.startAsyncWallClock(); 85 measurer.startAsyncWallClock();
92 } 86 }
93 measurer.currentTask = previous; 87 measurer.currentTask = previous;
94 } 88 }
95 89
96 /// Helper method for [measure]. Don't call this method directly as it 90 _measureZoned(action()) {
97 /// assumes that [watch] isn't null.
98 measureZoned(action()) {
99 // Using zones, we're able to track asynchronous operations correctly, as 91 // Using zones, we're able to track asynchronous operations correctly, as
100 // our zone will be asked to invoke `then` blocks. Then blocks (the closure 92 // our zone will be asked to invoke `then` blocks. Then blocks (the closure
101 // passed to runZoned, and other closures) are run via the `run` functions 93 // passed to runZoned, and other closures) are run via the `run` functions
102 // below. 94 // below.
103 95
104 assert(watch != null); 96 assert(_watch != null);
105 97
106 // The current zone is already measuring `this` task. 98 // The current zone is already measuring `this` task.
107 if (Zone.current[measurer] == this) return action(); 99 if (Zone.current[measurer] == this) return action();
108 100
109 /// Run [f] in [zone]. Running must be delegated to [parent] to ensure that 101 /// Run [f] in [zone]. Running must be delegated to [parent] to ensure that
110 /// various state is set up correctly (in particular that `Zone.current` 102 /// various state is set up correctly (in particular that `Zone.current`
111 /// has the right value). Since [measureZoned] can be called recursively 103 /// has the right value). Since [_measureZoned] can be called recursively
112 /// (synchronously), some of the measuring zones we create will be parents 104 /// (synchronously), some of the measuring zones we create will be parents
113 /// of other measuring zones, but we still need to call through the parent 105 /// of other measuring zones, but we still need to call through the parent
114 /// chain. Consequently, we use a zone value keyed by [measurer] to see if 106 /// chain. Consequently, we use a zone value keyed by [measurer] to see if
115 /// we should measure or not when delegating. 107 /// we should measure or not when delegating.
116 run(Zone self, ZoneDelegate parent, Zone zone, f()) { 108 run(Zone self, ZoneDelegate parent, Zone zone, f()) {
117 if (zone[measurer] != this) return parent.run(zone, f); 109 if (zone[measurer] != this) return parent.run(zone, f);
118 CompilerTask previous = start(); 110 CompilerTask previous = _start();
119 try { 111 try {
120 return parent.run(zone, f); 112 return parent.run(zone, f);
121 } finally { 113 } finally {
122 stop(previous); 114 _stop(previous);
123 } 115 }
124 } 116 }
125 117
126 /// Same as [run] except that [f] takes one argument, [arg]. 118 /// Same as [run] except that [f] takes one argument, [arg].
127 runUnary(Zone self, ZoneDelegate parent, Zone zone, f(arg), arg) { 119 runUnary(Zone self, ZoneDelegate parent, Zone zone, f(arg), arg) {
128 if (zone[measurer] != this) return parent.runUnary(zone, f, arg); 120 if (zone[measurer] != this) return parent.runUnary(zone, f, arg);
129 CompilerTask previous = start(); 121 CompilerTask previous = _start();
130 try { 122 try {
131 return parent.runUnary(zone, f, arg); 123 return parent.runUnary(zone, f, arg);
132 } finally { 124 } finally {
133 stop(previous); 125 _stop(previous);
134 } 126 }
135 } 127 }
136 128
137 /// Same as [run] except that [f] takes two arguments ([a1] and [a2]). 129 /// Same as [run] except that [f] takes two arguments ([a1] and [a2]).
138 runBinary(Zone self, ZoneDelegate parent, Zone zone, f(a1, a2), a1, a2) { 130 runBinary(Zone self, ZoneDelegate parent, Zone zone, f(a1, a2), a1, a2) {
139 if (zone[measurer] != this) return parent.runBinary(zone, f, a1, a2); 131 if (zone[measurer] != this) return parent.runBinary(zone, f, a1, a2);
140 CompilerTask previous = start(); 132 CompilerTask previous = _start();
141 try { 133 try {
142 return parent.runBinary(zone, f, a1, a2); 134 return parent.runBinary(zone, f, a1, a2);
143 } finally { 135 } finally {
144 stop(previous); 136 _stop(previous);
145 } 137 }
146 } 138 }
147 139
148 return runZoned(action, 140 return runZoned(action,
149 zoneValues: {measurer: this}, 141 zoneValues: {measurer: this},
150 zoneSpecification: new ZoneSpecification( 142 zoneSpecification: new ZoneSpecification(
151 run: run, runUnary: runUnary, runBinary: runBinary)); 143 run: run, runUnary: runUnary, runBinary: runBinary));
152 } 144 }
153 145
154 /// Asynchronous version of [measure]. Use this when action returns a future 146 /// Asynchronous version of [measure]. Use this when action returns a future
155 /// that's truly asynchronous, such I/O. Only one task can use this method 147 /// that's truly asynchronous, such I/O. Only one task can use this method
156 /// concurrently. 148 /// concurrently.
157 /// 149 ///
158 /// Note: we assume that this method is used only by the compiler input 150 /// Note: we assume that this method is used only by the compiler input
159 /// provider, but it could be used by other tasks as long as the input 151 /// provider, but it could be used by other tasks as long as the input
160 /// provider will not be called by those tasks. 152 /// provider will not be called by those tasks.
161 measureIo(Future action()) { 153 measureIo(Future action()) {
162 return watch == null ? action() : measureIoHelper(action); 154 if (_isDisabled) return action();
163 }
164 155
165 /// Helper method for [measureIo]. Don't call this directly as it assumes
166 /// that [watch] isn't null.
167 Future measureIoHelper(Future action()) {
168 assert(watch != null);
169 if (measurer.currentAsyncTask == null) { 156 if (measurer.currentAsyncTask == null) {
170 measurer.currentAsyncTask = this; 157 measurer.currentAsyncTask = this;
171 } else if (measurer.currentAsyncTask != this) { 158 } else if (measurer.currentAsyncTask != this) {
172 throw "Can't track async task '$name' because" 159 throw "Can't track async task '$name' because"
173 " '${measurer.currentAsyncTask.name}' is already being tracked."; 160 " '${measurer.currentAsyncTask.name}' is already being tracked.";
174 } 161 }
175 asyncCount++; 162 asyncCount++;
176 return measure(action).whenComplete(() { 163 return measure(action).whenComplete(() {
177 asyncCount--; 164 asyncCount--;
178 if (asyncCount == 0) measurer.currentAsyncTask = null; 165 if (asyncCount == 0) measurer.currentAsyncTask = null;
179 }); 166 });
180 } 167 }
181 168
182 /// Convenience function for combining
183 /// [DiagnosticReporter.withCurrentElement] and [measure].
184 measureElement(Element element, action()) {
185 return watch == null
186 ? reporter.withCurrentElement(element, action)
187 : measureElementHelper(element, action);
188 }
189
190 /// Helper method for [measureElement]. Don't call this directly as it
191 /// assumes that [watch] isn't null.
192 measureElementHelper(Element element, action()) {
193 assert(watch != null);
194 return reporter.withCurrentElement(element, () => measure(action));
195 }
196
197 /// Measure the time spent in [action] (if in verbose mode) and accumulate it 169 /// Measure the time spent in [action] (if in verbose mode) and accumulate it
198 /// under a subtask with the given name. 170 /// under a subtask with the given name.
199 measureSubtask(String name, action()) { 171 measureSubtask(String name, action()) {
200 return watch == null ? action() : measureSubtaskHelper(name, action); 172 if (_isDisabled) return action();
201 }
202 173
203 /// Helper method for [measureSubtask]. Don't call this directly as it
204 /// assumes that [watch] isn't null.
205 measureSubtaskHelper(String name, action()) {
206 assert(watch != null);
207 // Use a nested CompilerTask for the measurement to ensure nested [measure] 174 // Use a nested CompilerTask for the measurement to ensure nested [measure]
208 // calls work correctly. The subtasks will never themselves have nested 175 // calls work correctly. The subtasks will never themselves have nested
209 // subtasks because they are not accessible outside. 176 // subtasks because they are not accessible outside.
210 GenericTask subtask = 177 GenericTask subtask =
211 _subtasks.putIfAbsent(name, () => new GenericTask(name, compiler)); 178 _subtasks.putIfAbsent(name, () => new GenericTask(name, measurer));
212 return subtask.measure(action); 179 return subtask.measure(action);
213 } 180 }
214 181
215 Iterable<String> get subtasks => _subtasks.keys; 182 Iterable<String> get subtasks => _subtasks.keys;
216 183
217 int getSubtaskTime(String subtask) => _subtasks[subtask].timing; 184 int getSubtaskTime(String subtask) => _subtasks[subtask].timing;
218 185
219 bool getSubtaskIsRunning(String subtask) => _subtasks[subtask].isRunning; 186 bool getSubtaskIsRunning(String subtask) => _subtasks[subtask].isRunning;
187
188 /// Used by the dart2js_incremental to provide measurements on each
189 /// incremental compile.
190 clearMeasurements() {
191 if (_isDisabled) return;
192 _watch.reset();
193 _subtasks.values.forEach((s) => s.clearMeasurements());
194 }
220 } 195 }
221 196
222 class GenericTask extends CompilerTask { 197 class GenericTask extends CompilerTask {
223 final String name; 198 final String name;
224 199 GenericTask(this.name, Measurer measurer) : super(measurer);
225 GenericTask(this.name, Compiler compiler) : super(compiler);
226 } 200 }
227 201
228 class Measurer { 202 class Measurer {
229 /// Measures the total runtime from this object was constructed. 203 /// Measures the total runtime from this object was constructed.
230 /// 204 ///
231 /// Note: MUST be first field to ensure [wallclock] is started before other 205 /// Note: MUST be the first field of this class to ensure [wallclock] is
232 /// computations. 206 /// started before other computations.
233 final Stopwatch wallClock = new Stopwatch()..start(); 207 final Stopwatch wallClock = new Stopwatch()..start();
234 208
235 /// Measures gaps between zoned closures due to asynchronicity. 209 /// Measures gaps between zoned closures due to asynchronicity.
236 final Stopwatch asyncWallClock = new Stopwatch(); 210 final Stopwatch asyncWallClock = new Stopwatch();
237 211
212 /// Whether measurement of tasks is enabled.
213 final bool enableTaskMeasurements;
214
215 Measurer({this.enableTaskMeasurements: false});
216
238 /// The currently running task, that is, the task whose [Stopwatch] is 217 /// The currently running task, that is, the task whose [Stopwatch] is
239 /// currently running. 218 /// currently running.
240 CompilerTask currentTask; 219 CompilerTask currentTask;
241 220
242 /// The current task which should be charged for asynchronous gaps. 221 /// The current task which should be charged for asynchronous gaps.
243 CompilerTask currentAsyncTask; 222 CompilerTask currentAsyncTask;
244 223
245 /// Start counting the total elapsed time since the compiler started. 224 /// Start counting the total elapsed time since the compiler started.
246 void startWallClock() { 225 void startWallClock() {
247 wallClock.start(); 226 wallClock.start();
248 } 227 }
249 228
250 /// Start counting the total elapsed time since the compiler started. 229 /// Start counting the total elapsed time since the compiler started.
251 void stopWallClock() { 230 void stopWallClock() {
252 wallClock.stop(); 231 wallClock.stop();
253 } 232 }
254 233
255 /// Call this before returning to the eventloop. 234 /// Call this before returning to the eventloop.
256 void startAsyncWallClock() { 235 void startAsyncWallClock() {
257 if (currentAsyncTask != null) { 236 if (currentAsyncTask != null) {
258 currentAsyncTask.watch.start(); 237 currentAsyncTask._watch.start();
259 } else { 238 } else {
260 asyncWallClock.start(); 239 asyncWallClock.start();
261 } 240 }
262 } 241 }
263 242
264 /// Call this when the eventloop returns control to us. 243 /// Call this when the eventloop returns control to us.
265 void stopAsyncWallClock() { 244 void stopAsyncWallClock() {
266 if (currentAsyncTask != null) { 245 if (currentAsyncTask != null) {
267 currentAsyncTask.watch.stop(); 246 currentAsyncTask._watch.stop();
268 } 247 }
269 asyncWallClock.stop(); 248 asyncWallClock.stop();
270 } 249 }
271 } 250 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698