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 base::ProcessHandle pid = focused_tab_process_info_.second; |
460 content::ZygoteHost::GetInstance()->AdjustRendererOOMScore( | 461 content::ZygoteHost::GetInstance()->AdjustRendererOOMScore( |
461 focused_tab_pid_, chrome::kLowestRendererOomScore); | 462 pid, chrome::kLowestRendererOomScore); |
462 pid_to_oom_score_[focused_tab_pid_] = chrome::kLowestRendererOomScore; | 463 oom_score_map_[focused_tab_process_info_.first] = |
| 464 chrome::kLowestRendererOomScore; |
463 } | 465 } |
464 | 466 |
465 void OomPriorityManager::OnFocusTabScoreAdjustmentTimeout() { | 467 void OomPriorityManager::OnFocusTabScoreAdjustmentTimeout() { |
466 BrowserThread::PostTask( | 468 BrowserThread::PostTask( |
467 BrowserThread::FILE, FROM_HERE, | 469 BrowserThread::FILE, FROM_HERE, |
468 base::Bind(&OomPriorityManager::AdjustFocusedTabScoreOnFileThread, | 470 base::Bind(&OomPriorityManager::AdjustFocusedTabScoreOnFileThread, |
469 base::Unretained(this))); | 471 base::Unretained(this))); |
470 } | 472 } |
471 | 473 |
472 void OomPriorityManager::Observe(int type, | 474 void OomPriorityManager::Observe(int type, |
473 const content::NotificationSource& source, | 475 const content::NotificationSource& source, |
474 const content::NotificationDetails& details) { | 476 const content::NotificationDetails& details) { |
475 base::ProcessHandle handle = 0; | 477 base::AutoLock oom_score_autolock(oom_score_lock_); |
476 base::AutoLock pid_to_oom_score_autolock(pid_to_oom_score_lock_); | |
477 switch (type) { | 478 switch (type) { |
478 case content::NOTIFICATION_RENDERER_PROCESS_CLOSED: { | 479 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: { | 480 case content::NOTIFICATION_RENDERER_PROCESS_TERMINATED: { |
486 handle = content::Source<content::RenderProcessHost>(source)-> | 481 content::RenderProcessHost* host = |
487 GetHandle(); | 482 content::Source<content::RenderProcessHost>(source).ptr(); |
488 pid_to_oom_score_.erase(handle); | 483 oom_score_map_.erase(host->GetID()); |
489 break; | 484 break; |
490 } | 485 } |
491 case content::NOTIFICATION_RENDER_WIDGET_VISIBILITY_CHANGED: { | 486 case content::NOTIFICATION_RENDER_WIDGET_VISIBILITY_CHANGED: { |
492 bool visible = *content::Details<bool>(details).ptr(); | 487 bool visible = *content::Details<bool>(details).ptr(); |
493 if (visible) { | 488 if (visible) { |
494 focused_tab_pid_ = | 489 content::RenderProcessHost* render_host = |
495 content::Source<content::RenderWidgetHost>(source).ptr()-> | 490 content::Source<content::RenderWidgetHost>(source).ptr()-> |
496 GetProcess()->GetHandle(); | 491 GetProcess(); |
| 492 focused_tab_process_info_ = std::make_pair(render_host->GetID(), |
| 493 render_host->GetHandle()); |
497 | 494 |
498 // If the currently focused tab already has a lower score, do not | 495 // 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 | 496 // set it. This can happen in case the newly focused tab is script |
500 // connected to the previous tab. | 497 // connected to the previous tab. |
501 ProcessScoreMap::iterator it; | 498 ProcessScoreMap::iterator it; |
502 it = pid_to_oom_score_.find(focused_tab_pid_); | 499 it = oom_score_map_.find(focused_tab_process_info_.first); |
503 if (it == pid_to_oom_score_.end() | 500 if (it == oom_score_map_.end() |
504 || it->second != chrome::kLowestRendererOomScore) { | 501 || it->second != chrome::kLowestRendererOomScore) { |
505 // By starting a timer we guarantee that the tab is focused for | 502 // By starting a timer we guarantee that the tab is focused for |
506 // certain amount of time. Secondly, it also does not add overhead | 503 // certain amount of time. Secondly, it also does not add overhead |
507 // to the tab switching time. | 504 // to the tab switching time. |
508 if (focus_tab_score_adjust_timer_.IsRunning()) | 505 if (focus_tab_score_adjust_timer_.IsRunning()) |
509 focus_tab_score_adjust_timer_.Reset(); | 506 focus_tab_score_adjust_timer_.Reset(); |
510 else | 507 else |
511 focus_tab_score_adjust_timer_.Start(FROM_HERE, | 508 focus_tab_score_adjust_timer_.Start(FROM_HERE, |
512 TimeDelta::FromMilliseconds(kFocusedTabScoreAdjustIntervalMs), | 509 TimeDelta::FromMilliseconds(kFocusedTabScoreAdjustIntervalMs), |
513 this, &OomPriorityManager::OnFocusTabScoreAdjustmentTimeout); | 510 this, &OomPriorityManager::OnFocusTabScoreAdjustmentTimeout); |
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
574 TabStats stats; | 571 TabStats stats; |
575 stats.is_app = is_browser_for_app; | 572 stats.is_app = is_browser_for_app; |
576 stats.is_reloadable_ui = | 573 stats.is_reloadable_ui = |
577 IsReloadableUI(contents->GetLastCommittedURL()); | 574 IsReloadableUI(contents->GetLastCommittedURL()); |
578 stats.is_playing_audio = chrome::IsPlayingAudio(contents); | 575 stats.is_playing_audio = chrome::IsPlayingAudio(contents); |
579 stats.is_pinned = model->IsTabPinned(i); | 576 stats.is_pinned = model->IsTabPinned(i); |
580 stats.is_selected = browser_active && model->IsTabSelected(i); | 577 stats.is_selected = browser_active && model->IsTabSelected(i); |
581 stats.is_discarded = model->IsTabDiscarded(i); | 578 stats.is_discarded = model->IsTabDiscarded(i); |
582 stats.last_active = contents->GetLastActiveTime(); | 579 stats.last_active = contents->GetLastActiveTime(); |
583 stats.renderer_handle = contents->GetRenderProcessHost()->GetHandle(); | 580 stats.renderer_handle = contents->GetRenderProcessHost()->GetHandle(); |
| 581 stats.child_process_host_id = contents->GetRenderProcessHost()->GetID(); |
584 stats.title = contents->GetTitle(); | 582 stats.title = contents->GetTitle(); |
585 stats.tab_contents_id = IdFromWebContents(contents); | 583 stats.tab_contents_id = IdFromWebContents(contents); |
586 stats_list.push_back(stats); | 584 stats_list.push_back(stats); |
587 } | 585 } |
588 } | 586 } |
589 // We process the active browser window in the first iteration. | 587 // We process the active browser window in the first iteration. |
590 browser_active = false; | 588 browser_active = false; |
591 } | 589 } |
592 // Sort the data we collected so that least desirable to be | 590 // Sort the data we collected so that least desirable to be |
593 // killed is first, most desirable is last. | 591 // killed is first, most desirable is last. |
594 std::sort(stats_list.begin(), stats_list.end(), CompareTabStats); | 592 std::sort(stats_list.begin(), stats_list.end(), CompareTabStats); |
595 return stats_list; | 593 return stats_list; |
596 } | 594 } |
597 | 595 |
598 // static | 596 // static |
599 std::vector<base::ProcessHandle> OomPriorityManager::GetProcessHandles( | 597 std::vector<OomPriorityManager::ProcessInfo> |
| 598 OomPriorityManager::GetChildProcessInfos( |
600 const TabStatsList& stats_list) { | 599 const TabStatsList& stats_list) { |
601 std::vector<base::ProcessHandle> process_handles; | 600 std::vector<ProcessInfo> process_infos; |
602 std::set<base::ProcessHandle> already_seen; | 601 std::set<base::ProcessHandle> already_seen; |
603 for (TabStatsList::const_iterator iterator = stats_list.begin(); | 602 for (TabStatsList::const_iterator iterator = stats_list.begin(); |
604 iterator != stats_list.end(); ++iterator) { | 603 iterator != stats_list.end(); ++iterator) { |
605 // stats_list contains entries for already-discarded tabs. If the PID | 604 // 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. | 605 // (renderer_handle) is zero, we don't need to adjust the oom_score. |
607 if (iterator->renderer_handle == 0) | 606 if (iterator->renderer_handle == 0) |
608 continue; | 607 continue; |
609 | 608 |
610 bool inserted = already_seen.insert(iterator->renderer_handle).second; | 609 bool inserted = already_seen.insert(iterator->renderer_handle).second; |
611 if (!inserted) { | 610 if (!inserted) { |
612 // We've already seen this process handle. | 611 // We've already seen this process handle. |
613 continue; | 612 continue; |
614 } | 613 } |
615 | 614 |
616 process_handles.push_back(iterator->renderer_handle); | 615 process_infos.push_back(std::make_pair( |
| 616 iterator->child_process_host_id, iterator->renderer_handle)); |
617 } | 617 } |
618 return process_handles; | 618 return process_infos; |
619 } | 619 } |
620 | 620 |
621 void OomPriorityManager::AdjustOomPrioritiesOnFileThread( | 621 void OomPriorityManager::AdjustOomPrioritiesOnFileThread( |
622 TabStatsList stats_list) { | 622 TabStatsList stats_list) { |
623 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | 623 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); |
624 base::AutoLock pid_to_oom_score_autolock(pid_to_oom_score_lock_); | 624 base::AutoLock oom_score_autolock(oom_score_lock_); |
625 | 625 |
626 // Remove any duplicate PIDs. Order of the list is maintained, so each | 626 // 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 | 627 // renderer process will take on the oom_score_adj of the most important |
628 // (least likely to be killed) tab. | 628 // (least likely to be killed) tab. |
629 std::vector<base::ProcessHandle> process_handles = | 629 std::vector<ProcessInfo> process_infos = GetChildProcessInfos(stats_list); |
630 GetProcessHandles(stats_list); | |
631 | 630 |
632 // Now we assign priorities based on the sorted list. We're | 631 // Now we assign priorities based on the sorted list. We're |
633 // assigning priorities in the range of kLowestRendererOomScore to | 632 // assigning priorities in the range of kLowestRendererOomScore to |
634 // kHighestRendererOomScore (defined in chrome_constants.h). | 633 // kHighestRendererOomScore (defined in chrome_constants.h). |
635 // oom_score_adj takes values from -1000 to 1000. Negative values | 634 // oom_score_adj takes values from -1000 to 1000. Negative values |
636 // are reserved for system processes, and we want to give some room | 635 // 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 | 636 // 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 | 637 // above the renderers in priority, so the defined range gives us |
639 // some variation in priority without taking up the whole range. In | 638 // some variation in priority without taking up the whole range. In |
640 // the end, however, it's a pretty arbitrary range to use. Higher | 639 // the end, however, it's a pretty arbitrary range to use. Higher |
641 // values are more likely to be killed by the OOM killer. | 640 // values are more likely to be killed by the OOM killer. |
642 float priority = chrome::kLowestRendererOomScore; | 641 float priority = chrome::kLowestRendererOomScore; |
643 const int kPriorityRange = chrome::kHighestRendererOomScore - | 642 const int kPriorityRange = chrome::kHighestRendererOomScore - |
644 chrome::kLowestRendererOomScore; | 643 chrome::kLowestRendererOomScore; |
645 float priority_increment = | 644 float priority_increment = |
646 static_cast<float>(kPriorityRange) / process_handles.size(); | 645 static_cast<float>(kPriorityRange) / process_infos.size(); |
647 for (std::vector<base::ProcessHandle>::iterator iterator = | 646 for (const auto& process_info : process_infos) { |
648 process_handles.begin(); | |
649 iterator != process_handles.end(); ++iterator) { | |
650 int score = static_cast<int>(priority + 0.5f); | 647 int score = static_cast<int>(priority + 0.5f); |
651 ProcessScoreMap::iterator it = pid_to_oom_score_.find(*iterator); | 648 ProcessScoreMap::iterator it = |
| 649 oom_score_map_.find(process_info.first); |
652 // If a process has the same score as the newly calculated value, | 650 // If a process has the same score as the newly calculated value, |
653 // do not set it. | 651 // do not set it. |
654 if (it == pid_to_oom_score_.end() || it->second != score) { | 652 if (it == oom_score_map_.end() || it->second != score) { |
655 content::ZygoteHost::GetInstance()->AdjustRendererOOMScore(*iterator, | 653 content::ZygoteHost::GetInstance()->AdjustRendererOOMScore( |
656 score); | 654 process_info.second, score); |
657 pid_to_oom_score_[*iterator] = score; | 655 oom_score_map_[process_info.first] = score; |
658 } | 656 } |
659 priority += priority_increment; | 657 priority += priority_increment; |
660 } | 658 } |
661 } | 659 } |
662 | 660 |
663 } // namespace chromeos | 661 } // namespace chromeos |
OLD | NEW |