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

Unified Diff: content/common/gpu/gpu_channel.cc

Issue 12340118: GPU: Only allow the UI channel to preempt if all stubs are scheduled. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Address reviewer comments. Created 7 years, 10 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « content/common/gpu/gpu_channel.h ('k') | content/common/gpu/gpu_command_buffer_stub.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: content/common/gpu/gpu_channel.cc
diff --git a/content/common/gpu/gpu_channel.cc b/content/common/gpu/gpu_channel.cc
index c07d15ffc7a03ef590351dc6648a1aaab3444032..d2efa2b3cd3151622e05f450f0855c564bc6038a 100644
--- a/content/common/gpu/gpu_channel.cc
+++ b/content/common/gpu/gpu_channel.cc
@@ -157,7 +157,8 @@ class SyncPointMessageFilter : public IPC::ChannelProxy::MessageFilter {
channel_(NULL),
sync_point_manager_(sync_point_manager),
message_loop_(message_loop),
- messages_received_(0) {
+ messages_received_(0),
+ a_stub_is_descheduled_(false) {
}
virtual void OnFilterAdded(IPC::Channel* channel) OVERRIDE {
@@ -207,8 +208,16 @@ class SyncPointMessageFilter : public IPC::ChannelProxy::MessageFilter {
UpdatePreemptionState();
}
- void SetPreemptingFlag(gpu::PreemptionFlag* preempting_flag) {
+ void SetPreemptingFlagAndSchedulingState(
+ gpu::PreemptionFlag* preempting_flag,
+ bool a_stub_is_descheduled) {
preempting_flag_ = preempting_flag;
+ a_stub_is_descheduled_ = a_stub_is_descheduled;
+ }
+
+ void UpdateStubSchedulingState(bool a_stub_is_descheduled) {
+ a_stub_is_descheduled_ = a_stub_is_descheduled;
+ UpdatePreemptionState();
}
protected:
@@ -228,12 +237,18 @@ class SyncPointMessageFilter : public IPC::ChannelProxy::MessageFilter {
// We can preempt whenever any IPC processing takes more than
// kPreemptWaitTimeMs.
CHECKING,
- // We are currently preempting.
+ // We are currently preempting (i.e. no stub is descheduled).
PREEMPTING,
+ // We would like to preempt, but some stub is descheduled.
+ WOULD_PREEMPT_DESCHEDULED,
};
PreemptionState preemption_state_;
+ // Maximum amount of time that we can spend in PREEMPTING.
+ // It is reset when we transition to IDLE.
+ base::TimeDelta max_preemption_time_;
+
struct PendingMessage {
uint64 message_number;
base::TimeTicks time_received;
@@ -266,27 +281,50 @@ class SyncPointMessageFilter : public IPC::ChannelProxy::MessageFilter {
time_elapsed,
this, &SyncPointMessageFilter::UpdatePreemptionState);
} else {
- TransitionToPreempting();
+ if (a_stub_is_descheduled_)
+ TransitionToWouldPreemptDescheduled();
+ else
+ TransitionToPreempting();
}
}
break;
case PREEMPTING:
- if (pending_messages_.empty()) {
- TransitionToIdle();
- } else {
- base::TimeDelta time_elapsed =
- base::TimeTicks::Now() - pending_messages_.front().time_received;
- if (time_elapsed.InMilliseconds() < kStopPreemptThresholdMs)
- TransitionToIdle();
- }
+ // A TransitionToIdle() timer should always be running in this state.
+ DCHECK(timer_.IsRunning());
+ if (a_stub_is_descheduled_)
+ TransitionToWouldPreemptDescheduled();
+ else
+ TransitionToIdleIfCaughtUp();
+ break;
+ case WOULD_PREEMPT_DESCHEDULED:
+ // A TransitionToIdle() timer should never be running in this state.
+ DCHECK(!timer_.IsRunning());
+ if (!a_stub_is_descheduled_)
+ TransitionToPreempting();
+ else
+ TransitionToIdleIfCaughtUp();
break;
default:
NOTREACHED();
}
}
+ void TransitionToIdleIfCaughtUp() {
+ DCHECK(preemption_state_ == PREEMPTING ||
+ preemption_state_ == WOULD_PREEMPT_DESCHEDULED);
+ if (pending_messages_.empty()) {
+ TransitionToIdle();
+ } else {
+ base::TimeDelta time_elapsed =
+ base::TimeTicks::Now() - pending_messages_.front().time_received;
+ if (time_elapsed.InMilliseconds() < kStopPreemptThresholdMs)
+ TransitionToIdle();
+ }
+ }
+
void TransitionToIdle() {
- DCHECK_EQ(preemption_state_, PREEMPTING);
+ DCHECK(preemption_state_ == PREEMPTING ||
+ preemption_state_ == WOULD_PREEMPT_DESCHEDULED);
// Stop any outstanding timer set to force us from PREEMPTING to IDLE.
timer_.Stop();
@@ -313,15 +351,19 @@ class SyncPointMessageFilter : public IPC::ChannelProxy::MessageFilter {
DCHECK(!timer_.IsRunning());
preemption_state_ = CHECKING;
+ max_preemption_time_ = base::TimeDelta::FromMilliseconds(kMaxPreemptTimeMs);
UpdatePreemptionState();
}
void TransitionToPreempting() {
- DCHECK_EQ(preemption_state_, CHECKING);
+ DCHECK(preemption_state_ == CHECKING ||
+ preemption_state_ == WOULD_PREEMPT_DESCHEDULED);
+ DCHECK(!a_stub_is_descheduled_);
// Stop any pending state update checks that we may have queued
// while CHECKING.
- timer_.Stop();
+ if (preemption_state_ == CHECKING)
+ timer_.Stop();
preemption_state_ = PREEMPTING;
preempting_flag_->Set();
@@ -329,12 +371,39 @@ class SyncPointMessageFilter : public IPC::ChannelProxy::MessageFilter {
timer_.Start(
FROM_HERE,
- base::TimeDelta::FromMilliseconds(kMaxPreemptTimeMs),
+ max_preemption_time_,
this, &SyncPointMessageFilter::TransitionToIdle);
UpdatePreemptionState();
}
+ void TransitionToWouldPreemptDescheduled() {
+ DCHECK(preemption_state_ == CHECKING ||
+ preemption_state_ == PREEMPTING);
+ DCHECK(a_stub_is_descheduled_);
+
+ if (preemption_state_ == CHECKING) {
+ // Stop any pending state update checks that we may have queued
+ // while CHECKING.
+ timer_.Stop();
+ } else {
+ // Stop any TransitionToIdle() timers that we may have queued
+ // while PREEMPTING.
+ timer_.Stop();
+ max_preemption_time_ = timer_.desired_run_time() - base::TimeTicks::Now();
+ if (max_preemption_time_ < base::TimeDelta()) {
+ TransitionToIdle();
+ return;
+ }
+ }
+
+ preemption_state_ = WOULD_PREEMPT_DESCHEDULED;
+ preempting_flag_->Reset();
+ TRACE_COUNTER_ID1("gpu", "GpuChannel::Preempting", this, 0);
+
+ UpdatePreemptionState();
+ }
+
static void InsertSyncPointOnMainThread(
base::WeakPtr<GpuChannel>* gpu_channel,
scoped_refptr<SyncPointManager> manager,
@@ -380,6 +449,8 @@ class SyncPointMessageFilter : public IPC::ChannelProxy::MessageFilter {
uint64 messages_received_;
base::OneShotTimer<SyncPointMessageFilter> timer_;
+
+ bool a_stub_is_descheduled_;
};
GpuChannel::GpuChannel(GpuChannelManager* gpu_channel_manager,
@@ -399,7 +470,8 @@ GpuChannel::GpuChannel(GpuChannelManager* gpu_channel_manager,
handle_messages_scheduled_(false),
processed_get_state_fast_(false),
currently_processing_message_(NULL),
- weak_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)) {
+ weak_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)),
+ num_stubs_descheduled_(0) {
DCHECK(gpu_channel_manager);
DCHECK(client_id);
@@ -545,6 +617,27 @@ void GpuChannel::OnScheduled() {
handle_messages_scheduled_ = true;
}
+void GpuChannel::StubSchedulingChanged(bool scheduled) {
+ bool a_stub_was_descheduled = num_stubs_descheduled_ > 0;
+ if (scheduled) {
+ num_stubs_descheduled_--;
+ OnScheduled();
+ } else {
+ num_stubs_descheduled_++;
+ }
+ DCHECK_LE(num_stubs_descheduled_, stubs_.size());
+ bool a_stub_is_descheduled = num_stubs_descheduled_ > 0;
+
+ if (a_stub_is_descheduled != a_stub_was_descheduled) {
+ if (preempting_flag_.get()) {
+ io_message_loop_->PostTask(
+ FROM_HERE,
+ base::Bind(&SyncPointMessageFilter::UpdateStubSchedulingState,
+ filter_, a_stub_is_descheduled));
+ }
+ }
+}
+
void GpuChannel::CreateViewCommandBuffer(
const gfx::GLSurfaceHandle& window,
int32 surface_id,
@@ -649,8 +742,8 @@ gpu::PreemptionFlag* GpuChannel::GetPreemptionFlag() {
preempting_flag_ = new gpu::PreemptionFlag;
io_message_loop_->PostTask(
FROM_HERE,
- base::Bind(&SyncPointMessageFilter::SetPreemptingFlag,
- filter_, preempting_flag_));
+ base::Bind(&SyncPointMessageFilter::SetPreemptingFlagAndSchedulingState,
+ filter_, preempting_flag_, num_stubs_descheduled_ > 0));
}
return preempting_flag_.get();
}
@@ -799,8 +892,12 @@ void GpuChannel::OnDestroyCommandBuffer(int32 route_id) {
stubs_.Remove(route_id);
// In case the renderer is currently blocked waiting for a sync reply from
// the stub, we need to make sure to reschedule the GpuChannel here.
- if (need_reschedule)
+ if (need_reschedule) {
OnScheduled();
piman 2013/02/28 22:27:48 nit: this will be called from StubsSchedulingChang
jonathan.backer 2013/03/01 00:42:34 Done.
+ // This stub won't get a chance to reschedule, so update the count
+ // now.
+ StubSchedulingChanged(true);
+ }
}
}
« no previous file with comments | « content/common/gpu/gpu_channel.h ('k') | content/common/gpu/gpu_command_buffer_stub.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698