Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(246)

Side by Side Diff: chrome/browser/memory/tab_manager_delegate_chromeos.cc

Issue 2247433002: TabManager: Set OOM scores via a new debugd interface on ChromeOS. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: fix unittest Created 4 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2015 The Chromium Authors. All rights reserved. 1 // Copyright 2015 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/memory/tab_manager_delegate_chromeos.h" 5 #include "chrome/browser/memory/tab_manager_delegate_chromeos.h"
6 6
7 #include <stdint.h>
8
7 #include <algorithm> 9 #include <algorithm>
8 #include <set> 10 #include <map>
9 #include <string> 11 #include <string>
10 #include <vector> 12 #include <vector>
11 13
12 #include "ash/shell.h" 14 #include "ash/shell.h"
13 #include "base/bind.h" 15 #include "base/bind.h"
14 #include "base/command_line.h" 16 #include "base/command_line.h"
15 #include "base/files/file_path.h" 17 #include "base/files/file_path.h"
16 #include "base/files/file_util.h" 18 #include "base/files/file_util.h"
17 #include "base/memory/memory_pressure_monitor_chromeos.h" 19 #include "base/memory/memory_pressure_monitor_chromeos.h"
18 #include "base/metrics/histogram_macros.h" 20 #include "base/metrics/histogram_macros.h"
19 #include "base/process/process_handle.h" // kNullProcessHandle. 21 #include "base/process/process_handle.h" // kNullProcessHandle.
20 #include "base/process/process_metrics.h" 22 #include "base/process/process_metrics.h"
21 #include "base/strings/string16.h" 23 #include "base/strings/string16.h"
22 #include "base/strings/string_number_conversions.h" 24 #include "base/strings/string_number_conversions.h"
23 #include "base/strings/string_util.h" 25 #include "base/strings/string_util.h"
24 #include "base/strings/utf_string_conversions.h" 26 #include "base/strings/utf_string_conversions.h"
25 #include "base/synchronization/lock.h"
26 #include "base/time/time.h" 27 #include "base/time/time.h"
27 #include "chrome/browser/chromeos/arc/arc_process.h" 28 #include "chrome/browser/chromeos/arc/arc_process.h"
28 #include "chrome/browser/chromeos/arc/arc_process_service.h" 29 #include "chrome/browser/chromeos/arc/arc_process_service.h"
29 #include "chrome/browser/memory/tab_stats.h" 30 #include "chrome/browser/memory/tab_stats.h"
30 #include "chrome/browser/ui/browser.h" 31 #include "chrome/browser/ui/browser.h"
31 #include "chrome/browser/ui/browser_list.h" 32 #include "chrome/browser/ui/browser_list.h"
32 #include "chrome/browser/ui/tabs/tab_strip_model.h" 33 #include "chrome/browser/ui/tabs/tab_strip_model.h"
33 #include "chrome/common/chrome_constants.h" 34 #include "chrome/common/chrome_constants.h"
34 #include "chrome/common/chrome_features.h" 35 #include "chrome/common/chrome_features.h"
36 #include "chromeos/dbus/dbus_thread_manager.h"
35 #include "components/arc/arc_bridge_service.h" 37 #include "components/arc/arc_bridge_service.h"
36 #include "components/arc/common/process.mojom.h" 38 #include "components/arc/common/process.mojom.h"
37 #include "components/arc/metrics/oom_kills_histogram.h" 39 #include "components/arc/metrics/oom_kills_histogram.h"
38 #include "components/exo/shell_surface.h" 40 #include "components/exo/shell_surface.h"
39 #include "content/public/browser/browser_thread.h" 41 #include "content/public/browser/browser_thread.h"
40 #include "content/public/browser/notification_service.h" 42 #include "content/public/browser/notification_service.h"
41 #include "content/public/browser/notification_types.h" 43 #include "content/public/browser/notification_types.h"
42 #include "content/public/browser/render_process_host.h" 44 #include "content/public/browser/render_process_host.h"
43 #include "content/public/browser/render_widget_host.h" 45 #include "content/public/browser/render_widget_host.h"
44 #include "content/public/browser/zygote_host_linux.h" 46 #include "content/public/browser/zygote_host_linux.h"
(...skipping 28 matching lines...) Expand all
73 return false; 75 return false;
74 std::string application_id = exo::ShellSurface::GetApplicationId(window); 76 std::string application_id = exo::ShellSurface::GetApplicationId(window);
75 return base::StartsWith(application_id, kArcProcessNamePrefix, 77 return base::StartsWith(application_id, kArcProcessNamePrefix,
76 base::CompareCase::SENSITIVE); 78 base::CompareCase::SENSITIVE);
77 } 79 }
78 80
79 bool IsArcMemoryManagementEnabled() { 81 bool IsArcMemoryManagementEnabled() {
80 return base::FeatureList::IsEnabled(features::kArcMemoryManagement); 82 return base::FeatureList::IsEnabled(features::kArcMemoryManagement);
81 } 83 }
82 84
85 void OnSetOomScoreAdj(bool success, const std::string& output) {
86 VLOG(2) << "OnSetOomScoreAdj " << success << " " << output;
87 if (!success || output != "")
88 LOG(WARNING) << "Set OOM score error: " << output;
89 }
90
83 } // namespace 91 } // namespace
84 92
85 std::ostream& operator<<(std::ostream& os, const ProcessType& type) { 93 std::ostream& operator<<(std::ostream& os, const ProcessType& type) {
86 switch (type) { 94 switch (type) {
87 case ProcessType::FOCUSED_APP: 95 case ProcessType::FOCUSED_APP:
88 return os << "FOCUSED_APP/FOCUSED_TAB"; 96 return os << "FOCUSED_APP/FOCUSED_TAB";
89 case ProcessType::VISIBLE_APP: 97 case ProcessType::VISIBLE_APP:
90 return os << "VISIBLE_APP"; 98 return os << "VISIBLE_APP";
91 case ProcessType::BACKGROUND_APP: 99 case ProcessType::BACKGROUND_APP:
92 return os << "BACKGROUND_APP"; 100 return os << "BACKGROUND_APP";
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after
152 return ProcessType::BACKGROUND_TAB; 160 return ProcessType::BACKGROUND_TAB;
153 } 161 }
154 NOTREACHED() << "Unexpected process type"; 162 NOTREACHED() << "Unexpected process type";
155 return ProcessType::UNKNOWN_TYPE; 163 return ProcessType::UNKNOWN_TYPE;
156 } 164 }
157 165
158 // Holds the info of a newly focused tab or app window. The focused process is 166 // Holds the info of a newly focused tab or app window. The focused process is
159 // set to highest priority (lowest OOM score), but not immediately. To avoid 167 // set to highest priority (lowest OOM score), but not immediately. To avoid
160 // redundant settings the OOM score adjusting only happens after a timeout. If 168 // redundant settings the OOM score adjusting only happens after a timeout. If
161 // the process loses focus before the timeout, the adjustment is canceled. 169 // the process loses focus before the timeout, the adjustment is canceled.
162 //
163 // This information might be set on UI thread and looked up on FILE thread. So a
164 // lock is needed to avoid racing.
165 class TabManagerDelegate::FocusedProcess { 170 class TabManagerDelegate::FocusedProcess {
166 public: 171 public:
167 static const int kInvalidArcAppNspid = 0; 172 static const int kInvalidArcAppNspid = 0;
168 struct Data {
169 union {
170 // If a chrome tqab.
171 base::ProcessHandle pid;
172 // If an ARC app.
173 int nspid;
174 };
175 bool is_arc_app;
176 };
177 173
178 void SetTabPid(base::ProcessHandle pid) { 174 FocusedProcess() { Reset(); }
179 Data* data = new Data();
180 data->is_arc_app = false;
181 data->pid = pid;
182 175
183 base::AutoLock lock(lock_); 176 void SetTabPid(const base::ProcessHandle pid) {
184 data_.reset(data); 177 pid_ = pid;
178 nspid_ = kInvalidArcAppNspid;
185 } 179 }
186 180
187 void SetArcAppNspid(int nspid) { 181 void SetArcAppNspid(const int nspid) {
188 Data* data = new Data(); 182 pid_ = base::kNullProcessHandle;
189 data->is_arc_app = true; 183 nspid_ = nspid;
190 data->nspid = nspid;
191
192 base::AutoLock lock(lock_);
193 data_.reset(data);
194 } 184 }
195 185
196 // Getter. Returns kNullProcessHandle if the process is not a tab. 186 base::ProcessHandle GetTabPid() const { return pid_; }
197 base::ProcessHandle GetTabPid() {
198 base::AutoLock lock(lock_);
199 if (data_ && !data_->is_arc_app)
200 return data_->pid;
201 return base::kNullProcessHandle;
202 }
203 187
204 // Getter. Returns kInvalidArcAppNspid if the process is not an arc app. 188 int GetArcAppNspid() const { return nspid_; }
205 int GetArcAppNspid() {
206 base::AutoLock lock(lock_);
207 if (data_ && data_->is_arc_app)
208 return data_->nspid;
209 return kInvalidArcAppNspid;
210 }
211 189
212 // An atomic operation which checks whether the containing instance is an ARC 190 // Checks whether the containing instance is an ARC app. If so it resets the
213 // app. If so it resets the data and returns true. Useful when canceling an 191 // data and returns true. Useful when canceling an ongoing OOM score setting
214 // ongoing OOM score setting for a focused ARC app because the focus has been 192 // for a focused ARC app because the focus has been shifted away shortly.
215 // shifted away shortly.
216 bool ResetIfIsArcApp() { 193 bool ResetIfIsArcApp() {
217 base::AutoLock lock(lock_); 194 if (nspid_ != kInvalidArcAppNspid) {
218 if (data_ && data_->is_arc_app) { 195 Reset();
219 data_.reset();
220 return true; 196 return true;
221 } 197 }
222 return false; 198 return false;
223 } 199 }
224 200
225 private: 201 private:
226 std::unique_ptr<Data> data_; 202 void Reset() {
227 // Protects rw access to data_; 203 pid_ = base::kNullProcessHandle;
228 base::Lock lock_; 204 nspid_ = kInvalidArcAppNspid;
205 }
206
207 // The focused app could be a Chrome tab or an Android app, but not both.
208 // At most one of them contains a valid value at any time.
209
210 // If a chrome tab.
211 base::ProcessHandle pid_;
212 // If an Android app.
213 int nspid_;
229 }; 214 };
230 215
231 // TabManagerDelegate::MemoryStat implementation. 216 // TabManagerDelegate::MemoryStat implementation.
232 217
233 // static 218 // static
234 int TabManagerDelegate::MemoryStat::ReadIntFromFile( 219 int TabManagerDelegate::MemoryStat::ReadIntFromFile(
235 const char* file_name, const int default_val) { 220 const char* file_name, const int default_val) {
236 std::string file_string; 221 std::string file_string;
237 if (!base::ReadFileToString(base::FilePath(file_name), &file_string)) { 222 if (!base::ReadFileToString(base::FilePath(file_name), &file_string)) {
238 LOG(WARNING) << "Unable to read file" << file_name; 223 LOG(WARNING) << "Unable to read file" << file_name;
(...skipping 219 matching lines...) Expand 10 before | Expand all | Expand 10 after
458 // LowMemoryKillImpl will be called asynchronously so nothing left to do. 443 // LowMemoryKillImpl will be called asynchronously so nothing left to do.
459 return; 444 return;
460 } 445 }
461 // If the list of ARC processes is not available, call LowMemoryKillImpl 446 // If the list of ARC processes is not available, call LowMemoryKillImpl
462 // synchronously with an empty list of apps. 447 // synchronously with an empty list of apps.
463 std::vector<arc::ArcProcess> dummy_apps; 448 std::vector<arc::ArcProcess> dummy_apps;
464 LowMemoryKillImpl(tab_list, dummy_apps); 449 LowMemoryKillImpl(tab_list, dummy_apps);
465 } 450 }
466 451
467 int TabManagerDelegate::GetCachedOomScore(ProcessHandle process_handle) { 452 int TabManagerDelegate::GetCachedOomScore(ProcessHandle process_handle) {
468 base::AutoLock oom_score_autolock(oom_score_lock_); 453 DCHECK_CURRENTLY_ON(BrowserThread::UI);
469 auto it = oom_score_map_.find(process_handle); 454 auto it = oom_score_map_.find(process_handle);
470 if (it != oom_score_map_.end()) { 455 if (it != oom_score_map_.end()) {
471 return it->second; 456 return it->second;
472 } 457 }
473 // An impossible value for oom_score_adj. 458 // An impossible value for oom_score_adj.
474 return -1001; 459 return -1001;
475 } 460 }
476 461
477 void TabManagerDelegate::AdjustFocusedTabScoreOnFileThread() { 462 void TabManagerDelegate::OnFocusTabScoreAdjustmentTimeout() {
478 DCHECK_CURRENTLY_ON(BrowserThread::FILE); 463 DCHECK_CURRENTLY_ON(BrowserThread::UI);
479 base::ProcessHandle pid = focused_process_->GetTabPid(); 464 base::ProcessHandle pid = focused_process_->GetTabPid();
480 // The focused process doesn't render a tab. Could happen when the focus 465 // The focused process doesn't render a tab. Could happen when the focus
481 // just switched to an ARC app. We can not avoid the race. 466 // just switched to an ARC app before the timeout. We can not avoid the race.
482 if (pid == base::kNullProcessHandle) 467 if (pid == base::kNullProcessHandle)
483 return; 468 return;
484 { 469
485 base::AutoLock oom_score_autolock(oom_score_lock_); 470 // Update the OOM score cache.
486 oom_score_map_[pid] = chrome::kLowestRendererOomScore; 471 oom_score_map_[pid] = chrome::kLowestRendererOomScore;
487 } 472
473 // Sets OOM score.
488 VLOG(3) << "Set OOM score " << chrome::kLowestRendererOomScore 474 VLOG(3) << "Set OOM score " << chrome::kLowestRendererOomScore
489 << " for focused tab " << pid; 475 << " for focused tab " << pid;
490 content::ZygoteHost::GetInstance()->AdjustRendererOOMScore( 476 std::map<int, int> dict;
491 pid, chrome::kLowestRendererOomScore); 477 dict[pid] = chrome::kLowestRendererOomScore;
492 } 478 GetDebugDaemonClient()->SetOomScoreAdj(dict, base::Bind(&OnSetOomScoreAdj));
493
494 void TabManagerDelegate::OnFocusTabScoreAdjustmentTimeout() {
495 BrowserThread::PostTask(
496 BrowserThread::FILE, FROM_HERE,
497 base::Bind(&TabManagerDelegate::AdjustFocusedTabScoreOnFileThread,
498 base::Unretained(this)));
499 } 479 }
500 480
501 void TabManagerDelegate::AdjustFocusedTabScore(base::ProcessHandle pid) { 481 void TabManagerDelegate::AdjustFocusedTabScore(base::ProcessHandle pid) {
482 DCHECK_CURRENTLY_ON(BrowserThread::UI);
483
502 // Clear running timer if one was set for a previous focused tab/app. 484 // Clear running timer if one was set for a previous focused tab/app.
503 if (focus_process_score_adjust_timer_.IsRunning()) 485 if (focus_process_score_adjust_timer_.IsRunning())
504 focus_process_score_adjust_timer_.Stop(); 486 focus_process_score_adjust_timer_.Stop();
505 focused_process_->SetTabPid(pid); 487 focused_process_->SetTabPid(pid);
506 488
507 bool not_lowest_score = false; 489 // If the currently focused tab already has a lower score, do not
508 { 490 // set it. This can happen in case the newly focused tab is script
509 base::AutoLock oom_score_autolock(oom_score_lock_); 491 // connected to the previous tab.
510 // If the currently focused tab already has a lower score, do not 492 ProcessScoreMap::iterator it = oom_score_map_.find(pid);
511 // set it. This can happen in case the newly focused tab is script 493 const bool not_lowest_score = (it == oom_score_map_.end() ||
512 // connected to the previous tab. 494 it->second != chrome::kLowestRendererOomScore);
513 ProcessScoreMap::iterator it = oom_score_map_.find(pid); 495
514 not_lowest_score = (it == oom_score_map_.end() ||
515 it->second != chrome::kLowestRendererOomScore);
516 }
517 if (not_lowest_score) { 496 if (not_lowest_score) {
518 // By starting a timer we guarantee that the tab is focused for 497 // By starting a timer we guarantee that the tab is focused for
519 // certain amount of time. Secondly, it also does not add overhead 498 // certain amount of time. Secondly, it also does not add overhead
520 // to the tab switching time. 499 // to the tab switching time.
521 // If there's an existing running timer (could be for ARC app), it 500 // If there's an existing running timer (could be for ARC app), it
522 // would be replaced by a new task. 501 // would be replaced by a new task.
523 focus_process_score_adjust_timer_.Start( 502 focus_process_score_adjust_timer_.Start(
524 FROM_HERE, 503 FROM_HERE,
525 TimeDelta::FromMilliseconds(kFocusedProcessScoreAdjustIntervalMs), 504 TimeDelta::FromMilliseconds(kFocusedProcessScoreAdjustIntervalMs),
526 this, &TabManagerDelegate::OnFocusTabScoreAdjustmentTimeout); 505 this, &TabManagerDelegate::OnFocusTabScoreAdjustmentTimeout);
527 } 506 }
528 } 507 }
529 508
530 void TabManagerDelegate::Observe(int type, 509 void TabManagerDelegate::Observe(int type,
531 const content::NotificationSource& source, 510 const content::NotificationSource& source,
532 const content::NotificationDetails& details) { 511 const content::NotificationDetails& details) {
533 switch (type) { 512 switch (type) {
534 case content::NOTIFICATION_RENDERER_PROCESS_CLOSED: 513 case content::NOTIFICATION_RENDERER_PROCESS_CLOSED:
535 case content::NOTIFICATION_RENDERER_PROCESS_TERMINATED: { 514 case content::NOTIFICATION_RENDERER_PROCESS_TERMINATED: {
536 content::RenderProcessHost* host = 515 content::RenderProcessHost* host =
537 content::Source<content::RenderProcessHost>(source).ptr(); 516 content::Source<content::RenderProcessHost>(source).ptr();
538 { 517 oom_score_map_.erase(host->GetHandle());
539 base::AutoLock oom_score_autolock(oom_score_lock_);
540 oom_score_map_.erase(host->GetHandle());
541 }
542 // Coming here we know that a renderer was just killed and memory should 518 // Coming here we know that a renderer was just killed and memory should
543 // come back into the pool. However - the memory pressure observer did 519 // come back into the pool. However - the memory pressure observer did
544 // not yet update its status and therefore we ask it to redo the 520 // not yet update its status and therefore we ask it to redo the
545 // measurement, calling us again if we have to release more. 521 // measurement, calling us again if we have to release more.
546 // Note: We do not only accelerate the discarding speed by doing another 522 // Note: We do not only accelerate the discarding speed by doing another
547 // check in short succession - we also accelerate it because the timer 523 // check in short succession - we also accelerate it because the timer
548 // driven MemoryPressureMonitor will continue to produce timed events 524 // driven MemoryPressureMonitor will continue to produce timed events
549 // on top. So the longer the cleanup phase takes, the more tabs will 525 // on top. So the longer the cleanup phase takes, the more tabs will
550 // get discarded in parallel. 526 // get discarded in parallel.
551 base::chromeos::MemoryPressureMonitor* monitor = 527 base::chromeos::MemoryPressureMonitor* monitor =
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after
604 } 580 }
605 581
606 // Excludes persistent ARC apps, but still preserves active chrome tabs and 582 // Excludes persistent ARC apps, but still preserves active chrome tabs and
607 // focused ARC apps. The latter ones should not be killed by TabManager here, 583 // focused ARC apps. The latter ones should not be killed by TabManager here,
608 // but we want to adjust their oom_score_adj. 584 // but we want to adjust their oom_score_adj.
609 // static 585 // static
610 std::vector<TabManagerDelegate::Candidate> 586 std::vector<TabManagerDelegate::Candidate>
611 TabManagerDelegate::GetSortedCandidates( 587 TabManagerDelegate::GetSortedCandidates(
612 const TabStatsList& tab_list, 588 const TabStatsList& tab_list,
613 const std::vector<arc::ArcProcess>& arc_processes) { 589 const std::vector<arc::ArcProcess>& arc_processes) {
614 static constexpr char kAppLauncherProcessName[] =
615 "org.chromium.arc.applauncher";
616
617 std::vector<Candidate> candidates; 590 std::vector<Candidate> candidates;
618 candidates.reserve(tab_list.size() + arc_processes.size()); 591 candidates.reserve(tab_list.size() + arc_processes.size());
619 592
620 for (const auto& tab : tab_list) { 593 for (const auto& tab : tab_list) {
621 candidates.emplace_back(&tab); 594 candidates.emplace_back(&tab);
622 } 595 }
623 596
597 // A special process on Android side which serves as a dummy "focused" app
598 // when the focused window is a Chrome side window (i.e., all Android
599 // processes are running in the background). We don't want to kill it anyway.
600 static constexpr char kArcInBackgroundDummyprocess[] =
601 "org.chromium.arc.home";
602
624 for (const auto& app : arc_processes) { 603 for (const auto& app : arc_processes) {
625 // Skip persistent android processes since they should never be killed here. 604 // Skip persistent android processes since they should never be killed here.
626 // Neither do we set their OOM scores so their score remains minimum. 605 // Neither do we set their OOM scores so their score remains minimum.
627 //
628 // AppLauncher is treated specially in ARC++. For example it is taken
629 // as the dummy foreground app from Android's point of view when the focused
630 // window is not an Android app. We prefer never kill it.
631 if (app.process_state() <= arc::mojom::ProcessState::PERSISTENT_UI || 606 if (app.process_state() <= arc::mojom::ProcessState::PERSISTENT_UI ||
632 app.process_name() == kAppLauncherProcessName) 607 app.process_name() == kArcInBackgroundDummyprocess) {
633 continue; 608 continue;
609 }
634 candidates.emplace_back(&app); 610 candidates.emplace_back(&app);
635 } 611 }
636 612
637 // Sort candidates according to priority. 613 // Sort candidates according to priority.
638 std::sort(candidates.begin(), candidates.end()); 614 std::sort(candidates.begin(), candidates.end());
639 615
640 return candidates; 616 return candidates;
641 } 617 }
642 618
643 bool TabManagerDelegate::KillArcProcess(const int nspid) { 619 bool TabManagerDelegate::KillArcProcess(const int nspid) {
644 if (!arc_process_instance_) 620 if (!arc_process_instance_)
645 return false; 621 return false;
646 arc_process_instance_->KillProcess(nspid, "LowMemoryKill"); 622 arc_process_instance_->KillProcess(nspid, "LowMemoryKill");
647 return true; 623 return true;
648 } 624 }
649 625
650 bool TabManagerDelegate::KillTab(int64_t tab_id) { 626 bool TabManagerDelegate::KillTab(int64_t tab_id) {
651 // Check |tab_manager_| is alive before taking tabs into consideration. 627 // Check |tab_manager_| is alive before taking tabs into consideration.
652 return tab_manager_ && 628 return tab_manager_ &&
653 tab_manager_->CanDiscardTab(tab_id) && 629 tab_manager_->CanDiscardTab(tab_id) &&
654 tab_manager_->DiscardTabById(tab_id); 630 tab_manager_->DiscardTabById(tab_id);
655 } 631 }
656 632
633
634 chromeos::DebugDaemonClient* TabManagerDelegate::GetDebugDaemonClient() {
635 return chromeos::DBusThreadManager::Get()->GetDebugDaemonClient();
636 }
637
657 void TabManagerDelegate::LowMemoryKillImpl( 638 void TabManagerDelegate::LowMemoryKillImpl(
658 const TabStatsList& tab_list, 639 const TabStatsList& tab_list,
659 const std::vector<arc::ArcProcess>& arc_processes) { 640 const std::vector<arc::ArcProcess>& arc_processes) {
660 641
661 VLOG(2) << "LowMemoryKilleImpl"; 642 VLOG(2) << "LowMemoryKilleImpl";
662 const std::vector<TabManagerDelegate::Candidate> candidates = 643 const std::vector<TabManagerDelegate::Candidate> candidates =
663 GetSortedCandidates(tab_list, arc_processes); 644 GetSortedCandidates(tab_list, arc_processes);
664 645
665 int target_memory_to_free_kb = mem_stat_->TargetMemoryToFreeKB(); 646 int target_memory_to_free_kb = mem_stat_->TargetMemoryToFreeKB();
666 // Kill processes until the estimated amount of freed memory is sufficient to 647 // Kill processes until the estimated amount of freed memory is sufficient to
(...skipping 14 matching lines...) Expand all
681 if (it->app()) { 662 if (it->app()) {
682 int estimated_memory_freed_kb = 663 int estimated_memory_freed_kb =
683 mem_stat_->EstimatedMemoryFreedKB(it->app()->pid()); 664 mem_stat_->EstimatedMemoryFreedKB(it->app()->pid());
684 if (KillArcProcess(it->app()->nspid())) { 665 if (KillArcProcess(it->app()->nspid())) {
685 target_memory_to_free_kb -= estimated_memory_freed_kb; 666 target_memory_to_free_kb -= estimated_memory_freed_kb;
686 uma_->ReportKill(estimated_memory_freed_kb); 667 uma_->ReportKill(estimated_memory_freed_kb);
687 VLOG(2) << "Killed " << *it; 668 VLOG(2) << "Killed " << *it;
688 } 669 }
689 } else { 670 } else {
690 int64_t tab_id = it->tab()->tab_contents_id; 671 int64_t tab_id = it->tab()->tab_contents_id;
672 // The estimation is problematic since multiple tabs may share the same
673 // process, while the calculation counts memory used by the whole process.
674 // So |estimated_memory_freed_kb| is an over-estimation.
691 int estimated_memory_freed_kb = 675 int estimated_memory_freed_kb =
692 mem_stat_->EstimatedMemoryFreedKB(it->tab()->renderer_handle); 676 mem_stat_->EstimatedMemoryFreedKB(it->tab()->renderer_handle);
693 if (KillTab(tab_id)) { 677 if (KillTab(tab_id)) {
694 target_memory_to_free_kb -= estimated_memory_freed_kb; 678 target_memory_to_free_kb -= estimated_memory_freed_kb;
695 uma_->ReportKill(estimated_memory_freed_kb); 679 uma_->ReportKill(estimated_memory_freed_kb);
696 VLOG(2) << "Killed " << *it; 680 VLOG(2) << "Killed " << *it;
697 } 681 }
698 } 682 }
699 if (target_memory_to_free_kb < 0) 683 if (target_memory_to_free_kb < 0)
700 break; 684 break;
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
735 719
736 ProcessScoreMap new_map; 720 ProcessScoreMap new_map;
737 721
738 // Higher priority part. 722 // Higher priority part.
739 DistributeOomScoreInRange(candidates.begin(), lower_priority_part, 723 DistributeOomScoreInRange(candidates.begin(), lower_priority_part,
740 chrome::kLowestRendererOomScore, range_middle, 724 chrome::kLowestRendererOomScore, range_middle,
741 &new_map); 725 &new_map);
742 // Lower priority part. 726 // Lower priority part.
743 DistributeOomScoreInRange(lower_priority_part, candidates.end(), range_middle, 727 DistributeOomScoreInRange(lower_priority_part, candidates.end(), range_middle,
744 chrome::kHighestRendererOomScore, &new_map); 728 chrome::kHighestRendererOomScore, &new_map);
745 base::AutoLock oom_score_autolock(oom_score_lock_);
746 oom_score_map_.swap(new_map); 729 oom_score_map_.swap(new_map);
747 } 730 }
748 731
749 void TabManagerDelegate::SetOomScoreAdjForApp(int nspid, int score) {
750 if (!arc_process_instance_)
751 return;
752 if (arc_process_instance_version_ < 2) {
753 VLOG(1) << "ProcessInstance version < 2 does not "
754 "support SetOomScoreAdj() yet.";
755 return;
756 }
757 arc_process_instance_->SetOomScoreAdj(nspid, score);
758 }
759
760 void TabManagerDelegate::SetOomScoreAdjForTabs(
761 const std::vector<std::pair<base::ProcessHandle, int>>& entries) {
762 BrowserThread::PostTask(
763 BrowserThread::FILE, FROM_HERE,
764 base::Bind(&TabManagerDelegate::SetOomScoreAdjForTabsOnFileThread,
765 base::Unretained(this), entries));
766 }
767
768 void TabManagerDelegate::SetOomScoreAdjForTabsOnFileThread(
769 const std::vector<std::pair<base::ProcessHandle, int>>& entries) {
770 DCHECK_CURRENTLY_ON(BrowserThread::FILE);
771 for (const auto& entry : entries) {
772 content::ZygoteHost::GetInstance()->AdjustRendererOOMScore(entry.first,
773 entry.second);
774 }
775 }
776
777 void TabManagerDelegate::DistributeOomScoreInRange( 732 void TabManagerDelegate::DistributeOomScoreInRange(
778 std::vector<TabManagerDelegate::Candidate>::const_iterator begin, 733 std::vector<TabManagerDelegate::Candidate>::const_iterator begin,
779 std::vector<TabManagerDelegate::Candidate>::const_iterator end, 734 std::vector<TabManagerDelegate::Candidate>::const_iterator end,
780 int range_begin, 735 int range_begin,
781 int range_end, 736 int range_end,
782 ProcessScoreMap* new_map) { 737 ProcessScoreMap* new_map) {
783 // OOM score setting for tabs involves file system operation so should be 738 // Processes whose OOM scores should be updated. Ignore duplicated pids but
784 // done on file thread. 739 // the last occurrence.
785 std::vector<std::pair<base::ProcessHandle, int>> oom_score_for_tabs; 740 std::map<base::ProcessHandle, int32_t> oom_scores_to_change;
786 741
787 // Though there might be duplicate process handles, it doesn't matter to 742 // Though there might be duplicate process handles, it doesn't matter to
788 // overestimate the number of processes here since the we don't need to 743 // overestimate the number of processes here since the we don't need to
789 // use up the full range. 744 // use up the full range.
790 int num = (end - begin); 745 int num = (end - begin);
791 const float priority_increment = 746 const float priority_increment =
792 static_cast<float>(range_end - range_begin) / num; 747 static_cast<float>(range_end - range_begin) / num;
793 748
794 float priority = range_begin; 749 float priority = range_begin;
795 for (auto cur = begin; cur != end; ++cur) { 750 for (auto cur = begin; cur != end; ++cur) {
796 int score = static_cast<int>(priority + 0.5f); 751 int score = static_cast<int>(priority + 0.5f);
752
753 base::ProcessHandle pid = base::kNullProcessHandle;
797 if (cur->app()) { 754 if (cur->app()) {
798 // Use pid as map keys so it's globally unique. 755 pid = cur->app()->pid();
799 (*new_map)[cur->app()->pid()] = score;
800 int cur_app_pid_score = 0;
801 {
802 base::AutoLock oom_score_autolock(oom_score_lock_);
803 cur_app_pid_score = oom_score_map_[cur->app()->pid()];
804 }
805 if (cur_app_pid_score != score) {
806 VLOG(3) << "Set OOM score " << score << " for " << *cur;
807 SetOomScoreAdjForApp(cur->app()->nspid(), score);
808 }
809 } else { 756 } else {
810 base::ProcessHandle process_handle = cur->tab()->renderer_handle; 757 pid = cur->tab()->renderer_handle;
811 // 1. tab_list contains entries for already-discarded tabs. If the PID 758 // 1. tab_list contains entries for already-discarded tabs. If the PID
812 // (renderer_handle) is zero, we don't need to adjust the oom_score. 759 // (renderer_handle) is zero, we don't need to adjust the oom_score.
813 // 2. Only add unseen process handle so if there's multiple tab maps to 760 // 2. Only add unseen process handle so if there's multiple tab maps to
814 // the same process, the process is set to an OOM score based on its "most 761 // the same process, the process is set to an OOM score based on its "most
815 // important" tab. 762 // important" tab.
816 if (process_handle != 0 && 763 if (pid == base::kNullProcessHandle ||
817 new_map->find(process_handle) == new_map->end()) { 764 new_map->find(pid) != new_map->end())
818 (*new_map)[process_handle] = score; 765 continue;
819 int process_handle_score = 0; 766 }
820 { 767
821 base::AutoLock oom_score_autolock(oom_score_lock_); 768 if (pid == base::kNullProcessHandle)
822 process_handle_score = oom_score_map_[process_handle]; 769 continue;
823 } 770
824 if (process_handle_score != score) { 771 // Update the to-be-cached OOM score map. Use pid as map keys so it's
825 oom_score_for_tabs.push_back(std::make_pair(process_handle, score)); 772 // globally unique.
826 VLOG(3) << "Set OOM score " << score << " for " << *cur; 773 (*new_map)[pid] = score;
827 } 774
828 } else { 775 // Need to update OOM score if the calculated score is different from
829 continue; // Skip priority increment. 776 // current cached score.
830 } 777 if (oom_score_map_[pid] != score) {
778 VLOG(3) << "Update OOM score " << score << " for " << *cur;
779 oom_scores_to_change[pid] = static_cast<int32_t>(score);
831 } 780 }
832 priority += priority_increment; 781 priority += priority_increment;
833 } 782 }
834 783
835 if (oom_score_for_tabs.size()) 784 if (oom_scores_to_change.size())
836 SetOomScoreAdjForTabs(oom_score_for_tabs); 785 GetDebugDaemonClient()->SetOomScoreAdj(
786 oom_scores_to_change, base::Bind(&OnSetOomScoreAdj));
837 } 787 }
838 788
839 } // namespace memory 789 } // namespace memory
OLDNEW
« no previous file with comments | « chrome/browser/memory/tab_manager_delegate_chromeos.h ('k') | chrome/browser/memory/tab_manager_delegate_chromeos_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698