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

Side by Side Diff: sdk/lib/io/timer_impl.dart

Issue 858973002: - Reduce the amount of messages being sent for Timer.run(). (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: Created 5 years, 11 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
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2013, 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 part of dart.io; 5 part of dart.io;
6 6
7 // Timer heap implemented as a array-based binary heap[0]. 7 // Timer heap implemented as a array-based binary heap[0].
8 // This allows for O(1) `first`, O(log(n)) `remove`/`removeFirst` and O(log(n)) 8 // This allows for O(1) `first`, O(log(n)) `remove`/`removeFirst` and O(log(n))
9 // `add`. 9 // `add`.
10 // 10 //
(...skipping 114 matching lines...) Expand 10 before | Expand all | Expand 10 after
125 static _Timer _lastZeroTimer; 125 static _Timer _lastZeroTimer;
126 126
127 // We use an id to be able to sort timers with the same expiration time. 127 // We use an id to be able to sort timers with the same expiration time.
128 // ids are recycled after ID_MASK enqueues or when the timer queue is empty. 128 // ids are recycled after ID_MASK enqueues or when the timer queue is empty.
129 static int _ID_MASK = 0x1fffffff; 129 static int _ID_MASK = 0x1fffffff;
130 static int _idCount = 0; 130 static int _idCount = 0;
131 131
132 static RawReceivePort _receivePort; 132 static RawReceivePort _receivePort;
133 static SendPort _sendPort; 133 static SendPort _sendPort;
134 static int _scheduledWakeupTime; 134 static int _scheduledWakeupTime;
135 // Keep track whether at least one message is pending in the event loop. This
136 // way we do not have to notify for every pending _firstZeroTimer.
137 static var _messagePending = false;
138
135 static bool _handlingCallbacks = false; 139 static bool _handlingCallbacks = false;
136 140
137 Function _callback; // Closure to call when timer fires. null if canceled. 141 Function _callback; // Closure to call when timer fires. null if canceled.
138 int _wakeupTime; // Expiration time. 142 int _wakeupTime; // Expiration time.
139 int _milliSeconds; // Duration specified at creation. 143 int _milliSeconds; // Duration specified at creation.
140 bool _repeating; // Indicates periodic timers. 144 bool _repeating; // Indicates periodic timers.
141 var _indexOrNext; // Index if part of the TimerHeap, link otherwise. 145 var _indexOrNext; // Index if part of the TimerHeap, link otherwise.
142 int _id; // Incrementing id to enable sorting of timers with same expiry. 146 int _id; // Incrementing id to enable sorting of timers with same expiry.
143 147
144 // Get the next available id. We accept collisions and reordering when the 148 // Get the next available id. We accept collisions and reordering when the
(...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after
248 252
249 253
250 static void _notifyEventHandler() { 254 static void _notifyEventHandler() {
251 if (_handlingCallbacks) { 255 if (_handlingCallbacks) {
252 // While we are already handling callbacks we will not notify the event 256 // While we are already handling callbacks we will not notify the event
253 // handler. _handleTimeout will call _notifyEventHandler once all pending 257 // handler. _handleTimeout will call _notifyEventHandler once all pending
254 // timers are processed. 258 // timers are processed.
255 return; 259 return;
256 } 260 }
257 261
258 if (_firstZeroTimer == null && _heap.isEmpty) { 262 if ((_firstZeroTimer == null) && _heap.isEmpty) {
259 // No pending timers: Close the receive port and let the event handler 263 // No pending timers: Close the receive port and let the event handler
260 // know. 264 // know.
261 if (_receivePort != null) { 265 if (_receivePort != null) {
262 _EventHandler._sendData(null, _sendPort, _NO_TIMER); 266 _EventHandler._sendData(null, _sendPort, _NO_TIMER);
263 _shutdownTimerHandler(); 267 _shutdownTimerHandler();
264 } 268 }
265 } else { 269 } else {
266 if (_receivePort == null) { 270 if (_receivePort == null) {
267 // Create a receive port and register a message handler for the timer 271 // Create a receive port and register a message handler for the timer
268 // events. 272 // events.
269 _createTimerHandler(); 273 _createTimerHandler();
270 } 274 }
271 if (_firstZeroTimer != null) { 275 if (_firstZeroTimer != null) {
272 _sendPort.send(null); 276 if (!_messagePending) {
277 _sendPort.send(null);
278 _messagePending = true; // Reset when the port receives a message.
279 }
273 } else { 280 } else {
274 var wakeupTime = _heap.first._wakeupTime; 281 var wakeupTime = _heap.first._wakeupTime;
275 if ((_scheduledWakeupTime == null) || 282 if ((_scheduledWakeupTime == null) ||
276 (wakeupTime != _scheduledWakeupTime)) { 283 (wakeupTime != _scheduledWakeupTime)) {
277 _EventHandler._sendData(null, _sendPort, wakeupTime); 284 _EventHandler._sendData(null, _sendPort, wakeupTime);
278 _scheduledWakeupTime = wakeupTime; 285 _scheduledWakeupTime = wakeupTime;
279 } 286 }
280 } 287 }
281 } 288 }
282 } 289 }
283 290
284 static void _handleTimeout(pendingImmediateCallback) { 291 static void _handleTimeout(pendingImmediateCallback) {
285 int currentTime = new DateTime.now().millisecondsSinceEpoch; 292 // Fast exit if no timers have been scheduled.
293 if (_heap.isEmpty && (_firstZeroTimer == null)) {
Søren Gjesse 2015/01/20 15:36:27 maybe assert(_receivePort == null)
Ivan Posva 2015/01/20 16:01:17 Done.
294 return;
295 }
296
286 // Collect all pending timers. 297 // Collect all pending timers.
287 var head = null; 298 var head = null;
288 var tail = null; 299 var tail = null;
289 // Keep track of the lowest wakeup times for both the list and heap. If 300 if (_heap.isEmpty) {
290 // the respective queue is empty move its time beyond the current time. 301 // Only immediate timers are scheduled. Take over the whole list as is.
291 var heapTime = _heap.isEmpty ? 302 assert(_firstZeroTimer != null);
292 (currentTime + 1) : _heap.first._wakeupTime; 303 assert(_lastZeroTimer != null);
293 var listTime = (_firstZeroTimer == null) ? 304 head = _firstZeroTimer;
294 (currentTime + 1) : _firstZeroTimer._wakeupTime; 305 tail = _lastZeroTimer;
306 _firstZeroTimer = null;
307 _lastZeroTimer = null;
308 } else {
309 assert(!_heap.isEmpty);
zra 2015/01/20 15:23:34 Why is this assert needed?
Ivan Posva 2015/01/20 16:01:17 It is more of a documentation and making sure the
310 // Keep track of the lowest wakeup times for both the list and heap. If
311 // the respective queue is empty move its time beyond the current time.
312 var currentTime = new DateTime.now().millisecondsSinceEpoch;
313 var heapTime = _heap.first._wakeupTime;
314 var listTime = (_firstZeroTimer == null) ?
315 (currentTime + 1) : _firstZeroTimer._wakeupTime;
zra 2015/01/20 15:23:34 Indentation
Ivan Posva 2015/01/20 16:01:17 Done.
295 316
296 while ((heapTime <= currentTime) || (listTime <= currentTime)) { 317 while ((heapTime <= currentTime) || (listTime <= currentTime)) {
297 var timer; 318 var timer;
298 // Consume the timers in order by removing from heap or list based on 319 // Consume the timers in order by removing from heap or list based on
299 // their wakeup time and update the queue's time. 320 // their wakeup time and update the queue's time.
300 assert((heapTime != listTime) || 321 assert((heapTime != listTime) ||
301 ((_heap.first != null) && (_firstZeroTimer != null))); 322 ((_heap.first != null) && (_firstZeroTimer != null)));
302 if ((heapTime < listTime) || 323 if ((heapTime < listTime) ||
303 ((heapTime == listTime) && 324 ((heapTime == listTime) &&
304 (_heap.first._id < _firstZeroTimer._id))) { 325 (_heap.first._id < _firstZeroTimer._id))) {
305 timer = _heap.removeFirst(); 326 timer = _heap.removeFirst();
306 heapTime = _heap.isEmpty ? (currentTime + 1) : _heap.first._wakeupTime; 327 heapTime = _heap.isEmpty ? (currentTime + 1) : _heap.first._wakeupTime ;
zra 2015/01/20 15:23:34 Long line
Ivan Posva 2015/01/20 16:01:17 Done.
307 } else {
308 timer = _firstZeroTimer;
309 assert(timer._milliSeconds == 0);
310 _firstZeroTimer = timer._indexOrNext;
311 if (_firstZeroTimer == null) {
312 _lastZeroTimer = null;
313 listTime = currentTime + 1;
314 } else { 328 } else {
315 // We want to drain all entries from the list as they should have 329 timer = _firstZeroTimer;
316 // been pending for 0 ms. To prevent issues with current time moving 330 assert(timer._milliSeconds == 0);
317 // we ensure that the listTime does not go beyond current, unless the 331 _firstZeroTimer = timer._indexOrNext;
318 // list is empty. 332 if (_firstZeroTimer == null) {
319 listTime = _firstZeroTimer._wakeupTime; 333 _lastZeroTimer = null;
320 if (listTime > currentTime) { 334 listTime = currentTime + 1;
321 listTime = currentTime; 335 } else {
336 // We want to drain all entries from the list as they should have
337 // been pending for 0 ms. To prevent issues with current time moving
338 // we ensure that the listTime does not go beyond current, unless
339 // the list is empty.
340 listTime = _firstZeroTimer._wakeupTime;
341 if (listTime > currentTime) {
342 listTime = currentTime;
343 }
322 } 344 }
323 } 345 }
324 }
325 346
326 // Append this timer to the pending timer list. 347 // Append this timer to the pending timer list.
327 timer._indexOrNext = null; 348 timer._indexOrNext = null;
328 if (head == null) { 349 if (head == null) {
329 assert(tail == null); 350 assert(tail == null);
330 head = timer; 351 head = timer;
331 tail = timer; 352 tail = timer;
332 } else { 353 } else {
333 tail._indexOrNext = timer; 354 tail._indexOrNext = timer;
334 tail = timer; 355 tail = timer;
356 }
335 } 357 }
336 } 358 }
337 359
338 // No timers queued: Early exit. 360 // No timers queued: Early exit.
339 if (head == null) { 361 if (head == null) {
340 return; 362 return;
341 } 363 }
342 364
343 // If there are no pending timers currently reset the id space before we 365 // If there are no pending timers currently reset the id space before we
344 // have a chance to enqueue new timers. 366 // have a chance to enqueue new timers.
(...skipping 17 matching lines...) Expand all
362 // one of the later timers which will set the callback to 384 // one of the later timers which will set the callback to
363 // null. 385 // null.
364 if (timer._callback != null) { 386 if (timer._callback != null) {
365 var callback = timer._callback; 387 var callback = timer._callback;
366 if (!timer._repeating) { 388 if (!timer._repeating) {
367 // Mark timer as inactive. 389 // Mark timer as inactive.
368 timer._callback = null; 390 timer._callback = null;
369 } 391 }
370 callback(timer); 392 callback(timer);
371 // Re-insert repeating timer if not canceled. 393 // Re-insert repeating timer if not canceled.
372 if (timer._repeating && (timer._callback != null)) { 394 if (timer._repeating && (timer._callback != null)) {
Søren Gjesse 2015/01/20 15:36:26 I know this is not part of the change, but reading
Ivan Posva 2015/01/20 16:01:17 I understand what you mean, but this is as if you
373 timer._advanceWakeupTime(); 395 timer._advanceWakeupTime();
374 timer._addTimerToHeap(); 396 timer._addTimerToHeap();
375 } 397 }
376 // Execute pending micro tasks. 398 // Execute pending micro tasks.
377 pendingImmediateCallback(); 399 pendingImmediateCallback();
378 } 400 }
379 } 401 }
380 } finally { 402 } finally {
381 _handlingCallbacks = false; 403 _handlingCallbacks = false;
382 _notifyEventHandler(); 404 _notifyEventHandler();
383 } 405 }
384 } 406 }
385 407
386 // Creates a receive port and registers an empty handler on that port. Just 408 // Creates a receive port and registers an empty handler on that port. Just
387 // the triggering of the event loop will ensure that timers are executed. 409 // the triggering of the event loop will ensure that timers are executed.
388 static _ignoreMessage(_) => null; 410 static _ignoreMessage(_) {
411 _messagePending = false;
412 }
389 413
390 static void _createTimerHandler() { 414 static void _createTimerHandler() {
391 assert(_receivePort == null); 415 assert(_receivePort == null);
392 _receivePort = new RawReceivePort(_ignoreMessage); 416 _receivePort = new RawReceivePort(_ignoreMessage);
393 _sendPort = _receivePort.sendPort; 417 _sendPort = _receivePort.sendPort;
394 _scheduledWakeupTime = null; 418 _scheduledWakeupTime = null;
419 _messagePending = false;
395 } 420 }
396 421
397 static void _shutdownTimerHandler() { 422 static void _shutdownTimerHandler() {
398 _receivePort.close(); 423 _receivePort.close();
399 _receivePort = null; 424 _receivePort = null;
400 _sendPort = null; 425 _sendPort = null;
401 _scheduledWakeupTime = null; 426 _scheduledWakeupTime = null;
427 _messagePending = false;
402 } 428 }
403 429
404 // The Timer factory registered with the dart:async library by the embedder. 430 // The Timer factory registered with the dart:async library by the embedder.
405 static Timer _factory(int milliSeconds, 431 static Timer _factory(int milliSeconds,
406 void callback(Timer timer), 432 void callback(Timer timer),
407 bool repeating) { 433 bool repeating) {
408 if (repeating) { 434 if (repeating) {
409 return new _Timer.periodic(milliSeconds, callback); 435 return new _Timer.periodic(milliSeconds, callback);
410 } 436 }
411 return new _Timer(milliSeconds, callback); 437 return new _Timer(milliSeconds, callback);
412 } 438 }
413 } 439 }
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698