summaryrefslogtreecommitdiffstats
path: root/content
diff options
context:
space:
mode:
authorsimonhatch@chromium.org <simonhatch@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-05-31 00:04:21 +0000
committersimonhatch@chromium.org <simonhatch@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-05-31 00:04:21 +0000
commitd36860d7e8eecd9e4e3e44b6a0cbfc1a9b1ac8c6 (patch)
tree8661c4c3264e274ec718260640fdd746a9e9b150 /content
parentb3a504cdf5f611b4658689958cb8e396b04bf1e7 (diff)
downloadchromium_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')
-rw-r--r--content/browser/browser_child_process_host_impl.cc4
-rw-r--r--content/browser/browser_child_process_host_impl.h3
-rw-r--r--content/browser/loader/resource_dispatcher_host_unittest.cc4
-rw-r--r--content/browser/worker_host/worker_process_host.cc10
-rw-r--r--content/browser/worker_host/worker_process_host.h6
-rw-r--r--content/browser/worker_host/worker_service_impl.cc207
-rw-r--r--content/browser/worker_host/worker_service_impl.h10
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_;