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

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

Powered by Google App Engine
This is Rietveld 408576698