Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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 "chrome/browser/chromeos/memory/oom_priority_manager.h" | 5 #include "chrome/browser/chromeos/memory/oom_priority_manager.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 #include <set> | 8 #include <set> |
| 9 #include <vector> | 9 #include <vector> |
| 10 | 10 |
| (...skipping 153 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 164 is_selected(false), | 164 is_selected(false), |
| 165 is_discarded(false), | 165 is_discarded(false), |
| 166 renderer_handle(0), | 166 renderer_handle(0), |
| 167 tab_contents_id(0) { | 167 tab_contents_id(0) { |
| 168 } | 168 } |
| 169 | 169 |
| 170 OomPriorityManager::TabStats::~TabStats() { | 170 OomPriorityManager::TabStats::~TabStats() { |
| 171 } | 171 } |
| 172 | 172 |
| 173 OomPriorityManager::OomPriorityManager() | 173 OomPriorityManager::OomPriorityManager() |
| 174 : focused_tab_pid_(0), | 174 : focused_tab_process_info_(std::make_pair(0, 0)), |
| 175 low_memory_observer_(new LowMemoryObserver), | 175 low_memory_observer_(new LowMemoryObserver), |
| 176 discard_count_(0), | 176 discard_count_(0), |
| 177 recent_tab_discard_(false) { | 177 recent_tab_discard_(false) { |
| 178 registrar_.Add(this, | 178 registrar_.Add(this, |
| 179 content::NOTIFICATION_RENDERER_PROCESS_CLOSED, | 179 content::NOTIFICATION_RENDERER_PROCESS_CLOSED, |
| 180 content::NotificationService::AllBrowserContextsAndSources()); | 180 content::NotificationService::AllBrowserContextsAndSources()); |
| 181 registrar_.Add(this, | 181 registrar_.Add(this, |
| 182 content::NOTIFICATION_RENDERER_PROCESS_TERMINATED, | 182 content::NOTIFICATION_RENDERER_PROCESS_TERMINATED, |
| 183 content::NotificationService::AllBrowserContextsAndSources()); | 183 content::NotificationService::AllBrowserContextsAndSources()); |
| 184 registrar_.Add(this, | 184 registrar_.Add(this, |
| (...skipping 26 matching lines...) Expand all Loading... | |
| 211 | 211 |
| 212 void OomPriorityManager::Stop() { | 212 void OomPriorityManager::Stop() { |
| 213 timer_.Stop(); | 213 timer_.Stop(); |
| 214 recent_tab_discard_timer_.Stop(); | 214 recent_tab_discard_timer_.Stop(); |
| 215 if (low_memory_observer_.get()) | 215 if (low_memory_observer_.get()) |
| 216 low_memory_observer_->Stop(); | 216 low_memory_observer_->Stop(); |
| 217 } | 217 } |
| 218 | 218 |
| 219 std::vector<base::string16> OomPriorityManager::GetTabTitles() { | 219 std::vector<base::string16> OomPriorityManager::GetTabTitles() { |
| 220 TabStatsList stats = GetTabStatsOnUIThread(); | 220 TabStatsList stats = GetTabStatsOnUIThread(); |
| 221 base::AutoLock pid_to_oom_score_autolock(pid_to_oom_score_lock_); | 221 base::AutoLock oom_score_autolock(oom_score_lock_); |
| 222 std::vector<base::string16> titles; | 222 std::vector<base::string16> titles; |
| 223 titles.reserve(stats.size()); | 223 titles.reserve(stats.size()); |
| 224 TabStatsList::iterator it = stats.begin(); | 224 TabStatsList::iterator it = stats.begin(); |
| 225 for ( ; it != stats.end(); ++it) { | 225 for ( ; it != stats.end(); ++it) { |
| 226 base::string16 str; | 226 base::string16 str; |
| 227 str.reserve(4096); | 227 str.reserve(4096); |
| 228 int score = pid_to_oom_score_[it->renderer_handle]; | 228 int score = oom_score_map_[it->child_process_host_id]; |
| 229 str += base::IntToString16(score); | 229 str += base::IntToString16(score); |
| 230 str += base::ASCIIToUTF16(" - "); | 230 str += base::ASCIIToUTF16(" - "); |
| 231 str += it->title; | 231 str += it->title; |
| 232 str += base::ASCIIToUTF16(it->is_app ? " app" : ""); | 232 str += base::ASCIIToUTF16(it->is_app ? " app" : ""); |
| 233 str += base::ASCIIToUTF16(it->is_reloadable_ui ? " reloadable_ui" : ""); | 233 str += base::ASCIIToUTF16(it->is_reloadable_ui ? " reloadable_ui" : ""); |
| 234 str += base::ASCIIToUTF16(it->is_playing_audio ? " playing_audio" : ""); | 234 str += base::ASCIIToUTF16(it->is_playing_audio ? " playing_audio" : ""); |
| 235 str += base::ASCIIToUTF16(it->is_pinned ? " pinned" : ""); | 235 str += base::ASCIIToUTF16(it->is_pinned ? " pinned" : ""); |
| 236 str += base::ASCIIToUTF16(it->is_discarded ? " discarded" : ""); | 236 str += base::ASCIIToUTF16(it->is_discarded ? " discarded" : ""); |
| 237 titles.push_back(str); | 237 titles.push_back(str); |
| 238 } | 238 } |
| (...skipping 210 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 449 // with ad networks and statistics scripts. Ideally we would like to check | 449 // with ad networks and statistics scripts. Ideally we would like to check |
| 450 // for beforeUnload handlers, which are likely to present a dialog asking | 450 // for beforeUnload handlers, which are likely to present a dialog asking |
| 451 // if the user wants to discard state. crbug.com/123049 | 451 // if the user wants to discard state. crbug.com/123049 |
| 452 | 452 |
| 453 // Being more recently active is more important. | 453 // Being more recently active is more important. |
| 454 return first.last_active > second.last_active; | 454 return first.last_active > second.last_active; |
| 455 } | 455 } |
| 456 | 456 |
| 457 void OomPriorityManager::AdjustFocusedTabScoreOnFileThread() { | 457 void OomPriorityManager::AdjustFocusedTabScoreOnFileThread() { |
| 458 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | 458 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); |
| 459 base::AutoLock pid_to_oom_score_autolock(pid_to_oom_score_lock_); | 459 base::AutoLock oom_score_autolock(oom_score_lock_); |
| 460 content::ZygoteHost::GetInstance()->AdjustRendererOOMScore( | 460 content::ZygoteHost::GetInstance()->AdjustRendererOOMScore( |
| 461 focused_tab_pid_, chrome::kLowestRendererOomScore); | 461 focused_tab_process_info_.second, chrome::kLowestRendererOomScore); |
|
James Cook
2014/12/01 19:25:58
nit: Please pull this out into a local variable (l
sramajay
2014/12/02 15:36:57
Done.
| |
| 462 pid_to_oom_score_[focused_tab_pid_] = chrome::kLowestRendererOomScore; | 462 oom_score_map_[focused_tab_process_info_.first] = |
| 463 chrome::kLowestRendererOomScore; | |
| 463 } | 464 } |
| 464 | 465 |
| 465 void OomPriorityManager::OnFocusTabScoreAdjustmentTimeout() { | 466 void OomPriorityManager::OnFocusTabScoreAdjustmentTimeout() { |
| 466 BrowserThread::PostTask( | 467 BrowserThread::PostTask( |
| 467 BrowserThread::FILE, FROM_HERE, | 468 BrowserThread::FILE, FROM_HERE, |
| 468 base::Bind(&OomPriorityManager::AdjustFocusedTabScoreOnFileThread, | 469 base::Bind(&OomPriorityManager::AdjustFocusedTabScoreOnFileThread, |
| 469 base::Unretained(this))); | 470 base::Unretained(this))); |
| 470 } | 471 } |
| 471 | 472 |
| 472 void OomPriorityManager::Observe(int type, | 473 void OomPriorityManager::Observe(int type, |
| 473 const content::NotificationSource& source, | 474 const content::NotificationSource& source, |
| 474 const content::NotificationDetails& details) { | 475 const content::NotificationDetails& details) { |
| 475 base::ProcessHandle handle = 0; | 476 base::AutoLock oom_score_autolock(oom_score_lock_); |
| 476 base::AutoLock pid_to_oom_score_autolock(pid_to_oom_score_lock_); | |
| 477 switch (type) { | 477 switch (type) { |
| 478 case content::NOTIFICATION_RENDERER_PROCESS_CLOSED: { | 478 case content::NOTIFICATION_RENDERER_PROCESS_CLOSED: |
| 479 handle = | |
| 480 content::Details<content::RenderProcessHost::RendererClosedDetails>( | |
| 481 details)->handle; | |
| 482 pid_to_oom_score_.erase(handle); | |
| 483 break; | |
| 484 } | |
| 485 case content::NOTIFICATION_RENDERER_PROCESS_TERMINATED: { | 479 case content::NOTIFICATION_RENDERER_PROCESS_TERMINATED: { |
| 486 handle = content::Source<content::RenderProcessHost>(source)-> | 480 content::RenderProcessHost* host = |
| 487 GetHandle(); | 481 content::Source<content::RenderProcessHost>(source).ptr(); |
| 488 pid_to_oom_score_.erase(handle); | 482 oom_score_map_.erase(host->GetID()); |
| 489 break; | 483 break; |
| 490 } | 484 } |
| 491 case content::NOTIFICATION_RENDER_WIDGET_VISIBILITY_CHANGED: { | 485 case content::NOTIFICATION_RENDER_WIDGET_VISIBILITY_CHANGED: { |
| 492 bool visible = *content::Details<bool>(details).ptr(); | 486 bool visible = *content::Details<bool>(details).ptr(); |
| 493 if (visible) { | 487 if (visible) { |
| 494 focused_tab_pid_ = | 488 content::RenderProcessHost* render_host = |
| 495 content::Source<content::RenderWidgetHost>(source).ptr()-> | 489 content::Source<content::RenderWidgetHost>(source).ptr()-> |
| 496 GetProcess()->GetHandle(); | 490 GetProcess(); |
| 491 focused_tab_process_info_ = std::make_pair(render_host->GetID(), | |
| 492 render_host->GetHandle()); | |
| 497 | 493 |
| 498 // If the currently focused tab already has a lower score, do not | 494 // If the currently focused tab already has a lower score, do not |
| 499 // set it. This can happen in case the newly focused tab is script | 495 // set it. This can happen in case the newly focused tab is script |
| 500 // connected to the previous tab. | 496 // connected to the previous tab. |
| 501 ProcessScoreMap::iterator it; | 497 ProcessScoreMap::iterator it; |
| 502 it = pid_to_oom_score_.find(focused_tab_pid_); | 498 it = oom_score_map_.find(focused_tab_process_info_.first); |
|
James Cook
2014/12/01 19:25:58
This is fine because the lines above show that fir
sramajay
2014/12/02 15:36:57
Acknowledged.
| |
| 503 if (it == pid_to_oom_score_.end() | 499 if (it == oom_score_map_.end() |
| 504 || it->second != chrome::kLowestRendererOomScore) { | 500 || it->second != chrome::kLowestRendererOomScore) { |
| 505 // By starting a timer we guarantee that the tab is focused for | 501 // By starting a timer we guarantee that the tab is focused for |
| 506 // certain amount of time. Secondly, it also does not add overhead | 502 // certain amount of time. Secondly, it also does not add overhead |
| 507 // to the tab switching time. | 503 // to the tab switching time. |
| 508 if (focus_tab_score_adjust_timer_.IsRunning()) | 504 if (focus_tab_score_adjust_timer_.IsRunning()) |
| 509 focus_tab_score_adjust_timer_.Reset(); | 505 focus_tab_score_adjust_timer_.Reset(); |
| 510 else | 506 else |
| 511 focus_tab_score_adjust_timer_.Start(FROM_HERE, | 507 focus_tab_score_adjust_timer_.Start(FROM_HERE, |
| 512 TimeDelta::FromMilliseconds(kFocusedTabScoreAdjustIntervalMs), | 508 TimeDelta::FromMilliseconds(kFocusedTabScoreAdjustIntervalMs), |
| 513 this, &OomPriorityManager::OnFocusTabScoreAdjustmentTimeout); | 509 this, &OomPriorityManager::OnFocusTabScoreAdjustmentTimeout); |
| (...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 574 TabStats stats; | 570 TabStats stats; |
| 575 stats.is_app = is_browser_for_app; | 571 stats.is_app = is_browser_for_app; |
| 576 stats.is_reloadable_ui = | 572 stats.is_reloadable_ui = |
| 577 IsReloadableUI(contents->GetLastCommittedURL()); | 573 IsReloadableUI(contents->GetLastCommittedURL()); |
| 578 stats.is_playing_audio = chrome::IsPlayingAudio(contents); | 574 stats.is_playing_audio = chrome::IsPlayingAudio(contents); |
| 579 stats.is_pinned = model->IsTabPinned(i); | 575 stats.is_pinned = model->IsTabPinned(i); |
| 580 stats.is_selected = browser_active && model->IsTabSelected(i); | 576 stats.is_selected = browser_active && model->IsTabSelected(i); |
| 581 stats.is_discarded = model->IsTabDiscarded(i); | 577 stats.is_discarded = model->IsTabDiscarded(i); |
| 582 stats.last_active = contents->GetLastActiveTime(); | 578 stats.last_active = contents->GetLastActiveTime(); |
| 583 stats.renderer_handle = contents->GetRenderProcessHost()->GetHandle(); | 579 stats.renderer_handle = contents->GetRenderProcessHost()->GetHandle(); |
| 580 stats.child_process_host_id = contents->GetRenderProcessHost()->GetID(); | |
| 584 stats.title = contents->GetTitle(); | 581 stats.title = contents->GetTitle(); |
| 585 stats.tab_contents_id = IdFromWebContents(contents); | 582 stats.tab_contents_id = IdFromWebContents(contents); |
| 586 stats_list.push_back(stats); | 583 stats_list.push_back(stats); |
| 587 } | 584 } |
| 588 } | 585 } |
| 589 // We process the active browser window in the first iteration. | 586 // We process the active browser window in the first iteration. |
| 590 browser_active = false; | 587 browser_active = false; |
| 591 } | 588 } |
| 592 // Sort the data we collected so that least desirable to be | 589 // Sort the data we collected so that least desirable to be |
| 593 // killed is first, most desirable is last. | 590 // killed is first, most desirable is last. |
| 594 std::sort(stats_list.begin(), stats_list.end(), CompareTabStats); | 591 std::sort(stats_list.begin(), stats_list.end(), CompareTabStats); |
| 595 return stats_list; | 592 return stats_list; |
| 596 } | 593 } |
| 597 | 594 |
| 598 // static | 595 // static |
| 599 std::vector<base::ProcessHandle> OomPriorityManager::GetProcessHandles( | 596 std::vector<OomPriorityManager::ProcessInfo> |
| 597 OomPriorityManager::GetChildProcessInfos( | |
| 600 const TabStatsList& stats_list) { | 598 const TabStatsList& stats_list) { |
| 601 std::vector<base::ProcessHandle> process_handles; | 599 std::vector<ProcessInfo> process_infos; |
| 602 std::set<base::ProcessHandle> already_seen; | 600 std::set<base::ProcessHandle> already_seen; |
| 603 for (TabStatsList::const_iterator iterator = stats_list.begin(); | 601 for (TabStatsList::const_iterator iterator = stats_list.begin(); |
| 604 iterator != stats_list.end(); ++iterator) { | 602 iterator != stats_list.end(); ++iterator) { |
| 605 // stats_list contains entries for already-discarded tabs. If the PID | 603 // stats_list contains entries for already-discarded tabs. If the PID |
| 606 // (renderer_handle) is zero, we don't need to adjust the oom_score. | 604 // (renderer_handle) is zero, we don't need to adjust the oom_score. |
| 607 if (iterator->renderer_handle == 0) | 605 if (iterator->renderer_handle == 0) |
| 608 continue; | 606 continue; |
| 609 | 607 |
| 610 bool inserted = already_seen.insert(iterator->renderer_handle).second; | 608 bool inserted = already_seen.insert(iterator->renderer_handle).second; |
| 611 if (!inserted) { | 609 if (!inserted) { |
| 612 // We've already seen this process handle. | 610 // We've already seen this process handle. |
| 613 continue; | 611 continue; |
| 614 } | 612 } |
| 615 | 613 |
| 616 process_handles.push_back(iterator->renderer_handle); | 614 process_infos.push_back(std::make_pair( |
| 615 iterator->child_process_host_id, iterator->renderer_handle)); | |
| 617 } | 616 } |
| 618 return process_handles; | 617 return process_infos; |
| 619 } | 618 } |
| 620 | 619 |
| 621 void OomPriorityManager::AdjustOomPrioritiesOnFileThread( | 620 void OomPriorityManager::AdjustOomPrioritiesOnFileThread( |
| 622 TabStatsList stats_list) { | 621 TabStatsList stats_list) { |
| 623 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | 622 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); |
| 624 base::AutoLock pid_to_oom_score_autolock(pid_to_oom_score_lock_); | 623 base::AutoLock oom_score_autolock(oom_score_lock_); |
| 625 | 624 |
| 626 // Remove any duplicate PIDs. Order of the list is maintained, so each | 625 // Remove any duplicate PIDs. Order of the list is maintained, so each |
| 627 // renderer process will take on the oom_score_adj of the most important | 626 // renderer process will take on the oom_score_adj of the most important |
| 628 // (least likely to be killed) tab. | 627 // (least likely to be killed) tab. |
| 629 std::vector<base::ProcessHandle> process_handles = | 628 std::vector<ProcessInfo> process_infos = GetChildProcessInfos(stats_list); |
| 630 GetProcessHandles(stats_list); | |
| 631 | 629 |
| 632 // Now we assign priorities based on the sorted list. We're | 630 // Now we assign priorities based on the sorted list. We're |
| 633 // assigning priorities in the range of kLowestRendererOomScore to | 631 // assigning priorities in the range of kLowestRendererOomScore to |
| 634 // kHighestRendererOomScore (defined in chrome_constants.h). | 632 // kHighestRendererOomScore (defined in chrome_constants.h). |
| 635 // oom_score_adj takes values from -1000 to 1000. Negative values | 633 // oom_score_adj takes values from -1000 to 1000. Negative values |
| 636 // are reserved for system processes, and we want to give some room | 634 // are reserved for system processes, and we want to give some room |
| 637 // below the range we're using to allow for things that want to be | 635 // below the range we're using to allow for things that want to be |
| 638 // above the renderers in priority, so the defined range gives us | 636 // above the renderers in priority, so the defined range gives us |
| 639 // some variation in priority without taking up the whole range. In | 637 // some variation in priority without taking up the whole range. In |
| 640 // the end, however, it's a pretty arbitrary range to use. Higher | 638 // the end, however, it's a pretty arbitrary range to use. Higher |
| 641 // values are more likely to be killed by the OOM killer. | 639 // values are more likely to be killed by the OOM killer. |
| 642 float priority = chrome::kLowestRendererOomScore; | 640 float priority = chrome::kLowestRendererOomScore; |
| 643 const int kPriorityRange = chrome::kHighestRendererOomScore - | 641 const int kPriorityRange = chrome::kHighestRendererOomScore - |
| 644 chrome::kLowestRendererOomScore; | 642 chrome::kLowestRendererOomScore; |
| 645 float priority_increment = | 643 float priority_increment = |
| 646 static_cast<float>(kPriorityRange) / process_handles.size(); | 644 static_cast<float>(kPriorityRange) / process_infos.size(); |
| 647 for (std::vector<base::ProcessHandle>::iterator iterator = | 645 for (auto process_info : process_infos) { |
|
James Cook
2014/12/01 19:25:58
nit: consider "const auto&" here to avoid copying
sramajay
2014/12/02 15:36:57
Done.
| |
| 648 process_handles.begin(); | |
| 649 iterator != process_handles.end(); ++iterator) { | |
| 650 int score = static_cast<int>(priority + 0.5f); | 646 int score = static_cast<int>(priority + 0.5f); |
| 651 ProcessScoreMap::iterator it = pid_to_oom_score_.find(*iterator); | 647 ProcessScoreMap::iterator it = |
| 648 oom_score_map_.find(process_info.first); | |
| 652 // If a process has the same score as the newly calculated value, | 649 // If a process has the same score as the newly calculated value, |
| 653 // do not set it. | 650 // do not set it. |
| 654 if (it == pid_to_oom_score_.end() || it->second != score) { | 651 if (it == oom_score_map_.end() || it->second != score) { |
| 655 content::ZygoteHost::GetInstance()->AdjustRendererOOMScore(*iterator, | 652 content::ZygoteHost::GetInstance()->AdjustRendererOOMScore( |
| 656 score); | 653 process_info.second, score); |
| 657 pid_to_oom_score_[*iterator] = score; | 654 oom_score_map_[process_info.first] = score; |
| 658 } | 655 } |
| 659 priority += priority_increment; | 656 priority += priority_increment; |
| 660 } | 657 } |
| 661 } | 658 } |
| 662 | 659 |
| 663 } // namespace chromeos | 660 } // namespace chromeos |
| OLD | NEW |