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

Side by Side Diff: content/browser/memory/memory_coordinator_impl.cc

Issue 2579233002: Merge MemoryCoordinator and MemoryCoordinatorImpl into one class (Closed)
Patch Set: addressed comments Created 4 years 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
OLDNEW
1 // Copyright 2016 The Chromium Authors. All rights reserved. 1 // Copyright 2016 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 "content/browser/memory/memory_coordinator_impl.h" 5 #include "content/browser/memory/memory_coordinator_impl.h"
6 6
7 #include "base/memory/memory_coordinator_client_registry.h"
7 #include "base/metrics/histogram_macros.h" 8 #include "base/metrics/histogram_macros.h"
9 #include "base/process/process_handle.h"
8 #include "base/process/process_metrics.h" 10 #include "base/process/process_metrics.h"
9 #include "base/strings/string_number_conversions.h" 11 #include "base/strings/string_number_conversions.h"
10 #include "base/threading/thread_task_runner_handle.h" 12 #include "base/threading/thread_task_runner_handle.h"
11 #include "base/trace_event/trace_event.h" 13 #include "base/trace_event/trace_event.h"
12 #include "content/browser/memory/memory_monitor.h" 14 #include "content/browser/memory/memory_monitor.h"
13 #include "content/browser/memory/memory_state_updater.h" 15 #include "content/browser/memory/memory_state_updater.h"
16 #include "content/public/browser/content_browser_client.h"
14 #include "content/public/browser/notification_service.h" 17 #include "content/public/browser/notification_service.h"
15 #include "content/public/browser/notification_types.h" 18 #include "content/public/browser/notification_types.h"
16 #include "content/public/browser/render_process_host.h" 19 #include "content/public/browser/render_process_host.h"
17 #include "content/public/browser/render_widget_host.h" 20 #include "content/public/browser/render_widget_host.h"
18 #include "content/public/common/content_features.h" 21 #include "content/public/common/content_features.h"
22 #include "mojo/public/cpp/bindings/binding.h"
19 23
20 namespace content { 24 namespace content {
21 25
22 namespace { 26 namespace {
23 27
24 mojom::MemoryState ToMojomMemoryState(base::MemoryState state) { 28 mojom::MemoryState ToMojomMemoryState(base::MemoryState state) {
25 switch (state) { 29 switch (state) {
26 case base::MemoryState::UNKNOWN: 30 case base::MemoryState::UNKNOWN:
27 return mojom::MemoryState::UNKNOWN; 31 return mojom::MemoryState::UNKNOWN;
28 case base::MemoryState::NORMAL: 32 case base::MemoryState::NORMAL:
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after
88 break; 92 break;
89 } 93 }
90 } else { 94 } else {
91 NOTREACHED(); 95 NOTREACHED();
92 } 96 }
93 #undef RECORD_METRICS 97 #undef RECORD_METRICS
94 } 98 }
95 99
96 } // namespace 100 } // namespace
97 101
102 // The implementation of MemoryCoordinatorHandle. See memory_coordinator.mojom
103 // for the role of this class.
104 class MemoryCoordinatorHandleImpl : public mojom::MemoryCoordinatorHandle {
105 public:
106 MemoryCoordinatorHandleImpl(mojom::MemoryCoordinatorHandleRequest request,
107 MemoryCoordinatorImpl* coordinator,
108 int render_process_id);
109 ~MemoryCoordinatorHandleImpl() override;
110
111 // mojom::MemoryCoordinatorHandle:
112 void AddChild(mojom::ChildMemoryCoordinatorPtr child) override;
113
114 mojom::ChildMemoryCoordinatorPtr& child() { return child_; }
115 mojo::Binding<mojom::MemoryCoordinatorHandle>& binding() { return binding_; }
116
117 private:
118 MemoryCoordinatorImpl* coordinator_;
119 int render_process_id_;
120 mojom::ChildMemoryCoordinatorPtr child_;
121 mojo::Binding<mojom::MemoryCoordinatorHandle> binding_;
122
123 DISALLOW_COPY_AND_ASSIGN(MemoryCoordinatorHandleImpl);
124 };
125
126 MemoryCoordinatorHandleImpl::MemoryCoordinatorHandleImpl(
127 mojom::MemoryCoordinatorHandleRequest request,
128 MemoryCoordinatorImpl* coordinator,
129 int render_process_id)
130 : coordinator_(coordinator),
131 render_process_id_(render_process_id),
132 binding_(this, std::move(request)) {
133 DCHECK(coordinator_);
134 }
135
136 MemoryCoordinatorHandleImpl::~MemoryCoordinatorHandleImpl() {}
137
138 void MemoryCoordinatorHandleImpl::AddChild(
139 mojom::ChildMemoryCoordinatorPtr child) {
140 DCHECK(!child_.is_bound());
141 child_ = std::move(child);
142 coordinator_->OnChildAdded(render_process_id_);
143 }
144
98 // SingletonTraits for MemoryCoordinator. Returns MemoryCoordinatorImpl 145 // SingletonTraits for MemoryCoordinator. Returns MemoryCoordinatorImpl
99 // as an actual instance. 146 // as an actual instance.
100 struct MemoryCoordinatorSingletonTraits 147 struct MemoryCoordinatorImplSingletonTraits
101 : public base::LeakySingletonTraits<MemoryCoordinator> { 148 : public base::LeakySingletonTraits<MemoryCoordinatorImpl> {
102 static MemoryCoordinator* New() { 149 static MemoryCoordinatorImpl* New() {
103 return new MemoryCoordinatorImpl(base::ThreadTaskRunnerHandle::Get(), 150 return new MemoryCoordinatorImpl(base::ThreadTaskRunnerHandle::Get(),
104 CreateMemoryMonitor()); 151 CreateMemoryMonitor());
105 } 152 }
106 }; 153 };
107 154
108 // static 155 // static
109 MemoryCoordinator* MemoryCoordinator::GetInstance() { 156 MemoryCoordinatorImpl* MemoryCoordinatorImpl::GetInstance() {
110 if (!base::FeatureList::IsEnabled(features::kMemoryCoordinator)) 157 if (!base::FeatureList::IsEnabled(features::kMemoryCoordinator))
111 return nullptr; 158 return nullptr;
112 return base::Singleton<MemoryCoordinator, 159 return base::Singleton<MemoryCoordinatorImpl,
113 MemoryCoordinatorSingletonTraits>::get(); 160 MemoryCoordinatorImplSingletonTraits>::get();
114 } 161 }
115 162
116 MemoryCoordinatorImpl::MemoryCoordinatorImpl( 163 MemoryCoordinatorImpl::MemoryCoordinatorImpl(
117 scoped_refptr<base::SingleThreadTaskRunner> task_runner, 164 scoped_refptr<base::SingleThreadTaskRunner> task_runner,
118 std::unique_ptr<MemoryMonitor> memory_monitor) 165 std::unique_ptr<MemoryMonitor> memory_monitor)
119 : memory_monitor_(std::move(memory_monitor)), 166 : delegate_(GetContentClient()->browser()->GetMemoryCoordinatorDelegate()),
167 memory_monitor_(std::move(memory_monitor)),
120 state_updater_(base::MakeUnique<MemoryStateUpdater>(this, task_runner)) { 168 state_updater_(base::MakeUnique<MemoryStateUpdater>(this, task_runner)) {
121 DCHECK(memory_monitor_.get()); 169 DCHECK(memory_monitor_.get());
122 } 170 }
123 171
124 MemoryCoordinatorImpl::~MemoryCoordinatorImpl() {} 172 MemoryCoordinatorImpl::~MemoryCoordinatorImpl() {}
125 173
126 void MemoryCoordinatorImpl::Start() { 174 void MemoryCoordinatorImpl::Start() {
127 DCHECK(CalledOnValidThread()); 175 DCHECK(CalledOnValidThread());
128 DCHECK(last_state_change_.is_null()); 176 DCHECK(last_state_change_.is_null());
129 177
130 notification_registrar_.Add( 178 notification_registrar_.Add(
131 this, NOTIFICATION_RENDER_WIDGET_VISIBILITY_CHANGED, 179 this, NOTIFICATION_RENDER_WIDGET_VISIBILITY_CHANGED,
132 NotificationService::AllBrowserContextsAndSources()); 180 NotificationService::AllBrowserContextsAndSources());
133 last_state_change_ = base::TimeTicks::Now(); 181 last_state_change_ = base::TimeTicks::Now();
134 state_updater_->ScheduleUpdateState(base::TimeDelta()); 182 state_updater_->ScheduleUpdateState(base::TimeDelta());
135 } 183 }
136 184
137 void MemoryCoordinatorImpl::OnChildAdded(int render_process_id) { 185 void MemoryCoordinatorImpl::CreateHandle(
138 // Populate the global state as an initial state of a newly created process. 186 int render_process_id,
139 auto new_state = ToMojomMemoryState(GetGlobalMemoryState()); 187 mojom::MemoryCoordinatorHandleRequest request) {
140 SetChildMemoryState(render_process_id, new_state); 188 std::unique_ptr<MemoryCoordinatorHandleImpl> handle(
189 new MemoryCoordinatorHandleImpl(std::move(request), this,
190 render_process_id));
191 handle->binding().set_connection_error_handler(
192 base::Bind(&MemoryCoordinatorImpl::OnConnectionError,
193 base::Unretained(this), render_process_id));
194 CreateChildInfoMapEntry(render_process_id, std::move(handle));
195 }
196
197 bool MemoryCoordinatorImpl::SetChildMemoryState(int render_process_id,
198 mojom::MemoryState memory_state) {
199 // Can't set an invalid memory state.
200 if (memory_state == mojom::MemoryState::UNKNOWN)
201 return false;
202
203 // Can't send a message to a child that doesn't exist.
204 auto iter = children_.find(render_process_id);
205 if (iter == children_.end())
206 return false;
207
208 // Can't send a message to a child that isn't bound.
209 if (!iter->second.handle->child().is_bound())
210 return false;
211
212 memory_state = OverrideGlobalState(memory_state, iter->second);
213
214 // A nop doesn't need to be sent, but is considered successful.
215 if (iter->second.memory_state == memory_state)
216 return true;
217
218 // Can't suspend the given renderer.
219 if (memory_state == mojom::MemoryState::SUSPENDED &&
220 !CanSuspendRenderer(render_process_id))
221 return false;
222
223 // Update the internal state and send the message.
224 iter->second.memory_state = memory_state;
225 iter->second.handle->child()->OnStateChange(memory_state);
226 return true;
227 }
228
229 mojom::MemoryState MemoryCoordinatorImpl::GetChildMemoryState(
230 int render_process_id) const {
231 auto iter = children_.find(render_process_id);
232 if (iter == children_.end())
233 return mojom::MemoryState::UNKNOWN;
234 return iter->second.memory_state;
235 }
236
237 void MemoryCoordinatorImpl::RecordMemoryPressure(
238 base::MemoryPressureMonitor::MemoryPressureLevel level) {
239 DCHECK(GetGlobalMemoryState() != base::MemoryState::UNKNOWN);
240 int state = static_cast<int>(GetGlobalMemoryState());
241 switch (level) {
242 case base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE:
243 UMA_HISTOGRAM_ENUMERATION(
244 "Memory.Coordinator.StateOnModerateNotificationReceived",
245 state, base::kMemoryStateMax);
246 break;
247 case base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL:
248 UMA_HISTOGRAM_ENUMERATION(
249 "Memory.Coordinator.StateOnCriticalNotificationReceived",
250 state, base::kMemoryStateMax);
251 break;
252 case base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE:
253 NOTREACHED();
254 }
141 } 255 }
142 256
143 base::MemoryState MemoryCoordinatorImpl::GetGlobalMemoryState() const { 257 base::MemoryState MemoryCoordinatorImpl::GetGlobalMemoryState() const {
144 return current_state_; 258 return current_state_;
145 } 259 }
146 260
147 base::MemoryState MemoryCoordinatorImpl::GetCurrentMemoryState() const { 261 base::MemoryState MemoryCoordinatorImpl::GetCurrentMemoryState() const {
148 // SUSPENDED state may not make sense to the browser process. Use THROTTLED 262 // SUSPENDED state may not make sense to the browser process. Use THROTTLED
149 // instead when the global state is SUSPENDED. 263 // instead when the global state is SUSPENDED.
150 // TODO(bashi): Maybe worth considering another state for the browser. 264 // TODO(bashi): Maybe worth considering another state for the browser.
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after
195 TRACE_EVENT2("memory-infra", "MemoryCoordinatorImpl::ChangeStateIfNeeded", 309 TRACE_EVENT2("memory-infra", "MemoryCoordinatorImpl::ChangeStateIfNeeded",
196 "prev", MemoryStateToString(prev_state), 310 "prev", MemoryStateToString(prev_state),
197 "next", MemoryStateToString(next_state)); 311 "next", MemoryStateToString(next_state));
198 RecordStateChange(prev_state, next_state, 312 RecordStateChange(prev_state, next_state,
199 last_state_change_ - prev_last_state_change); 313 last_state_change_ - prev_last_state_change);
200 NotifyStateToClients(); 314 NotifyStateToClients();
201 NotifyStateToChildren(); 315 NotifyStateToChildren();
202 return true; 316 return true;
203 } 317 }
204 318
319 void MemoryCoordinatorImpl::AddChildForTesting(
320 int dummy_render_process_id, mojom::ChildMemoryCoordinatorPtr child) {
321 mojom::MemoryCoordinatorHandlePtr mch;
322 auto request = mojo::GetProxy(&mch);
323 std::unique_ptr<MemoryCoordinatorHandleImpl> handle(
324 new MemoryCoordinatorHandleImpl(std::move(request), this,
325 dummy_render_process_id));
326 handle->AddChild(std::move(child));
327 CreateChildInfoMapEntry(dummy_render_process_id, std::move(handle));
328 }
329
330 void MemoryCoordinatorImpl::OnConnectionError(int render_process_id) {
331 children_.erase(render_process_id);
332 }
333
334 bool MemoryCoordinatorImpl::CanSuspendRenderer(int render_process_id) {
335 // If there is no delegate (i.e. unittests), renderers are always suspendable.
336 if (!delegate_)
337 return true;
338 auto* render_process_host = RenderProcessHost::FromID(render_process_id);
339 if (!render_process_host || !render_process_host->IsProcessBackgrounded())
340 return false;
341 if (render_process_host->GetWorkerRefCount() > 0)
342 return false;
343 return delegate_->CanSuspendBackgroundedRenderer(render_process_id);
344 }
345
346 void MemoryCoordinatorImpl::OnChildAdded(int render_process_id) {
347 // Populate the global state as an initial state of a newly created process.
348 auto new_state = ToMojomMemoryState(GetGlobalMemoryState());
349 SetChildMemoryState(render_process_id, new_state);
350 }
351
352 mojom::MemoryState MemoryCoordinatorImpl::OverrideGlobalState(
353 mojom::MemoryState memory_state,
354 const ChildInfo& child) {
355 // We don't suspend foreground renderers. Throttle them instead.
356 if (child.is_visible && memory_state == mojom::MemoryState::SUSPENDED)
357 return mojom::MemoryState::THROTTLED;
358 #if defined(OS_ANDROID)
359 // On Android, we throttle background renderers immediately.
360 // TODO(bashi): Create a specialized class of MemoryCoordinator for Android
361 // and move this ifdef to the class.
362 if (!child.is_visible && memory_state == mojom::MemoryState::NORMAL)
363 return mojom::MemoryState::THROTTLED;
364 // TODO(bashi): Suspend background renderers after a certain period of time.
365 #endif // defined(OS_ANDROID)
366 return memory_state;
367 }
368
369 void MemoryCoordinatorImpl::SetDelegateForTesting(
370 std::unique_ptr<MemoryCoordinatorDelegate> delegate) {
371 CHECK(!delegate_);
372 delegate_ = std::move(delegate);
373 }
374
375 void MemoryCoordinatorImpl::CreateChildInfoMapEntry(
376 int render_process_id,
377 std::unique_ptr<MemoryCoordinatorHandleImpl> handle) {
378 auto& child_info = children_[render_process_id];
379 // Process always start with normal memory state.
380 // We'll set renderer's memory state to the current global state when the
381 // corresponding renderer process is ready to communicate. Renderer processes
382 // call AddChild() when they are ready.
383 child_info.memory_state = mojom::MemoryState::NORMAL;
384 child_info.is_visible = true;
385 child_info.handle = std::move(handle);
386 }
387
205 void MemoryCoordinatorImpl::NotifyStateToClients() { 388 void MemoryCoordinatorImpl::NotifyStateToClients() {
206 auto state = GetCurrentMemoryState(); 389 auto state = GetCurrentMemoryState();
207 base::MemoryCoordinatorClientRegistry::GetInstance()->Notify(state); 390 base::MemoryCoordinatorClientRegistry::GetInstance()->Notify(state);
208 } 391 }
209 392
210 void MemoryCoordinatorImpl::NotifyStateToChildren() { 393 void MemoryCoordinatorImpl::NotifyStateToChildren() {
211 auto mojo_state = ToMojomMemoryState(current_state_); 394 auto mojo_state = ToMojomMemoryState(current_state_);
212 // It's OK to call SetChildMemoryState() unconditionally because it checks 395 // It's OK to call SetChildMemoryState() unconditionally because it checks
213 // whether this state transition is valid. 396 // whether this state transition is valid.
214 for (auto& iter : children()) 397 for (auto& iter : children())
(...skipping 22 matching lines...) Expand all
237 render_process_host->GetHandle()); 420 render_process_host->GetHandle());
238 metrics->GetWorkingSetKBytes(&working_set); 421 metrics->GetWorkingSetKBytes(&working_set);
239 total_private_kb += working_set.priv; 422 total_private_kb += working_set.priv;
240 } 423 }
241 #endif 424 #endif
242 425
243 RecordMetricsOnStateChange(prev_state, next_state, duration, 426 RecordMetricsOnStateChange(prev_state, next_state, duration,
244 total_private_kb / 1024); 427 total_private_kb / 1024);
245 } 428 }
246 429
430 MemoryCoordinatorImpl::ChildInfo::ChildInfo() {}
431
432 MemoryCoordinatorImpl::ChildInfo::ChildInfo(const ChildInfo& rhs) {
433 // This is a nop, but exists for compatibility with STL containers.
434 }
435
436 MemoryCoordinatorImpl::ChildInfo::~ChildInfo() {}
437
247 } // namespace content 438 } // namespace content
OLDNEW
« no previous file with comments | « content/browser/memory/memory_coordinator_impl.h ('k') | content/browser/memory/memory_coordinator_impl_browsertest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698