OLD | NEW |
---|---|
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/memory/memory_coordinator_client_registry.h" |
8 #include "base/memory/ptr_util.h" | 8 #include "base/memory/ptr_util.h" |
9 #include "base/metrics/histogram_macros.h" | 9 #include "base/metrics/histogram_macros.h" |
10 #include "base/process/process_handle.h" | 10 #include "base/process/process_handle.h" |
(...skipping 148 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
159 } | 159 } |
160 | 160 |
161 // static | 161 // static |
162 MemoryCoordinatorImpl* MemoryCoordinatorImpl::GetInstance() { | 162 MemoryCoordinatorImpl* MemoryCoordinatorImpl::GetInstance() { |
163 if (!base::FeatureList::IsEnabled(features::kMemoryCoordinator)) | 163 if (!base::FeatureList::IsEnabled(features::kMemoryCoordinator)) |
164 return nullptr; | 164 return nullptr; |
165 return base::Singleton<MemoryCoordinatorImpl, | 165 return base::Singleton<MemoryCoordinatorImpl, |
166 MemoryCoordinatorImplSingletonTraits>::get(); | 166 MemoryCoordinatorImplSingletonTraits>::get(); |
167 } | 167 } |
168 | 168 |
169 const int kDefaultMinimumTransitionPeriodSeconds = 30; | |
170 | |
169 MemoryCoordinatorImpl::MemoryCoordinatorImpl( | 171 MemoryCoordinatorImpl::MemoryCoordinatorImpl( |
170 scoped_refptr<base::SingleThreadTaskRunner> task_runner, | 172 scoped_refptr<base::SingleThreadTaskRunner> task_runner, |
171 std::unique_ptr<MemoryMonitor> memory_monitor) | 173 std::unique_ptr<MemoryMonitor> memory_monitor) |
172 : delegate_(GetContentClient()->browser()->GetMemoryCoordinatorDelegate()), | 174 : delegate_(GetContentClient()->browser()->GetMemoryCoordinatorDelegate()), |
173 memory_monitor_(std::move(memory_monitor)), | 175 memory_monitor_(std::move(memory_monitor)), |
174 state_updater_(base::MakeUnique<MemoryStateUpdater>(this, task_runner)) { | 176 state_updater_(base::MakeUnique<MemoryStateUpdater>(this, task_runner)), |
177 minimum_state_transition_period_(base::TimeDelta::FromSeconds( | |
178 kDefaultMinimumTransitionPeriodSeconds)) { | |
175 DCHECK(memory_monitor_.get()); | 179 DCHECK(memory_monitor_.get()); |
176 base::MemoryCoordinatorProxy::SetMemoryCoordinator(this); | 180 base::MemoryCoordinatorProxy::SetMemoryCoordinator(this); |
177 } | 181 } |
178 | 182 |
179 MemoryCoordinatorImpl::~MemoryCoordinatorImpl() {} | 183 MemoryCoordinatorImpl::~MemoryCoordinatorImpl() {} |
180 | 184 |
181 void MemoryCoordinatorImpl::Start() { | 185 void MemoryCoordinatorImpl::Start() { |
182 DCHECK(CalledOnValidThread()); | 186 DCHECK(CalledOnValidThread()); |
183 DCHECK(last_state_change_.is_null()); | 187 DCHECK(last_state_change_.is_null()); |
184 | 188 |
185 notification_registrar_.Add( | 189 notification_registrar_.Add( |
186 this, NOTIFICATION_RENDER_WIDGET_VISIBILITY_CHANGED, | 190 this, NOTIFICATION_RENDER_WIDGET_VISIBILITY_CHANGED, |
187 NotificationService::AllBrowserContextsAndSources()); | 191 NotificationService::AllBrowserContextsAndSources()); |
188 last_state_change_ = base::TimeTicks::Now(); | 192 last_state_change_ = base::TimeTicks::Now(); |
189 state_updater_->ScheduleUpdateState(base::TimeDelta()); | 193 state_updater_->ScheduleUpdateCondition(base::TimeDelta()); |
190 } | 194 } |
191 | 195 |
192 void MemoryCoordinatorImpl::CreateHandle( | 196 void MemoryCoordinatorImpl::CreateHandle( |
193 int render_process_id, | 197 int render_process_id, |
194 mojom::MemoryCoordinatorHandleRequest request) { | 198 mojom::MemoryCoordinatorHandleRequest request) { |
195 std::unique_ptr<MemoryCoordinatorHandleImpl> handle( | 199 std::unique_ptr<MemoryCoordinatorHandleImpl> handle( |
196 new MemoryCoordinatorHandleImpl(std::move(request), this, | 200 new MemoryCoordinatorHandleImpl(std::move(request), this, |
197 render_process_id)); | 201 render_process_id)); |
198 handle->binding().set_connection_error_handler( | 202 handle->binding().set_connection_error_handler( |
199 base::Bind(&MemoryCoordinatorImpl::OnConnectionError, | 203 base::Bind(&MemoryCoordinatorImpl::OnConnectionError, |
200 base::Unretained(this), render_process_id)); | 204 base::Unretained(this), render_process_id)); |
201 CreateChildInfoMapEntry(render_process_id, std::move(handle)); | 205 CreateChildInfoMapEntry(render_process_id, std::move(handle)); |
202 } | 206 } |
203 | 207 |
204 bool MemoryCoordinatorImpl::SetChildMemoryState(int render_process_id, | 208 bool MemoryCoordinatorImpl::SetChildMemoryState(int render_process_id, |
205 MemoryState memory_state) { | 209 MemoryState memory_state) { |
206 // Can't set an invalid memory state. | 210 // Can't set an invalid memory state. |
207 if (memory_state == MemoryState::UNKNOWN) | 211 if (memory_state == MemoryState::UNKNOWN) |
208 return false; | 212 return false; |
209 | 213 |
210 // Can't send a message to a child that doesn't exist. | 214 // Can't send a message to a child that doesn't exist. |
211 auto iter = children_.find(render_process_id); | 215 auto iter = children_.find(render_process_id); |
212 if (iter == children_.end()) | 216 if (iter == children_.end()) |
213 return false; | 217 return false; |
214 | 218 |
215 // Can't send a message to a child that isn't bound. | 219 // Can't send a message to a child that isn't bound. |
216 if (!iter->second.handle->child().is_bound()) | 220 if (!iter->second.handle->child().is_bound()) |
217 return false; | 221 return false; |
218 | 222 |
219 memory_state = OverrideGlobalState(memory_state, iter->second); | 223 memory_state = OverrideState(memory_state, iter->second); |
220 | 224 |
221 // A nop doesn't need to be sent, but is considered successful. | 225 // A nop doesn't need to be sent, but is considered successful. |
222 if (iter->second.memory_state == memory_state) | 226 if (iter->second.memory_state == memory_state) |
223 return true; | 227 return true; |
224 | 228 |
225 // Can't suspend the given renderer. | 229 // Can't suspend the given renderer. |
226 if (memory_state == MemoryState::SUSPENDED && | 230 if (memory_state == MemoryState::SUSPENDED && |
227 !CanSuspendRenderer(render_process_id)) | 231 !CanSuspendRenderer(render_process_id)) |
228 return false; | 232 return false; |
229 | 233 |
234 base::TimeTicks now = base::TimeTicks::Now(); | |
235 // State should remain unchanged for a certain period of time. | |
236 if (now - iter->second.last_state_change < minimum_state_transition_period_) | |
237 return false; | |
238 | |
230 // Update the internal state and send the message. | 239 // Update the internal state and send the message. |
231 iter->second.memory_state = memory_state; | 240 iter->second.memory_state = memory_state; |
241 iter->second.last_state_change = now; | |
232 iter->second.handle->child()->OnStateChange(ToMojomMemoryState(memory_state)); | 242 iter->second.handle->child()->OnStateChange(ToMojomMemoryState(memory_state)); |
233 return true; | 243 return true; |
234 } | 244 } |
235 | 245 |
236 base::MemoryState MemoryCoordinatorImpl::GetChildMemoryState( | 246 base::MemoryState MemoryCoordinatorImpl::GetChildMemoryState( |
237 int render_process_id) const { | 247 int render_process_id) const { |
238 auto iter = children_.find(render_process_id); | 248 auto iter = children_.find(render_process_id); |
239 if (iter == children_.end()) | 249 if (iter == children_.end()) |
240 return base::MemoryState::UNKNOWN; | 250 return base::MemoryState::UNKNOWN; |
241 return iter->second.memory_state; | 251 return iter->second.memory_state; |
242 } | 252 } |
243 | 253 |
244 void MemoryCoordinatorImpl::RecordMemoryPressure( | 254 void MemoryCoordinatorImpl::RecordMemoryPressure( |
245 base::MemoryPressureMonitor::MemoryPressureLevel level) { | 255 base::MemoryPressureMonitor::MemoryPressureLevel level) { |
246 DCHECK(GetGlobalMemoryState() != base::MemoryState::UNKNOWN); | 256 // TODO(bashi): Update metrics. |
247 int state = static_cast<int>(GetGlobalMemoryState()); | 257 int condition = static_cast<int>(GetMemoryCondtion()); |
248 switch (level) { | 258 switch (level) { |
249 case base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE: | 259 case base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE: |
250 UMA_HISTOGRAM_ENUMERATION( | 260 UMA_HISTOGRAM_ENUMERATION( |
251 "Memory.Coordinator.StateOnModerateNotificationReceived", | 261 "Memory.Coordinator.StateOnModerateNotificationReceived", condition, |
252 state, base::kMemoryStateMax); | 262 base::kMemoryStateMax); |
253 break; | 263 break; |
254 case base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL: | 264 case base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL: |
255 UMA_HISTOGRAM_ENUMERATION( | 265 UMA_HISTOGRAM_ENUMERATION( |
256 "Memory.Coordinator.StateOnCriticalNotificationReceived", | 266 "Memory.Coordinator.StateOnCriticalNotificationReceived", condition, |
257 state, base::kMemoryStateMax); | 267 base::kMemoryStateMax); |
258 break; | 268 break; |
259 case base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE: | 269 case base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE: |
260 NOTREACHED(); | 270 NOTREACHED(); |
261 } | 271 } |
262 } | 272 } |
263 | 273 |
264 base::MemoryState MemoryCoordinatorImpl::GetGlobalMemoryState() const { | 274 base::MemoryState MemoryCoordinatorImpl::GetCurrentMemoryState() const { |
265 return current_state_; | 275 return current_state_; |
266 } | 276 } |
267 | 277 |
268 base::MemoryState MemoryCoordinatorImpl::GetCurrentMemoryState() const { | |
269 // SUSPENDED state may not make sense to the browser process. Use THROTTLED | |
270 // instead when the global state is SUSPENDED. | |
271 // TODO(bashi): Maybe worth considering another state for the browser. | |
272 return current_state_ == MemoryState::SUSPENDED ? MemoryState::THROTTLED | |
273 : current_state_; | |
274 } | |
275 | |
276 void MemoryCoordinatorImpl::SetCurrentMemoryStateForTesting( | 278 void MemoryCoordinatorImpl::SetCurrentMemoryStateForTesting( |
277 base::MemoryState memory_state) { | 279 base::MemoryState memory_state) { |
278 // This changes the current state temporariy for testing. The state will be | 280 current_state_ = memory_state; |
279 // updated 1 minute later. | |
280 ForceSetGlobalState(memory_state, base::TimeDelta::FromMinutes(1)); | |
281 } | 281 } |
282 | 282 |
283 void MemoryCoordinatorImpl::ForceSetGlobalState(base::MemoryState new_state, | 283 void MemoryCoordinatorImpl::ForceSetMemoryCondition(MemoryCondition condition, |
284 base::TimeDelta duration) { | 284 base::TimeDelta duration) { |
285 DCHECK(new_state != MemoryState::UNKNOWN); | 285 UpdateConditionIfNeeded(condition); |
286 ChangeStateIfNeeded(current_state_, new_state); | 286 state_updater_->ScheduleUpdateCondition(duration); |
287 state_updater_->ScheduleUpdateState(duration); | |
288 } | 287 } |
289 | 288 |
290 void MemoryCoordinatorImpl::Observe(int type, | 289 void MemoryCoordinatorImpl::Observe(int type, |
291 const NotificationSource& source, | 290 const NotificationSource& source, |
292 const NotificationDetails& details) { | 291 const NotificationDetails& details) { |
bashi
2017/02/27 06:53:58
FYI: This is called when a user switches tabs.
| |
293 DCHECK(type == NOTIFICATION_RENDER_WIDGET_VISIBILITY_CHANGED); | 292 DCHECK(type == NOTIFICATION_RENDER_WIDGET_VISIBILITY_CHANGED); |
294 RenderWidgetHost* render_widget_host = Source<RenderWidgetHost>(source).ptr(); | 293 RenderWidgetHost* render_widget_host = Source<RenderWidgetHost>(source).ptr(); |
295 RenderProcessHost* process = render_widget_host->GetProcess(); | 294 RenderProcessHost* process = render_widget_host->GetProcess(); |
296 if (!process) | 295 if (!process) |
297 return; | 296 return; |
298 auto iter = children().find(process->GetID()); | 297 auto iter = children().find(process->GetID()); |
299 if (iter == children().end()) | 298 if (iter == children().end()) |
300 return; | 299 return; |
301 iter->second.is_visible = *Details<bool>(details).ptr(); | 300 iter->second.is_visible = *Details<bool>(details).ptr(); |
302 auto new_state = GetGlobalMemoryState(); | 301 // TODO(bashi): Tentative. |
302 MemoryState new_state = MemoryState::NORMAL; | |
303 if (!iter->second.is_visible && | |
304 GetMemoryCondtion() != MemoryCondition::NORMAL) | |
305 new_state = MemoryState::THROTTLED; | |
303 SetChildMemoryState(iter->first, new_state); | 306 SetChildMemoryState(iter->first, new_state); |
bashi
2017/02/27 06:53:58
This basically means:
Foregrounded renderers: cha
| |
304 } | 307 } |
305 | 308 |
306 base::MemoryState MemoryCoordinatorImpl::GetStateForProcess( | 309 base::MemoryState MemoryCoordinatorImpl::GetStateForProcess( |
307 base::ProcessHandle handle) { | 310 base::ProcessHandle handle) { |
308 DCHECK(CalledOnValidThread()); | 311 DCHECK(CalledOnValidThread()); |
309 if (handle == base::kNullProcessHandle) | 312 if (handle == base::kNullProcessHandle) |
310 return MemoryState::UNKNOWN; | 313 return MemoryState::UNKNOWN; |
311 if (handle == base::GetCurrentProcessHandle()) | 314 if (handle == base::GetCurrentProcessHandle()) |
312 return GetCurrentMemoryState(); | 315 return current_state_; |
313 | 316 |
314 for (auto& iter : children()) { | 317 for (auto& iter : children()) { |
315 auto* render_process_host = GetRenderProcessHost(iter.first); | 318 auto* render_process_host = GetRenderProcessHost(iter.first); |
316 if (render_process_host && render_process_host->GetHandle() == handle) | 319 if (render_process_host && render_process_host->GetHandle() == handle) |
317 return iter.second.memory_state; | 320 return iter.second.memory_state; |
318 } | 321 } |
319 return MemoryState::UNKNOWN; | 322 return MemoryState::UNKNOWN; |
320 } | 323 } |
321 | 324 |
322 bool MemoryCoordinatorImpl::ChangeStateIfNeeded(base::MemoryState prev_state, | 325 const char* MemoryConditionToString(MemoryCondition condition) { |
323 base::MemoryState next_state) { | 326 switch (condition) { |
327 case MemoryCondition::NORMAL: | |
328 return "normal"; | |
329 case MemoryCondition::WARNING: | |
330 return "warning"; | |
331 case MemoryCondition::CRITICAL: | |
332 return "critical"; | |
333 } | |
334 } | |
335 | |
336 void MemoryCoordinatorImpl::UpdateConditionIfNeeded( | |
337 MemoryCondition next_condition) { | |
324 DCHECK(CalledOnValidThread()); | 338 DCHECK(CalledOnValidThread()); |
325 if (prev_state == next_state) | 339 if (memory_condition_ == next_condition) |
326 return false; | 340 return; |
327 | 341 |
328 base::TimeTicks prev_last_state_change = last_state_change_; | 342 MemoryCondition prev_condition = memory_condition_; |
329 last_state_change_ = base::TimeTicks::Now(); | 343 memory_condition_ = next_condition; |
330 current_state_ = next_state; | |
331 | 344 |
332 TRACE_EVENT2(TRACE_DISABLED_BY_DEFAULT("memory-infra"), | 345 TRACE_EVENT2(TRACE_DISABLED_BY_DEFAULT("memory-infra"), |
333 "MemoryCoordinatorImpl::ChangeStateIfNeeded", "prev", | 346 "MemoryCoordinatorImpl::UpdateConditionIfNeeded", "prev", |
334 MemoryStateToString(prev_state), "next", | 347 MemoryConditionToString(prev_condition), "next", |
335 MemoryStateToString(next_state)); | 348 MemoryConditionToString(next_condition)); |
336 RecordStateChange(prev_state, next_state, | 349 |
bashi
2017/02/27 06:53:58
Most of UMAs recorded here weren't helpful. We wil
| |
337 last_state_change_ - prev_last_state_change); | 350 // TODO(bashi): Record some metrics. |
338 NotifyStateToClients(); | 351 |
339 NotifyStateToChildren(); | 352 // TODO(bashi): Below actions are tentative. We might want to prioritize |
340 return true; | 353 // processes and handle them one-by-one. |
bashi
2017/02/27 06:53:58
I think we need to discuss what we should do here.
| |
354 if (next_condition == MemoryCondition::NORMAL) { | |
355 NotifyStateToChildren(MemoryState::NORMAL); | |
356 UpdateCurrentMemoryState(MemoryState::NORMAL); | |
357 } | |
358 if (prev_condition == MemoryCondition::NORMAL && | |
359 next_condition == MemoryCondition::WARNING) { | |
360 NotifyStateToChildren(MemoryState::THROTTLED); | |
361 // Idea: Purge memory from background processes. | |
362 } | |
363 if (prev_condition != MemoryCondition::CRITICAL && | |
364 next_condition == MemoryCondition::CRITICAL) { | |
365 UpdateCurrentMemoryState(MemoryState::THROTTLED); | |
366 // Idea: Throttle memory allocation in foreground renderers. | |
367 // Idea: Start discarding tabs. | |
368 } | |
369 } | |
370 | |
371 void MemoryCoordinatorImpl::UpdateCurrentMemoryState( | |
372 base::MemoryState memory_state) { | |
373 base::TimeTicks now = base::TimeTicks::Now(); | |
374 if (now - last_state_change_ < minimum_state_transition_period_) | |
375 return; | |
376 last_state_change_ = now; | |
377 current_state_ = memory_state; | |
378 NotifyStateToClients(memory_state); | |
341 } | 379 } |
342 | 380 |
343 void MemoryCoordinatorImpl::DiscardTab() { | 381 void MemoryCoordinatorImpl::DiscardTab() { |
344 if (delegate_) | 382 if (delegate_) |
345 delegate_->DiscardTab(); | 383 delegate_->DiscardTab(); |
346 } | 384 } |
347 | 385 |
348 RenderProcessHost* MemoryCoordinatorImpl::GetRenderProcessHost( | 386 RenderProcessHost* MemoryCoordinatorImpl::GetRenderProcessHost( |
349 int render_process_id) { | 387 int render_process_id) { |
350 return RenderProcessHost::FromID(render_process_id); | 388 return RenderProcessHost::FromID(render_process_id); |
(...skipping 27 matching lines...) Expand all Loading... | |
378 if (render_process_host->GetWorkerRefCount() > 0) | 416 if (render_process_host->GetWorkerRefCount() > 0) |
379 return false; | 417 return false; |
380 // Assumes that we can't suspend renderers if there is no delegate. | 418 // Assumes that we can't suspend renderers if there is no delegate. |
381 if (!delegate_) | 419 if (!delegate_) |
382 return false; | 420 return false; |
383 return delegate_->CanSuspendBackgroundedRenderer(render_process_id); | 421 return delegate_->CanSuspendBackgroundedRenderer(render_process_id); |
384 } | 422 } |
385 | 423 |
386 void MemoryCoordinatorImpl::OnChildAdded(int render_process_id) { | 424 void MemoryCoordinatorImpl::OnChildAdded(int render_process_id) { |
387 // Populate the global state as an initial state of a newly created process. | 425 // Populate the global state as an initial state of a newly created process. |
388 auto new_state = GetGlobalMemoryState(); | 426 auto new_state = GetMemoryCondtion() == MemoryCondition::CRITICAL |
427 ? MemoryState::THROTTLED | |
428 : MemoryState::NORMAL; | |
389 SetChildMemoryState(render_process_id, new_state); | 429 SetChildMemoryState(render_process_id, new_state); |
390 } | 430 } |
391 | 431 |
392 base::MemoryState MemoryCoordinatorImpl::OverrideGlobalState( | 432 base::MemoryState MemoryCoordinatorImpl::OverrideState(MemoryState memory_state, |
393 MemoryState memory_state, | 433 const ChildInfo& child) { |
394 const ChildInfo& child) { | |
395 // We don't suspend foreground renderers. Throttle them instead. | 434 // We don't suspend foreground renderers. Throttle them instead. |
396 if (child.is_visible && memory_state == MemoryState::SUSPENDED) | 435 if (child.is_visible && memory_state == MemoryState::SUSPENDED) |
397 return MemoryState::THROTTLED; | 436 return MemoryState::THROTTLED; |
398 #if defined(OS_ANDROID) | 437 #if defined(OS_ANDROID) |
399 // On Android, we throttle background renderers immediately. | 438 // On Android, we throttle background renderers immediately. |
400 // TODO(bashi): Create a specialized class of MemoryCoordinator for Android | 439 // TODO(bashi): Create a specialized class of MemoryCoordinator for Android |
401 // and move this ifdef to the class. | 440 // and move this ifdef to the class. |
402 if (!child.is_visible && memory_state == MemoryState::NORMAL) | 441 if (!child.is_visible && memory_state == MemoryState::NORMAL) |
403 return MemoryState::THROTTLED; | 442 return MemoryState::THROTTLED; |
404 // TODO(bashi): Suspend background renderers after a certain period of time. | 443 // TODO(bashi): Suspend background renderers after a certain period of time. |
405 #endif // defined(OS_ANDROID) | 444 #endif // defined(OS_ANDROID) |
406 return memory_state; | 445 return memory_state; |
407 } | 446 } |
408 | 447 |
409 void MemoryCoordinatorImpl::CreateChildInfoMapEntry( | 448 void MemoryCoordinatorImpl::CreateChildInfoMapEntry( |
410 int render_process_id, | 449 int render_process_id, |
411 std::unique_ptr<MemoryCoordinatorHandleImpl> handle) { | 450 std::unique_ptr<MemoryCoordinatorHandleImpl> handle) { |
412 auto& child_info = children_[render_process_id]; | 451 auto& child_info = children_[render_process_id]; |
413 // Process always start with normal memory state. | 452 // Process always start with normal memory state. |
414 // We'll set renderer's memory state to the current global state when the | 453 // We'll set renderer's memory state to the current global state when the |
415 // corresponding renderer process is ready to communicate. Renderer processes | 454 // corresponding renderer process is ready to communicate. Renderer processes |
416 // call AddChild() when they are ready. | 455 // call AddChild() when they are ready. |
417 child_info.memory_state = MemoryState::NORMAL; | 456 child_info.memory_state = MemoryState::NORMAL; |
457 child_info.last_state_change = base::TimeTicks::Now(); | |
418 child_info.is_visible = true; | 458 child_info.is_visible = true; |
419 child_info.handle = std::move(handle); | 459 child_info.handle = std::move(handle); |
420 } | 460 } |
421 | 461 |
422 void MemoryCoordinatorImpl::NotifyStateToClients() { | 462 void MemoryCoordinatorImpl::NotifyStateToClients(MemoryState state) { |
423 auto state = GetCurrentMemoryState(); | |
424 base::MemoryCoordinatorClientRegistry::GetInstance()->Notify(state); | 463 base::MemoryCoordinatorClientRegistry::GetInstance()->Notify(state); |
425 } | 464 } |
426 | 465 |
427 void MemoryCoordinatorImpl::NotifyStateToChildren() { | 466 void MemoryCoordinatorImpl::NotifyStateToChildren(MemoryState state) { |
428 // It's OK to call SetChildMemoryState() unconditionally because it checks | 467 // It's OK to call SetChildMemoryState() unconditionally because it checks |
429 // whether this state transition is valid. | 468 // whether this state transition is valid. |
430 for (auto& iter : children()) | 469 for (auto& iter : children()) |
431 SetChildMemoryState(iter.first, current_state_); | 470 SetChildMemoryState(iter.first, state); |
432 } | 471 } |
433 | 472 |
434 void MemoryCoordinatorImpl::RecordStateChange(MemoryState prev_state, | 473 void MemoryCoordinatorImpl::RecordStateChange(MemoryState prev_state, |
435 MemoryState next_state, | 474 MemoryState next_state, |
436 base::TimeDelta duration) { | 475 base::TimeDelta duration) { |
437 size_t total_private_kb = 0; | 476 size_t total_private_kb = 0; |
438 | 477 |
439 // TODO(bashi): On MacOS we can't get process metrics for child processes and | 478 // TODO(bashi): On MacOS we can't get process metrics for child processes and |
440 // therefore can't calculate the total private memory. | 479 // therefore can't calculate the total private memory. |
441 #if !defined(OS_MACOSX) | 480 #if !defined(OS_MACOSX) |
(...skipping 20 matching lines...) Expand all Loading... | |
462 | 501 |
463 MemoryCoordinatorImpl::ChildInfo::ChildInfo() {} | 502 MemoryCoordinatorImpl::ChildInfo::ChildInfo() {} |
464 | 503 |
465 MemoryCoordinatorImpl::ChildInfo::ChildInfo(const ChildInfo& rhs) { | 504 MemoryCoordinatorImpl::ChildInfo::ChildInfo(const ChildInfo& rhs) { |
466 // This is a nop, but exists for compatibility with STL containers. | 505 // This is a nop, but exists for compatibility with STL containers. |
467 } | 506 } |
468 | 507 |
469 MemoryCoordinatorImpl::ChildInfo::~ChildInfo() {} | 508 MemoryCoordinatorImpl::ChildInfo::~ChildInfo() {} |
470 | 509 |
471 } // namespace content | 510 } // namespace content |
OLD | NEW |