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

Unified Diff: components/ntp_snippets/user_classifier.cc

Issue 2315273002: Measure usage metrics to prepare for adaptive fetching rates in M55 (Closed)
Patch Set: Bernhard's comments Created 4 years, 3 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 side-by-side diff with in-line comments
Download patch
Index: components/ntp_snippets/user_classifier.cc
diff --git a/components/ntp_snippets/user_classifier.cc b/components/ntp_snippets/user_classifier.cc
new file mode 100644
index 0000000000000000000000000000000000000000..ef179b320a6bcba3e06b1a5530f06a9810dd557e
--- /dev/null
+++ b/components/ntp_snippets/user_classifier.cc
@@ -0,0 +1,156 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/ntp_snippets/user_classifier.h"
+
+#include <float.h>
+
+#include <algorithm>
+#include <string>
+
+#include "base/metrics/histogram_macros.h"
+#include "base/strings/string_number_conversions.h"
+#include "components/ntp_snippets/pref_names.h"
+#include "components/prefs/pref_registry_simple.h"
+#include "components/prefs/pref_service.h"
+
+namespace {
+
+// TODO(jkrcal): Make all of this configurable via variations_service.
+
+// The discount factor for computing the discounted-average metrics. Must be
+// strictly larger than 0 and strictly smaller than 1!
+const double kDiscountFactorPerDay = 0.25;
+
+// Never consider any larger interval than this (so that extreme situations such
+// as losing your phone or going for a long offline vacation do not skew the
+// average too much).
+const double kMaxHours = 7 * 24;
+
+// Ignore events within |kMinHours| hours since the last event (|kMinHours| is
+// the length of the browsing session where subsequent events of the same type
+// do not count again).
+const double kMinHours = 0.5;
+
+const char kHistogramAverageHoursToOpenNTP[] =
+ "NewTabPage.UserClassifier.AverageHoursToOpenNTP";
+const char kHistogramAverageHoursToShowSuggestions[] =
+ "NewTabPage.UserClassifier.AverageHoursToShowSuggestions";
+const char kHistogramAverageHoursToUseSuggestions[] =
+ "NewTabPage.UserClassifier.AverageHoursToUseSuggestions";
+
+} // namespace
+
+namespace ntp_snippets {
+
+UserClassifier::UserClassifier(PrefService* pref_service)
+ : pref_service_(pref_service),
+ // Compute discount_rate_per_hour such that
+ // kDiscountFactorPerDay = 1 - e^{-discount_rate_per_hour * 24}.
+ discount_rate_per_hour_(std::log(1 / (1 - kDiscountFactorPerDay)) / 24) {}
+
+UserClassifier::~UserClassifier() {}
+
+// static
+void UserClassifier::RegisterProfilePrefs(PrefRegistrySimple* registry) {
+ registry->RegisterDoublePref(
+ prefs::kUserClassifierAverageNTPOpenedPerHour, 1);
+ registry->RegisterDoublePref(
+ prefs::kUserClassifierAverageSuggestionsShownPerHour, 1);
+ registry->RegisterDoublePref(
+ prefs::kUserClassifierAverageSuggestionsUsedPerHour, 1);
+
+ registry->RegisterInt64Pref(prefs::kUserClassifierLastTimeToOpenNTP, 0);
+ registry->RegisterInt64Pref(prefs::kUserClassifierLastTimeToShowSuggestions,
+ 0);
+ registry->RegisterInt64Pref(prefs::kUserClassifierLastTimeToUseSuggestions,
+ 0);
+}
+
+void UserClassifier::OnNTPOpened() {
+ UpdateMetricOnEvent(prefs::kUserClassifierAverageNTPOpenedPerHour,
+ prefs::kUserClassifierLastTimeToOpenNTP);
+
+ double avg = GetEstimateHoursBetweenEvents(
+ prefs::kUserClassifierAverageNTPOpenedPerHour);
+ UMA_HISTOGRAM_CUSTOM_COUNTS(kHistogramAverageHoursToOpenNTP, avg, 1,
+ kMaxHours, 50);
+}
+
+void UserClassifier::OnSuggestionsShown() {
+ UpdateMetricOnEvent(prefs::kUserClassifierAverageSuggestionsShownPerHour,
+ prefs::kUserClassifierLastTimeToShowSuggestions);
+
+ double avg = GetEstimateHoursBetweenEvents(
+ prefs::kUserClassifierAverageSuggestionsShownPerHour);
+ UMA_HISTOGRAM_CUSTOM_COUNTS(kHistogramAverageHoursToShowSuggestions, avg, 1,
+ kMaxHours, 50);
+}
+
+void UserClassifier::OnSuggestionsUsed() {
+ UpdateMetricOnEvent(prefs::kUserClassifierAverageSuggestionsUsedPerHour,
+ prefs::kUserClassifierLastTimeToUseSuggestions);
+
+ double avg = GetEstimateHoursBetweenEvents(
+ prefs::kUserClassifierAverageSuggestionsUsedPerHour);
+ UMA_HISTOGRAM_CUSTOM_COUNTS(kHistogramAverageHoursToUseSuggestions, avg, 1,
+ kMaxHours, 50);
+}
+
+void UserClassifier::UpdateMetricOnEvent(const char* metric_pref_name,
+ const char* last_time_pref_name) {
+ if (!pref_service_)
+ return;
+
+ double hours_since_last_time =
+ std::min(kMaxHours, GetHoursSinceLastTime(last_time_pref_name));
+ // Ignore events within the same "browsing session".
+ if (hours_since_last_time < kMinHours)
+ return;
+ SetLastTimeToNow(last_time_pref_name);
+
+ double avg_events_per_hour = pref_service_->GetDouble(metric_pref_name);
+ // Compute and store the new discounted average according to the formula
+ // avg_events := 1 + e^{-discount_rate_per_hour * hours_since} * avg_events.
+ double new_avg_events_per_hour =
+ 1 +
+ std::exp(discount_rate_per_hour_ * hours_since_last_time) *
+ avg_events_per_hour;
+ pref_service_->SetDouble(metric_pref_name, new_avg_events_per_hour);
+}
+
+double UserClassifier::GetEstimateHoursBetweenEvents(
+ const char* metric_pref_name) {
+ double avg_events_per_hour = pref_service_->GetDouble(metric_pref_name);
+
+ // Right after the first update, the metric is equal to 1.
+ if (avg_events_per_hour <= 1)
+ return kMaxHours;
+
+ // This is the estimate with the assumption that last event happened right
+ // now and the system is in the steady-state. Solve estimate_hours in the
+ // steady-state equation:
+ // avg_events = 1 + e^{-discount_rate * estimate_hours} * avg_events.
+ return std::min(kMaxHours,
+ std::log(avg_events_per_hour / (avg_events_per_hour - 1)) /
+ discount_rate_per_hour_);
+}
+
+double UserClassifier::GetHoursSinceLastTime(
+ const char* last_time_pref_name) {
+ if (!pref_service_->HasPrefPath(last_time_pref_name))
+ return DBL_MAX;
+
+ base::TimeDelta since_last_time =
+ base::Time::Now() - base::Time::FromInternalValue(
+ pref_service_->GetInt64(last_time_pref_name));
+ return since_last_time.InSecondsF() / 3600;
+}
+
+void UserClassifier::SetLastTimeToNow(const char* last_time_pref_name) {
+ pref_service_->SetInt64(last_time_pref_name,
+ base::Time::Now().ToInternalValue());
+}
+
+} // namespace ntp_snippets

Powered by Google App Engine
This is Rietveld 408576698