diff options
author | simonhatch@chromium.org <simonhatch@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-05-31 00:04:21 +0000 |
---|---|---|
committer | simonhatch@chromium.org <simonhatch@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-05-31 00:04:21 +0000 |
commit | d36860d7e8eecd9e4e3e44b6a0cbfc1a9b1ac8c6 (patch) | |
tree | 8661c4c3264e274ec718260640fdd746a9e9b150 /content | |
parent | b3a504cdf5f611b4658689958cb8e396b04bf1e7 (diff) | |
download | chromium_src-d36860d7e8eecd9e4e3e44b6a0cbfc1a9b1ac8c6.zip chromium_src-d36860d7e8eecd9e4e3e44b6a0cbfc1a9b1ac8c6.tar.gz chromium_src-d36860d7e8eecd9e4e3e44b6a0cbfc1a9b1ac8c6.tar.bz2 |
Lower the priority of shared workers that aren't associated with the foreground tab.
This should help out less powerful devices in the case where there's a shared worker in another tab and a cpu intensive page in the foreground.
BUG=
TEST=Open a doc, see webworker running, switch tabs and check webworker's priority by outputting contents of /sys/fs/cgroup/cpu/chrome_renderers/background/cgroup.proc on ChromeOS. With an open doc in a background tab, run 720p video (ie. youtube) at fullscreen, should stay fairly smooth.
Committed: https://src.chromium.org/viewvc/chrome?view=rev&revision=199840
Committed: https://src.chromium.org/viewvc/chrome?view=rev&revision=200932
Review URL: https://chromiumcodereview.appspot.com/14137016
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@203272 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'content')
7 files changed, 241 insertions, 3 deletions
diff --git a/content/browser/browser_child_process_host_impl.cc b/content/browser/browser_child_process_host_impl.cc index a4f339c..44cee2e 100644 --- a/content/browser/browser_child_process_host_impl.cc +++ b/content/browser/browser_child_process_host_impl.cc @@ -204,6 +204,10 @@ void BrowserChildProcessHostImpl::ForceShutdown() { child_process_host_->ForceShutdown(); } +void BrowserChildProcessHostImpl::SetBackgrounded(bool backgrounded) { + child_process_->SetProcessBackgrounded(backgrounded); +} + void BrowserChildProcessHostImpl::SetTerminateChildOnShutdown( bool terminate_on_shutdown) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); diff --git a/content/browser/browser_child_process_host_impl.h b/content/browser/browser_child_process_host_impl.h index e3fdcb5..9933ca3 100644 --- a/content/browser/browser_child_process_host_impl.h +++ b/content/browser/browser_child_process_host_impl.h @@ -61,6 +61,9 @@ class CONTENT_EXPORT BrowserChildProcessHostImpl // Removes this host from the host list. Calls ChildProcessHost::ForceShutdown void ForceShutdown(); + // Callers can reduce the BrowserChildProcess' priority. + void SetBackgrounded(bool backgrounded); + // Controls whether the child process should be terminated on browser // shutdown. Default is to always terminate. void SetTerminateChildOnShutdown(bool terminate_on_shutdown); diff --git a/content/browser/loader/resource_dispatcher_host_unittest.cc b/content/browser/loader/resource_dispatcher_host_unittest.cc index 0f887ea9..73fa420 100644 --- a/content/browser/loader/resource_dispatcher_host_unittest.cc +++ b/content/browser/loader/resource_dispatcher_host_unittest.cc @@ -16,6 +16,7 @@ #include "content/browser/child_process_security_policy_impl.h" #include "content/browser/loader/resource_dispatcher_host_impl.h" #include "content/browser/loader/resource_message_filter.h" +#include "content/browser/worker_host/worker_service_impl.h" #include "content/common/child_process_host_impl.h" #include "content/common/resource_messages.h" #include "content/common/view_messages.h" @@ -591,6 +592,9 @@ class ResourceDispatcherHostTest : public testing::Test, if (ResourceDispatcherHostImpl::Get()) ResourceDispatcherHostImpl::Get()->CancelRequestsForContext( browser_context_->GetResourceContext()); + + WorkerServiceImpl::GetInstance()->PerformTeardownForTesting(); + browser_context_.reset(); message_loop_.RunUntilIdle(); } diff --git a/content/browser/worker_host/worker_process_host.cc b/content/browser/worker_host/worker_process_host.cc index c200804..14cf9ea 100644 --- a/content/browser/worker_host/worker_process_host.cc +++ b/content/browser/worker_host/worker_process_host.cc @@ -114,7 +114,8 @@ WorkerProcessHost::WorkerProcessHost( ResourceContext* resource_context, const WorkerStoragePartition& partition) : resource_context_(resource_context), - partition_(partition) { + partition_(partition), + process_launched_(false) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); DCHECK(resource_context_); process_.reset( @@ -318,6 +319,9 @@ bool WorkerProcessHost::FilterMessage(const IPC::Message& message, } void WorkerProcessHost::OnProcessLaunched() { + process_launched_ = true; + + WorkerServiceImpl::GetInstance()->NotifyWorkerProcessCreated(); } bool WorkerProcessHost::OnMessageReceived(const IPC::Message& message) { @@ -538,6 +542,10 @@ void WorkerProcessHost::TerminateWorker(int worker_route_id) { Send(new WorkerMsg_TerminateWorkerContext(worker_route_id)); } +void WorkerProcessHost::SetBackgrounded(bool backgrounded) { + process_->SetBackgrounded(backgrounded); +} + const ChildProcessData& WorkerProcessHost::GetData() { return process_->GetData(); } diff --git a/content/browser/worker_host/worker_process_host.h b/content/browser/worker_host/worker_process_host.h index dd1d58f..4a86b86 100644 --- a/content/browser/worker_host/worker_process_host.h +++ b/content/browser/worker_host/worker_process_host.h @@ -158,6 +158,9 @@ class WorkerProcessHost : public BrowserChildProcessHostDelegate, // Terminates the given worker, i.e. based on a UI action. CONTENT_EXPORT void TerminateWorker(int worker_route_id); + // Callers can reduce the WorkerProcess' priority. + void SetBackgrounded(bool backgrounded); + CONTENT_EXPORT const ChildProcessData& GetData(); typedef std::list<WorkerInstance> Instances; @@ -167,6 +170,8 @@ class WorkerProcessHost : public BrowserChildProcessHostDelegate, return resource_context_; } + bool process_launched() const { return process_launched_; } + protected: friend class WorkerServiceImpl; @@ -221,6 +226,7 @@ class WorkerProcessHost : public BrowserChildProcessHostDelegate, scoped_refptr<WorkerMessageFilter> worker_message_filter_; scoped_ptr<BrowserChildProcessHostImpl> process_; + bool process_launched_; DISALLOW_COPY_AND_ASSIGN(WorkerProcessHost); }; diff --git a/content/browser/worker_host/worker_service_impl.cc b/content/browser/worker_host/worker_service_impl.cc index 703b31f..bd6a19d 100644 --- a/content/browser/worker_host/worker_service_impl.cc +++ b/content/browser/worker_host/worker_service_impl.cc @@ -10,12 +10,20 @@ #include "base/logging.h" #include "base/threading/thread.h" #include "content/browser/devtools/worker_devtools_manager.h" +#include "content/browser/renderer_host/render_widget_host_impl.h" #include "content/browser/worker_host/worker_message_filter.h" #include "content/browser/worker_host/worker_process_host.h" #include "content/common/view_messages.h" #include "content/common/worker_messages.h" #include "content/public/browser/child_process_data.h" +#include "content/public/browser/notification_service.h" +#include "content/public/browser/notification_types.h" +#include "content/public/browser/render_process_host.h" +#include "content/public/browser/render_view_host.h" +#include "content/public/browser/render_widget_host.h" +#include "content/public/browser/render_widget_host_view.h" #include "content/public/browser/resource_context.h" +#include "content/public/browser/web_contents.h" #include "content/public/browser/worker_service_observer.h" #include "content/public/common/content_switches.h" #include "content/public/common/process_type.h" @@ -25,6 +33,192 @@ namespace content { const int WorkerServiceImpl::kMaxWorkersWhenSeparate = 64; const int WorkerServiceImpl::kMaxWorkersPerTabWhenSeparate = 16; +class WorkerPrioritySetter + : public NotificationObserver, + public base::RefCountedThreadSafe<WorkerPrioritySetter, + BrowserThread::DeleteOnUIThread> { + public: + WorkerPrioritySetter(); + + // Posts a task to the UI thread to register to receive notifications. + void Initialize(); + + // Invoked by WorkerServiceImpl when a worker process is created. + void NotifyWorkerProcessCreated(); + + private: + friend class base::RefCountedThreadSafe<WorkerPrioritySetter>; + friend struct BrowserThread::DeleteOnThread<BrowserThread::UI>; + friend class base::DeleteHelper<WorkerPrioritySetter>; + virtual ~WorkerPrioritySetter(); + + // Posts a task to perform a worker priority update. + void PostTaskToGatherAndUpdateWorkerPriorities(); + + // Gathers up a list of the visible tabs and then updates priorities for + // all the shared workers. + void GatherVisibleIDsAndUpdateWorkerPriorities(); + + // Registers as an observer to receive notifications about + // widgets being shown. + void RegisterObserver(); + + // Sets priorities for shared workers given a set of visible tabs (as a + // std::set of std::pair<render_process, render_view> ids. + void UpdateWorkerPrioritiesFromVisibleSet( + const std::set<std::pair<int, int> >* visible); + + // Called to refresh worker priorities when focus changes between tabs. + void OnRenderWidgetVisibilityChanged(std::pair<int, int>); + + // NotificationObserver implementation. + virtual void Observe(int type, + const NotificationSource& source, + const NotificationDetails& details) OVERRIDE; + + NotificationRegistrar registrar_; +}; + +WorkerPrioritySetter::WorkerPrioritySetter() { +} + +WorkerPrioritySetter::~WorkerPrioritySetter() { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); +} + +void WorkerPrioritySetter::Initialize() { + BrowserThread::PostTask( + BrowserThread::UI, FROM_HERE, + base::Bind(&WorkerPrioritySetter::RegisterObserver, this)); +} + +void WorkerPrioritySetter::NotifyWorkerProcessCreated() { + PostTaskToGatherAndUpdateWorkerPriorities(); +} + +void WorkerPrioritySetter::PostTaskToGatherAndUpdateWorkerPriorities() { + BrowserThread::PostTask( + BrowserThread::UI, FROM_HERE, + base::Bind( + &WorkerPrioritySetter::GatherVisibleIDsAndUpdateWorkerPriorities, + this)); +} + +void WorkerPrioritySetter::GatherVisibleIDsAndUpdateWorkerPriorities() { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + std::set<std::pair<int, int> >* visible_renderer_ids = + new std::set<std::pair<int, int> >(); + + // Gather up all the visible renderer process/view pairs + for (RenderProcessHost::iterator it = + RenderProcessHost::AllHostsIterator(); + !it.IsAtEnd(); it.Advance()) { + RenderProcessHost* render_process_host = it.GetCurrentValue(); + if (render_process_host->VisibleWidgetCount()) { + for (RenderProcessHost::RenderWidgetHostsIterator rit = + render_process_host->GetRenderWidgetHostsIterator(); !rit.IsAtEnd(); + rit.Advance()) { + RenderWidgetHost* render_widget = + render_process_host->GetRenderWidgetHostByID(rit.GetCurrentKey()); + if (render_widget) { + RenderWidgetHostView* render_view = render_widget->GetView(); + if (render_view && render_view->IsShowing()) { + visible_renderer_ids->insert( + std::pair<int, int>(render_process_host->GetID(), + render_widget->GetRoutingID())); + } + } + } + } + } + + BrowserThread::PostTask( + BrowserThread::IO, FROM_HERE, + base::Bind(&WorkerPrioritySetter::UpdateWorkerPrioritiesFromVisibleSet, + this, base::Owned(visible_renderer_ids))); +} + +void WorkerPrioritySetter::UpdateWorkerPrioritiesFromVisibleSet( + const std::set<std::pair<int, int> >* visible_renderer_ids) { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); + + for (WorkerProcessHostIterator iter; !iter.Done(); ++iter) { + if (!iter->process_launched()) + continue; + bool throttle = true; + + for (WorkerProcessHost::Instances::const_iterator instance = + iter->instances().begin(); instance != iter->instances().end(); + ++instance) { + + // This code assumes one worker per process + WorkerProcessHost::Instances::const_iterator first_instance = + iter->instances().begin(); + if (first_instance == iter->instances().end()) + continue; + + WorkerDocumentSet::DocumentInfoSet::const_iterator info = + first_instance->worker_document_set()->documents().begin(); + + for (; info != first_instance->worker_document_set()->documents().end(); + ++info) { + std::pair<int, int> id( + info->render_process_id(), info->render_view_id()); + if (visible_renderer_ids->find(id) != visible_renderer_ids->end()) { + throttle = false; + break; + } + } + + if (!throttle ) { + break; + } + } + + iter->SetBackgrounded(throttle); + } +} + +void WorkerPrioritySetter::OnRenderWidgetVisibilityChanged( + std::pair<int, int> id) { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); + std::set<std::pair<int, int> > visible_renderer_ids; + + visible_renderer_ids.insert(id); + + UpdateWorkerPrioritiesFromVisibleSet(&visible_renderer_ids); +} + +void WorkerPrioritySetter::RegisterObserver() { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + registrar_.Add(this, NOTIFICATION_RENDER_WIDGET_VISIBILITY_CHANGED, + NotificationService::AllBrowserContextsAndSources()); + registrar_.Add(this, NOTIFICATION_RENDERER_PROCESS_CREATED, + NotificationService::AllBrowserContextsAndSources()); +} + +void WorkerPrioritySetter::Observe(int type, + const NotificationSource& source, const NotificationDetails& details) { + if (type == NOTIFICATION_RENDER_WIDGET_VISIBILITY_CHANGED) { + bool visible = *Details<bool>(details).ptr(); + + if (visible) { + int render_widget_id = + Source<RenderWidgetHost>(source).ptr()->GetRoutingID(); + int render_process_pid = + Source<RenderWidgetHost>(source).ptr()->GetProcess()->GetID(); + + BrowserThread::PostTask( + BrowserThread::IO, FROM_HERE, + base::Bind(&WorkerPrioritySetter::OnRenderWidgetVisibilityChanged, + this, std::pair<int, int>(render_process_pid, render_widget_id))); + } + } + else if (type == NOTIFICATION_RENDERER_PROCESS_CREATED) { + PostTaskToGatherAndUpdateWorkerPriorities(); + } +} + WorkerService* WorkerService::GetInstance() { return WorkerServiceImpl::GetInstance(); } @@ -34,7 +228,10 @@ WorkerServiceImpl* WorkerServiceImpl::GetInstance() { return Singleton<WorkerServiceImpl>::get(); } -WorkerServiceImpl::WorkerServiceImpl() : next_worker_route_id_(0) { +WorkerServiceImpl::WorkerServiceImpl() + : priority_setter_(new WorkerPrioritySetter()), + next_worker_route_id_(0) { + priority_setter_->Initialize(); } WorkerServiceImpl::~WorkerServiceImpl() { @@ -42,6 +239,10 @@ WorkerServiceImpl::~WorkerServiceImpl() { // gone already. } +void WorkerServiceImpl::PerformTeardownForTesting() { + priority_setter_ = NULL; +} + void WorkerServiceImpl::OnWorkerMessageFilterClosing( WorkerMessageFilter* filter) { for (WorkerProcessHostIterator iter; !iter.Done(); ++iter) { @@ -457,6 +658,10 @@ void WorkerServiceImpl::NotifyWorkerDestroyed( WorkerDestroyed(process->GetData().id, worker_route_id)); } +void WorkerServiceImpl::NotifyWorkerProcessCreated() { + priority_setter_->NotifyWorkerProcessCreated(); +} + WorkerProcessHost::WorkerInstance* WorkerServiceImpl::FindSharedWorkerInstance( const GURL& url, const string16& name, diff --git a/content/browser/worker_host/worker_service_impl.h b/content/browser/worker_host/worker_service_impl.h index 845f433..a81d134 100644 --- a/content/browser/worker_host/worker_service_impl.h +++ b/content/browser/worker_host/worker_service_impl.h @@ -11,6 +11,7 @@ #include "base/observer_list.h" #include "base/threading/non_thread_safe.h" #include "content/browser/worker_host/worker_process_host.h" +#include "content/public/browser/notification_observer.h" #include "content/public/browser/notification_registrar.h" #include "content/public/browser/worker_service.h" @@ -21,6 +22,7 @@ namespace content { class ResourceContext; class WorkerServiceObserver; class WorkerStoragePartition; +class WorkerPrioritySetter; class CONTENT_EXPORT WorkerServiceImpl : public NON_EXPORTED_BASE(WorkerService) { @@ -28,6 +30,9 @@ class CONTENT_EXPORT WorkerServiceImpl // Returns the WorkerServiceImpl singleton. static WorkerServiceImpl* GetInstance(); + // Releases the priority setter to avoid memory leak error. + void PerformTeardownForTesting(); + // WorkerService implementation: virtual bool TerminateWorker(int process_id, int route_id) OVERRIDE; virtual std::vector<WorkerInfo> GetWorkers() OVERRIDE; @@ -72,6 +77,8 @@ class CONTENT_EXPORT WorkerServiceImpl WorkerProcessHost* process, int worker_route_id); + void NotifyWorkerProcessCreated(); + // Used when we run each worker in a separate process. static const int kMaxWorkersWhenSeparate; static const int kMaxWorkersPerTabWhenSeparate; @@ -122,7 +129,8 @@ class CONTENT_EXPORT WorkerServiceImpl const WorkerStoragePartition& worker_partition, ResourceContext* resource_context); - NotificationRegistrar registrar_; + scoped_refptr<WorkerPrioritySetter> priority_setter_; + int next_worker_route_id_; WorkerProcessHost::Instances queued_workers_; |