OLD | NEW |
---|---|
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 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 "athena/resource_manager/public/resource_manager.h" | 5 #include "athena/resource_manager/public/resource_manager.h" |
6 | 6 |
7 #include <algorithm> | 7 #include <algorithm> |
8 #include <vector> | 8 #include <vector> |
9 | 9 |
10 #include "athena/activity/public/activity.h" | 10 #include "athena/activity/public/activity.h" |
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
74 | 74 |
75 // WindowListProviderObserver: | 75 // WindowListProviderObserver: |
76 virtual void OnWindowStackingChanged() OVERRIDE; | 76 virtual void OnWindowStackingChanged() OVERRIDE; |
77 virtual void OnWindowRemoved(aura::Window* removed_window, | 77 virtual void OnWindowRemoved(aura::Window* removed_window, |
78 int index) OVERRIDE; | 78 int index) OVERRIDE; |
79 | 79 |
80 private: | 80 private: |
81 // Manage the resources for our activities. | 81 // Manage the resources for our activities. |
82 void ManageResource(); | 82 void ManageResource(); |
83 | 83 |
84 // Check that the visibility of activities is properly set. | |
85 void CheckVisibilityStates(); | |
86 | |
87 // Check if activities can be unloaded to reduce memory pressure. | |
88 void TryToUnloadAnActivity(); | |
89 | |
84 // Order our activity list to the order of activities of the stream. | 90 // Order our activity list to the order of activities of the stream. |
85 // TODO(skuhne): Once the ActivityManager is responsible to create this list | 91 // TODO(skuhne): Once the ActivityManager is responsible to create this list |
86 // for us, we can remove this code here. | 92 // for us, we can remove this code here. |
87 void UpdateActivityOrder(); | 93 void UpdateActivityOrder(); |
88 | 94 |
95 // Resources were released and a quiet period is needed before we release | |
96 // more since it takes a while to trickle through the system. | |
97 void ResourcesGotReleased(); | |
oshima
2014/09/22 16:22:51
OnResourceReleased is more common.
Mr4D (OOO till 08-26)
2014/09/23 00:28:56
Done.
[Even though I have to say that the On.. no
| |
98 | |
99 // The memory pressure has increased, previously applied measures did not show | |
100 // effect and immediate action is required. | |
101 void MemoryPressureIncreased(); | |
oshima
2014/09/22 16:22:51
ditto. OnMemoryPressureIncreased
Mr4D (OOO till 08-26)
2014/09/23 00:28:56
Done. And ditto.
| |
102 | |
103 // Returns true when the previous memory release was long enough ago to try | |
104 // unloading another activity. | |
105 bool AllowedToUnloadActivity(); | |
106 | |
89 // The sorted (new(front) -> old(back)) activity list. | 107 // The sorted (new(front) -> old(back)) activity list. |
90 // TODO(skuhne): Once the ActivityManager is responsible to create this list | 108 // TODO(skuhne): Once the ActivityManager is responsible to create this list |
91 // for us, we can remove this code here. | 109 // for us, we can remove this code here. |
92 std::vector<Activity*> activity_list_; | 110 std::vector<Activity*> activity_list_; |
93 | 111 |
94 // The resource manager delegate. | 112 // The resource manager delegate. |
95 scoped_ptr<ResourceManagerDelegate> delegate_; | 113 scoped_ptr<ResourceManagerDelegate> delegate_; |
96 | 114 |
97 // Keeping a reference to the current memory pressure. | 115 // Keeping a reference to the current memory pressure. |
98 MemoryPressureObserver::MemoryPressure current_memory_pressure_; | 116 MemoryPressureObserver::MemoryPressure current_memory_pressure_; |
(...skipping 135 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
234 // Manage the resources of each activity. | 252 // Manage the resources of each activity. |
235 ManageResource(); | 253 ManageResource(); |
236 } | 254 } |
237 | 255 |
238 void ResourceManagerImpl::OnWindowRemoved(aura::Window* removed_window, | 256 void ResourceManagerImpl::OnWindowRemoved(aura::Window* removed_window, |
239 int index) { | 257 int index) { |
240 } | 258 } |
241 | 259 |
242 void ResourceManagerImpl::OnMemoryPressure( | 260 void ResourceManagerImpl::OnMemoryPressure( |
243 MemoryPressureObserver::MemoryPressure pressure) { | 261 MemoryPressureObserver::MemoryPressure pressure) { |
262 if (pressure > current_memory_pressure_) | |
263 MemoryPressureIncreased(); | |
244 current_memory_pressure_ = pressure; | 264 current_memory_pressure_ = pressure; |
245 ManageResource(); | 265 ManageResource(); |
246 } | 266 } |
247 | 267 |
248 ResourceManagerDelegate* ResourceManagerImpl::GetDelegate() { | 268 ResourceManagerDelegate* ResourceManagerImpl::GetDelegate() { |
249 return delegate_.get(); | 269 return delegate_.get(); |
250 } | 270 } |
251 | 271 |
252 void ResourceManagerImpl::ManageResource() { | 272 void ResourceManagerImpl::ManageResource() { |
253 // If there is none or only one app running we cannot do anything. | 273 // If there is none or only one app running we cannot do anything. |
254 if (activity_list_.size() <= 1U) | 274 if (activity_list_.size() <= 1U) |
255 return; | 275 return; |
256 | 276 |
257 if (pause_) { | 277 if (pause_) { |
258 queued_command_ = true; | 278 queued_command_ = true; |
259 return; | 279 return; |
260 } | 280 } |
261 | 281 |
262 // TODO(skuhne): This algorithm needs to take all kinds of predictive analysis | 282 // Check that the visibility of items is properly set. Note that this might |
263 // and running applications into account. For this first patch we only do a | 283 // already trigger a release of resources. If this happens, |
264 // very simple "floating window" algorithm which is surely not good enough. | 284 // AllowedToUnloadActivity() will return false. |
265 size_t max_running_activities = 5; | 285 CheckVisibilityStates(); |
266 switch (current_memory_pressure_) { | |
267 case MEMORY_PRESSURE_UNKNOWN: | |
268 // If we do not know how much memory we have we assume that it must be a | |
269 // high consumption. | |
270 // Fallthrough. | |
271 case MEMORY_PRESSURE_HIGH: | |
272 max_running_activities = 5; | |
273 break; | |
274 case MEMORY_PRESSURE_CRITICAL: | |
275 max_running_activities = 0; | |
276 break; | |
277 case MEMORY_PRESSURE_MODERATE: | |
278 max_running_activities = 7; | |
279 break; | |
280 case MEMORY_PRESSURE_LOW: | |
281 // This doesn't really matter. We do not change anything but turning | |
282 // activities visible. | |
283 max_running_activities = 10000; | |
284 break; | |
285 } | |
286 | 286 |
287 // Since resource deallocation takes time, we avoid to release more resources | |
288 // in short succession. Note that we come here periodically and if one call | |
289 // is not triggering an unload, the next one will. | |
290 if (AllowedToUnloadActivity()) | |
291 TryToUnloadAnActivity(); | |
292 } | |
293 | |
294 void ResourceManagerImpl::CheckVisibilityStates() { | |
oshima
2014/09/22 16:22:50
how about UpdateVisibilityStates?
Mr4D (OOO till 08-26)
2014/09/23 00:28:56
Done.
| |
287 // The first n activities should be treated as "visible", means they updated | 295 // The first n activities should be treated as "visible", means they updated |
288 // in overview mode and will keep their layer resources for faster switch | 296 // in overview mode and will keep their layer resources for faster switch |
289 // times. Usually we use |kMaxVisibleActivities| items, but when the memory | 297 // times. Usually we use |kMaxVisibleActivities| items, but when the memory |
290 // pressure gets critical we only hold as many as are really visible. | 298 // pressure gets critical we only hold as many as are really visible. |
291 size_t max_activities = kMaxVisibleActivities; | 299 size_t max_activities = kMaxVisibleActivities; |
292 if (current_memory_pressure_ == MEMORY_PRESSURE_CRITICAL) | 300 if (current_memory_pressure_ == MEMORY_PRESSURE_CRITICAL) |
293 max_activities = 1 + (in_splitview_mode_ ? 1 : 0); | 301 max_activities = 1 + (in_splitview_mode_ ? 1 : 0); |
oshima
2014/09/22 16:22:51
in_spit_view_mode ? 2 : 1
Mr4D (OOO till 08-26)
2014/09/23 00:28:56
Done.
| |
294 | 302 |
295 // Restart and / or bail if the order of activities changes due to our calls. | 303 // Restart and / or bail if the order of activities changes due to our calls. |
296 activity_order_changed_ = false; | 304 activity_order_changed_ = false; |
297 | 305 |
298 // Change the visibility of our activities in a pre-processing step. This is | 306 // Change the visibility of our activities in a pre-processing step. This is |
299 // required since it might change the order/number of activities. | 307 // required since it might change the order/number of activities. |
300 size_t index = 0; | 308 size_t index = 0; |
301 while (index < activity_list_.size()) { | 309 while (index < activity_list_.size()) { |
302 Activity* activity = activity_list_[index]; | 310 Activity* activity = activity_list_[index]; |
303 Activity::ActivityState state = activity->GetCurrentState(); | 311 Activity::ActivityState state = activity->GetCurrentState(); |
304 | 312 |
305 // The first |kMaxVisibleActivities| entries should be visible, all others | 313 // The first |kMaxVisibleActivities| entries should be visible, all others |
306 // invisible or at a lower activity state. | 314 // invisible or at a lower activity state. |
307 if (index < max_activities || | 315 if (index < max_activities || |
308 (state == Activity::ACTIVITY_INVISIBLE || | 316 (state == Activity::ACTIVITY_INVISIBLE || |
309 state == Activity::ACTIVITY_VISIBLE)) { | 317 state == Activity::ACTIVITY_VISIBLE)) { |
310 Activity::ActivityState visiblity_state = | 318 Activity::ActivityState visiblity_state = |
311 index < max_activities ? Activity::ACTIVITY_VISIBLE : | 319 index < max_activities ? Activity::ACTIVITY_VISIBLE : |
312 Activity::ACTIVITY_INVISIBLE; | 320 Activity::ACTIVITY_INVISIBLE; |
313 // Only change the state when it changes. Note that when the memory | 321 // Only change the state when it changes. Note that when the memory |
314 // pressure is critical, only the primary activities (1 or 2) are made | 322 // pressure is critical, only the primary activities (1 or 2) are made |
315 // visible. Furthermore, in relaxed mode we only want to turn visible, | 323 // visible. Furthermore, in relaxed mode we only want to turn visible, |
316 // never invisible. | 324 // never invisible. |
317 if (visiblity_state != state && | 325 if (visiblity_state != state && |
318 (current_memory_pressure_ != MEMORY_PRESSURE_LOW || | 326 (current_memory_pressure_ != MEMORY_PRESSURE_LOW || |
319 visiblity_state == Activity::ACTIVITY_VISIBLE)) { | 327 visiblity_state == Activity::ACTIVITY_VISIBLE)) { |
320 activity->SetCurrentState(visiblity_state); | 328 activity->SetCurrentState(visiblity_state); |
321 // If we turned an activity invisible, we should not at the same time | 329 // If we turned an activity invisible, we are already releasing memory |
322 // throw an activity out of memory. Thus we grant one more invisible | 330 // and can hold off releasing more for now. |
323 // Activity in that case. | |
324 if (visiblity_state == Activity::ACTIVITY_INVISIBLE) | 331 if (visiblity_state == Activity::ACTIVITY_INVISIBLE) |
325 max_running_activities++; | 332 ResourcesGotReleased(); |
326 } | 333 } |
327 } | 334 } |
328 | 335 |
329 // See which index we should handle next. | 336 // See which index we should handle next. |
330 if (activity_order_changed_) { | 337 if (activity_order_changed_) { |
331 activity_order_changed_ = false; | 338 activity_order_changed_ = false; |
332 index = 0; | 339 index = 0; |
333 } else { | 340 } else { |
334 ++index; | 341 ++index; |
335 } | 342 } |
336 } | 343 } |
344 } | |
337 | 345 |
338 // If there is only a low memory pressure, or our last call to release | 346 void ResourceManagerImpl::TryToUnloadAnActivity() { |
339 // resources cannot have had any impact yet, we return. | 347 // TODO(skuhne): This algorithm needs to take all kinds of predictive analysis |
340 // TODO(skuhne): The upper part of this function bumps up the state (to | 348 // and running applications into account. For this first patch we only do a |
341 // visible) and the lower part might unload one. Going forward this algorithm | 349 // very simple "floating window" algorithm which is surely not good enough. |
342 // will change significantly and when it does we might want to break this into | 350 size_t max_running_activities = 5; |
343 // two separate pieces. | 351 switch (current_memory_pressure_) { |
344 if (current_memory_pressure_ == MEMORY_PRESSURE_LOW || | 352 case MEMORY_PRESSURE_UNKNOWN: |
345 base::Time::Now() < next_resource_management_time_) | 353 // If we do not know how much memory we have we assume that it must be a |
346 return; | 354 // high consumption. |
347 // Do not release too many activities in short succession since it takes time | 355 // Fallthrough. |
348 // to release resources. As such wait the memory pressure interval before the | 356 case MEMORY_PRESSURE_HIGH: |
349 // next call. | 357 max_running_activities = 5; |
350 next_resource_management_time_ = base::Time::Now() + | 358 break; |
351 wait_time_for_resource_deallocation_; | 359 case MEMORY_PRESSURE_CRITICAL: |
360 max_running_activities = 0; | |
361 break; | |
362 case MEMORY_PRESSURE_MODERATE: | |
363 max_running_activities = 7; | |
364 break; | |
365 case MEMORY_PRESSURE_LOW: | |
366 NOTREACHED(); | |
367 return; | |
368 } | |
352 | 369 |
353 // Check if/which activity we want to unload. | 370 // Check if / which activity we want to unload. |
354 Activity* oldest_media_activity = NULL; | 371 Activity* oldest_media_activity = NULL; |
355 std::vector<Activity*> unloadable_activities; | 372 std::vector<Activity*> unloadable_activities; |
356 for (std::vector<Activity*>::iterator it = activity_list_.begin(); | 373 for (std::vector<Activity*>::iterator it = activity_list_.begin(); |
357 it != activity_list_.end(); ++it) { | 374 it != activity_list_.end(); ++it) { |
358 Activity::ActivityState state = (*it)->GetCurrentState(); | 375 Activity::ActivityState state = (*it)->GetCurrentState(); |
359 // The activity should neither be unloaded nor visible. | 376 // The activity should neither be unloaded nor visible. |
360 if (state != Activity::ACTIVITY_UNLOADED && | 377 if (state != Activity::ACTIVITY_UNLOADED && |
361 state != Activity::ACTIVITY_VISIBLE) { | 378 state != Activity::ACTIVITY_VISIBLE) { |
362 if ((*it)->GetMediaState() == Activity::ACTIVITY_MEDIA_STATE_NONE) { | 379 if ((*it)->GetMediaState() == Activity::ACTIVITY_MEDIA_STATE_NONE) { |
363 // Does not play media - so we can unload this immediately. | 380 // Does not play media - so we can unload this immediately. |
364 unloadable_activities.push_back(*it); | 381 unloadable_activities.push_back(*it); |
365 } else { | 382 } else { |
366 oldest_media_activity = *it; | 383 oldest_media_activity = *it; |
367 } | 384 } |
368 } | 385 } |
369 } | 386 } |
370 | 387 |
371 if (unloadable_activities.size() > max_running_activities) { | 388 if (unloadable_activities.size() > max_running_activities) { |
389 ResourcesGotReleased(); | |
372 unloadable_activities.back()->SetCurrentState(Activity::ACTIVITY_UNLOADED); | 390 unloadable_activities.back()->SetCurrentState(Activity::ACTIVITY_UNLOADED); |
373 return; | 391 return; |
374 } else if (current_memory_pressure_ == MEMORY_PRESSURE_CRITICAL) { | 392 } else if (current_memory_pressure_ == MEMORY_PRESSURE_CRITICAL) { |
375 if (oldest_media_activity) { | 393 if (oldest_media_activity) { |
394 ResourcesGotReleased(); | |
376 oldest_media_activity->SetCurrentState(Activity::ACTIVITY_UNLOADED); | 395 oldest_media_activity->SetCurrentState(Activity::ACTIVITY_UNLOADED); |
377 LOG(WARNING) << "Unloading item to releave critical memory pressure"; | 396 LOG(WARNING) << "Unloading item to releave critical memory pressure"; |
378 return; | 397 return; |
379 } | 398 } |
380 LOG(ERROR) << "[ResourceManager]: Single activity uses too much memory."; | 399 LOG(ERROR) << "[ResourceManager]: Single activity uses too much memory."; |
381 return; | 400 return; |
382 } | 401 } |
383 | 402 |
384 if (current_memory_pressure_ != MEMORY_PRESSURE_UNKNOWN) { | 403 if (current_memory_pressure_ != MEMORY_PRESSURE_UNKNOWN) { |
385 // Only show this warning when the memory pressure is actually known. This | 404 // Only show this warning when the memory pressure is actually known. This |
(...skipping 29 matching lines...) Expand all Loading... | |
415 } | 434 } |
416 } | 435 } |
417 // At this point the old list should be empty and we can swap the lists. | 436 // At this point the old list should be empty and we can swap the lists. |
418 DCHECK(!activity_list_.size()); | 437 DCHECK(!activity_list_.size()); |
419 activity_list_ = new_activity_list; | 438 activity_list_ = new_activity_list; |
420 | 439 |
421 // Remember that the activity order has changed. | 440 // Remember that the activity order has changed. |
422 activity_order_changed_ = true; | 441 activity_order_changed_ = true; |
423 } | 442 } |
424 | 443 |
444 void ResourceManagerImpl::ResourcesGotReleased() { | |
445 // Do not release too many activities in short succession since it takes time | |
446 // to release resources. As such wait the memory pressure interval before the | |
447 // next call. | |
448 next_resource_management_time_ = base::Time::Now() + | |
449 wait_time_for_resource_deallocation_; | |
450 } | |
451 | |
452 void ResourceManagerImpl::MemoryPressureIncreased() { | |
453 // By setting the timer to Now, the next call will immediately be performed. | |
454 next_resource_management_time_ = base::Time::Now(); | |
oshima
2014/09/22 16:22:50
Note that Now() may not always increase (that is,
Mr4D (OOO till 08-26)
2014/09/23 00:28:56
Which would be ok! All which is required is that R
oshima
2014/09/23 00:42:35
Just in case you might have misunderstood my comme
| |
455 } | |
456 | |
457 bool ResourceManagerImpl::AllowedToUnloadActivity() { | |
458 return current_memory_pressure_ != MEMORY_PRESSURE_LOW && | |
459 base::Time::Now() >= next_resource_management_time_; | |
460 } | |
461 | |
425 // static | 462 // static |
426 void ResourceManager::Create() { | 463 void ResourceManager::Create() { |
427 DCHECK(!instance); | 464 DCHECK(!instance); |
428 instance = new ResourceManagerImpl( | 465 instance = new ResourceManagerImpl( |
429 ResourceManagerDelegate::CreateResourceManagerDelegate()); | 466 ResourceManagerDelegate::CreateResourceManagerDelegate()); |
430 } | 467 } |
431 | 468 |
432 // static | 469 // static |
433 ResourceManager* ResourceManager::Get() { | 470 ResourceManager* ResourceManager::Get() { |
434 return instance; | 471 return instance; |
435 } | 472 } |
436 | 473 |
437 // static | 474 // static |
438 void ResourceManager::Shutdown() { | 475 void ResourceManager::Shutdown() { |
439 DCHECK(instance); | 476 DCHECK(instance); |
440 delete instance; | 477 delete instance; |
441 instance = NULL; | 478 instance = NULL; |
442 } | 479 } |
443 | 480 |
444 ResourceManager::ResourceManager() {} | 481 ResourceManager::ResourceManager() {} |
445 | 482 |
446 ResourceManager::~ResourceManager() { | 483 ResourceManager::~ResourceManager() { |
447 DCHECK(instance); | 484 DCHECK(instance); |
448 instance = NULL; | 485 instance = NULL; |
449 } | 486 } |
450 | 487 |
451 } // namespace athena | 488 } // namespace athena |
OLD | NEW |