Chromium Code Reviews| Index: content/browser/memory/memory_coordinator_impl.cc |
| diff --git a/content/browser/memory/memory_coordinator_impl.cc b/content/browser/memory/memory_coordinator_impl.cc |
| index 776ce283100a477c4979ead20a61df487522134a..a5255b5edca7562349d4e64e4d636d057b6994d8 100644 |
| --- a/content/browser/memory/memory_coordinator_impl.cc |
| +++ b/content/browser/memory/memory_coordinator_impl.cc |
| @@ -76,6 +76,7 @@ MemoryCoordinatorImpl::MemoryCoordinatorImpl( |
| std::unique_ptr<MemoryMonitor> memory_monitor) |
| : task_runner_(task_runner), |
| memory_monitor_(std::move(memory_monitor)), |
| + remaining_global_budget_mb_(0), |
| weak_ptr_factory_(this) { |
| DCHECK(memory_monitor_.get()); |
| update_state_callback_ = base::Bind(&MemoryCoordinatorImpl::UpdateState, |
| @@ -132,6 +133,10 @@ void MemoryCoordinatorImpl::SetCurrentMemoryStateForTesting( |
| } |
| } |
| +int64_t MemoryCoordinatorImpl::GetRemainingGlobalBudget() const { |
| + return remaining_global_budget_mb_; |
| +} |
| + |
| void MemoryCoordinatorImpl::Observe(int type, |
| const NotificationSource& source, |
| const NotificationDetails& details) { |
| @@ -150,15 +155,18 @@ void MemoryCoordinatorImpl::Observe(int type, |
| SetMemoryState(iter->first, new_state); |
| } |
| -base::MemoryState MemoryCoordinatorImpl::CalculateNextState() { |
| +base::MemoryState MemoryCoordinatorImpl::CalculateNextState( |
| + int free_memory_until_critical_mb) { |
| using MemoryState = base::MemoryState; |
| - int available = memory_monitor_->GetFreeMemoryUntilCriticalMB(); |
| - if (available <= 0) |
| + // If memory is already critical then immediately go to the most aggressive |
| + // state. |
| + if (free_memory_until_critical_mb <= 0) |
| return MemoryState::SUSPENDED; |
| - int expected_renderer_count = available / expected_renderer_size_; |
| - |
| + // Determine the next state. |
| + int expected_renderer_count = |
| + free_memory_until_critical_mb / expected_renderer_size_; |
| switch (current_state_) { |
| case MemoryState::NORMAL: |
| if (expected_renderer_count <= new_renderers_until_suspended_) |
| @@ -179,17 +187,30 @@ base::MemoryState MemoryCoordinatorImpl::CalculateNextState() { |
| return MemoryState::THROTTLED; |
| return MemoryState::SUSPENDED; |
| case MemoryState::UNKNOWN: |
| - // Fall through |
| + // Fall through. |
| default: |
| NOTREACHED(); |
| return MemoryState::UNKNOWN; |
| } |
| } |
| +int64_t MemoryCoordinatorImpl::CalculateRemainingGlobalBudget( |
| + int free_memory_until_critical_mb) { |
| + int renderer_count = new_renderers_until_throttled_; |
|
Hannes Payer (out of office)
2016/11/11 12:55:19
I do not understand why you use kDefaultNewRendere
bashi
2016/11/12 01:30:53
Because we don't know what an appropriate value fo
|
| + if (current_state_ != MemoryState::NORMAL) |
| + renderer_count = new_renderers_back_to_normal_; |
|
haraken
2016/11/05 12:52:21
Shouldn't new_renderers_back_to_normal_ be always
bashi
2016/11/07 00:16:37
We have different parameters for # of renderers to
chrisha
2016/11/07 19:33:41
Yeah, this enables a "dead band" to prevent thrash
|
| + |
| + return free_memory_until_critical_mb - |
| + renderer_count * expected_renderer_size_; |
| +} |
| + |
| void MemoryCoordinatorImpl::UpdateState() { |
| base::TimeTicks now = base::TimeTicks::Now(); |
| + |
| + int available = memory_monitor_->GetFreeMemoryUntilCriticalMB(); |
| + |
| MemoryState prev_state = current_state_; |
| - MemoryState next_state = CalculateNextState(); |
| + MemoryState next_state = CalculateNextState(available); |
| if (last_state_change_.is_null() || current_state_ != next_state) { |
| current_state_ = next_state; |
| @@ -207,6 +228,16 @@ void MemoryCoordinatorImpl::UpdateState() { |
| } else { |
| ScheduleUpdateState(monitoring_interval_); |
| } |
| + |
| + // Update the global budget. This is used by some passive clients of the |
| + // memory coordinator to smoothly scale their own resource consumption in |
| + // sync with the memory coordinator. |
| + int64_t prev_remaining = remaining_global_budget_mb_; |
| + int64_t next_remaining = CalculateRemainingGlobalBudget(available); |
| + if (prev_remaining != next_remaining) { |
|
bashi
2016/11/07 00:16:37
How likely does this condition become true? |free_
chrisha
2016/11/07 19:33:41
Very unlikely to remain true, but this is a cheap
bashi
2016/11/07 23:17:08
Acknowledged.
chrisha
2016/12/15 21:10:24
(This is a moot point with a "pull" model.)
|
| + remaining_global_budget_mb_ = next_remaining; |
| + NotifyRemainingGlobalBudgetToChildren(); |
|
haraken
2016/11/05 12:52:21
How frequently will this IPC be called?
bashi
2016/11/07 00:16:37
My guess is that it's almost the same as how frequ
chrisha
2016/11/07 19:33:41
Yup. Although we should likely still continue to c
bashi
2016/11/07 23:17:08
Yeah, as haraken@ said, async API may not be usefu
Hannes Payer (out of office)
2016/11/11 12:55:19
Currently, I am only planning to take advantage of
chrisha
2016/12/15 21:10:24
Moved to a "pull" model.
|
| + } |
| } |
| void MemoryCoordinatorImpl::NotifyStateToClients() { |
| @@ -222,6 +253,11 @@ void MemoryCoordinatorImpl::NotifyStateToChildren() { |
| SetMemoryState(iter.first, mojo_state); |
| } |
| +void MemoryCoordinatorImpl::NotifyRemainingGlobalBudgetToChildren() { |
| + for (auto& iter : children()) |
| + SetRemainingGlobalBudget(iter.first, remaining_global_budget_mb_); |
| +} |
| + |
| void MemoryCoordinatorImpl::ScheduleUpdateState(base::TimeDelta delta) { |
| task_runner_->PostDelayedTask(FROM_HERE, update_state_callback_, delta); |
| } |