summaryrefslogtreecommitdiffstats
path: root/chrome/browser
diff options
context:
space:
mode:
authorjamescook@chromium.org <jamescook@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-04-18 17:47:32 +0000
committerjamescook@chromium.org <jamescook@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-04-18 17:47:32 +0000
commitd6d4daeb79e56a071818436148d5fbd62c4f2d8f (patch)
treec2848b58cc3b6182bf862ba99e2eec3a743ad4e4 /chrome/browser
parent0e6ee141ecd519c6b849ffd60f5e58ee7ad05f12 (diff)
downloadchromium_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.cc126
-rw-r--r--chrome/browser/oom_priority_manager.h25
-rw-r--r--chrome/browser/ui/browser.cc9
-rw-r--r--chrome/browser/ui/views/sad_tab_view.cc41
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);