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); |
} |