Commit 82322eee authored by Michael Crouse's avatar Michael Crouse Committed by Commit Bot

Add UKM for model features used by the prediction manager.

This change records any requested/used model feature supported by the client
and requested to be used by a prediction model.

Bug: 1052435
Change-Id: I16e8e7b9cab39b173bdc0be5e329fb181853d656
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2057121
Commit-Queue: Michael Crouse <mcrouse@chromium.org>
Reviewed-by: default avatarRobert Kaplow <rkaplow@chromium.org>
Reviewed-by: default avatarTarun Bansal <tbansal@chromium.org>
Reviewed-by: default avatarSophie Chang <sophiechang@chromium.org>
Cr-Commit-Position: refs/heads/master@{#742747}
parent 85a333ec
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
#include "chrome/browser/optimization_guide/optimization_guide_web_contents_observer.h" #include "chrome/browser/optimization_guide/optimization_guide_web_contents_observer.h"
#include "components/optimization_guide/hints_processing_util.h" #include "components/optimization_guide/hints_processing_util.h"
#include "content/public/browser/navigation_handle.h" #include "content/public/browser/navigation_handle.h"
#include "net/nqe/effective_connection_type.h"
#include "services/metrics/public/cpp/ukm_builders.h" #include "services/metrics/public/cpp/ukm_builders.h"
#include "services/metrics/public/cpp/ukm_recorder.h" #include "services/metrics/public/cpp/ukm_recorder.h"
#include "services/metrics/public/cpp/ukm_source.h" #include "services/metrics/public/cpp/ukm_source.h"
...@@ -192,6 +193,62 @@ void OptimizationGuideNavigationData::RecordOptimizationGuideUKM() const { ...@@ -192,6 +193,62 @@ void OptimizationGuideNavigationData::RecordOptimizationGuideUKM() const {
} }
} }
for (const auto model_feature : prediction_model_features_) {
switch (model_feature.first) {
case optimization_guide::proto::CLIENT_MODEL_FEATURE_UNKNOWN: {
continue;
}
case optimization_guide::proto::
CLIENT_MODEL_FEATURE_EFFECTIVE_CONNECTION_TYPE: {
builder.SetPredictionModelFeatureEffectiveConnectionType(
static_cast<net::EffectiveConnectionType>(model_feature.second));
did_record_metric = true;
continue;
}
case optimization_guide::proto::CLIENT_MODEL_FEATURE_PAGE_TRANSITION: {
builder.SetPredictionModelFeaturePageTransition(
static_cast<ui::PageTransition>(model_feature.second));
did_record_metric = true;
continue;
}
case optimization_guide::proto::
CLIENT_MODEL_FEATURE_SITE_ENGAGEMENT_SCORE: {
builder.SetPredictionModelFeatureSiteEngagementScore(
static_cast<int>(std::roundf(model_feature.second / 10.0) * 10));
did_record_metric = true;
continue;
}
case optimization_guide::proto::
CLIENT_MODEL_FEATURE_SAME_ORIGIN_NAVIGATION: {
builder.SetPredictionModelFeatureIsSameOriginNavigation(
static_cast<int>(model_feature.second));
did_record_metric = true;
continue;
}
case optimization_guide::proto::
CLIENT_MODEL_FEATURE_FIRST_CONTENTFUL_PAINT_SESSION_MEAN: {
builder.SetPredictionModelFeatureNavigationToFCPSessionMean(
static_cast<int>(model_feature.second));
did_record_metric = true;
continue;
}
case optimization_guide::proto::
CLIENT_MODEL_FEATURE_FIRST_CONTENTFUL_PAINT_SESSION_STANDARD_DEVIATION: {
builder.SetPredictionModelFeatureNavigationToFCPSessionStdDev(
static_cast<int>(model_feature.second));
did_record_metric = true;
continue;
}
case optimization_guide::proto::
CLIENT_MODEL_FEATURE_FIRST_CONTENTFUL_PAINT_PREVIOUS_PAGE_LOAD: {
builder.SetPredictionModelFeaturePreviousPageLoadNavigationToFCP(
static_cast<int>(model_feature.second));
did_record_metric = true;
continue;
}
}
}
// Record hint metrics. // Record hint metrics.
if (serialized_hint_version_string_.has_value() && if (serialized_hint_version_string_.has_value() &&
!serialized_hint_version_string_.value().empty()) { !serialized_hint_version_string_.value().empty()) {
...@@ -324,3 +381,17 @@ void OptimizationGuideNavigationData:: ...@@ -324,3 +381,17 @@ void OptimizationGuideNavigationData::
optimization_target_model_prediction_scores_[optimization_target] = optimization_target_model_prediction_scores_[optimization_target] =
model_prediction_score; model_prediction_score;
} }
void OptimizationGuideNavigationData::SetValueForModelFeature(
optimization_guide::proto::ClientModelFeature model_feature,
float value) {
prediction_model_features_[model_feature] = value;
}
base::Optional<float>
OptimizationGuideNavigationData::GetValueForModelFeatureForTesting(
optimization_guide::proto::ClientModelFeature model_feature) {
auto it = prediction_model_features_.find(model_feature);
if (it == prediction_model_features_.end())
return base::nullopt;
return it->second;
}
...@@ -83,6 +83,14 @@ class OptimizationGuideNavigationData { ...@@ -83,6 +83,14 @@ class OptimizationGuideNavigationData {
optimization_guide::proto::OptimizationTarget optimization_target, optimization_guide::proto::OptimizationTarget optimization_target,
double model_prediction_score); double model_prediction_score);
// Returns the value of the model feature if it has been provided.
base::Optional<float> GetValueForModelFeatureForTesting(
optimization_guide::proto::ClientModelFeature model_feature);
// Sets the value provided to the model for a particular model feature.
void SetValueForModelFeature(
optimization_guide::proto::ClientModelFeature model_feature,
float value);
// Whether the hint cache had a hint for the navigation before commit. // Whether the hint cache had a hint for the navigation before commit.
base::Optional<bool> has_hint_before_commit() const { base::Optional<bool> has_hint_before_commit() const {
return has_hint_before_commit_; return has_hint_before_commit_;
...@@ -195,6 +203,10 @@ class OptimizationGuideNavigationData { ...@@ -195,6 +203,10 @@ class OptimizationGuideNavigationData {
base::flat_map<optimization_guide::proto::OptimizationTarget, double> base::flat_map<optimization_guide::proto::OptimizationTarget, double>
optimization_target_model_prediction_scores_; optimization_target_model_prediction_scores_;
// The features used to make a prediction for any target.
base::flat_map<optimization_guide::proto::ClientModelFeature, float>
prediction_model_features_;
// Whether the hint cache had a hint for the navigation before commit. // Whether the hint cache had a hint for the navigation before commit.
base::Optional<bool> has_hint_before_commit_; base::Optional<bool> has_hint_before_commit_;
......
...@@ -20,6 +20,13 @@ using testing::AnyOf; ...@@ -20,6 +20,13 @@ using testing::AnyOf;
using testing::HasSubstr; using testing::HasSubstr;
using testing::Not; using testing::Not;
typedef struct {
optimization_guide::proto::ClientModelFeature feature;
base::StringPiece ukm_metric_name;
float feature_value;
int expected_value;
} ClientHostModelFeaturesTestCase;
TEST(OptimizationGuideNavigationDataTest, RecordMetricsNoDataNoCommit) { TEST(OptimizationGuideNavigationDataTest, RecordMetricsNoDataNoCommit) {
base::test::TaskEnvironment env; base::test::TaskEnvironment env;
...@@ -976,3 +983,57 @@ TEST(OptimizationGuideNavigationDataTest, DeepCopy) { ...@@ -976,3 +983,57 @@ TEST(OptimizationGuideNavigationDataTest, DeepCopy) {
*data_copy.GetModelPredictionScoreForOptimizationTarget( *data_copy.GetModelPredictionScoreForOptimizationTarget(
optimization_guide::proto::OPTIMIZATION_TARGET_PAINFUL_PAGE_LOAD)); optimization_guide::proto::OPTIMIZATION_TARGET_PAINFUL_PAGE_LOAD));
} }
TEST(OptimizationGuideNavigationDataTest,
RecordMetricsPredictionModelHostModelFeatures) {
base::test::TaskEnvironment env;
ClientHostModelFeaturesTestCase test_cases[] = {
{optimization_guide::proto::
CLIENT_MODEL_FEATURE_FIRST_CONTENTFUL_PAINT_SESSION_MEAN,
ukm::builders::OptimizationGuide::
kPredictionModelFeatureNavigationToFCPSessionMeanName,
2.0, 2},
{optimization_guide::proto::
CLIENT_MODEL_FEATURE_FIRST_CONTENTFUL_PAINT_SESSION_STANDARD_DEVIATION,
ukm::builders::OptimizationGuide::
kPredictionModelFeatureNavigationToFCPSessionStdDevName,
3.0, 3},
{optimization_guide::proto::CLIENT_MODEL_FEATURE_PAGE_TRANSITION,
ukm::builders::OptimizationGuide::
kPredictionModelFeaturePageTransitionName,
20.0, 20},
{optimization_guide::proto::CLIENT_MODEL_FEATURE_SAME_ORIGIN_NAVIGATION,
ukm::builders::OptimizationGuide::
kPredictionModelFeatureIsSameOriginNavigationName,
1.0, 1},
{optimization_guide::proto::CLIENT_MODEL_FEATURE_SITE_ENGAGEMENT_SCORE,
ukm::builders::OptimizationGuide::
kPredictionModelFeatureSiteEngagementScoreName,
5.5, 10},
{optimization_guide::proto::
CLIENT_MODEL_FEATURE_EFFECTIVE_CONNECTION_TYPE,
ukm::builders::OptimizationGuide::
kPredictionModelFeatureEffectiveConnectionTypeName,
3.0, 3},
{optimization_guide::proto::
CLIENT_MODEL_FEATURE_FIRST_CONTENTFUL_PAINT_PREVIOUS_PAGE_LOAD,
ukm::builders::OptimizationGuide::
kPredictionModelFeaturePreviousPageLoadNavigationToFCPName,
200.0, 200},
};
for (const auto& test_case : test_cases) {
ukm::TestAutoSetUkmRecorder ukm_recorder;
OptimizationGuideNavigationData data(/*navigation_id=*/1);
data.SetValueForModelFeature(test_case.feature, test_case.feature_value);
data.RecordMetrics(/*has_committed=*/false);
auto entries = ukm_recorder.GetEntriesByName(
ukm::builders::OptimizationGuide::kEntryName);
EXPECT_EQ(1u, entries.size());
auto* entry = entries[0];
EXPECT_TRUE(ukm_recorder.EntryHasMetric(entry, test_case.ukm_metric_name));
ukm_recorder.ExpectEntryMetric(entry, test_case.ukm_metric_name,
test_case.expected_value);
}
}
...@@ -271,15 +271,19 @@ base::Optional<float> PredictionManager::GetValueForClientFeature( ...@@ -271,15 +271,19 @@ base::Optional<float> PredictionManager::GetValueForClientFeature(
if (!proto::ClientModelFeature_Parse(model_feature, &client_model_feature)) if (!proto::ClientModelFeature_Parse(model_feature, &client_model_feature))
return base::nullopt; return base::nullopt;
base::Optional<float> value;
switch (client_model_feature) { switch (client_model_feature) {
case proto::CLIENT_MODEL_FEATURE_UNKNOWN: { case proto::CLIENT_MODEL_FEATURE_UNKNOWN: {
return base::nullopt; return base::nullopt;
} }
case proto::CLIENT_MODEL_FEATURE_EFFECTIVE_CONNECTION_TYPE: { case proto::CLIENT_MODEL_FEATURE_EFFECTIVE_CONNECTION_TYPE: {
return static_cast<float>(current_effective_connection_type_); value = static_cast<float>(current_effective_connection_type_);
break;
} }
case proto::CLIENT_MODEL_FEATURE_PAGE_TRANSITION: { case proto::CLIENT_MODEL_FEATURE_PAGE_TRANSITION: {
return static_cast<float>(navigation_handle->GetPageTransition()); value = static_cast<float>(navigation_handle->GetPageTransition());
break;
} }
case proto::CLIENT_MODEL_FEATURE_SITE_ENGAGEMENT_SCORE: { case proto::CLIENT_MODEL_FEATURE_SITE_ENGAGEMENT_SCORE: {
Profile* profile = Profile::FromBrowserContext( Profile* profile = Profile::FromBrowserContext(
...@@ -287,8 +291,9 @@ base::Optional<float> PredictionManager::GetValueForClientFeature( ...@@ -287,8 +291,9 @@ base::Optional<float> PredictionManager::GetValueForClientFeature(
SiteEngagementService* engagement_service = SiteEngagementService* engagement_service =
SiteEngagementService::Get(profile); SiteEngagementService::Get(profile);
// Precision loss is acceptable/expected for prediction models. // Precision loss is acceptable/expected for prediction models.
return static_cast<float>( value = static_cast<float>(
engagement_service->GetScore(navigation_handle->GetURL())); engagement_service->GetScore(navigation_handle->GetURL()));
break;
} }
case proto::CLIENT_MODEL_FEATURE_SAME_ORIGIN_NAVIGATION: { case proto::CLIENT_MODEL_FEATURE_SAME_ORIGIN_NAVIGATION: {
OptimizationGuideNavigationData* nav_data = OptimizationGuideNavigationData* nav_data =
...@@ -300,32 +305,43 @@ base::Optional<float> PredictionManager::GetValueForClientFeature( ...@@ -300,32 +305,43 @@ base::Optional<float> PredictionManager::GetValueForClientFeature(
LOCAL_HISTOGRAM_BOOLEAN( LOCAL_HISTOGRAM_BOOLEAN(
"OptimizationGuide.PredictionManager.IsSameOrigin", is_same_origin); "OptimizationGuide.PredictionManager.IsSameOrigin", is_same_origin);
return static_cast<float>(is_same_origin); value = static_cast<float>(is_same_origin);
break;
} }
case proto::CLIENT_MODEL_FEATURE_FIRST_CONTENTFUL_PAINT_SESSION_MEAN: { case proto::CLIENT_MODEL_FEATURE_FIRST_CONTENTFUL_PAINT_SESSION_MEAN: {
if (session_fcp_.GetNumberOfSamples() == 0) { value = session_fcp_.GetNumberOfSamples() == 0
return static_cast<float>( ? static_cast<float>(pref_service_->GetDouble(
pref_service_->GetDouble(prefs::kSessionStatisticFCPMean)); prefs::kSessionStatisticFCPMean))
} : session_fcp_.GetMean();
return session_fcp_.GetMean(); break;
} }
case proto:: case proto::
CLIENT_MODEL_FEATURE_FIRST_CONTENTFUL_PAINT_SESSION_STANDARD_DEVIATION: { CLIENT_MODEL_FEATURE_FIRST_CONTENTFUL_PAINT_SESSION_STANDARD_DEVIATION: {
if (session_fcp_.GetNumberOfSamples() == 0) { value = session_fcp_.GetNumberOfSamples() == 0
return static_cast<float>( ? static_cast<float>(pref_service_->GetDouble(
pref_service_->GetDouble(prefs::kSessionStatisticFCPStdDev)); prefs::kSessionStatisticFCPStdDev))
} : session_fcp_.GetStdDev();
return session_fcp_.GetStdDev(); break;
} }
case proto:: case proto::
CLIENT_MODEL_FEATURE_FIRST_CONTENTFUL_PAINT_PREVIOUS_PAGE_LOAD: { CLIENT_MODEL_FEATURE_FIRST_CONTENTFUL_PAINT_PREVIOUS_PAGE_LOAD: {
return previous_load_fcp_ms_.value_or(static_cast<float>( value = previous_load_fcp_ms_.value_or(static_cast<float>(
pref_service_->GetDouble(prefs::kSessionStatisticFCPMean))); pref_service_->GetDouble(prefs::kSessionStatisticFCPMean)));
break;
} }
default: { default: {
return base::nullopt; return base::nullopt;
} }
} }
OptimizationGuideNavigationData* navigation_data =
OptimizationGuideNavigationData::GetFromNavigationHandle(
navigation_handle);
if (value && navigation_data) {
navigation_data->SetValueForModelFeature(client_model_feature, *value);
return value;
}
return base::nullopt;
} }
base::flat_map<std::string, float> PredictionManager::BuildFeatureMap( base::flat_map<std::string, float> PredictionManager::BuildFeatureMap(
......
...@@ -468,6 +468,10 @@ class PredictionManagerTest ...@@ -468,6 +468,10 @@ class PredictionManagerTest
return GetParam() == proto::CLIENT_MODEL_FEATURE_SAME_ORIGIN_NAVIGATION; return GetParam() == proto::CLIENT_MODEL_FEATURE_SAME_ORIGIN_NAVIGATION;
} }
bool IsUnknownFeature() {
return GetParam() == proto::CLIENT_MODEL_FEATURE_UNKNOWN;
}
void TearDown() override { void TearDown() override {
optimization_guide::ProtoDatabaseProviderTestBase::TearDown(); optimization_guide::ProtoDatabaseProviderTestBase::TearDown();
} }
...@@ -1499,6 +1503,16 @@ TEST_P(PredictionManagerTest, ClientFeature) { ...@@ -1499,6 +1503,16 @@ TEST_P(PredictionManagerTest, ClientFeature) {
EXPECT_TRUE(test_prediction_model); EXPECT_TRUE(test_prediction_model);
EXPECT_TRUE(test_prediction_model->WasModelEvaluated()); EXPECT_TRUE(test_prediction_model->WasModelEvaluated());
OptimizationGuideNavigationData* navigation_data =
OptimizationGuideNavigationData::GetFromNavigationHandle(
navigation_handle.get());
EXPECT_TRUE(navigation_data);
if (IsUnknownFeature()) {
EXPECT_FALSE(
navigation_data->GetValueForModelFeatureForTesting(GetParam()));
} else {
EXPECT_TRUE(navigation_data->GetValueForModelFeatureForTesting(GetParam()));
}
} }
INSTANTIATE_TEST_SUITE_P(ClientFeature, INSTANTIATE_TEST_SUITE_P(ClientFeature,
......
...@@ -6566,6 +6566,49 @@ be describing additional metrics about the same event. ...@@ -6566,6 +6566,49 @@ be describing additional metrics about the same event.
evaluated for the page load. evaluated for the page load.
</summary> </summary>
</metric> </metric>
<metric name="PredictionModelFeatureEffectiveConnectionType">
<summary>
The |net::EffectiveConnectionType| at the time a prediction was requested.
Recorded once per page load.
</summary>
</metric>
<metric name="PredictionModelFeatureIsSameOriginNavigation">
<summary>
Whether the current navigatation is the same origin as the previous one at
the time a prediction was requested. Recorded once per page load.
</summary>
</metric>
<metric name="PredictionModelFeatureNavigationToFCPSessionMean">
<summary>
The average navigation to first contentful paint for the current session
at the time a prediction was requested. Recorded once per page load.
</summary>
</metric>
<metric name="PredictionModelFeatureNavigationToFCPSessionStdDev">
<summary>
The standard deviation of navigation to first contentful paint for page
loads in the current session at the time a prediction was requested.
Recorded once per page load.
</summary>
</metric>
<metric name="PredictionModelFeaturePageTransition">
<summary>
The |ui::PageTransition| of the current navigation at the time a
prediction was requested. Recorded once per page load.
</summary>
</metric>
<metric name="PredictionModelFeaturePreviousPageLoadNavigationToFCP">
<summary>
The navigation to to first contentful paint for the previous page load at
the time a prediction was requested. Recorded once per page load.
</summary>
</metric>
<metric name="PredictionModelFeatureSiteEngagementScore">
<summary>
The site engagement score of the host of the current navigation at the
time a prediction was requested. Recorded once per page load.
</summary>
</metric>
</event> </event>
<event name="PageDomainInfo"> <event name="PageDomainInfo">
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment