diff options
author | jamescook@chromium.org <jamescook@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-04-18 17:47:32 +0000 |
---|---|---|
committer | jamescook@chromium.org <jamescook@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-04-18 17:47:32 +0000 |
commit | d6d4daeb79e56a071818436148d5fbd62c4f2d8f (patch) | |
tree | c2848b58cc3b6182bf862ba99e2eec3a743ad4e4 /chrome/browser | |
parent | 0e6ee141ecd519c6b849ffd60f5e58ee7ad05f12 (diff) | |
download | chromium_src-d6d4daeb79e56a071818436148d5fbd62c4f2d8f.zip chromium_src-d6d4daeb79e56a071818436148d5fbd62c4f2d8f.tar.gz chromium_src-d6d4daeb79e56a071818436148d5fbd62c4f2d8f.tar.bz2 |
cros: Record UMA stats for tab discards in low memory conditions
* Per discussion with jar@, bin users into categories by number of tabs they have open as a proxy for how "heavily" they use Chrome.
* Separately track time-to-first-discard, as that should be longer as users take a little while to open up all their tabs.
* Also report snapshot of system-wide memory consumption at the time of the discard, to investigate tuning the kernel low-memory signal threshold.
BUG=123179
TEST=use chrome://discards to discard a few tabs, then check chrome://histograms and search for "TabDiscard" to verify the discards were counted
Review URL: https://chromiumcodereview.appspot.com/9969189
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@132811 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser')
-rw-r--r-- | chrome/browser/oom_priority_manager.cc | 126 | ||||
-rw-r--r-- | chrome/browser/oom_priority_manager.h | 25 | ||||
-rw-r--r-- | chrome/browser/ui/browser.cc | 9 | ||||
-rw-r--r-- | chrome/browser/ui/views/sad_tab_view.cc | 41 |
4 files changed, 173 insertions, 28 deletions
diff --git a/chrome/browser/oom_priority_manager.cc b/chrome/browser/oom_priority_manager.cc index 3dc9353..adf635d 100644 --- a/chrome/browser/oom_priority_manager.cc +++ b/chrome/browser/oom_priority_manager.cc @@ -9,6 +9,7 @@ #include "base/bind.h" #include "base/bind_helpers.h" +#include "base/metrics/histogram.h" #include "base/process.h" #include "base/process_util.h" #include "base/string16.h" @@ -46,10 +47,23 @@ namespace browser { namespace { +// Record a time in seconds, over a potential interval of about a day. Must be a +// macro and not a function because the histograms system requires a unique +// static variable at the site of each call. +#define HISTOGRAM_SECONDS(name, sample) HISTOGRAM_CUSTOM_COUNTS( \ + name, sample, 1, 10000, 50) +// Record a size in megabytes, over a potential interval up to 32 GB. +#define HISTOGRAM_MEGABYTES(name, sample) HISTOGRAM_CUSTOM_COUNTS( \ + name, sample, 1, 32768, 50) + // The default interval in seconds after which to adjust the oom_score_adj // value. const int kAdjustmentIntervalSeconds = 10; +// If there has been no priority adjustment in this interval, we assume the +// machine was suspended and correct our timing statistics. +const int kSuspendThresholdSeconds = kAdjustmentIntervalSeconds * 4; + // The default interval in milliseconds to wait before setting the score of // currently focused tab. const int kFocusedTabScoreAdjustIntervalMs = 500; @@ -60,29 +74,6 @@ int64 IdFromTabContents(WebContents* web_contents) { return reinterpret_cast<int64>(web_contents); } -// Discards a tab with the given unique ID. Returns true if discard occurred. -bool DiscardTabById(int64 target_web_contents_id) { - for (BrowserList::const_iterator browser_iterator = BrowserList::begin(); - browser_iterator != BrowserList::end(); ++browser_iterator) { - Browser* browser = *browser_iterator; - TabStripModel* model = browser->tabstrip_model(); - for (int idx = 0; idx < model->count(); idx++) { - // Can't discard tabs that are already discarded. - if (model->IsTabDiscarded(idx)) - continue; - WebContents* web_contents = model->GetTabContentsAt(idx)->web_contents(); - int64 web_contents_id = IdFromTabContents(web_contents); - if (web_contents_id == target_web_contents_id) { - LOG(WARNING) << "Discarding tab " << idx - << " id " << target_web_contents_id; - model->DiscardTabContentsAt(idx); - return true; - } - } - } - return false; -} - } // namespace //////////////////////////////////////////////////////////////////////////////// @@ -100,7 +91,9 @@ OomPriorityManager::TabStats::~TabStats() { } OomPriorityManager::OomPriorityManager() - : focused_tab_pid_(0), low_memory_observer_(new LowMemoryObserver) { + : focused_tab_pid_(0), + low_memory_observer_(new LowMemoryObserver), + discard_count_(0) { registrar_.Add(this, content::NOTIFICATION_RENDERER_PROCESS_CLOSED, content::NotificationService::AllBrowserContextsAndSources()); @@ -124,6 +117,7 @@ void OomPriorityManager::Start() { &OomPriorityManager::AdjustOomPriorities); } low_memory_observer_->Start(); + start_time_ = TimeTicks::Now(); } void OomPriorityManager::Stop() { @@ -167,6 +161,76 @@ bool OomPriorityManager::DiscardTab() { return false; } +bool OomPriorityManager::DiscardTabById(int64 target_web_contents_id) { + for (BrowserList::const_iterator browser_iterator = BrowserList::begin(); + browser_iterator != BrowserList::end(); ++browser_iterator) { + Browser* browser = *browser_iterator; + TabStripModel* model = browser->tabstrip_model(); + for (int idx = 0; idx < model->count(); idx++) { + // Can't discard tabs that are already discarded. + if (model->IsTabDiscarded(idx)) + continue; + WebContents* web_contents = model->GetTabContentsAt(idx)->web_contents(); + int64 web_contents_id = IdFromTabContents(web_contents); + if (web_contents_id == target_web_contents_id) { + LOG(WARNING) << "Discarding tab " << idx + << " id " << target_web_contents_id; + // Record statistics before discarding because we want to capture the + // memory state that lead to the discard. + RecordDiscardStatistics(); + model->DiscardTabContentsAt(idx); + return true; + } + } + } + return false; +} + +void OomPriorityManager::RecordDiscardStatistics() { + // Record a raw count so we can compare to discard reloads. + discard_count_++; + HISTOGRAM_COUNTS_10000("Tabs.Discard.DiscardCount", discard_count_); + + // TODO(jamescook): Maybe incorporate extension count? + HISTOGRAM_COUNTS_100("Tabs.Discard.TabCount", GetTabCount()); + + // TODO(jamescook): If the time stats prove too noisy, then divide up users + // based on how heavily they use Chrome using tab count as a proxy. + // Bin into <= 1, <= 2, <= 4, <= 8, etc. + if (last_discard_time_.is_null()) { + // This is the first discard this session. + TimeDelta interval = TimeTicks::Now() - start_time_; + int interval_seconds = static_cast<int>(interval.InSeconds()); + HISTOGRAM_SECONDS("Tabs.Discard.InitialTime", interval_seconds); + } else { + // Not the first discard, so compute time since last discard. + TimeDelta interval = TimeTicks::Now() - last_discard_time_; + int interval_seconds = static_cast<int>(interval.InSeconds()); + HISTOGRAM_SECONDS("Tabs.Discard.IntervalTime", interval_seconds); + } + // Record Chrome's concept of system memory usage at the time of the discard. + base::SystemMemoryInfoKB memory; + if (base::GetSystemMemoryInfo(&memory)) { + int mem_anonymous_kb = memory.active_anon + memory.inactive_anon; + HISTOGRAM_MEGABYTES("Tabs.Discard.MemAnonymousMB", mem_anonymous_kb / 1024); + int mem_available_kb = + memory.active_file + memory.inactive_file + memory.free; + HISTOGRAM_MEGABYTES("Tabs.Discard.MemAvailableMB", mem_available_kb / 1024); + } + // Set up to record the next interval. + last_discard_time_ = TimeTicks::Now(); +} + +int OomPriorityManager::GetTabCount() const { + int tab_count = 0; + for (BrowserList::const_iterator browser_it = BrowserList::begin(); + browser_it != BrowserList::end(); ++browser_it) { + Browser* browser = *browser_it; + tab_count += browser->tabstrip_model()->count(); + } + return tab_count; +} + // Returns true if |first| is considered less desirable to be killed // than |second|. bool OomPriorityManager::CompareTabStats(TabStats first, @@ -269,6 +333,20 @@ void OomPriorityManager::Observe(int type, void OomPriorityManager::AdjustOomPriorities() { if (BrowserList::size() == 0) return; + + // Check for a discontinuity in time caused by the machine being suspended. + if (!last_adjust_time_.is_null()) { + TimeDelta suspend_time = TimeTicks::Now() - last_adjust_time_; + if (suspend_time.InSeconds() > kSuspendThresholdSeconds) { + // We were probably suspended, move our event timers forward in time so + // when we subtract them out later we are counting "uptime". + start_time_ += suspend_time; + if (!last_discard_time_.is_null()) + last_discard_time_ += suspend_time; + } + } + last_adjust_time_ = TimeTicks::Now(); + TabStatsList stats_list = GetTabStatsOnUIThread(); BrowserThread::PostTask( BrowserThread::FILE, FROM_HERE, diff --git a/chrome/browser/oom_priority_manager.h b/chrome/browser/oom_priority_manager.h index e53d478..866ec4d 100644 --- a/chrome/browser/oom_priority_manager.h +++ b/chrome/browser/oom_priority_manager.h @@ -66,6 +66,17 @@ class OomPriorityManager : public content::NotificationObserver { }; typedef std::vector<TabStats> TabStatsList; + // Discards a tab with the given unique ID. Returns true if discard occurred. + bool DiscardTabById(int64 target_web_contents_id); + + // Records UMA histogram statistics for a tab discard. We record statistics + // for user triggered discards via chrome://discards/ because that allows us + // to manually test the system. + void RecordDiscardStatistics(); + + // Returns the number of tabs open in all browser instances. + int GetTabCount() const; + TabStatsList GetTabStatsOnUIThread(); // Called when the timer fires, sets oom_adjust_score for all renderers. @@ -99,6 +110,20 @@ class OomPriorityManager : public content::NotificationObserver { scoped_ptr<LowMemoryObserver> low_memory_observer_; + // Wall-clock time when the priority manager started running. + base::TimeTicks start_time_; + + // Wall-clock time of last tab discard during this browsing session, or 0 if + // no discard has happened yet. + base::TimeTicks last_discard_time_; + + // Wall-clock time of last priority adjustment, used to correct the above + // times for discontinuities caused by suspend/resume. + base::TimeTicks last_adjust_time_; + + // Number of times we have discarded a tab, for statistics. + int discard_count_; + DISALLOW_COPY_AND_ASSIGN(OomPriorityManager); }; diff --git a/chrome/browser/ui/browser.cc b/chrome/browser/ui/browser.cc index b7c90ee..66744f5 100644 --- a/chrome/browser/ui/browser.cc +++ b/chrome/browser/ui/browser.cc @@ -3539,8 +3539,9 @@ void Browser::ActiveTabChanged(TabContentsWrapper* old_contents, base::TERMINATION_STATUS_PROCESS_WAS_KILLED) { const CommandLine& parsed_command_line = *CommandLine::ForCurrentProcess(); if (parsed_command_line.HasSwitch(switches::kReloadKilledTabs)) { - // Log to track down crash crbug.com/119068 LOG(WARNING) << "Reloading killed tab at " << index; + static int reload_count = 0; + HISTOGRAM_COUNTS_10000("Tabs.SadTab.ReloadCount", ++reload_count); Reload(CURRENT_TAB); did_reload = true; } @@ -3548,9 +3549,9 @@ void Browser::ActiveTabChanged(TabContentsWrapper* old_contents, // Discarded tabs always get reloaded. if (!did_reload && IsTabDiscarded(index)) { - // Log to track down crash crbug.com/119068 - LOG(WARNING) << "Reloading discarded tab at " << index - << " gesture " << user_gesture; + LOG(WARNING) << "Reloading discarded tab at " << index; + static int reload_count = 0; + HISTOGRAM_COUNTS_10000("Tabs.Discard.ReloadCount", ++reload_count); Reload(CURRENT_TAB); } diff --git a/chrome/browser/ui/views/sad_tab_view.cc b/chrome/browser/ui/views/sad_tab_view.cc index 10adbff..560cc52 100644 --- a/chrome/browser/ui/views/sad_tab_view.cc +++ b/chrome/browser/ui/views/sad_tab_view.cc @@ -59,8 +59,29 @@ SadTabView::SadTabView(WebContents* web_contents, Kind kind) // Sometimes the user will never see this tab, so keep track of the total // number of creation events to compare to display events. + // TODO(jamescook): Remove this after R20 stable. Keep it for now so we can + // compare R20 to earlier versions. UMA_HISTOGRAM_COUNTS("SadTab.Created", kind_); + // These stats should use the same counting approach and bucket size used for + // tab discard events in chrome/browser/oom_priority_manager.cc so they can be + // directly compared. + // TODO(jamescook): Maybe track time between sad tabs? + switch (kind_) { + case CRASHED: { + static int crashed = 0; + HISTOGRAM_COUNTS_10000("Tabs.SadTab.CrashCreated", ++crashed); + break; + } + case KILLED: { + static int killed = 0; + HISTOGRAM_COUNTS_10000("Tabs.SadTab.KillCreated", ++killed); + break; + } + default: + NOTREACHED(); + } + // Set the background color. set_background(views::Background::CreateSolidBackground( (kind_ == CRASHED) ? kCrashColor : kKillColor)); @@ -180,7 +201,27 @@ void SadTabView::ViewHierarchyChanged(bool is_add, void SadTabView::OnPaint(gfx::Canvas* canvas) { if (!painted_) { // User actually saw the error, keep track for user experience stats. + // TODO(jamescook): Remove this after R20 stable. Keep it for now so we can + // compare R20 to earlier versions. UMA_HISTOGRAM_COUNTS("SadTab.Displayed", kind_); + + // These stats should use the same counting approach and bucket size used + // for tab discard events in chrome/browser/oom_priority_manager.cc so they + // can be directly compared. + switch (kind_) { + case CRASHED: { + static int crashed = 0; + HISTOGRAM_COUNTS_10000("Tabs.SadTab.CrashDisplayed", ++crashed); + break; + } + case KILLED: { + static int killed = 0; + HISTOGRAM_COUNTS_10000("Tabs.SadTab.KillDisplayed", ++killed); + break; + } + default: + NOTREACHED(); + } painted_ = true; } View::OnPaint(canvas); |