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 |