Skip to content

Commit

Permalink
Add daily discard/reload histograms
Browse files Browse the repository at this point in the history
Add histograms Discarding.Daily{Discards|Reloads}.{Extension|Urgent}.
These discard/reload histograms are reported per calendar day.

(cherry picked from commit 26bdf55)

Bug: b:205905993
Change-Id: I3f8c526913c4e18a0f3d2349c026620017e58add
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3460191
Reviewed-by: Yusuke Sato <yusukes@chromium.org>
Reviewed-by: Francois Pierre Doray <fdoray@chromium.org>
Reviewed-by: Olivier Li Shing Tat-Dupuis <olivierli@google.com>
Reviewed-by: Olivier Li <olivierli@chromium.org>
Commit-Queue: Vovo Yang <vovoy@chromium.org>
Cr-Original-Commit-Position: refs/heads/main@{#973054}
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3505724
Auto-Submit: Vovo Yang <vovoy@chromium.org>
Commit-Queue: Olivier Li <olivierli@chromium.org>
Cr-Commit-Position: refs/branch-heads/4896@{#341}
Cr-Branched-From: 1f63ff4-refs/heads/main@{#972766}
  • Loading branch information
Kuo-Hsin Yang authored and Chromium LUCI CQ committed Mar 7, 2022
1 parent 7111ea4 commit f962a27
Show file tree
Hide file tree
Showing 9 changed files with 317 additions and 2 deletions.
53 changes: 52 additions & 1 deletion chrome/browser/metrics/tab_stats/tab_stats_data_store.cc
Expand Up @@ -8,6 +8,7 @@
#include <utility>

#include "base/containers/contains.h"
#include "base/notreached.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_list.h"
#include "chrome/browser/ui/tabs/tab_strip_model.h"
Expand All @@ -33,7 +34,10 @@ TabStatsDataStore::TabsStats::TabsStats()
total_tab_count_max(0U),
max_tab_per_window(0U),
window_count(0U),
window_count_max(0U) {}
window_count_max(0U) {
tab_discard_counts.fill(0U);
tab_reload_counts.fill(0U);
}
TabStatsDataStore::TabsStats::TabsStats(const TabsStats& other) = default;
TabStatsDataStore::TabsStats& TabStatsDataStore::TabsStats::operator=(
const TabsStats& other) = default;
Expand All @@ -47,6 +51,20 @@ TabStatsDataStore::TabStatsDataStore(PrefService* pref_service)
pref_service->GetInteger(::prefs::kTabStatsMaxTabsPerWindow);
tab_stats_.window_count_max =
pref_service->GetInteger(::prefs::kTabStatsWindowCountMax);

// Loads discard/reload counters.
tab_stats_.tab_discard_counts[static_cast<size_t>(
LifecycleUnitDiscardReason::EXTERNAL)] =
pref_service->GetInteger(::prefs::kTabStatsDiscardsExternal);
tab_stats_.tab_discard_counts[static_cast<size_t>(
LifecycleUnitDiscardReason::URGENT)] =
pref_service->GetInteger(::prefs::kTabStatsDiscardsUrgent);
tab_stats_.tab_reload_counts[static_cast<size_t>(
LifecycleUnitDiscardReason::EXTERNAL)] =
pref_service->GetInteger(::prefs::kTabStatsReloadsExternal);
tab_stats_.tab_reload_counts[static_cast<size_t>(
LifecycleUnitDiscardReason::URGENT)] =
pref_service->GetInteger(::prefs::kTabStatsReloadsUrgent);
}

TabStatsDataStore::~TabStatsDataStore() {}
Expand Down Expand Up @@ -179,6 +197,39 @@ void TabStatsDataStore::ResetIntervalData(
AddTabToIntervalMap(iter.first, GetTabID(iter.first), true, interval_map);
}

void TabStatsDataStore::OnTabDiscardStateChange(
LifecycleUnitDiscardReason discard_reason,
bool is_discarded) {
size_t discard_reason_index = static_cast<size_t>(discard_reason);
size_t& count = is_discarded
? tab_stats_.tab_discard_counts[discard_reason_index]
: tab_stats_.tab_reload_counts[discard_reason_index];
count++;
switch (discard_reason) {
case LifecycleUnitDiscardReason::EXTERNAL:
if (is_discarded)
pref_service_->SetInteger(::prefs::kTabStatsDiscardsExternal, count);
else
pref_service_->SetInteger(::prefs::kTabStatsReloadsExternal, count);
break;
case LifecycleUnitDiscardReason::URGENT:
if (is_discarded)
pref_service_->SetInteger(::prefs::kTabStatsDiscardsUrgent, count);
else
pref_service_->SetInteger(::prefs::kTabStatsReloadsUrgent, count);
break;
}
}

void TabStatsDataStore::ClearTabDiscardAndReloadCounts() {
tab_stats_.tab_discard_counts.fill(0U);
tab_stats_.tab_reload_counts.fill(0U);
pref_service_->SetInteger(::prefs::kTabStatsDiscardsExternal, 0);
pref_service_->SetInteger(::prefs::kTabStatsDiscardsUrgent, 0);
pref_service_->SetInteger(::prefs::kTabStatsReloadsExternal, 0);
pref_service_->SetInteger(::prefs::kTabStatsReloadsUrgent, 0);
}

absl::optional<TabStatsDataStore::TabID> TabStatsDataStore::GetTabIDForTesting(
content::WebContents* web_contents) {
if (!base::Contains(existing_tabs_, web_contents))
Expand Down
21 changes: 21 additions & 0 deletions chrome/browser/metrics/tab_stats/tab_stats_data_store.h
Expand Up @@ -5,6 +5,7 @@
#ifndef CHROME_BROWSER_METRICS_TAB_STATS_TAB_STATS_DATA_STORE_H_
#define CHROME_BROWSER_METRICS_TAB_STATS_TAB_STATS_DATA_STORE_H_

#include <array>
#include <memory>
#include <vector>

Expand Down Expand Up @@ -58,6 +59,16 @@ class TabStatsDataStore : public TabStatsObserver {

// The maximum total number of windows opened at the same time.
size_t window_count_max;

// The number of tabs discarded, per discard reason.
std::array<size_t,
static_cast<size_t>(LifecycleUnitDiscardReason::kMaxValue) + 1>
tab_discard_counts;

// The number of tabs reloaded after a discard, per discard reason.
std::array<size_t,
static_cast<size_t>(LifecycleUnitDiscardReason::kMaxValue) + 1>
tab_reload_counts;
};

// Structure describing the state of a tab during an interval of time.
Expand Down Expand Up @@ -118,6 +129,16 @@ class TabStatsDataStore : public TabStatsObserver {
// Reset |interval_map| with the list of current tabs.
void ResetIntervalData(TabsStateDuringIntervalMap* interval_map);

// Updates discard/reload counts when the discarded state of a tab changes.
// Updates the discard count when is_discarded is true. Updates the reload
// count when is_discarded is false.
void OnTabDiscardStateChange(LifecycleUnitDiscardReason discard_reason,
bool is_discarded);

// Clears the discard and reload counters. Called after reporting the counter
// values.
void ClearTabDiscardAndReloadCounts();

const TabsStats& tab_stats() const { return tab_stats_; }
absl::optional<TabID> GetTabIDForTesting(content::WebContents* web_contents);
base::flat_map<content::WebContents*, TabID>* existing_tabs_for_testing() {
Expand Down
44 changes: 44 additions & 0 deletions chrome/browser/metrics/tab_stats/tab_stats_data_store_unittest.cc
Expand Up @@ -69,6 +69,50 @@ TEST_F(TabStatsDataStoreTest, TabStatsGetsReloadedFromLocalState) {
EXPECT_EQ(0U, stats2.total_tab_count);
}

TEST_F(TabStatsDataStoreTest, DiscardsFromLocalState) {
// This test updates the discard/reload counts to a data store instance and
// then reinitialize it. The data store instance should restore the discard
// and reload counts from the pref service.
constexpr size_t kExpectedDiscardsExternal = 3;
constexpr size_t kExpectedDiscardsUrgent = 5;
constexpr size_t kExpectedReloadsExternal = 8;
constexpr size_t kExpectedReloadsUrgent = 13;
for (size_t i = 0; i < kExpectedDiscardsExternal; ++i) {
data_store_->OnTabDiscardStateChange(LifecycleUnitDiscardReason::EXTERNAL,
/*is_discarded=*/true);
}
for (size_t i = 0; i < kExpectedDiscardsUrgent; ++i) {
data_store_->OnTabDiscardStateChange(LifecycleUnitDiscardReason::URGENT,
/*is_discarded=*/true);
}
for (size_t i = 0; i < kExpectedReloadsExternal; ++i) {
data_store_->OnTabDiscardStateChange(LifecycleUnitDiscardReason::EXTERNAL,
/*is_discarded=*/false);
}
for (size_t i = 0; i < kExpectedReloadsUrgent; ++i) {
data_store_->OnTabDiscardStateChange(LifecycleUnitDiscardReason::URGENT,
/*is_discarded=*/false);
}

const size_t external =
static_cast<size_t>(LifecycleUnitDiscardReason::EXTERNAL);
const size_t urgent = static_cast<size_t>(LifecycleUnitDiscardReason::URGENT);
TabsStats stats = data_store_->tab_stats();
EXPECT_EQ(kExpectedDiscardsExternal, stats.tab_discard_counts[external]);
EXPECT_EQ(kExpectedDiscardsUrgent, stats.tab_discard_counts[urgent]);
EXPECT_EQ(kExpectedReloadsExternal, stats.tab_reload_counts[external]);
EXPECT_EQ(kExpectedReloadsUrgent, stats.tab_reload_counts[urgent]);

// Resets the |data_store_| and checks discard/reload counters are restored.
data_store_ = std::make_unique<TabStatsDataStore>(&pref_service_);

TabsStats stats2 = data_store_->tab_stats();
EXPECT_EQ(kExpectedDiscardsExternal, stats2.tab_discard_counts[external]);
EXPECT_EQ(kExpectedDiscardsUrgent, stats2.tab_discard_counts[urgent]);
EXPECT_EQ(kExpectedReloadsExternal, stats2.tab_reload_counts[external]);
EXPECT_EQ(kExpectedReloadsUrgent, stats2.tab_reload_counts[urgent]);
}

TEST_F(TabStatsDataStoreTest, TrackTabUsageDuringInterval) {
std::vector<std::unique_ptr<content::WebContents>> web_contents_vec;
for (size_t i = 0; i < 3; ++i) {
Expand Down
47 changes: 47 additions & 0 deletions chrome/browser/metrics/tab_stats/tab_stats_tracker.cc
Expand Up @@ -133,6 +133,16 @@ const char
TabStatsTracker::UmaStatsReportingDelegate::kCollapsedTabHistogramName[] =
"TabGroups.CollapsedTabCount";

// Daily discard/reload histograms.
const char TabStatsTracker::UmaStatsReportingDelegate::
kDailyDiscardsExternalHistogramName[] = "Discarding.DailyDiscards.External";
const char TabStatsTracker::UmaStatsReportingDelegate::
kDailyDiscardsUrgentHistogramName[] = "Discarding.DailyDiscards.Urgent";
const char TabStatsTracker::UmaStatsReportingDelegate::
kDailyReloadsExternalHistogramName[] = "Discarding.DailyReloads.External";
const char TabStatsTracker::UmaStatsReportingDelegate::
kDailyReloadsUrgentHistogramName[] = "Discarding.DailyReloads.Urgent";

const TabStatsDataStore::TabsStats& TabStatsTracker::tab_stats() const {
return tab_stats_data_store_->tab_stats();
}
Expand Down Expand Up @@ -205,12 +215,15 @@ TabStatsTracker::TabStatsTracker(PrefService* pref_service)
heartbeat_timer_.Start(FROM_HERE, kTabsHeartbeatReportingInterval,
base::BindRepeating(&TabStatsTracker::OnHeartbeatEvent,
base::Unretained(this)));

g_browser_process->GetTabManager()->AddObserver(this);
}

TabStatsTracker::~TabStatsTracker() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
BrowserList::GetInstance()->RemoveObserver(this);
base::PowerMonitor::RemovePowerSuspendObserver(this);
g_browser_process->GetTabManager()->RemoveObserver(this);
}

// static
Expand Down Expand Up @@ -252,6 +265,12 @@ void TabStatsTracker::RegisterPrefs(PrefRegistrySimple* registry) {
registry->RegisterIntegerPref(::prefs::kTabStatsMaxTabsPerWindow, 0);
registry->RegisterIntegerPref(::prefs::kTabStatsWindowCountMax, 0);
DailyEvent::RegisterPref(registry, ::prefs::kTabStatsDailySample);

// Preferences for saving discard/reload counts.
registry->RegisterIntegerPref(::prefs::kTabStatsDiscardsExternal, 0);
registry->RegisterIntegerPref(::prefs::kTabStatsDiscardsUrgent, 0);
registry->RegisterIntegerPref(::prefs::kTabStatsReloadsExternal, 0);
registry->RegisterIntegerPref(::prefs::kTabStatsReloadsUrgent, 0);
}

void TabStatsTracker::SetDelegateForTesting(
Expand All @@ -263,6 +282,7 @@ void TabStatsTracker::TabStatsDailyObserver::OnDailyEvent(
DailyEvent::IntervalType type) {
reporting_delegate_->ReportDailyMetrics(data_store_->tab_stats());
data_store_->ResetMaximumsToCurrentState();
data_store_->ClearTabDiscardAndReloadCounts();
}

class TabStatsTracker::WebContentsUsageObserver
Expand Down Expand Up @@ -442,6 +462,19 @@ void TabStatsTracker::OnResume() {
tab_stats_data_store_->tab_stats().total_tab_count);
}

// resource_coordinator::TabLifecycleObserver:
void TabStatsTracker::OnDiscardedStateChange(
content::WebContents* contents,
::mojom::LifecycleUnitDiscardReason reason,
bool is_discarded) {
// Increment the count in the data store for tabs metrics reporting.
tab_stats_data_store_->OnTabDiscardStateChange(reason, is_discarded);
}

void TabStatsTracker::OnAutoDiscardableStateChange(
content::WebContents* contents,
bool is_auto_discardable) {}

void TabStatsTracker::OnInterval(
base::TimeDelta interval,
TabStatsDataStore::TabsStateDuringIntervalMap* interval_map) {
Expand Down Expand Up @@ -509,6 +542,20 @@ void TabStatsTracker::UmaStatsReportingDelegate::ReportDailyMetrics(
kMaxTabsPerWindowInADayHistogramName, tab_stats.max_tab_per_window);
UmaHistogramCounts10000WithBatteryStateVariant(kMaxWindowsInADayHistogramName,
tab_stats.window_count_max);

// Reports the discard/reload counts.
const size_t external_index =
static_cast<size_t>(LifecycleUnitDiscardReason::EXTERNAL);
const size_t urgent_index =
static_cast<size_t>(LifecycleUnitDiscardReason::URGENT);
base::UmaHistogramCounts10000(kDailyDiscardsExternalHistogramName,
tab_stats.tab_discard_counts[external_index]);
base::UmaHistogramCounts10000(kDailyDiscardsUrgentHistogramName,
tab_stats.tab_discard_counts[urgent_index]);
base::UmaHistogramCounts10000(kDailyReloadsExternalHistogramName,
tab_stats.tab_reload_counts[external_index]);
base::UmaHistogramCounts10000(kDailyReloadsUrgentHistogramName,
tab_stats.tab_reload_counts[urgent_index]);
}

void TabStatsTracker::UmaStatsReportingDelegate::ReportHeartbeatMetrics(
Expand Down
19 changes: 18 additions & 1 deletion chrome/browser/metrics/tab_stats/tab_stats_tracker.h
Expand Up @@ -19,6 +19,7 @@
#include "build/build_config.h"
#include "chrome/browser/metrics/tab_stats/tab_stats_data_store.h"
#include "chrome/browser/metrics/tab_stats/tab_stats_tracker_delegate.h"
#include "chrome/browser/resource_coordinator/tab_lifecycle_observer.h"
#include "chrome/browser/ui/browser_list_observer.h"
#include "chrome/browser/ui/tabs/tab_strip_model_observer.h"
#include "components/metrics/daily_event.h"
Expand All @@ -39,7 +40,8 @@ FORWARD_DECLARE_TEST(TabStatsTrackerBrowserTest,
// std::make_unique<TabStatsTracker>(g_browser_process->local_state()));
class TabStatsTracker : public TabStripModelObserver,
public BrowserListObserver,
public base::PowerSuspendObserver {
public base::PowerSuspendObserver,
public resource_coordinator::TabLifecycleObserver {
public:
// Constructor. |pref_service| must outlive this object.
explicit TabStatsTracker(PrefService* pref_service);
Expand Down Expand Up @@ -157,6 +159,14 @@ class TabStatsTracker : public TabStripModelObserver,
// base::PowerSuspendObserver:
void OnResume() override;

// resource_coordinator::TabLifecycleObserver:
void OnDiscardedStateChange(content::WebContents* contents,
::mojom::LifecycleUnitDiscardReason reason,
bool is_discarded) override;

void OnAutoDiscardableStateChange(content::WebContents* contents,
bool is_auto_discardable) override;

// Callback when an interval timer triggers.
void OnInterval(base::TimeDelta interval,
TabStatsDataStore::TabsStateDuringIntervalMap* interval_map);
Expand Down Expand Up @@ -263,6 +273,13 @@ class TabStatsTracker::UmaStatsReportingDelegate {
// The name of the histogram that records the number of collapsed tabs.
static const char kCollapsedTabHistogramName[];

// The names of the histograms that record daily discard/reload counts caused
// by external/urgent event.
static const char kDailyDiscardsExternalHistogramName[];
static const char kDailyDiscardsUrgentHistogramName[];
static const char kDailyReloadsExternalHistogramName[];
static const char kDailyReloadsUrgentHistogramName[];

UmaStatsReportingDelegate() = default;

UmaStatsReportingDelegate(const UmaStatsReportingDelegate&) = delete;
Expand Down

0 comments on commit f962a27

Please sign in to comment.