| Index: athena/resource_manager/resource_manager_impl.cc
|
| diff --git a/athena/resource_manager/resource_manager_impl.cc b/athena/resource_manager/resource_manager_impl.cc
|
| index 8025f751366c32f64de208ab264af1cd29645065..8e10cb8b8b3fbc8015d5763bb9bf6d6dcf2949ea 100644
|
| --- a/athena/resource_manager/resource_manager_impl.cc
|
| +++ b/athena/resource_manager/resource_manager_impl.cc
|
| @@ -81,11 +81,29 @@ class ResourceManagerImpl : public ResourceManager,
|
| // Manage the resources for our activities.
|
| void ManageResource();
|
|
|
| + // Check that the visibility of activities is properly set.
|
| + void UpdateVisibilityStates();
|
| +
|
| + // Check if activities can be unloaded to reduce memory pressure.
|
| + void TryToUnloadAnActivity();
|
| +
|
| // Order our activity list to the order of activities of the stream.
|
| // TODO(skuhne): Once the ActivityManager is responsible to create this list
|
| // for us, we can remove this code here.
|
| void UpdateActivityOrder();
|
|
|
| + // Resources were released and a quiet period is needed before we release
|
| + // more since it takes a while to trickle through the system.
|
| + void OnResourcesReleased();
|
| +
|
| + // The memory pressure has increased, previously applied measures did not show
|
| + // effect and immediate action is required.
|
| + void OnMemoryPressureIncreased();
|
| +
|
| + // Returns true when the previous memory release was long enough ago to try
|
| + // unloading another activity.
|
| + bool AllowedToUnloadActivity();
|
| +
|
| // The sorted (new(front) -> old(back)) activity list.
|
| // TODO(skuhne): Once the ActivityManager is responsible to create this list
|
| // for us, we can remove this code here.
|
| @@ -115,7 +133,7 @@ class ResourceManagerImpl : public ResourceManager,
|
| bool in_overview_mode_;
|
|
|
| // True if we are in split view mode.
|
| - bool in_splitview_mode_;
|
| + bool in_split_view_mode_;
|
|
|
| // The last time the resource manager was called to release resources.
|
| // Avoid too aggressive resource de-allocation by enforcing a wait time of
|
| @@ -145,7 +163,7 @@ ResourceManagerImpl::ResourceManagerImpl(ResourceManagerDelegate* delegate)
|
| queued_command_(false),
|
| activity_order_changed_(false),
|
| in_overview_mode_(false),
|
| - in_splitview_mode_(false),
|
| + in_split_view_mode_(false),
|
| next_resource_management_time_(base::Time::Now()),
|
| wait_time_for_resource_deallocation_(base::TimeDelta::FromMilliseconds(
|
| delegate_->MemoryPressureIntervalInMS())) {
|
| @@ -205,7 +223,7 @@ void ResourceManagerImpl::OnOverviewModeExit() {
|
|
|
| void ResourceManagerImpl::OnSplitViewModeEnter() {
|
| // Re-apply the memory pressure to make sure enough items are visible.
|
| - in_splitview_mode_ = true;
|
| + in_split_view_mode_ = true;
|
| ManageResource();
|
| }
|
|
|
| @@ -213,7 +231,7 @@ void ResourceManagerImpl::OnSplitViewModeEnter() {
|
| void ResourceManagerImpl::OnSplitViewModeExit() {
|
| // We don't do immediately something yet. The next ManageResource call will
|
| // come soon.
|
| - in_splitview_mode_ = false;
|
| + in_split_view_mode_ = false;
|
| }
|
|
|
| void ResourceManagerImpl::OnWindowStackingChanged() {
|
| @@ -241,6 +259,8 @@ void ResourceManagerImpl::OnWindowRemoved(aura::Window* removed_window,
|
|
|
| void ResourceManagerImpl::OnMemoryPressure(
|
| MemoryPressureObserver::MemoryPressure pressure) {
|
| + if (pressure > current_memory_pressure_)
|
| + OnMemoryPressureIncreased();
|
| current_memory_pressure_ = pressure;
|
| ManageResource();
|
| }
|
| @@ -259,38 +279,26 @@ void ResourceManagerImpl::ManageResource() {
|
| return;
|
| }
|
|
|
| - // TODO(skuhne): This algorithm needs to take all kinds of predictive analysis
|
| - // and running applications into account. For this first patch we only do a
|
| - // very simple "floating window" algorithm which is surely not good enough.
|
| - size_t max_running_activities = 5;
|
| - switch (current_memory_pressure_) {
|
| - case MEMORY_PRESSURE_UNKNOWN:
|
| - // If we do not know how much memory we have we assume that it must be a
|
| - // high consumption.
|
| - // Fallthrough.
|
| - case MEMORY_PRESSURE_HIGH:
|
| - max_running_activities = 5;
|
| - break;
|
| - case MEMORY_PRESSURE_CRITICAL:
|
| - max_running_activities = 0;
|
| - break;
|
| - case MEMORY_PRESSURE_MODERATE:
|
| - max_running_activities = 7;
|
| - break;
|
| - case MEMORY_PRESSURE_LOW:
|
| - // This doesn't really matter. We do not change anything but turning
|
| - // activities visible.
|
| - max_running_activities = 10000;
|
| - break;
|
| - }
|
| + // Check that the visibility of items is properly set. Note that this might
|
| + // already trigger a release of resources. If this happens,
|
| + // AllowedToUnloadActivity() will return false.
|
| + UpdateVisibilityStates();
|
|
|
| + // Since resource deallocation takes time, we avoid to release more resources
|
| + // in short succession. Note that we come here periodically and if one call
|
| + // is not triggering an unload, the next one will.
|
| + if (AllowedToUnloadActivity())
|
| + TryToUnloadAnActivity();
|
| +}
|
| +
|
| +void ResourceManagerImpl::UpdateVisibilityStates() {
|
| // The first n activities should be treated as "visible", means they updated
|
| // in overview mode and will keep their layer resources for faster switch
|
| // times. Usually we use |kMaxVisibleActivities| items, but when the memory
|
| // pressure gets critical we only hold as many as are really visible.
|
| size_t max_activities = kMaxVisibleActivities;
|
| if (current_memory_pressure_ == MEMORY_PRESSURE_CRITICAL)
|
| - max_activities = 1 + (in_splitview_mode_ ? 1 : 0);
|
| + max_activities = in_split_view_mode_ ? 2 : 1;
|
|
|
| // Restart and / or bail if the order of activities changes due to our calls.
|
| activity_order_changed_ = false;
|
| @@ -318,11 +326,10 @@ void ResourceManagerImpl::ManageResource() {
|
| (current_memory_pressure_ != MEMORY_PRESSURE_LOW ||
|
| visiblity_state == Activity::ACTIVITY_VISIBLE)) {
|
| activity->SetCurrentState(visiblity_state);
|
| - // If we turned an activity invisible, we should not at the same time
|
| - // throw an activity out of memory. Thus we grant one more invisible
|
| - // Activity in that case.
|
| + // If we turned an activity invisible, we are already releasing memory
|
| + // and can hold off releasing more for now.
|
| if (visiblity_state == Activity::ACTIVITY_INVISIBLE)
|
| - max_running_activities++;
|
| + OnResourcesReleased();
|
| }
|
| }
|
|
|
| @@ -334,23 +341,33 @@ void ResourceManagerImpl::ManageResource() {
|
| ++index;
|
| }
|
| }
|
| +}
|
|
|
| - // If there is only a low memory pressure, or our last call to release
|
| - // resources cannot have had any impact yet, we return.
|
| - // TODO(skuhne): The upper part of this function bumps up the state (to
|
| - // visible) and the lower part might unload one. Going forward this algorithm
|
| - // will change significantly and when it does we might want to break this into
|
| - // two separate pieces.
|
| - if (current_memory_pressure_ == MEMORY_PRESSURE_LOW ||
|
| - base::Time::Now() < next_resource_management_time_)
|
| - return;
|
| - // Do not release too many activities in short succession since it takes time
|
| - // to release resources. As such wait the memory pressure interval before the
|
| - // next call.
|
| - next_resource_management_time_ = base::Time::Now() +
|
| - wait_time_for_resource_deallocation_;
|
| +void ResourceManagerImpl::TryToUnloadAnActivity() {
|
| + // TODO(skuhne): This algorithm needs to take all kinds of predictive analysis
|
| + // and running applications into account. For this first patch we only do a
|
| + // very simple "floating window" algorithm which is surely not good enough.
|
| + size_t max_running_activities = 5;
|
| + switch (current_memory_pressure_) {
|
| + case MEMORY_PRESSURE_UNKNOWN:
|
| + // If we do not know how much memory we have we assume that it must be a
|
| + // high consumption.
|
| + // Fallthrough.
|
| + case MEMORY_PRESSURE_HIGH:
|
| + max_running_activities = 5;
|
| + break;
|
| + case MEMORY_PRESSURE_CRITICAL:
|
| + max_running_activities = 0;
|
| + break;
|
| + case MEMORY_PRESSURE_MODERATE:
|
| + max_running_activities = 7;
|
| + break;
|
| + case MEMORY_PRESSURE_LOW:
|
| + NOTREACHED();
|
| + return;
|
| + }
|
|
|
| - // Check if/which activity we want to unload.
|
| + // Check if / which activity we want to unload.
|
| Activity* oldest_media_activity = NULL;
|
| std::vector<Activity*> unloadable_activities;
|
| for (std::vector<Activity*>::iterator it = activity_list_.begin();
|
| @@ -369,10 +386,12 @@ void ResourceManagerImpl::ManageResource() {
|
| }
|
|
|
| if (unloadable_activities.size() > max_running_activities) {
|
| + OnResourcesReleased();
|
| unloadable_activities.back()->SetCurrentState(Activity::ACTIVITY_UNLOADED);
|
| return;
|
| } else if (current_memory_pressure_ == MEMORY_PRESSURE_CRITICAL) {
|
| if (oldest_media_activity) {
|
| + OnResourcesReleased();
|
| oldest_media_activity->SetCurrentState(Activity::ACTIVITY_UNLOADED);
|
| LOG(WARNING) << "Unloading item to releave critical memory pressure";
|
| return;
|
| @@ -422,6 +441,24 @@ void ResourceManagerImpl::UpdateActivityOrder() {
|
| activity_order_changed_ = true;
|
| }
|
|
|
| +void ResourceManagerImpl::OnResourcesReleased() {
|
| + // Do not release too many activities in short succession since it takes time
|
| + // to release resources. As such wait the memory pressure interval before the
|
| + // next call.
|
| + next_resource_management_time_ = base::Time::Now() +
|
| + wait_time_for_resource_deallocation_;
|
| +}
|
| +
|
| +void ResourceManagerImpl::OnMemoryPressureIncreased() {
|
| + // By setting the timer to Now, the next call will immediately be performed.
|
| + next_resource_management_time_ = base::Time::Now();
|
| +}
|
| +
|
| +bool ResourceManagerImpl::AllowedToUnloadActivity() {
|
| + return current_memory_pressure_ != MEMORY_PRESSURE_LOW &&
|
| + base::Time::Now() >= next_resource_management_time_;
|
| +}
|
| +
|
| // static
|
| void ResourceManager::Create() {
|
| DCHECK(!instance);
|
|
|