0

Prerender2Fallback: Disable BlockUntilHeadTimeout for prerender

In an experiment of Prerender2FallbackPrefetchSpecRules, we had a result
that BlockUntilHeadTimeout might degrades prerender activation. This CL
disables it and adds a feature parameter to control the behavior.

For more details, see
https://docs.google.com/document/d/1ZP7lYrtqZL9jC2xXieNY_UBMJL1sCrfmzTB8K6v4sD4/edit?resourcekey=0-fkbeQhkT3PhBb9FnnPgnZA&tab=t.wphan8fb23kr

Fixed: 405288111
Change-Id: I2bd5902d21d59d1ff59f04c9ea5a1cb79df12e7c
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/6380014
Commit-Queue: Ken Okada <kenoss@chromium.org>
Reviewed-by: Hiroki Nakagawa <nhiroki@chromium.org>
Auto-Submit: Ken Okada <kenoss@chromium.org>
Reviewed-by: Taiyo Mizuhashi <taiyo@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1437924}
This commit is contained in:
kenoss
2025-03-25 21:04:33 -07:00
committed by Chromium LUCI CQ
parent 3019accff6
commit 5cc0bcf722
7 changed files with 46 additions and 16 deletions

@ -46,12 +46,14 @@ PrefetchMatchResolver::CandidateData::~CandidateData() = default;
PrefetchMatchResolver::PrefetchMatchResolver(
PrefetchContainer::Key navigated_key,
PrefetchServiceWorkerState expected_service_worker_state,
bool is_nav_prerender,
base::WeakPtr<PrefetchService> prefetch_service,
Callback callback)
: navigated_key_(std::move(navigated_key)),
expected_service_worker_state_(expected_service_worker_state),
prefetch_service_(std::move(prefetch_service)),
callback_(std::move(callback)) {
callback_(std::move(callback)),
is_nav_prerender_(is_nav_prerender) {
switch (expected_service_worker_state_) {
case PrefetchServiceWorkerState::kAllowed:
NOTREACHED();
@ -86,22 +88,21 @@ void PrefetchMatchResolver::FindPrefetch(
TRACE_EVENT0("loading", "PrefetchMatchResolver::FindPrefetch");
// See the comment of `self_`.
auto prefetch_match_resolver = base::WrapUnique(new PrefetchMatchResolver(
std::move(navigated_key), expected_service_worker_state,
std::move(navigated_key), expected_service_worker_state, is_nav_prerender,
prefetch_service.GetWeakPtr(), std::move(callback)));
PrefetchMatchResolver& ref = *prefetch_match_resolver.get();
ref.self_ = std::move(prefetch_match_resolver);
ref.FindPrefetchInternal(is_nav_prerender, prefetch_service,
ref.FindPrefetchInternal(prefetch_service,
std::move(serving_page_metrics_container));
}
void PrefetchMatchResolver::FindPrefetchInternal(
bool is_nav_prerender,
PrefetchService& prefetch_service,
base::WeakPtr<PrefetchServingPageMetricsContainer>
serving_page_metrics_container) {
auto [candidates, servable_states] = prefetch_service.CollectMatchCandidates(
navigated_key_, is_nav_prerender,
navigated_key_, is_nav_prerender_,
std::move(serving_page_metrics_container));
// Consume `candidates`.
for (auto& prefetch_container : candidates) {
@ -217,10 +218,10 @@ void PrefetchMatchResolver::StartWaitFor(
CHECK(!candidate_data->timeout_timer);
// TODO(crbug.com/356552413): Merge
// https://chromium-review.googlesource.com/c/chromium/src/+/5668924 and write
// tests.
base::TimeDelta timeout =
PrefetchBlockUntilHeadTimeout(prefetch_container.GetPrefetchType());
// https://chromium-review.googlesource.com/c/chromium/src/+/5668924 and
// write tests.
base::TimeDelta timeout = PrefetchBlockUntilHeadTimeout(
prefetch_container.GetPrefetchType(), is_nav_prerender_);
if (timeout.is_positive()) {
candidate_data->timeout_timer = std::make_unique<base::OneShotTimer>();
candidate_data->timeout_timer->Start(

@ -79,7 +79,8 @@ class CONTENT_EXPORT PrefetchMatchResolver final
explicit PrefetchMatchResolver(
PrefetchContainer::Key navigated_key,
PrefetchServiceWorkerState expected_service_worker_state,
base::WeakPtr<PrefetchService>,
bool is_nav_prerender,
base::WeakPtr<PrefetchService> prefetch_service,
Callback callback);
// Returns blocked duration. Returns null iff it's not blocked yet.
@ -97,8 +98,7 @@ class CONTENT_EXPORT PrefetchMatchResolver final
// - This implementation has timeout: `CandidateData::timeout_timer`.
// - This implementation collects candidate prefetches first. So, it doesn't
// handle prefetches started after this method started.
void FindPrefetchInternal(bool is_nav_prerender,
PrefetchService& prefetch_service,
void FindPrefetchInternal(PrefetchService& prefetch_service,
base::WeakPtr<PrefetchServingPageMetricsContainer>
serving_page_metrics_container);
// Each candidate `PrefetchContainer` proceeds to
@ -148,6 +148,7 @@ class CONTENT_EXPORT PrefetchMatchResolver final
const PrefetchServiceWorkerState expected_service_worker_state_;
base::WeakPtr<PrefetchService> prefetch_service_;
Callback callback_;
const bool is_nav_prerender_;
std::map<PrefetchContainer::Key, std::unique_ptr<CandidateData>> candidates_;
std::optional<base::TimeTicks> wait_started_at_ = std::nullopt;
};

@ -188,8 +188,23 @@ int PrefetchCanaryCheckRetries() {
features::kPrefetchUseContentRefactor, "canary_check_retries", 1);
}
base::TimeDelta PrefetchBlockUntilHeadTimeout(
const PrefetchType& prefetch_type) {
base::TimeDelta PrefetchBlockUntilHeadTimeout(const PrefetchType& prefetch_type,
bool is_nav_prerender) {
// Don't set a timeout for prerender because
//
// - The intention of prefetch ahead of prerender is not sending additional
// fetch request. The options of the behavior of the timeout case are
// 1. (Current behavior) Making prerender fail, or 2. Falling back to
// network.
// - 1 reduces the prerender activation rate.
//
// For more details, see
// https://docs.google.com/document/d/1ZP7lYrtqZL9jC2xXieNY_UBMJL1sCrfmzTB8K6v4sD4/edit?resourcekey=0-fkbeQhkT3PhBb9FnnPgnZA&tab=t.wphan8fb23kr
if (!features::kPrerender2FallbackPrefetchUseBlockUntilHeadTimetout.Get() &&
is_nav_prerender) {
return base::Seconds(0);
}
int timeout_in_milliseconds = 0;
if (IsSpeculationRuleType(prefetch_type.trigger_type())) {
switch (prefetch_type.GetEagerness()) {

@ -100,7 +100,8 @@ int PrefetchCanaryCheckRetries();
// The maximum amount of time to block until the head of a prefetch is received.
// If the value is zero or less, then a navigation can be blocked indefinitely.
CONTENT_EXPORT base::TimeDelta PrefetchBlockUntilHeadTimeout(
const PrefetchType& prefetch_type);
const PrefetchType& prefetch_type,
bool is_nav_prerender);
// Gets the histogram suffix to use for the given eagerness parameter.
CONTENT_EXPORT std::string GetPrefetchEagernessHistogramSuffix(

@ -4444,7 +4444,7 @@ TEST_P(PrefetchServiceAlwaysBlockUntilHeadTest,
std::string histogram_suffix =
GetPrefetchEagernessHistogramSuffix(GetParam());
base::TimeDelta block_until_head_timeout =
PrefetchBlockUntilHeadTimeout(prefetch_type);
PrefetchBlockUntilHeadTimeout(prefetch_type, /*is_nav_prerender=*/false);
histogram_tester.ExpectTotalCount(
base::StringPrintf(
"PrefetchProxy.AfterClick.BlockUntilHeadDuration2NoBias.Served.%s",

@ -41,6 +41,11 @@ const base::FeatureParam<size_t> kPrerender2FallbackBodySizeLimit{
&kPrerender2FallbackPrefetchSpecRules, "kPrerender2FallbackBodySizeLimit",
65536};
const base::FeatureParam<bool>
kPrerender2FallbackPrefetchUseBlockUntilHeadTimetout{
&kPrerender2FallbackPrefetchSpecRules,
"kPrerender2FallbackPrefetchUseBlockUntilHeadTimetout", true};
BASE_FEATURE(kPrerender2NoVarySearch,
"Prerender2NoVarySearch",
base::FEATURE_ENABLED_BY_DEFAULT);

@ -38,6 +38,13 @@ CONTENT_EXPORT extern const base::FeatureParam<
CONTENT_EXPORT extern const base::FeatureParam<size_t>
kPrerender2FallbackBodySizeLimit;
// Controls whether `PrefetchMatchResolver` use timeout for prefetch ahead of
// prerender. We are going not to use timeout as it makes prerender fail. For
// more details, see
// https://docs.google.com/document/d/1ZP7lYrtqZL9jC2xXieNY_UBMJL1sCrfmzTB8K6v4sD4/edit?resourcekey=0-fkbeQhkT3PhBb9FnnPgnZA&tab=t.wphan8fb23kr
CONTENT_EXPORT extern const base::FeatureParam<bool>
kPrerender2FallbackPrefetchUseBlockUntilHeadTimetout;
// This feature was used to launch Prerender2 support for No-Vary-Search header.
// This work has finished and the old implementation was deleted. Now this flag
// is just for injecting parameters through field trials as an umberella