Chromium Code Reviews| Index: chrome/browser/engagement/site_engagement_service.cc |
| diff --git a/chrome/browser/engagement/site_engagement_service.cc b/chrome/browser/engagement/site_engagement_service.cc |
| index 6e96a592fb04d18a5a24ca1984a0e41374a51198..392ee8cb5fe956d3ef7a8e3945f708ff0b588d30 100644 |
| --- a/chrome/browser/engagement/site_engagement_service.cc |
| +++ b/chrome/browser/engagement/site_engagement_service.cc |
| @@ -6,6 +6,7 @@ |
| #include <algorithm> |
| #include <cmath> |
| +#include <vector> |
| #include "base/command_line.h" |
| #include "base/time/clock.h" |
| @@ -22,6 +23,9 @@ |
| namespace { |
| +// Length of time between metrics logging. |
| +const base::TimeDelta metrics_interval = base::TimeDelta::FromMinutes(60); |
| + |
| // Delta within which to consider scores equal. |
| const double kScoreDelta = 0.001; |
| @@ -113,6 +117,15 @@ void SiteEngagementScore::AddPoints(double points) { |
| last_engagement_time_ = now; |
| } |
| +bool SiteEngagementScore::MaxPointsPerDayAdded() { |
| + if (!last_engagement_time_.is_null() && |
| + clock_->Now().LocalMidnight() != last_engagement_time_.LocalMidnight()) { |
| + return false; |
| + } |
| + |
| + return points_added_today_ == kMaxPointsPerDay; |
| +} |
| + |
| bool SiteEngagementScore::UpdateScoreDict(base::DictionaryValue* score_dict) { |
| double raw_score_orig = 0; |
| double points_added_today_orig = 0; |
| @@ -177,7 +190,7 @@ SiteEngagementService::SiteEngagementService(Profile* profile) |
| content::BrowserThread::PostAfterStartupTask( |
| FROM_HERE, content::BrowserThread::GetMessageLoopProxyForThread( |
| content::BrowserThread::UI), |
| - base::Bind(&SiteEngagementService::CleanupEngagementScores, |
| + base::Bind(&SiteEngagementService::AfterStartupTask, |
| weak_factory_.GetWeakPtr())); |
| } |
| @@ -186,11 +199,18 @@ SiteEngagementService::~SiteEngagementService() { |
| void SiteEngagementService::HandleNavigation(const GURL& url, |
| ui::PageTransition transition) { |
| + SiteEngagementMetrics::RecordEngagement( |
| + SiteEngagementMetrics::ENGAGEMENT_NAVIGATION); |
| AddPoints(url, SiteEngagementScore::kNavigationPoints); |
| + RecordMetrics(); |
| } |
| -void SiteEngagementService::HandleUserInput(const GURL& url) { |
| +void SiteEngagementService::HandleUserInput( |
| + const GURL& url, |
| + SiteEngagementMetrics::EngagementType type) { |
| + SiteEngagementMetrics::RecordEngagement(type); |
| AddPoints(url, SiteEngagementScore::kUserInputPoints); |
| + RecordMetrics(); |
| } |
| double SiteEngagementService::GetScore(const GURL& url) { |
| @@ -204,22 +224,12 @@ double SiteEngagementService::GetScore(const GURL& url) { |
| } |
| double SiteEngagementService::GetTotalEngagementPoints() { |
| - HostContentSettingsMap* settings_map = |
| - HostContentSettingsMapFactory::GetForProfile(profile_); |
| - scoped_ptr<ContentSettingsForOneType> engagement_settings = |
| - GetEngagementContentSettings(settings_map); |
| + std::map<GURL, double> score_map = GetScoreMap(); |
| double total_score = 0; |
| - for (const auto& site : *engagement_settings) { |
| - GURL origin(site.primary_pattern.ToString()); |
| - if (!origin.is_valid()) |
| - continue; |
| + for (const auto& value : score_map) |
| + total_score += value.second; |
| - scoped_ptr<base::DictionaryValue> score_dict = |
| - GetScoreDictForOrigin(settings_map, origin); |
| - SiteEngagementScore score(clock_.get(), *score_dict); |
| - total_score += score.Score(); |
| - } |
| return total_score; |
| } |
| @@ -268,6 +278,11 @@ void SiteEngagementService::AddPoints(const GURL& url, double points) { |
| } |
| } |
| +void SiteEngagementService::AfterStartupTask() { |
| + CleanupEngagementScores(); |
| + RecordMetrics(); |
| +} |
| + |
| void SiteEngagementService::CleanupEngagementScores() { |
| HostContentSettingsMap* settings_map = |
| HostContentSettingsMapFactory::GetForProfile(profile_); |
| @@ -290,3 +305,91 @@ void SiteEngagementService::CleanupEngagementScores() { |
| } |
| } |
| +void SiteEngagementService::RecordMetrics() { |
| + base::Time now = clock_->Now(); |
| + if (last_metrics_time_.is_null() || |
| + now - last_metrics_time_ >= metrics_interval) { |
| + last_metrics_time_ = now; |
| + std::map<GURL, double> score_map = GetScoreMap(); |
| + |
| + int origins_with_max_engagement = OriginsWithMaxEngagement(score_map); |
| + int total_origins = score_map.size(); |
| + int percent_origins_with_max_engagement = |
| + (total_origins == 0 ? 0 : (origins_with_max_engagement * 100) / |
| + total_origins); |
| + |
| + double total_engagement = GetTotalEngagementPoints(); |
| + double mean_engagement = |
| + (total_origins == 0 ? 0 : total_engagement / total_origins); |
| + |
| + SiteEngagementMetrics::RecordTotalOriginsEngaged(total_origins); |
| + SiteEngagementMetrics::RecordTotalSiteEngagement(total_engagement); |
| + SiteEngagementMetrics::RecordMeanEngagement(mean_engagement); |
| + SiteEngagementMetrics::RecordMedianEngagement( |
| + GetMedianEngagement(score_map)); |
| + SiteEngagementMetrics::RecordEngagementScores(score_map); |
| + |
| + SiteEngagementMetrics::RecordOriginsWithMaxDailyEngagement( |
| + OriginsWithMaxDailyEngagement()); |
| + SiteEngagementMetrics::RecordOriginsWithMaxEngagement( |
| + origins_with_max_engagement); |
| + SiteEngagementMetrics::RecordPercentOriginsWithMaxEngagement( |
| + percent_origins_with_max_engagement); |
| + } |
| +} |
| + |
| +double SiteEngagementService::GetMedianEngagement( |
| + std::map<GURL, double>& score_map) { |
| + if (score_map.size() == 0) |
| + return 0; |
| + |
| + std::vector<double> scores; |
| + scores.reserve(score_map.size()); |
| + for (const auto& value : score_map) |
| + scores.push_back(value.second); |
| + |
| + // Calculate the median as the middle value of the sorted engagement scores |
| + // if there are an odd number of scores, or the average of the two middle |
| + // scores otherwise. |
| + std::sort(scores.begin(), scores.end()); |
|
calamity
2015/10/02 05:31:18
Consider using std::nth_element to compute the med
dominickn
2015/10/02 06:06:17
I think this is a bit too micro-optimisation-ish t
|
| + size_t mid = scores.size() / 2; |
| + if (scores.size() % 2 == 1) |
| + return scores[mid]; |
| + else |
| + return (scores[mid - 1] + scores[mid]) / 2; |
| +} |
| + |
| +int SiteEngagementService::OriginsWithMaxDailyEngagement() { |
| + HostContentSettingsMap* settings_map = |
| + HostContentSettingsMapFactory::GetForProfile(profile_); |
| + scoped_ptr<ContentSettingsForOneType> engagement_settings = |
| + GetEngagementContentSettings(settings_map); |
| + |
| + int total_origins = 0; |
| + |
| + // We cannot call GetScoreMap as we need the score objects, not raw scores. |
| + for (const auto& site : *engagement_settings) { |
| + GURL origin(site.primary_pattern.ToString()); |
| + if (!origin.is_valid()) |
| + continue; |
| + |
| + scoped_ptr<base::DictionaryValue> score_dict = |
| + GetScoreDictForOrigin(settings_map, origin); |
| + SiteEngagementScore score(clock_.get(), *score_dict); |
| + if (score.MaxPointsPerDayAdded()) |
| + ++total_origins; |
| + } |
| + |
| + return total_origins; |
| +} |
| + |
| +int SiteEngagementService::OriginsWithMaxEngagement( |
| + std::map<GURL, double>& score_map) { |
| + int total_origins = 0; |
| + |
| + for (const auto& value : score_map) |
| + if (value.second == SiteEngagementScore::kMaxPoints) |
| + ++total_origins; |
| + |
| + return total_origins; |
| +} |