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

Side by Side Diff: chrome/browser/chromeos/memory/oom_priority_manager.cc

Issue 12221159: Add out of memory stats for graphics memory, discards per minute (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 7 years, 10 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 | Annotate | Revision Log
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/chromeos/memory/oom_priority_manager.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 #include <set> 8 #include <set>
9 #include <vector> 9 #include <vector>
10 10
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after
65 } 65 }
66 66
67 // Record a size in megabytes, over a potential interval up to 32 GB. 67 // Record a size in megabytes, over a potential interval up to 32 GB.
68 #define EXPERIMENT_HISTOGRAM_MEGABYTES(name, sample) \ 68 #define EXPERIMENT_HISTOGRAM_MEGABYTES(name, sample) \
69 EXPERIMENT_CUSTOM_COUNTS(name, sample, 1, 32768, 50) 69 EXPERIMENT_CUSTOM_COUNTS(name, sample, 1, 32768, 50)
70 70
71 // The default interval in seconds after which to adjust the oom_score_adj 71 // The default interval in seconds after which to adjust the oom_score_adj
72 // value. 72 // value.
73 const int kAdjustmentIntervalSeconds = 10; 73 const int kAdjustmentIntervalSeconds = 10;
74 74
75 // For each period of this length we record a statistic to indicate whether
76 // or not the user experienced a low memory event. If you change this interval
77 // you must replace Tabs.Discard.DiscardInLastMinute with a new statistic.
78 const int kRecentTabDiscardIntervalSeconds = 60;
79
75 // If there has been no priority adjustment in this interval, we assume the 80 // If there has been no priority adjustment in this interval, we assume the
76 // machine was suspended and correct our timing statistics. 81 // machine was suspended and correct our timing statistics.
77 const int kSuspendThresholdSeconds = kAdjustmentIntervalSeconds * 4; 82 const int kSuspendThresholdSeconds = kAdjustmentIntervalSeconds * 4;
78 83
79 // When switching to a new tab the tab's renderer's OOM score needs to be 84 // When switching to a new tab the tab's renderer's OOM score needs to be
80 // updated to reflect its front-most status and protect it from discard. 85 // updated to reflect its front-most status and protect it from discard.
81 // However, doing this immediately might slow down tab switch time, so wait 86 // However, doing this immediately might slow down tab switch time, so wait
82 // a little while before doing the adjustment. 87 // a little while before doing the adjustment.
83 const int kFocusedTabScoreAdjustIntervalMs = 500; 88 const int kFocusedTabScoreAdjustIntervalMs = 500;
84 89
85 // Returns a unique ID for a WebContents. Do not cast back to a pointer, as 90 // Returns a unique ID for a WebContents. Do not cast back to a pointer, as
86 // the WebContents could be deleted if the user closed the tab. 91 // the WebContents could be deleted if the user closed the tab.
87 int64 IdFromWebContents(WebContents* web_contents) { 92 int64 IdFromWebContents(WebContents* web_contents) {
88 return reinterpret_cast<int64>(web_contents); 93 return reinterpret_cast<int64>(web_contents);
89 } 94 }
90 95
96 // Records a statistics |sample| for UMA histogram |name| using a linear
97 // distribution of buckets.
98 void RecordLinearHistogram(const std::string& name,
99 int sample,
100 int maximum,
101 size_t bucket_count) {
102 // Do not use the UMA_HISTOGRAM_... macros here. They cache the Histogram
103 // instance and thus only work if |name| is constant.
104 base::HistogramBase* counter = base::LinearHistogram::FactoryGet(
105 name,
106 1, // Minimum. The 0 bin for underflow is automatically added.
107 maximum + 1, // Ensure bucket size of |maximum| / |bucket_count|.
108 bucket_count + 2, // Account for the underflow and overflow bins.
109 base::Histogram::kUmaTargetedHistogramFlag);
110 counter->Add(sample);
111 }
112
91 } // namespace 113 } // namespace
92 114
93 //////////////////////////////////////////////////////////////////////////////// 115 ////////////////////////////////////////////////////////////////////////////////
94 // OomMemoryDetails logs details about all Chrome processes during an out-of- 116 // OomMemoryDetails logs details about all Chrome processes during an out-of-
95 // memory event in an attempt to identify the culprit, then discards a tab and 117 // memory event in an attempt to identify the culprit, then discards a tab and
96 // deletes itself. 118 // deletes itself.
97 class OomMemoryDetails : public MemoryDetails { 119 class OomMemoryDetails : public MemoryDetails {
98 public: 120 public:
99 OomMemoryDetails(); 121 OomMemoryDetails();
100 122
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after
147 is_discarded(false), 169 is_discarded(false),
148 renderer_handle(0), 170 renderer_handle(0),
149 tab_contents_id(0) { 171 tab_contents_id(0) {
150 } 172 }
151 173
152 OomPriorityManager::TabStats::~TabStats() { 174 OomPriorityManager::TabStats::~TabStats() {
153 } 175 }
154 176
155 OomPriorityManager::OomPriorityManager() 177 OomPriorityManager::OomPriorityManager()
156 : focused_tab_pid_(0), 178 : focused_tab_pid_(0),
157 discard_count_(0) { 179 discard_count_(0),
180 recent_tab_discard_(false) {
158 // We only need the low memory observer if we want to discard tabs. 181 // We only need the low memory observer if we want to discard tabs.
159 if (!CommandLine::ForCurrentProcess()->HasSwitch(switches::kNoDiscardTabs)) 182 if (!CommandLine::ForCurrentProcess()->HasSwitch(switches::kNoDiscardTabs))
160 low_memory_observer_.reset(new LowMemoryObserver); 183 low_memory_observer_.reset(new LowMemoryObserver);
161 184
162 registrar_.Add(this, 185 registrar_.Add(this,
163 content::NOTIFICATION_RENDERER_PROCESS_CLOSED, 186 content::NOTIFICATION_RENDERER_PROCESS_CLOSED,
164 content::NotificationService::AllBrowserContextsAndSources()); 187 content::NotificationService::AllBrowserContextsAndSources());
165 registrar_.Add(this, 188 registrar_.Add(this,
166 content::NOTIFICATION_RENDERER_PROCESS_TERMINATED, 189 content::NOTIFICATION_RENDERER_PROCESS_TERMINATED,
167 content::NotificationService::AllBrowserContextsAndSources()); 190 content::NotificationService::AllBrowserContextsAndSources());
168 registrar_.Add(this, 191 registrar_.Add(this,
169 content::NOTIFICATION_RENDER_WIDGET_VISIBILITY_CHANGED, 192 content::NOTIFICATION_RENDER_WIDGET_VISIBILITY_CHANGED,
170 content::NotificationService::AllBrowserContextsAndSources()); 193 content::NotificationService::AllBrowserContextsAndSources());
171 } 194 }
172 195
173 OomPriorityManager::~OomPriorityManager() { 196 OomPriorityManager::~OomPriorityManager() {
174 Stop(); 197 Stop();
175 } 198 }
176 199
177 void OomPriorityManager::Start() { 200 void OomPriorityManager::Start() {
178 if (!timer_.IsRunning()) { 201 if (!timer_.IsRunning()) {
179 timer_.Start(FROM_HERE, 202 timer_.Start(FROM_HERE,
180 TimeDelta::FromSeconds(kAdjustmentIntervalSeconds), 203 TimeDelta::FromSeconds(kAdjustmentIntervalSeconds),
181 this, 204 this,
182 &OomPriorityManager::AdjustOomPriorities); 205 &OomPriorityManager::AdjustOomPriorities);
183 } 206 }
207 if (!recent_tab_discard_timer_.IsRunning()) {
208 recent_tab_discard_timer_.Start(
209 FROM_HERE,
210 TimeDelta::FromSeconds(kRecentTabDiscardIntervalSeconds),
211 this,
212 &OomPriorityManager::RecordRecentTabDiscard);
213 }
184 if (low_memory_observer_.get()) 214 if (low_memory_observer_.get())
185 low_memory_observer_->Start(); 215 low_memory_observer_->Start();
186 start_time_ = TimeTicks::Now(); 216 start_time_ = TimeTicks::Now();
187 } 217 }
188 218
189 void OomPriorityManager::Stop() { 219 void OomPriorityManager::Stop() {
190 timer_.Stop(); 220 timer_.Stop();
221 recent_tab_discard_timer_.Stop();
191 if (low_memory_observer_.get()) 222 if (low_memory_observer_.get())
192 low_memory_observer_->Stop(); 223 low_memory_observer_->Stop();
193 } 224 }
194 225
195 std::vector<string16> OomPriorityManager::GetTabTitles() { 226 std::vector<string16> OomPriorityManager::GetTabTitles() {
196 TabStatsList stats = GetTabStatsOnUIThread(); 227 TabStatsList stats = GetTabStatsOnUIThread();
197 base::AutoLock pid_to_oom_score_autolock(pid_to_oom_score_lock_); 228 base::AutoLock pid_to_oom_score_autolock(pid_to_oom_score_lock_);
198 std::vector<string16> titles; 229 std::vector<string16> titles;
199 titles.reserve(stats.size()); 230 titles.reserve(stats.size());
200 TabStatsList::iterator it = stats.begin(); 231 TabStatsList::iterator it = stats.begin();
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after
275 continue; 306 continue;
276 WebContents* web_contents = model->GetWebContentsAt(idx); 307 WebContents* web_contents = model->GetWebContentsAt(idx);
277 int64 web_contents_id = IdFromWebContents(web_contents); 308 int64 web_contents_id = IdFromWebContents(web_contents);
278 if (web_contents_id == target_web_contents_id) { 309 if (web_contents_id == target_web_contents_id) {
279 LOG(WARNING) << "Discarding tab " << idx 310 LOG(WARNING) << "Discarding tab " << idx
280 << " id " << target_web_contents_id; 311 << " id " << target_web_contents_id;
281 // Record statistics before discarding because we want to capture the 312 // Record statistics before discarding because we want to capture the
282 // memory state that lead to the discard. 313 // memory state that lead to the discard.
283 RecordDiscardStatistics(); 314 RecordDiscardStatistics();
284 model->DiscardWebContentsAt(idx); 315 model->DiscardWebContentsAt(idx);
316 recent_tab_discard_ = true;
285 return true; 317 return true;
286 } 318 }
287 } 319 }
288 } 320 }
289 return false; 321 return false;
290 } 322 }
291 323
292 void OomPriorityManager::RecordDiscardStatistics() { 324 void OomPriorityManager::RecordDiscardStatistics() {
293 // Record a raw count so we can compare to discard reloads. 325 // Record a raw count so we can compare to discard reloads.
294 discard_count_++; 326 discard_count_++;
(...skipping 25 matching lines...) Expand all
320 // Record Chrome's concept of system memory usage at the time of the discard. 352 // Record Chrome's concept of system memory usage at the time of the discard.
321 base::SystemMemoryInfoKB memory; 353 base::SystemMemoryInfoKB memory;
322 if (base::GetSystemMemoryInfo(&memory)) { 354 if (base::GetSystemMemoryInfo(&memory)) {
323 // TODO(jamescook): Remove this after R25 is deployed to stable. It does 355 // TODO(jamescook): Remove this after R25 is deployed to stable. It does
324 // not have sufficient resolution in the 2-4 GB range and does not properly 356 // not have sufficient resolution in the 2-4 GB range and does not properly
325 // account for graphics memory on ARM. Replace with MemAllocatedMB below. 357 // account for graphics memory on ARM. Replace with MemAllocatedMB below.
326 int mem_anonymous_mb = (memory.active_anon + memory.inactive_anon) / 1024; 358 int mem_anonymous_mb = (memory.active_anon + memory.inactive_anon) / 1024;
327 EXPERIMENT_HISTOGRAM_MEGABYTES("Tabs.Discard.MemAnonymousMB", 359 EXPERIMENT_HISTOGRAM_MEGABYTES("Tabs.Discard.MemAnonymousMB",
328 mem_anonymous_mb); 360 mem_anonymous_mb);
329 361
362 // Record graphics GEM object size in a histogram with 50 MB buckets.
363 int mem_graphics_gem_mb = 0;
364 if (memory.gem_size != -1)
365 mem_graphics_gem_mb = memory.gem_size / 1024 / 1024;
366 RecordLinearHistogram(
367 "Tabs.Discard.MemGraphicsMB", mem_graphics_gem_mb, 2500, 50);
368
369 // Record shared memory (used by renderer/GPU buffers).
370 int mem_shmem_mb = memory.shmem / 1024;
371 RecordLinearHistogram("Tabs.Discard.MemShmemMB", mem_shmem_mb, 2500, 50);
372
330 // On Intel, graphics objects are in anonymous pages, but on ARM they are 373 // On Intel, graphics objects are in anonymous pages, but on ARM they are
331 // not. For a total "allocated count" add in graphics pages on ARM. 374 // not. For a total "allocated count" add in graphics pages on ARM.
332 int mem_allocated_mb = mem_anonymous_mb; 375 int mem_allocated_mb = mem_anonymous_mb;
333 #if defined(ARCH_CPU_ARM_FAMILY) 376 #if defined(ARCH_CPU_ARM_FAMILY)
334 if (memory.gem_size != -1) 377 mem_allocated_mb += mem_graphics_gem_mb;
335 mem_allocated_mb += memory.gem_size / 1024 / 1024;
336 #endif 378 #endif
337 EXPERIMENT_CUSTOM_COUNTS("Tabs.Discard.MemAllocatedMB", mem_allocated_mb, 379 EXPERIMENT_CUSTOM_COUNTS("Tabs.Discard.MemAllocatedMB", mem_allocated_mb,
338 256, 32768, 50) 380 256, 32768, 50)
339 381
340 int mem_available_mb = 382 int mem_available_mb =
341 (memory.active_file + memory.inactive_file + memory.free) / 1024; 383 (memory.active_file + memory.inactive_file + memory.free) / 1024;
342 EXPERIMENT_HISTOGRAM_MEGABYTES("Tabs.Discard.MemAvailableMB", 384 EXPERIMENT_HISTOGRAM_MEGABYTES("Tabs.Discard.MemAvailableMB",
343 mem_available_mb); 385 mem_available_mb);
344 } 386 }
345 // Set up to record the next interval. 387 // Set up to record the next interval.
346 last_discard_time_ = TimeTicks::Now(); 388 last_discard_time_ = TimeTicks::Now();
347 } 389 }
348 390
391 void OomPriorityManager::RecordRecentTabDiscard() {
392 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
393 // If we change the interval we need to change the histogram name.
394 UMA_HISTOGRAM_BOOLEAN("Tabs.Discard.DiscardInLastMinute",
395 recent_tab_discard_);
396 // Reset for the next interval.
397 recent_tab_discard_ = false;
398 }
399
349 void OomPriorityManager::PurgeBrowserMemory() { 400 void OomPriorityManager::PurgeBrowserMemory() {
350 // Based on experimental evidence, attempts to free memory from renderers 401 // Based on experimental evidence, attempts to free memory from renderers
351 // have been too slow to use in OOM situations (V8 garbage collection) or 402 // have been too slow to use in OOM situations (V8 garbage collection) or
352 // do not lead to persistent decreased usage (image/bitmap caches). This 403 // do not lead to persistent decreased usage (image/bitmap caches). This
353 // function therefore only targets large blocks of memory in the browser. 404 // function therefore only targets large blocks of memory in the browser.
354 for (TabContentsIterator it; !it.done(); it.Next()) { 405 for (TabContentsIterator it; !it.done(); it.Next()) {
355 WebContents* web_contents = *it; 406 WebContents* web_contents = *it;
356 // Screenshots can consume ~5 MB per web contents for platforms that do 407 // Screenshots can consume ~5 MB per web contents for platforms that do
357 // touch back/forward. 408 // touch back/forward.
358 web_contents->GetController().ClearAllScreenshots(); 409 web_contents->GetController().ClearAllScreenshots();
(...skipping 222 matching lines...) Expand 10 before | Expand all | Expand 10 after
581 content::ZygoteHost::GetInstance()->AdjustRendererOOMScore( 632 content::ZygoteHost::GetInstance()->AdjustRendererOOMScore(
582 iterator->renderer_handle, score); 633 iterator->renderer_handle, score);
583 pid_to_oom_score_[iterator->renderer_handle] = score; 634 pid_to_oom_score_[iterator->renderer_handle] = score;
584 } 635 }
585 priority += priority_increment; 636 priority += priority_increment;
586 } 637 }
587 } 638 }
588 } 639 }
589 640
590 } // namespace chromeos 641 } // namespace chromeos
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698