Add out of memory stats for graphics memory, discards per minute

BUG=175805
TEST=Added to browser_tests OomPriorityManagerTest. Also, manual test (see bug)

Review URL: https://codereview.chromium.org/12221159

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@182134 0039d316-1c4b-4281-b951-d872f2087c98
parent 003e76c9
...@@ -72,6 +72,11 @@ const char kExperiment[] = "LowMemoryMargin"; ...@@ -72,6 +72,11 @@ const char kExperiment[] = "LowMemoryMargin";
// value. // value.
const int kAdjustmentIntervalSeconds = 10; const int kAdjustmentIntervalSeconds = 10;
// For each period of this length we record a statistic to indicate whether
// or not the user experienced a low memory event. If you change this interval
// you must replace Tabs.Discard.DiscardInLastMinute with a new statistic.
const int kRecentTabDiscardIntervalSeconds = 60;
// If there has been no priority adjustment in this interval, we assume the // If there has been no priority adjustment in this interval, we assume the
// machine was suspended and correct our timing statistics. // machine was suspended and correct our timing statistics.
const int kSuspendThresholdSeconds = kAdjustmentIntervalSeconds * 4; const int kSuspendThresholdSeconds = kAdjustmentIntervalSeconds * 4;
...@@ -88,6 +93,23 @@ int64 IdFromWebContents(WebContents* web_contents) { ...@@ -88,6 +93,23 @@ int64 IdFromWebContents(WebContents* web_contents) {
return reinterpret_cast<int64>(web_contents); return reinterpret_cast<int64>(web_contents);
} }
// Records a statistics |sample| for UMA histogram |name| using a linear
// distribution of buckets.
void RecordLinearHistogram(const std::string& name,
int sample,
int maximum,
size_t bucket_count) {
// Do not use the UMA_HISTOGRAM_... macros here. They cache the Histogram
// instance and thus only work if |name| is constant.
base::HistogramBase* counter = base::LinearHistogram::FactoryGet(
name,
1, // Minimum. The 0 bin for underflow is automatically added.
maximum + 1, // Ensure bucket size of |maximum| / |bucket_count|.
bucket_count + 2, // Account for the underflow and overflow bins.
base::Histogram::kUmaTargetedHistogramFlag);
counter->Add(sample);
}
} // namespace } // namespace
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
...@@ -154,7 +176,8 @@ OomPriorityManager::TabStats::~TabStats() { ...@@ -154,7 +176,8 @@ OomPriorityManager::TabStats::~TabStats() {
OomPriorityManager::OomPriorityManager() OomPriorityManager::OomPriorityManager()
: focused_tab_pid_(0), : focused_tab_pid_(0),
discard_count_(0) { discard_count_(0),
recent_tab_discard_(false) {
// We only need the low memory observer if we want to discard tabs. // We only need the low memory observer if we want to discard tabs.
if (!CommandLine::ForCurrentProcess()->HasSwitch(switches::kNoDiscardTabs)) if (!CommandLine::ForCurrentProcess()->HasSwitch(switches::kNoDiscardTabs))
low_memory_observer_.reset(new LowMemoryObserver); low_memory_observer_.reset(new LowMemoryObserver);
...@@ -181,6 +204,13 @@ void OomPriorityManager::Start() { ...@@ -181,6 +204,13 @@ void OomPriorityManager::Start() {
this, this,
&OomPriorityManager::AdjustOomPriorities); &OomPriorityManager::AdjustOomPriorities);
} }
if (!recent_tab_discard_timer_.IsRunning()) {
recent_tab_discard_timer_.Start(
FROM_HERE,
TimeDelta::FromSeconds(kRecentTabDiscardIntervalSeconds),
this,
&OomPriorityManager::RecordRecentTabDiscard);
}
if (low_memory_observer_.get()) if (low_memory_observer_.get())
low_memory_observer_->Start(); low_memory_observer_->Start();
start_time_ = TimeTicks::Now(); start_time_ = TimeTicks::Now();
...@@ -188,6 +218,7 @@ void OomPriorityManager::Start() { ...@@ -188,6 +218,7 @@ void OomPriorityManager::Start() {
void OomPriorityManager::Stop() { void OomPriorityManager::Stop() {
timer_.Stop(); timer_.Stop();
recent_tab_discard_timer_.Stop();
if (low_memory_observer_.get()) if (low_memory_observer_.get())
low_memory_observer_->Stop(); low_memory_observer_->Stop();
} }
...@@ -282,6 +313,7 @@ bool OomPriorityManager::DiscardTabById(int64 target_web_contents_id) { ...@@ -282,6 +313,7 @@ bool OomPriorityManager::DiscardTabById(int64 target_web_contents_id) {
// memory state that lead to the discard. // memory state that lead to the discard.
RecordDiscardStatistics(); RecordDiscardStatistics();
model->DiscardWebContentsAt(idx); model->DiscardWebContentsAt(idx);
recent_tab_discard_ = true;
return true; return true;
} }
} }
...@@ -327,12 +359,22 @@ void OomPriorityManager::RecordDiscardStatistics() { ...@@ -327,12 +359,22 @@ void OomPriorityManager::RecordDiscardStatistics() {
EXPERIMENT_HISTOGRAM_MEGABYTES("Tabs.Discard.MemAnonymousMB", EXPERIMENT_HISTOGRAM_MEGABYTES("Tabs.Discard.MemAnonymousMB",
mem_anonymous_mb); mem_anonymous_mb);
// Record graphics GEM object size in a histogram with 50 MB buckets.
int mem_graphics_gem_mb = 0;
if (memory.gem_size != -1)
mem_graphics_gem_mb = memory.gem_size / 1024 / 1024;
RecordLinearHistogram(
"Tabs.Discard.MemGraphicsMB", mem_graphics_gem_mb, 2500, 50);
// Record shared memory (used by renderer/GPU buffers).
int mem_shmem_mb = memory.shmem / 1024;
RecordLinearHistogram("Tabs.Discard.MemShmemMB", mem_shmem_mb, 2500, 50);
// On Intel, graphics objects are in anonymous pages, but on ARM they are // On Intel, graphics objects are in anonymous pages, but on ARM they are
// not. For a total "allocated count" add in graphics pages on ARM. // not. For a total "allocated count" add in graphics pages on ARM.
int mem_allocated_mb = mem_anonymous_mb; int mem_allocated_mb = mem_anonymous_mb;
#if defined(ARCH_CPU_ARM_FAMILY) #if defined(ARCH_CPU_ARM_FAMILY)
if (memory.gem_size != -1) mem_allocated_mb += mem_graphics_gem_mb;
mem_allocated_mb += memory.gem_size / 1024 / 1024;
#endif #endif
EXPERIMENT_CUSTOM_COUNTS("Tabs.Discard.MemAllocatedMB", mem_allocated_mb, EXPERIMENT_CUSTOM_COUNTS("Tabs.Discard.MemAllocatedMB", mem_allocated_mb,
256, 32768, 50) 256, 32768, 50)
...@@ -346,6 +388,15 @@ void OomPriorityManager::RecordDiscardStatistics() { ...@@ -346,6 +388,15 @@ void OomPriorityManager::RecordDiscardStatistics() {
last_discard_time_ = TimeTicks::Now(); last_discard_time_ = TimeTicks::Now();
} }
void OomPriorityManager::RecordRecentTabDiscard() {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
// If we change the interval we need to change the histogram name.
UMA_HISTOGRAM_BOOLEAN("Tabs.Discard.DiscardInLastMinute",
recent_tab_discard_);
// Reset for the next interval.
recent_tab_discard_ = false;
}
void OomPriorityManager::PurgeBrowserMemory() { void OomPriorityManager::PurgeBrowserMemory() {
// Based on experimental evidence, attempts to free memory from renderers // Based on experimental evidence, attempts to free memory from renderers
// have been too slow to use in OOM situations (V8 garbage collection) or // have been too slow to use in OOM situations (V8 garbage collection) or
......
...@@ -42,6 +42,9 @@ class OomPriorityManager : public content::NotificationObserver { ...@@ -42,6 +42,9 @@ class OomPriorityManager : public content::NotificationObserver {
// Number of discard events since Chrome started. // Number of discard events since Chrome started.
int discard_count() const { return discard_count_; } int discard_count() const { return discard_count_; }
// See member comment.
bool recent_tab_discard() const { return recent_tab_discard_; }
void Start(); void Start();
void Stop(); void Stop();
...@@ -91,6 +94,10 @@ class OomPriorityManager : public content::NotificationObserver { ...@@ -91,6 +94,10 @@ class OomPriorityManager : public content::NotificationObserver {
// to manually test the system. // to manually test the system.
void RecordDiscardStatistics(); void RecordDiscardStatistics();
// Record whether we ran out of memory during a recent time interval.
// This allows us to normalize low memory statistics versus usage.
void RecordRecentTabDiscard();
// Purges data structures in the browser that can be easily recomputed. // Purges data structures in the browser that can be easily recomputed.
void PurgeBrowserMemory(); void PurgeBrowserMemory();
...@@ -119,6 +126,7 @@ class OomPriorityManager : public content::NotificationObserver { ...@@ -119,6 +126,7 @@ class OomPriorityManager : public content::NotificationObserver {
base::RepeatingTimer<OomPriorityManager> timer_; base::RepeatingTimer<OomPriorityManager> timer_;
base::OneShotTimer<OomPriorityManager> focus_tab_score_adjust_timer_; base::OneShotTimer<OomPriorityManager> focus_tab_score_adjust_timer_;
base::RepeatingTimer<OomPriorityManager> recent_tab_discard_timer_;
content::NotificationRegistrar registrar_; content::NotificationRegistrar registrar_;
// This lock is for pid_to_oom_score_ and focus_tab_pid_. // This lock is for pid_to_oom_score_ and focus_tab_pid_.
...@@ -146,6 +154,10 @@ class OomPriorityManager : public content::NotificationObserver { ...@@ -146,6 +154,10 @@ class OomPriorityManager : public content::NotificationObserver {
// Number of times we have discarded a tab, for statistics. // Number of times we have discarded a tab, for statistics.
int discard_count_; int discard_count_;
// Whether a tab discard event has occurred during the last time interval,
// used for statistics normalized by usage.
bool recent_tab_discard_;
DISALLOW_COPY_AND_ASSIGN(OomPriorityManager); DISALLOW_COPY_AND_ASSIGN(OomPriorityManager);
}; };
......
...@@ -24,6 +24,10 @@ typedef InProcessBrowserTest OomPriorityManagerTest; ...@@ -24,6 +24,10 @@ typedef InProcessBrowserTest OomPriorityManagerTest;
IN_PROC_BROWSER_TEST_F(OomPriorityManagerTest, OomPriorityManagerBasics) { IN_PROC_BROWSER_TEST_F(OomPriorityManagerTest, OomPriorityManagerBasics) {
using content::WindowedNotificationObserver; using content::WindowedNotificationObserver;
chromeos::OomPriorityManager* oom_priority_manager =
g_browser_process->oom_priority_manager();
EXPECT_FALSE(oom_priority_manager->recent_tab_discard());
// Get three tabs open. // Get three tabs open.
WindowedNotificationObserver load1( WindowedNotificationObserver load1(
content::NOTIFICATION_NAV_ENTRY_COMMITTED, content::NOTIFICATION_NAV_ENTRY_COMMITTED,
...@@ -83,6 +87,7 @@ IN_PROC_BROWSER_TEST_F(OomPriorityManagerTest, OomPriorityManagerBasics) { ...@@ -83,6 +87,7 @@ IN_PROC_BROWSER_TEST_F(OomPriorityManagerTest, OomPriorityManagerBasics) {
EXPECT_TRUE(browser()->tab_strip_model()->IsTabDiscarded(0)); EXPECT_TRUE(browser()->tab_strip_model()->IsTabDiscarded(0));
EXPECT_FALSE(browser()->tab_strip_model()->IsTabDiscarded(1)); EXPECT_FALSE(browser()->tab_strip_model()->IsTabDiscarded(1));
EXPECT_FALSE(browser()->tab_strip_model()->IsTabDiscarded(2)); EXPECT_FALSE(browser()->tab_strip_model()->IsTabDiscarded(2));
EXPECT_TRUE(oom_priority_manager->recent_tab_discard());
// Run discard again, make sure it kills the second tab. // Run discard again, make sure it kills the second tab.
EXPECT_TRUE(g_browser_process->oom_priority_manager()->DiscardTab()); EXPECT_TRUE(g_browser_process->oom_priority_manager()->DiscardTab());
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment