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

Side by Side Diff: cc/scheduler/scheduler.cc

Issue 387493002: Fixing and enhancing OrderedSimpleTaskRunner to allow 100% deterministic tests. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Using SizeTToString rather then c++11 to_string. Created 6 years, 4 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 2011 The Chromium Authors. All rights reserved. 1 // Copyright 2011 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "cc/scheduler/scheduler.h" 5 #include "cc/scheduler/scheduler.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 #include "base/auto_reset.h" 8 #include "base/auto_reset.h"
9 #include "base/debug/trace_event.h" 9 #include "base/debug/trace_event.h"
10 #include "base/debug/trace_event_argument.h" 10 #include "base/debug/trace_event_argument.h"
11 #include "base/logging.h" 11 #include "base/logging.h"
12 #include "base/single_thread_task_runner.h" 12 #include "base/single_thread_task_runner.h"
13 #include "cc/debug/devtools_instrumentation.h" 13 #include "cc/debug/devtools_instrumentation.h"
14 #include "cc/debug/traced_value.h" 14 #include "cc/debug/traced_value.h"
15 #include "cc/scheduler/delay_based_time_source.h" 15 #include "cc/scheduler/delay_based_time_source.h"
16 #include "ui/gfx/frame_time.h"
17 16
18 namespace cc { 17 namespace cc {
19 18
20 Scheduler::SyntheticBeginFrameSource::SyntheticBeginFrameSource( 19 Scheduler::SyntheticBeginFrameSource::SyntheticBeginFrameSource(
21 Scheduler* scheduler, 20 Scheduler* scheduler,
22 base::SingleThreadTaskRunner* task_runner) 21 scoped_refptr<DelayBasedTimeSource> time_source)
23 : scheduler_(scheduler) { 22 : scheduler_(scheduler), time_source_(time_source) {
24 if (gfx::FrameTime::TimestampsAreHighRes()) {
25 time_source_ = DelayBasedTimeSourceHighRes::Create(
26 scheduler_->VSyncInterval(), task_runner);
27 } else {
28 time_source_ = DelayBasedTimeSource::Create(scheduler_->VSyncInterval(),
29 task_runner);
30 }
31 time_source_->SetClient(this); 23 time_source_->SetClient(this);
32 } 24 }
33 25
34 Scheduler::SyntheticBeginFrameSource::~SyntheticBeginFrameSource() { 26 Scheduler::SyntheticBeginFrameSource::~SyntheticBeginFrameSource() {
35 } 27 }
36 28
37 void Scheduler::SyntheticBeginFrameSource::CommitVSyncParameters( 29 void Scheduler::SyntheticBeginFrameSource::CommitVSyncParameters(
38 base::TimeTicks timebase, 30 base::TimeTicks timebase,
39 base::TimeDelta interval) { 31 base::TimeDelta interval) {
40 time_source_->SetTimebaseAndInterval(timebase, interval); 32 time_source_->SetTimebaseAndInterval(timebase, interval);
(...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after
119 } 111 }
120 112
121 Scheduler::~Scheduler() { 113 Scheduler::~Scheduler() {
122 if (synthetic_begin_frame_source_) { 114 if (synthetic_begin_frame_source_) {
123 synthetic_begin_frame_source_->SetNeedsBeginFrame(false, 115 synthetic_begin_frame_source_->SetNeedsBeginFrame(false,
124 &begin_retro_frame_args_); 116 &begin_retro_frame_args_);
125 } 117 }
126 } 118 }
127 119
128 void Scheduler::SetupSyntheticBeginFrames() { 120 void Scheduler::SetupSyntheticBeginFrames() {
121 scoped_refptr<DelayBasedTimeSource> time_source;
122 if (gfx::FrameTime::TimestampsAreHighRes()) {
123 time_source = DelayBasedTimeSourceHighRes::Create(VSyncInterval(),
124 impl_task_runner_.get());
125 } else {
126 time_source =
127 DelayBasedTimeSource::Create(VSyncInterval(), impl_task_runner_.get());
128 }
129 DCHECK(!synthetic_begin_frame_source_); 129 DCHECK(!synthetic_begin_frame_source_);
130 synthetic_begin_frame_source_.reset( 130 synthetic_begin_frame_source_.reset(
131 new SyntheticBeginFrameSource(this, impl_task_runner_.get())); 131 new SyntheticBeginFrameSource(this, time_source));
132 }
133
134 base::TimeTicks Scheduler::Now() const {
135 return gfx::FrameTime::Now();
132 } 136 }
133 137
134 void Scheduler::CommitVSyncParameters(base::TimeTicks timebase, 138 void Scheduler::CommitVSyncParameters(base::TimeTicks timebase,
135 base::TimeDelta interval) { 139 base::TimeDelta interval) {
136 // TODO(brianderson): We should not be receiving 0 intervals. 140 // TODO(brianderson): We should not be receiving 0 intervals.
137 if (interval == base::TimeDelta()) 141 if (interval == base::TimeDelta())
138 interval = BeginFrameArgs::DefaultInterval(); 142 interval = BeginFrameArgs::DefaultInterval();
139 vsync_interval_ = interval; 143 vsync_interval_ = interval;
140 if (!settings_.begin_frame_scheduling_enabled) 144 if (!settings_.begin_frame_scheduling_enabled)
141 synthetic_begin_frame_source_->CommitVSyncParameters(timebase, interval); 145 synthetic_begin_frame_source_->CommitVSyncParameters(timebase, interval);
(...skipping 113 matching lines...) Expand 10 before | Expand all | Expand 10 after
255 void Scheduler::NotifyBeginMainFrameStarted() { 259 void Scheduler::NotifyBeginMainFrameStarted() {
256 TRACE_EVENT0("cc", "Scheduler::NotifyBeginMainFrameStarted"); 260 TRACE_EVENT0("cc", "Scheduler::NotifyBeginMainFrameStarted");
257 state_machine_.NotifyBeginMainFrameStarted(); 261 state_machine_.NotifyBeginMainFrameStarted();
258 } 262 }
259 263
260 base::TimeTicks Scheduler::AnticipatedDrawTime() const { 264 base::TimeTicks Scheduler::AnticipatedDrawTime() const {
261 if (!last_set_needs_begin_frame_ || 265 if (!last_set_needs_begin_frame_ ||
262 begin_impl_frame_args_.interval <= base::TimeDelta()) 266 begin_impl_frame_args_.interval <= base::TimeDelta())
263 return base::TimeTicks(); 267 return base::TimeTicks();
264 268
265 base::TimeTicks now = gfx::FrameTime::Now(); 269 base::TimeTicks now = Now();
266 base::TimeTicks timebase = std::max(begin_impl_frame_args_.frame_time, 270 base::TimeTicks timebase = std::max(begin_impl_frame_args_.frame_time,
267 begin_impl_frame_args_.deadline); 271 begin_impl_frame_args_.deadline);
268 int64 intervals = 1 + ((now - timebase) / begin_impl_frame_args_.interval); 272 int64 intervals = 1 + ((now - timebase) / begin_impl_frame_args_.interval);
269 return timebase + (begin_impl_frame_args_.interval * intervals); 273 return timebase + (begin_impl_frame_args_.interval * intervals);
270 } 274 }
271 275
272 base::TimeTicks Scheduler::LastBeginImplFrameTime() { 276 base::TimeTicks Scheduler::LastBeginImplFrameTime() {
273 return begin_impl_frame_args_.frame_time; 277 return begin_impl_frame_args_.frame_time;
274 } 278 }
275 279
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after
330 begin_unthrottled_frame_posted_ = true; 334 begin_unthrottled_frame_posted_ = true;
331 impl_task_runner_->PostTask(FROM_HERE, begin_unthrottled_frame_closure_); 335 impl_task_runner_->PostTask(FROM_HERE, begin_unthrottled_frame_closure_);
332 } 336 }
333 337
334 // BeginUnthrottledFrame is used when we aren't throttling frame production. 338 // BeginUnthrottledFrame is used when we aren't throttling frame production.
335 // This will usually be because VSync is disabled. 339 // This will usually be because VSync is disabled.
336 void Scheduler::BeginUnthrottledFrame() { 340 void Scheduler::BeginUnthrottledFrame() {
337 DCHECK(!settings_.throttle_frame_production); 341 DCHECK(!settings_.throttle_frame_production);
338 DCHECK(begin_retro_frame_args_.empty()); 342 DCHECK(begin_retro_frame_args_.empty());
339 343
340 base::TimeTicks now = gfx::FrameTime::Now(); 344 base::TimeTicks now = Now();
341 base::TimeTicks deadline = now + vsync_interval_; 345 base::TimeTicks deadline = now + vsync_interval_;
342 346
343 BeginFrameArgs begin_frame_args = 347 BeginFrameArgs begin_frame_args =
344 BeginFrameArgs::Create(now, deadline, vsync_interval_); 348 BeginFrameArgs::Create(now, deadline, vsync_interval_);
345 BeginImplFrame(begin_frame_args); 349 BeginImplFrame(begin_frame_args);
346 350
347 begin_unthrottled_frame_posted_ = false; 351 begin_unthrottled_frame_posted_ = false;
348 } 352 }
349 353
350 // We may need to poll when we can't rely on BeginFrame to advance certain 354 // We may need to poll when we can't rely on BeginFrame to advance certain
(...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after
441 if (begin_retro_frame_args_.empty()) 445 if (begin_retro_frame_args_.empty())
442 return; 446 return;
443 447
444 // Discard expired BeginRetroFrames 448 // Discard expired BeginRetroFrames
445 // Today, we should always end up with at most one un-expired BeginRetroFrame 449 // Today, we should always end up with at most one un-expired BeginRetroFrame
446 // because deadlines will not be greater than the next frame time. We don't 450 // because deadlines will not be greater than the next frame time. We don't
447 // DCHECK though because some systems don't always have monotonic timestamps. 451 // DCHECK though because some systems don't always have monotonic timestamps.
448 // TODO(brianderson): In the future, long deadlines could result in us not 452 // TODO(brianderson): In the future, long deadlines could result in us not
449 // draining the queue if we don't catch up. If we consistently can't catch 453 // draining the queue if we don't catch up. If we consistently can't catch
450 // up, our fallback should be to lower our frame rate. 454 // up, our fallback should be to lower our frame rate.
451 base::TimeTicks now = gfx::FrameTime::Now(); 455 base::TimeTicks now = Now();
452 base::TimeDelta draw_duration_estimate = client_->DrawDurationEstimate(); 456 base::TimeDelta draw_duration_estimate = client_->DrawDurationEstimate();
453 while (!begin_retro_frame_args_.empty() && 457 while (!begin_retro_frame_args_.empty() &&
454 now > AdjustedBeginImplFrameDeadline(begin_retro_frame_args_.front(), 458 now > AdjustedBeginImplFrameDeadline(begin_retro_frame_args_.front(),
455 draw_duration_estimate)) { 459 draw_duration_estimate)) {
456 TRACE_EVENT1("cc", 460 TRACE_EVENT1("cc",
457 "Scheduler::BeginRetroFrame discarding", 461 "Scheduler::BeginRetroFrame discarding",
458 "frame_time", 462 "frame_time",
459 begin_retro_frame_args_.front().frame_time); 463 begin_retro_frame_args_.front().frame_time);
460 begin_retro_frame_args_.pop_front(); 464 begin_retro_frame_args_.pop_front();
461 } 465 }
462 466
463 if (begin_retro_frame_args_.empty()) { 467 if (begin_retro_frame_args_.empty()) {
464 DCHECK(settings_.throttle_frame_production); 468 DCHECK(settings_.throttle_frame_production);
465 TRACE_EVENT_INSTANT0("cc", 469 TRACE_EVENT_INSTANT0("cc",
466 "Scheduler::BeginRetroFrames all expired", 470 "Scheduler::BeginRetroFrames all expired",
467 TRACE_EVENT_SCOPE_THREAD); 471 TRACE_EVENT_SCOPE_THREAD);
468 } else { 472 } else {
469 BeginImplFrame(begin_retro_frame_args_.front()); 473 BeginImplFrame(begin_retro_frame_args_.front());
470 begin_retro_frame_args_.pop_front(); 474 begin_retro_frame_args_.pop_front();
471 } 475 }
472 } 476 }
473 477
474 // There could be a race between the posted BeginRetroFrame and a new 478 // There could be a race between the posted BeginRetroFrame and a new
475 // BeginFrame arriving via the normal mechanism. Scheduler::BeginFrame 479 // BeginFrame arriving via the normal mechanism. Scheduler::BeginFrame
476 // will check if there is a pending BeginRetroFrame to ensure we handle 480 // will check if there is a pending BeginRetroFrame to ensure we handle
477 // BeginFrames in FIFO order. 481 // BeginFrames in FIFO order.
478 void Scheduler::PostBeginRetroFrameIfNeeded() { 482 void Scheduler::PostBeginRetroFrameIfNeeded() {
483 TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("cc.debug.scheduler"),
484 "Scheduler::PostBeginRetroFrameIfNeeded",
485 "state",
486 AsValue());
479 if (!last_set_needs_begin_frame_) 487 if (!last_set_needs_begin_frame_)
480 return; 488 return;
481 489
482 if (begin_retro_frame_args_.empty() || begin_retro_frame_posted_) 490 if (begin_retro_frame_args_.empty() || begin_retro_frame_posted_)
483 return; 491 return;
484 492
485 // begin_retro_frame_args_ should always be empty for the 493 // begin_retro_frame_args_ should always be empty for the
486 // synchronous compositor. 494 // synchronous compositor.
487 DCHECK(!settings_.using_synchronous_renderer_compositor); 495 DCHECK(!settings_.using_synchronous_renderer_compositor);
488 496
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after
545 // expected BeginImplFrame start. This allows us to draw immediately when 553 // expected BeginImplFrame start. This allows us to draw immediately when
546 // there is a new active tree, instead of waiting for the next 554 // there is a new active tree, instead of waiting for the next
547 // BeginImplFrame. 555 // BeginImplFrame.
548 // TODO(brianderson): Handle long deadlines (that are past the next frame's 556 // TODO(brianderson): Handle long deadlines (that are past the next frame's
549 // frame time) properly instead of using this hack. 557 // frame time) properly instead of using this hack.
550 return args.frame_time + args.interval; 558 return args.frame_time + args.interval;
551 } 559 }
552 } 560 }
553 561
554 void Scheduler::ScheduleBeginImplFrameDeadline(base::TimeTicks deadline) { 562 void Scheduler::ScheduleBeginImplFrameDeadline(base::TimeTicks deadline) {
563 TRACE_EVENT1(
564 "cc", "Scheduler::ScheduleBeginImplFrameDeadline", "deadline", deadline);
555 if (settings_.using_synchronous_renderer_compositor) { 565 if (settings_.using_synchronous_renderer_compositor) {
556 // The synchronous renderer compositor has to make its GL calls 566 // The synchronous renderer compositor has to make its GL calls
557 // within this call. 567 // within this call.
558 // TODO(brianderson): Have the OutputSurface initiate the deadline tasks 568 // TODO(brianderson): Have the OutputSurface initiate the deadline tasks
559 // so the sychronous renderer compositor can take advantage of splitting 569 // so the sychronous renderer compositor can take advantage of splitting
560 // up the BeginImplFrame and deadline as well. 570 // up the BeginImplFrame and deadline as well.
561 OnBeginImplFrameDeadline(); 571 OnBeginImplFrameDeadline();
562 return; 572 return;
563 } 573 }
564 begin_impl_frame_deadline_task_.Cancel(); 574 begin_impl_frame_deadline_task_.Cancel();
565 begin_impl_frame_deadline_task_.Reset(begin_impl_frame_deadline_closure_); 575 begin_impl_frame_deadline_task_.Reset(begin_impl_frame_deadline_closure_);
566 576
567 base::TimeDelta delta = deadline - gfx::FrameTime::Now(); 577 base::TimeDelta delta = deadline - Now();
568 if (delta <= base::TimeDelta()) 578 if (delta <= base::TimeDelta())
569 delta = base::TimeDelta(); 579 delta = base::TimeDelta();
570 impl_task_runner_->PostDelayedTask( 580 impl_task_runner_->PostDelayedTask(
571 FROM_HERE, begin_impl_frame_deadline_task_.callback(), delta); 581 FROM_HERE, begin_impl_frame_deadline_task_.callback(), delta);
572 } 582 }
573 583
574 void Scheduler::OnBeginImplFrameDeadline() { 584 void Scheduler::OnBeginImplFrameDeadline() {
575 TRACE_EVENT0("cc", "Scheduler::OnBeginImplFrameDeadline"); 585 TRACE_EVENT0("cc", "Scheduler::OnBeginImplFrameDeadline");
576 begin_impl_frame_deadline_task_.Cancel(); 586 begin_impl_frame_deadline_task_.Cancel();
577 587
(...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after
689 state->BeginDictionary("state_machine"); 699 state->BeginDictionary("state_machine");
690 state_machine_.AsValueInto(state); 700 state_machine_.AsValueInto(state);
691 state->EndDictionary(); 701 state->EndDictionary();
692 if (synthetic_begin_frame_source_) { 702 if (synthetic_begin_frame_source_) {
693 state->BeginDictionary("synthetic_begin_frame_source_"); 703 state->BeginDictionary("synthetic_begin_frame_source_");
694 synthetic_begin_frame_source_->AsValueInto(state); 704 synthetic_begin_frame_source_->AsValueInto(state);
695 state->EndDictionary(); 705 state->EndDictionary();
696 } 706 }
697 707
698 state->BeginDictionary("scheduler_state"); 708 state->BeginDictionary("scheduler_state");
699 state->SetDouble( 709 state->SetDouble("time_until_anticipated_draw_time_ms",
700 "time_until_anticipated_draw_time_ms", 710 (AnticipatedDrawTime() - Now()).InMillisecondsF());
701 (AnticipatedDrawTime() - base::TimeTicks::Now()).InMillisecondsF());
brianderson 2014/08/20 20:04:30 It was a bug to call base::TimeTicks::Now() rather
mithro-old 2014/08/21 17:39:18 Acknowledged.
702 state->SetDouble("vsync_interval_ms", vsync_interval_.InMillisecondsF()); 711 state->SetDouble("vsync_interval_ms", vsync_interval_.InMillisecondsF());
703 state->SetDouble("estimated_parent_draw_time_ms", 712 state->SetDouble("estimated_parent_draw_time_ms",
704 estimated_parent_draw_time_.InMillisecondsF()); 713 estimated_parent_draw_time_.InMillisecondsF());
705 state->SetBoolean("last_set_needs_begin_frame_", last_set_needs_begin_frame_); 714 state->SetBoolean("last_set_needs_begin_frame_", last_set_needs_begin_frame_);
706 state->SetBoolean("begin_unthrottled_frame_posted_", 715 state->SetBoolean("begin_unthrottled_frame_posted_",
707 begin_unthrottled_frame_posted_); 716 begin_unthrottled_frame_posted_);
708 state->SetBoolean("begin_retro_frame_posted_", begin_retro_frame_posted_); 717 state->SetBoolean("begin_retro_frame_posted_", begin_retro_frame_posted_);
709 state->SetInteger("begin_retro_frame_args_", begin_retro_frame_args_.size()); 718 state->SetInteger("begin_retro_frame_args_", begin_retro_frame_args_.size());
710 state->SetBoolean("begin_impl_frame_deadline_task_", 719 state->SetBoolean("begin_impl_frame_deadline_task_",
711 !begin_impl_frame_deadline_task_.IsCancelled()); 720 !begin_impl_frame_deadline_task_.IsCancelled());
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
752 } 761 }
753 762
754 bool Scheduler::IsBeginMainFrameSentOrStarted() const { 763 bool Scheduler::IsBeginMainFrameSentOrStarted() const {
755 return (state_machine_.commit_state() == 764 return (state_machine_.commit_state() ==
756 SchedulerStateMachine::COMMIT_STATE_BEGIN_MAIN_FRAME_SENT || 765 SchedulerStateMachine::COMMIT_STATE_BEGIN_MAIN_FRAME_SENT ||
757 state_machine_.commit_state() == 766 state_machine_.commit_state() ==
758 SchedulerStateMachine::COMMIT_STATE_BEGIN_MAIN_FRAME_STARTED); 767 SchedulerStateMachine::COMMIT_STATE_BEGIN_MAIN_FRAME_STARTED);
759 } 768 }
760 769
761 } // namespace cc 770 } // namespace cc
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698