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

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

Issue 1188823002: [MemoryPressure] Move chrome/browser/chromeos/* to chrome/browser/memory/*. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 5 years, 6 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 (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/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
11 #include "ash/multi_profile_uma.h" 11 #include "ash/multi_profile_uma.h"
12 #include "ash/session/session_state_delegate.h" 12 #include "ash/session/session_state_delegate.h"
13 #include "ash/shell.h" 13 #include "ash/shell.h"
14 #include "base/bind.h" 14 #include "base/bind.h"
15 #include "base/bind_helpers.h" 15 #include "base/bind_helpers.h"
16 #include "base/command_line.h" 16 #include "base/command_line.h"
17 #include "base/memory/memory_pressure_monitor.h" 17 #include "base/memory/memory_pressure_monitor.h"
18 #include "base/metrics/field_trial.h" 18 #include "base/metrics/field_trial.h"
19 #include "base/metrics/histogram.h" 19 #include "base/metrics/histogram.h"
20 #include "base/process/process.h" 20 #include "base/process/process.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" 25 #include "base/synchronization/lock.h"
26 #include "base/threading/thread.h" 26 #include "base/threading/thread.h"
27 #include "build/build_config.h" 27 #include "build/build_config.h"
28 #include "chrome/browser/browser_process.h" 28 #include "chrome/browser/browser_process.h"
29 #include "chrome/browser/browser_process_platform_part_chromeos.h" 29 #include "chrome/browser/memory/oom_memory_details.h"
30 #include "chrome/browser/chromeos/memory/low_memory_observer.h" 30 #include "chrome/browser/memory/system_memory_stats_recorder.h"
31 #include "chrome/browser/chromeos/memory/oom_memory_details.h"
32 #include "chrome/browser/chromeos/memory/system_memory_stats_recorder.h"
33 #include "chrome/browser/ui/browser.h" 31 #include "chrome/browser/ui/browser.h"
34 #include "chrome/browser/ui/browser_iterator.h" 32 #include "chrome/browser/ui/browser_iterator.h"
35 #include "chrome/browser/ui/browser_list.h" 33 #include "chrome/browser/ui/browser_list.h"
36 #include "chrome/browser/ui/host_desktop.h" 34 #include "chrome/browser/ui/host_desktop.h"
37 #include "chrome/browser/ui/tab_contents/tab_contents_iterator.h" 35 #include "chrome/browser/ui/tab_contents/tab_contents_iterator.h"
38 #include "chrome/browser/ui/tabs/tab_strip_model.h" 36 #include "chrome/browser/ui/tabs/tab_strip_model.h"
39 #include "chrome/browser/ui/tabs/tab_utils.h" 37 #include "chrome/browser/ui/tabs/tab_utils.h"
40 #include "chrome/common/chrome_constants.h" 38 #include "chrome/common/chrome_constants.h"
41 #include "chrome/common/url_constants.h" 39 #include "chrome/common/url_constants.h"
42 #include "chromeos/chromeos_switches.h"
43 #include "content/public/browser/browser_thread.h" 40 #include "content/public/browser/browser_thread.h"
44 #include "content/public/browser/notification_service.h" 41 #include "content/public/browser/notification_service.h"
45 #include "content/public/browser/notification_types.h" 42 #include "content/public/browser/notification_types.h"
46 #include "content/public/browser/render_process_host.h" 43 #include "content/public/browser/render_process_host.h"
47 #include "content/public/browser/render_widget_host.h" 44 #include "content/public/browser/render_widget_host.h"
48 #include "content/public/browser/web_contents.h" 45 #include "content/public/browser/web_contents.h"
49 #include "content/public/browser/zygote_host_linux.h" 46 #include "content/public/browser/zygote_host_linux.h"
50 47
48 #ifdef OS_CHROMEOS
James Cook 2015/06/17 21:20:23 #if defined(OS_CHROMEOS)
Georges Khalil 2015/06/18 16:43:01 Done.
49 #include "chrome/browser/browser_process_platform_part_chromeos.h"
50 #include "chrome/browser/memory/low_memory_observer_chromeos.h"
51 #include "chromeos/chromeos_switches.h"
52 #endif
53
51 using base::TimeDelta; 54 using base::TimeDelta;
52 using base::TimeTicks; 55 using base::TimeTicks;
53 using content::BrowserThread; 56 using content::BrowserThread;
54 using content::WebContents; 57 using content::WebContents;
55 58
56 namespace chromeos { 59 namespace memory {
57
58 namespace { 60 namespace {
59 61
60 // The default interval in seconds after which to adjust the oom_score_adj 62 // The default interval in seconds after which to adjust the oom_score_adj
61 // value. 63 // value.
62 const int kAdjustmentIntervalSeconds = 10; 64 const int kAdjustmentIntervalSeconds = 10;
63 65
64 // For each period of this length we record a statistic to indicate whether 66 // For each period of this length we record a statistic to indicate whether
65 // or not the user experienced a low memory event. If you change this interval 67 // or not the user experienced a low memory event. If you change this interval
66 // you must replace Tabs.Discard.DiscardInLastMinute with a new statistic. 68 // you must replace Tabs.Discard.DiscardInLastMinute with a new statistic.
67 const int kRecentTabDiscardIntervalSeconds = 60; 69 const int kRecentTabDiscardIntervalSeconds = 60;
(...skipping 13 matching lines...) Expand all
81 int64 IdFromWebContents(WebContents* web_contents) { 83 int64 IdFromWebContents(WebContents* web_contents) {
82 return reinterpret_cast<int64>(web_contents); 84 return reinterpret_cast<int64>(web_contents);
83 } 85 }
84 86
85 } // namespace 87 } // namespace
86 88
87 //////////////////////////////////////////////////////////////////////////////// 89 ////////////////////////////////////////////////////////////////////////////////
88 // OomPriorityManager 90 // OomPriorityManager
89 91
90 OomPriorityManager::TabStats::TabStats() 92 OomPriorityManager::TabStats::TabStats()
91 : is_app(false), 93 : is_app(false),
92 is_reloadable_ui(false), 94 is_reloadable_ui(false),
93 is_playing_audio(false), 95 is_playing_audio(false),
94 is_pinned(false), 96 is_pinned(false),
95 is_selected(false), 97 is_selected(false),
96 is_discarded(false), 98 is_discarded(false),
97 renderer_handle(0), 99 renderer_handle(0),
98 tab_contents_id(0) { 100 tab_contents_id(0) {
99 } 101 }
100 102
101 OomPriorityManager::TabStats::~TabStats() { 103 OomPriorityManager::TabStats::~TabStats() {
102 } 104 }
103 105
104 OomPriorityManager::OomPriorityManager() 106 OomPriorityManager::OomPriorityManager()
105 : focused_tab_process_info_(std::make_pair(0, 0)), 107 : focused_tab_process_info_(std::make_pair(0, 0)),
106 discard_count_(0), 108 discard_count_(0),
107 recent_tab_discard_(false) { 109 recent_tab_discard_(false) {
108 // Use the old |LowMemoryObserver| when there is no |MemoryPressureMonitor|. 110 // Use the old |LowMemoryObserver| when there is no |MemoryPressureMonitor|.
109 if (!base::MemoryPressureMonitor::Get()) 111 if (!base::MemoryPressureMonitor::Get())
110 low_memory_observer_.reset(new LowMemoryObserver); 112 low_memory_observer_.reset(new LowMemoryObserver);
111 113
112 registrar_.Add(this, 114 registrar_.Add(this, content::NOTIFICATION_RENDERER_PROCESS_CLOSED,
113 content::NOTIFICATION_RENDERER_PROCESS_CLOSED, 115 content::NotificationService::AllBrowserContextsAndSources());
114 content::NotificationService::AllBrowserContextsAndSources()); 116 registrar_.Add(this, content::NOTIFICATION_RENDERER_PROCESS_TERMINATED,
115 registrar_.Add(this, 117 content::NotificationService::AllBrowserContextsAndSources());
116 content::NOTIFICATION_RENDERER_PROCESS_TERMINATED, 118 registrar_.Add(this, content::NOTIFICATION_RENDER_WIDGET_VISIBILITY_CHANGED,
117 content::NotificationService::AllBrowserContextsAndSources()); 119 content::NotificationService::AllBrowserContextsAndSources());
118 registrar_.Add(this,
119 content::NOTIFICATION_RENDER_WIDGET_VISIBILITY_CHANGED,
120 content::NotificationService::AllBrowserContextsAndSources());
121 } 120 }
122 121
123 OomPriorityManager::~OomPriorityManager() { 122 OomPriorityManager::~OomPriorityManager() {
124 Stop(); 123 Stop();
125 } 124 }
126 125
127 void OomPriorityManager::Start() { 126 void OomPriorityManager::Start() {
128 if (!timer_.IsRunning()) { 127 if (!timer_.IsRunning()) {
129 timer_.Start(FROM_HERE, 128 timer_.Start(FROM_HERE, TimeDelta::FromSeconds(kAdjustmentIntervalSeconds),
130 TimeDelta::FromSeconds(kAdjustmentIntervalSeconds), 129 this, &OomPriorityManager::AdjustOomPriorities);
131 this,
132 &OomPriorityManager::AdjustOomPriorities);
133 } 130 }
134 if (!recent_tab_discard_timer_.IsRunning()) { 131 if (!recent_tab_discard_timer_.IsRunning()) {
135 recent_tab_discard_timer_.Start( 132 recent_tab_discard_timer_.Start(
136 FROM_HERE, 133 FROM_HERE, TimeDelta::FromSeconds(kRecentTabDiscardIntervalSeconds),
137 TimeDelta::FromSeconds(kRecentTabDiscardIntervalSeconds), 134 this, &OomPriorityManager::RecordRecentTabDiscard);
138 this,
139 &OomPriorityManager::RecordRecentTabDiscard);
140 } 135 }
141 start_time_ = TimeTicks::Now(); 136 start_time_ = TimeTicks::Now();
142 // If a |LowMemoryObserver| exists we use the old system, otherwise we create 137 // If a |LowMemoryObserver| exists we use the old system, otherwise we create
143 // a |MemoryPressureListener| to listen for memory events. 138 // a |MemoryPressureListener| to listen for memory events.
144 if (low_memory_observer_) { 139 if (low_memory_observer_) {
145 low_memory_observer_->Start(); 140 low_memory_observer_->Start();
146 } else { 141 } else {
147 base::MemoryPressureMonitor* monitor = base::MemoryPressureMonitor::Get(); 142 base::MemoryPressureMonitor* monitor = base::MemoryPressureMonitor::Get();
148 if (monitor) { 143 if (monitor) {
149 memory_pressure_listener_.reset(new base::MemoryPressureListener( 144 memory_pressure_listener_.reset(
150 base::Bind(&OomPriorityManager::OnMemoryPressure, 145 new base::MemoryPressureListener(base::Bind(
151 base::Unretained(this)))); 146 &OomPriorityManager::OnMemoryPressure, base::Unretained(this))));
152 base::MemoryPressureListener::MemoryPressureLevel level = 147 base::MemoryPressureListener::MemoryPressureLevel level =
153 monitor->GetCurrentPressureLevel(); 148 monitor->GetCurrentPressureLevel();
154 if (level == 149 if (level ==
155 base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL) { 150 base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL) {
156 OnMemoryPressure(level); 151 OnMemoryPressure(level);
157 } 152 }
158 } 153 }
159 } 154 }
160 } 155 }
161 156
162 void OomPriorityManager::Stop() { 157 void OomPriorityManager::Stop() {
163 timer_.Stop(); 158 timer_.Stop();
164 recent_tab_discard_timer_.Stop(); 159 recent_tab_discard_timer_.Stop();
165 if (low_memory_observer_) 160 if (low_memory_observer_)
166 low_memory_observer_->Stop(); 161 low_memory_observer_->Stop();
167 else 162 else
168 memory_pressure_listener_.reset(); 163 memory_pressure_listener_.reset();
169 } 164 }
170 165
171 std::vector<base::string16> OomPriorityManager::GetTabTitles() { 166 std::vector<base::string16> OomPriorityManager::GetTabTitles() {
172 TabStatsList stats = GetTabStatsOnUIThread(); 167 TabStatsList stats = GetTabStatsOnUIThread();
173 base::AutoLock oom_score_autolock(oom_score_lock_); 168 base::AutoLock oom_score_autolock(oom_score_lock_);
174 std::vector<base::string16> titles; 169 std::vector<base::string16> titles;
175 titles.reserve(stats.size()); 170 titles.reserve(stats.size());
176 TabStatsList::iterator it = stats.begin(); 171 TabStatsList::iterator it = stats.begin();
177 for ( ; it != stats.end(); ++it) { 172 for (; it != stats.end(); ++it) {
178 base::string16 str; 173 base::string16 str;
179 str.reserve(4096); 174 str.reserve(4096);
180 int score = oom_score_map_[it->child_process_host_id]; 175 int score = oom_score_map_[it->child_process_host_id];
181 str += base::IntToString16(score); 176 str += base::IntToString16(score);
182 str += base::ASCIIToUTF16(" - "); 177 str += base::ASCIIToUTF16(" - ");
183 str += it->title; 178 str += it->title;
184 str += base::ASCIIToUTF16(it->is_app ? " app" : ""); 179 str += base::ASCIIToUTF16(it->is_app ? " app" : "");
185 str += base::ASCIIToUTF16(it->is_reloadable_ui ? " reloadable_ui" : ""); 180 str += base::ASCIIToUTF16(it->is_reloadable_ui ? " reloadable_ui" : "");
186 str += base::ASCIIToUTF16(it->is_playing_audio ? " playing_audio" : ""); 181 str += base::ASCIIToUTF16(it->is_playing_audio ? " playing_audio" : "");
187 str += base::ASCIIToUTF16(it->is_pinned ? " pinned" : ""); 182 str += base::ASCIIToUTF16(it->is_pinned ? " pinned" : "");
188 str += base::ASCIIToUTF16(it->is_discarded ? " discarded" : ""); 183 str += base::ASCIIToUTF16(it->is_discarded ? " discarded" : "");
189 titles.push_back(str); 184 titles.push_back(str);
190 } 185 }
191 return titles; 186 return titles;
192 } 187 }
193 188
194 // TODO(jamescook): This should consider tabs with references to other tabs, 189 // TODO(jamescook): This should consider tabs with references to other tabs,
195 // such as tabs created with JavaScript window.open(). We might want to 190 // such as tabs created with JavaScript window.open(). We might want to
196 // discard the entire set together, or use that in the priority computation. 191 // discard the entire set together, or use that in the priority computation.
197 bool OomPriorityManager::DiscardTab() { 192 bool OomPriorityManager::DiscardTab() {
198 DCHECK_CURRENTLY_ON(BrowserThread::UI); 193 DCHECK_CURRENTLY_ON(BrowserThread::UI);
199 TabStatsList stats = GetTabStatsOnUIThread(); 194 TabStatsList stats = GetTabStatsOnUIThread();
200 if (stats.empty()) 195 if (stats.empty())
201 return false; 196 return false;
202 // Loop until we find a non-discarded tab to kill. 197 // Loop until we find a non-discarded tab to kill.
203 for (TabStatsList::const_reverse_iterator stats_rit = stats.rbegin(); 198 for (TabStatsList::const_reverse_iterator stats_rit = stats.rbegin();
204 stats_rit != stats.rend(); 199 stats_rit != stats.rend(); ++stats_rit) {
205 ++stats_rit) {
206 int64 least_important_tab_id = stats_rit->tab_contents_id; 200 int64 least_important_tab_id = stats_rit->tab_contents_id;
207 if (DiscardTabById(least_important_tab_id)) 201 if (DiscardTabById(least_important_tab_id))
208 return true; 202 return true;
209 } 203 }
210 return false; 204 return false;
211 } 205 }
212 206
213 void OomPriorityManager::LogMemoryAndDiscardTab() { 207 void OomPriorityManager::LogMemoryAndDiscardTab() {
214 LogMemory("Tab Discards Memory details", 208 LogMemory("Tab Discards Memory details",
215 base::Bind(&OomPriorityManager::PurgeMemoryAndDiscardTabs)); 209 base::Bind(&OomPriorityManager::PurgeMemoryAndDiscardTabs));
(...skipping 25 matching lines...) Expand all
241 // are likely to have open. Most of the benefit is the from NTP URL. 235 // are likely to have open. Most of the benefit is the from NTP URL.
242 const char* const kReloadableUrlPrefixes[] = { 236 const char* const kReloadableUrlPrefixes[] = {
243 chrome::kChromeUIDownloadsURL, 237 chrome::kChromeUIDownloadsURL,
244 chrome::kChromeUIHistoryURL, 238 chrome::kChromeUIHistoryURL,
245 chrome::kChromeUINewTabURL, 239 chrome::kChromeUINewTabURL,
246 chrome::kChromeUISettingsURL, 240 chrome::kChromeUISettingsURL,
247 }; 241 };
248 // Prefix-match against the table above. Use strncmp to avoid allocating 242 // Prefix-match against the table above. Use strncmp to avoid allocating
249 // memory to convert the URL prefix constants into std::strings. 243 // memory to convert the URL prefix constants into std::strings.
250 for (size_t i = 0; i < arraysize(kReloadableUrlPrefixes); ++i) { 244 for (size_t i = 0; i < arraysize(kReloadableUrlPrefixes); ++i) {
251 if (!strncmp(url.spec().c_str(), 245 if (!strncmp(url.spec().c_str(), kReloadableUrlPrefixes[i],
252 kReloadableUrlPrefixes[i],
253 strlen(kReloadableUrlPrefixes[i]))) 246 strlen(kReloadableUrlPrefixes[i])))
254 return true; 247 return true;
255 } 248 }
256 return false; 249 return false;
257 } 250 }
258 251
259 bool OomPriorityManager::DiscardTabById(int64 target_web_contents_id) { 252 bool OomPriorityManager::DiscardTabById(int64 target_web_contents_id) {
260 for (chrome::BrowserIterator it; !it.done(); it.Next()) { 253 for (chrome::BrowserIterator it; !it.done(); it.Next()) {
261 Browser* browser = *it; 254 Browser* browser = *it;
262 TabStripModel* model = browser->tab_strip_model(); 255 TabStripModel* model = browser->tab_strip_model();
263 for (int idx = 0; idx < model->count(); idx++) { 256 for (int idx = 0; idx < model->count(); idx++) {
264 // Can't discard tabs that are already discarded or active. 257 // Can't discard tabs that are already discarded or active.
265 if (model->IsTabDiscarded(idx) || (model->active_index() == idx)) 258 if (model->IsTabDiscarded(idx) || (model->active_index() == idx))
266 continue; 259 continue;
267 WebContents* web_contents = model->GetWebContentsAt(idx); 260 WebContents* web_contents = model->GetWebContentsAt(idx);
268 int64 web_contents_id = IdFromWebContents(web_contents); 261 int64 web_contents_id = IdFromWebContents(web_contents);
269 if (web_contents_id == target_web_contents_id) { 262 if (web_contents_id == target_web_contents_id) {
270 LOG(WARNING) << "Discarding tab " << idx 263 LOG(WARNING) << "Discarding tab " << idx << " id "
271 << " id " << target_web_contents_id; 264 << target_web_contents_id;
272 // Record statistics before discarding because we want to capture the 265 // Record statistics before discarding because we want to capture the
273 // memory state that lead to the discard. 266 // memory state that lead to the discard.
274 RecordDiscardStatistics(); 267 RecordDiscardStatistics();
275 model->DiscardWebContentsAt(idx); 268 model->DiscardWebContentsAt(idx);
276 recent_tab_discard_ = true; 269 recent_tab_discard_ = true;
277 return true; 270 return true;
278 } 271 }
279 } 272 }
280 } 273 }
281 return false; 274 return false;
282 } 275 }
283 276
284 void OomPriorityManager::RecordDiscardStatistics() { 277 void OomPriorityManager::RecordDiscardStatistics() {
285 // Record a raw count so we can compare to discard reloads. 278 // Record a raw count so we can compare to discard reloads.
286 discard_count_++; 279 discard_count_++;
287 UMA_HISTOGRAM_CUSTOM_COUNTS( 280 UMA_HISTOGRAM_CUSTOM_COUNTS("Tabs.Discard.DiscardCount", discard_count_, 1,
288 "Tabs.Discard.DiscardCount", discard_count_, 1, 1000, 50); 281 1000, 50);
289 282
290 // TODO(jamescook): Maybe incorporate extension count? 283 // TODO(jamescook): Maybe incorporate extension count?
291 UMA_HISTOGRAM_CUSTOM_COUNTS( 284 UMA_HISTOGRAM_CUSTOM_COUNTS("Tabs.Discard.TabCount", GetTabCount(), 1, 100,
292 "Tabs.Discard.TabCount", GetTabCount(), 1, 100, 50); 285 50);
293 // Record the discarded tab in relation to the amount of simultaneously 286 // Record the discarded tab in relation to the amount of simultaneously
294 // logged in users. 287 // logged in users.
295 ash::MultiProfileUMA::RecordDiscardedTab( 288 ash::MultiProfileUMA::RecordDiscardedTab(ash::Shell::GetInstance()
296 ash::Shell::GetInstance()->session_state_delegate()-> 289 ->session_state_delegate()
297 NumberOfLoggedInUsers()); 290 ->NumberOfLoggedInUsers());
298 291
299 // TODO(jamescook): If the time stats prove too noisy, then divide up users 292 // TODO(jamescook): If the time stats prove too noisy, then divide up users
300 // based on how heavily they use Chrome using tab count as a proxy. 293 // based on how heavily they use Chrome using tab count as a proxy.
301 // Bin into <= 1, <= 2, <= 4, <= 8, etc. 294 // Bin into <= 1, <= 2, <= 4, <= 8, etc.
302 if (last_discard_time_.is_null()) { 295 if (last_discard_time_.is_null()) {
303 // This is the first discard this session. 296 // This is the first discard this session.
304 TimeDelta interval = TimeTicks::Now() - start_time_; 297 TimeDelta interval = TimeTicks::Now() - start_time_;
305 int interval_seconds = static_cast<int>(interval.InSeconds()); 298 int interval_seconds = static_cast<int>(interval.InSeconds());
306 // Record time in seconds over an interval of approximately 1 day. 299 // Record time in seconds over an interval of approximately 1 day.
307 UMA_HISTOGRAM_CUSTOM_COUNTS( 300 UMA_HISTOGRAM_CUSTOM_COUNTS("Tabs.Discard.InitialTime2", interval_seconds,
308 "Tabs.Discard.InitialTime2", interval_seconds, 1, 100000, 50); 301 1, 100000, 50);
309 } else { 302 } else {
310 // Not the first discard, so compute time since last discard. 303 // Not the first discard, so compute time since last discard.
311 TimeDelta interval = TimeTicks::Now() - last_discard_time_; 304 TimeDelta interval = TimeTicks::Now() - last_discard_time_;
312 int interval_ms = static_cast<int>(interval.InMilliseconds()); 305 int interval_ms = static_cast<int>(interval.InMilliseconds());
313 // Record time in milliseconds over an interval of approximately 1 day. 306 // Record time in milliseconds over an interval of approximately 1 day.
314 // Start at 100 ms to get extra resolution in the target 750 ms range. 307 // Start at 100 ms to get extra resolution in the target 750 ms range.
315 UMA_HISTOGRAM_CUSTOM_COUNTS( 308 UMA_HISTOGRAM_CUSTOM_COUNTS("Tabs.Discard.IntervalTime2", interval_ms, 100,
316 "Tabs.Discard.IntervalTime2", interval_ms, 100, 100000 * 1000, 50); 309 100000 * 1000, 50);
317 } 310 }
318 // Record chromeos's concept of system memory usage at the time of the 311 // Record chromeos's concept of system memory usage at the time of the
319 // discard. 312 // discard.
320 RecordMemoryStats(RECORD_MEMORY_STATS_TAB_DISCARDED); 313 RecordMemoryStats(RECORD_MEMORY_STATS_TAB_DISCARDED);
321 314
322 // Set up to record the next interval. 315 // Set up to record the next interval.
323 last_discard_time_ = TimeTicks::Now(); 316 last_discard_time_ = TimeTicks::Now();
324 } 317 }
325 318
326 void OomPriorityManager::RecordRecentTabDiscard() { 319 void OomPriorityManager::RecordRecentTabDiscard() {
(...skipping 22 matching lines...) Expand all
349 342
350 int OomPriorityManager::GetTabCount() const { 343 int OomPriorityManager::GetTabCount() const {
351 int tab_count = 0; 344 int tab_count = 0;
352 for (chrome::BrowserIterator it; !it.done(); it.Next()) 345 for (chrome::BrowserIterator it; !it.done(); it.Next())
353 tab_count += it->tab_strip_model()->count(); 346 tab_count += it->tab_strip_model()->count();
354 return tab_count; 347 return tab_count;
355 } 348 }
356 349
357 // Returns true if |first| is considered less desirable to be killed 350 // Returns true if |first| is considered less desirable to be killed
358 // than |second|. 351 // than |second|.
359 bool OomPriorityManager::CompareTabStats(TabStats first, 352 bool OomPriorityManager::CompareTabStats(TabStats first, TabStats second) {
360 TabStats second) {
361 // Being currently selected is most important to protect. 353 // Being currently selected is most important to protect.
362 if (first.is_selected != second.is_selected) 354 if (first.is_selected != second.is_selected)
363 return first.is_selected; 355 return first.is_selected;
364 356
365 // Tab with internal web UI like NTP or Settings are good choices to discard, 357 // Tab with internal web UI like NTP or Settings are good choices to discard,
366 // so protect non-Web UI and let the other conditionals finish the sort. 358 // so protect non-Web UI and let the other conditionals finish the sort.
367 if (first.is_reloadable_ui != second.is_reloadable_ui) 359 if (first.is_reloadable_ui != second.is_reloadable_ui)
368 return !first.is_reloadable_ui; 360 return !first.is_reloadable_ui;
369 361
370 // Being pinned is important to protect. 362 // Being pinned is important to protect.
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after
432 base::chromeos::MemoryPressureMonitor::Get(); 424 base::chromeos::MemoryPressureMonitor::Get();
433 if (monitor) 425 if (monitor)
434 monitor->ScheduleEarlyCheck(); 426 monitor->ScheduleEarlyCheck();
435 } 427 }
436 break; 428 break;
437 } 429 }
438 case content::NOTIFICATION_RENDER_WIDGET_VISIBILITY_CHANGED: { 430 case content::NOTIFICATION_RENDER_WIDGET_VISIBILITY_CHANGED: {
439 bool visible = *content::Details<bool>(details).ptr(); 431 bool visible = *content::Details<bool>(details).ptr();
440 if (visible) { 432 if (visible) {
441 content::RenderProcessHost* render_host = 433 content::RenderProcessHost* render_host =
442 content::Source<content::RenderWidgetHost>(source).ptr()-> 434 content::Source<content::RenderWidgetHost>(source)
443 GetProcess(); 435 .ptr()
444 focused_tab_process_info_ = std::make_pair(render_host->GetID(), 436 ->GetProcess();
445 render_host->GetHandle()); 437 focused_tab_process_info_ =
438 std::make_pair(render_host->GetID(), render_host->GetHandle());
446 439
447 // If the currently focused tab already has a lower score, do not 440 // If the currently focused tab already has a lower score, do not
448 // set it. This can happen in case the newly focused tab is script 441 // set it. This can happen in case the newly focused tab is script
449 // connected to the previous tab. 442 // connected to the previous tab.
450 ProcessScoreMap::iterator it; 443 ProcessScoreMap::iterator it;
451 it = oom_score_map_.find(focused_tab_process_info_.first); 444 it = oom_score_map_.find(focused_tab_process_info_.first);
452 if (it == oom_score_map_.end() 445 if (it == oom_score_map_.end() ||
453 || it->second != chrome::kLowestRendererOomScore) { 446 it->second != chrome::kLowestRendererOomScore) {
454 // By starting a timer we guarantee that the tab is focused for 447 // By starting a timer we guarantee that the tab is focused for
455 // certain amount of time. Secondly, it also does not add overhead 448 // certain amount of time. Secondly, it also does not add overhead
456 // to the tab switching time. 449 // to the tab switching time.
457 if (focus_tab_score_adjust_timer_.IsRunning()) 450 if (focus_tab_score_adjust_timer_.IsRunning())
458 focus_tab_score_adjust_timer_.Reset(); 451 focus_tab_score_adjust_timer_.Reset();
459 else 452 else
460 focus_tab_score_adjust_timer_.Start(FROM_HERE, 453 focus_tab_score_adjust_timer_.Start(
461 TimeDelta::FromMilliseconds(kFocusedTabScoreAdjustIntervalMs), 454 FROM_HERE,
462 this, &OomPriorityManager::OnFocusTabScoreAdjustmentTimeout); 455 TimeDelta::FromMilliseconds(kFocusedTabScoreAdjustIntervalMs),
456 this, &OomPriorityManager::OnFocusTabScoreAdjustmentTimeout);
463 } 457 }
464 } 458 }
465 break; 459 break;
466 } 460 }
467 default: 461 default:
468 NOTREACHED() << L"Received unexpected notification"; 462 NOTREACHED() << L"Received unexpected notification";
469 break; 463 break;
470 } 464 }
471 } 465 }
472 466
(...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after
540 browser_active = false; 534 browser_active = false;
541 } 535 }
542 // Sort the data we collected so that least desirable to be 536 // Sort the data we collected so that least desirable to be
543 // killed is first, most desirable is last. 537 // killed is first, most desirable is last.
544 std::sort(stats_list.begin(), stats_list.end(), CompareTabStats); 538 std::sort(stats_list.begin(), stats_list.end(), CompareTabStats);
545 return stats_list; 539 return stats_list;
546 } 540 }
547 541
548 // static 542 // static
549 std::vector<OomPriorityManager::ProcessInfo> 543 std::vector<OomPriorityManager::ProcessInfo>
550 OomPriorityManager::GetChildProcessInfos( 544 OomPriorityManager::GetChildProcessInfos(const TabStatsList& stats_list) {
551 const TabStatsList& stats_list) {
552 std::vector<ProcessInfo> process_infos; 545 std::vector<ProcessInfo> process_infos;
553 std::set<base::ProcessHandle> already_seen; 546 std::set<base::ProcessHandle> already_seen;
554 for (TabStatsList::const_iterator iterator = stats_list.begin(); 547 for (TabStatsList::const_iterator iterator = stats_list.begin();
555 iterator != stats_list.end(); ++iterator) { 548 iterator != stats_list.end(); ++iterator) {
556 // stats_list contains entries for already-discarded tabs. If the PID 549 // stats_list contains entries for already-discarded tabs. If the PID
557 // (renderer_handle) is zero, we don't need to adjust the oom_score. 550 // (renderer_handle) is zero, we don't need to adjust the oom_score.
558 if (iterator->renderer_handle == 0) 551 if (iterator->renderer_handle == 0)
559 continue; 552 continue;
560 553
561 bool inserted = already_seen.insert(iterator->renderer_handle).second; 554 bool inserted = already_seen.insert(iterator->renderer_handle).second;
562 if (!inserted) { 555 if (!inserted) {
563 // We've already seen this process handle. 556 // We've already seen this process handle.
564 continue; 557 continue;
565 } 558 }
566 559
567 process_infos.push_back(std::make_pair( 560 process_infos.push_back(std::make_pair(iterator->child_process_host_id,
568 iterator->child_process_host_id, iterator->renderer_handle)); 561 iterator->renderer_handle));
569 } 562 }
570 return process_infos; 563 return process_infos;
571 } 564 }
572 565
573 void OomPriorityManager::AdjustOomPrioritiesOnFileThread( 566 void OomPriorityManager::AdjustOomPrioritiesOnFileThread(
574 TabStatsList stats_list) { 567 TabStatsList stats_list) {
575 DCHECK_CURRENTLY_ON(BrowserThread::FILE); 568 DCHECK_CURRENTLY_ON(BrowserThread::FILE);
576 base::AutoLock oom_score_autolock(oom_score_lock_); 569 base::AutoLock oom_score_autolock(oom_score_lock_);
577 570
578 // Remove any duplicate PIDs. Order of the list is maintained, so each 571 // Remove any duplicate PIDs. Order of the list is maintained, so each
579 // renderer process will take on the oom_score_adj of the most important 572 // renderer process will take on the oom_score_adj of the most important
580 // (least likely to be killed) tab. 573 // (least likely to be killed) tab.
581 std::vector<ProcessInfo> process_infos = GetChildProcessInfos(stats_list); 574 std::vector<ProcessInfo> process_infos = GetChildProcessInfos(stats_list);
582 575
583 // Now we assign priorities based on the sorted list. We're 576 // Now we assign priorities based on the sorted list. We're
584 // assigning priorities in the range of kLowestRendererOomScore to 577 // assigning priorities in the range of kLowestRendererOomScore to
585 // kHighestRendererOomScore (defined in chrome_constants.h). 578 // kHighestRendererOomScore (defined in chrome_constants.h).
586 // oom_score_adj takes values from -1000 to 1000. Negative values 579 // oom_score_adj takes values from -1000 to 1000. Negative values
587 // are reserved for system processes, and we want to give some room 580 // are reserved for system processes, and we want to give some room
588 // below the range we're using to allow for things that want to be 581 // below the range we're using to allow for things that want to be
589 // above the renderers in priority, so the defined range gives us 582 // above the renderers in priority, so the defined range gives us
590 // some variation in priority without taking up the whole range. In 583 // some variation in priority without taking up the whole range. In
591 // the end, however, it's a pretty arbitrary range to use. Higher 584 // the end, however, it's a pretty arbitrary range to use. Higher
592 // values are more likely to be killed by the OOM killer. 585 // values are more likely to be killed by the OOM killer.
593 float priority = chrome::kLowestRendererOomScore; 586 float priority = chrome::kLowestRendererOomScore;
594 const int kPriorityRange = chrome::kHighestRendererOomScore - 587 const int kPriorityRange =
595 chrome::kLowestRendererOomScore; 588 chrome::kHighestRendererOomScore - chrome::kLowestRendererOomScore;
596 float priority_increment = 589 float priority_increment =
597 static_cast<float>(kPriorityRange) / process_infos.size(); 590 static_cast<float>(kPriorityRange) / process_infos.size();
598 for (const auto& process_info : process_infos) { 591 for (const auto& process_info : process_infos) {
599 int score = static_cast<int>(priority + 0.5f); 592 int score = static_cast<int>(priority + 0.5f);
600 ProcessScoreMap::iterator it = 593 ProcessScoreMap::iterator it = oom_score_map_.find(process_info.first);
601 oom_score_map_.find(process_info.first);
602 // If a process has the same score as the newly calculated value, 594 // If a process has the same score as the newly calculated value,
603 // do not set it. 595 // do not set it.
604 if (it == oom_score_map_.end() || it->second != score) { 596 if (it == oom_score_map_.end() || it->second != score) {
605 content::ZygoteHost::GetInstance()->AdjustRendererOOMScore( 597 content::ZygoteHost::GetInstance()->AdjustRendererOOMScore(
606 process_info.second, score); 598 process_info.second, score);
607 oom_score_map_[process_info.first] = score; 599 oom_score_map_[process_info.first] = score;
608 } 600 }
609 priority += priority_increment; 601 priority += priority_increment;
610 } 602 }
611 } 603 }
612 604
613 void OomPriorityManager::OnMemoryPressure( 605 void OomPriorityManager::OnMemoryPressure(
614 base::MemoryPressureListener::MemoryPressureLevel memory_pressure_level) { 606 base::MemoryPressureListener::MemoryPressureLevel memory_pressure_level) {
615 // For the moment we only do something when we reach a critical state. 607 // For the moment we only do something when we reach a critical state.
616 if (memory_pressure_level == 608 if (memory_pressure_level ==
617 base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL) { 609 base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL) {
618 LogMemoryAndDiscardTab(); 610 LogMemoryAndDiscardTab();
619 } 611 }
620 // TODO(skuhne): If more memory pressure levels are introduced, we might 612 // TODO(skuhne): If more memory pressure levels are introduced, we might
621 // consider to call PurgeBrowserMemory() before CRITICAL is reached. 613 // consider to call PurgeBrowserMemory() before CRITICAL is reached.
622 } 614 }
623 615
624 } // namespace chromeos 616 } // namespace memory
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698