Skip to content

Commit

Permalink
Fetch code cache earlier in NavigationBodyLoader
Browse files Browse the repository at this point in the history
The results from the NavigationThreadingOptimizations experiment have
shown that decreasing the time we wait for the code cache can have a
large affect on FCP/LCP. This change attempts to fetch the code cache
much earlier in commit so it will hopefully be ready when needed.

Note if the main contributor to the code cache response time is the
queue time of the response task in the renderer, this probably won't
help much. If experiment results don't show much of a speedup, that's
the next place to optimize.

Bug: 1266146
Change-Id: Ie8d702b467ce7455a65ade1ca70d30b2def22870
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3258419
Commit-Queue: Clark DuVall <cduvall@chromium.org>
Reviewed-by: John Abd-El-Malek <jam@chromium.org>
Reviewed-by: Jeremy Roman <jbroman@chromium.org>
Cr-Commit-Position: refs/heads/main@{#938553}
  • Loading branch information
clarkduvall authored and Chromium LUCI CQ committed Nov 4, 2021
1 parent 1808210 commit 038cd96
Show file tree
Hide file tree
Showing 10 changed files with 96 additions and 26 deletions.
12 changes: 10 additions & 2 deletions content/renderer/render_frame_impl.cc
Expand Up @@ -3737,6 +3737,12 @@ void RenderFrameImpl::DidCreateDocumentLoader(
document_loader->SetServiceWorkerNetworkProvider(
ServiceWorkerNetworkProviderForFrame::CreateInvalidInstance());
}

// Set the code cache host earlier if the kEarlyCodeCache feature is enabled
// to allow fetching the code cache as soon as possible.
if (base::FeatureList::IsEnabled(blink::features::kEarlyCodeCache)) {
document_loader->SetCodeCacheHost(std::move(pending_code_cache_host_));
}
}

void RenderFrameImpl::DidCommitNavigation(
Expand Down Expand Up @@ -3853,8 +3859,10 @@ void RenderFrameImpl::DidCommitNavigation(
// required. When pending_code_cache_host_ is nullptr this method just resets
// any earlier code cache host interface. Since we are committing a new
// navigation any interfaces requested prior to this point should not be used.
frame_->GetDocumentLoader()->SetCodeCacheHost(
std::move(pending_code_cache_host_));
if (!base::FeatureList::IsEnabled(blink::features::kEarlyCodeCache)) {
frame_->GetDocumentLoader()->SetCodeCacheHost(
std::move(pending_code_cache_host_));
}

// TODO(crbug.com/888079): Turn this into a DCHECK for origin equality when
// the linked bug is fixed. Currently sometimes the browser and renderer
Expand Down
4 changes: 4 additions & 0 deletions third_party/blink/common/features.cc
Expand Up @@ -1141,5 +1141,9 @@ const base::Feature kLateFormNewlineNormalization{
const base::Feature kAutoExpandDetailsElement{"AutoExpandDetailsElement",
base::FEATURE_ENABLED_BY_DEFAULT};

// Enables fetching the code cache earlier in navigation.
const base::Feature kEarlyCodeCache{"EarlyCodeCache",
base::FEATURE_DISABLED_BY_DEFAULT};

} // namespace features
} // namespace blink
2 changes: 2 additions & 0 deletions third_party/blink/public/common/features.h
Expand Up @@ -537,6 +537,8 @@ BLINK_COMMON_EXPORT extern const base::Feature kLateFormNewlineNormalization;
// and released to stable with no issues.
BLINK_COMMON_EXPORT extern const base::Feature kAutoExpandDetailsElement;

BLINK_COMMON_EXPORT extern const base::Feature kEarlyCodeCache;

} // namespace features
} // namespace blink

Expand Down
Expand Up @@ -76,6 +76,9 @@ class BLINK_EXPORT WebNavigationBodyLoader {
// Starts loading the body. Client must be non-null, and will receive
// the body, code cache and final result.
virtual void StartLoadingBody(Client*, CodeCacheHost* code_cache_host) = 0;

// Starts loading the code cache.
virtual void StartLoadingCodeCache(CodeCacheHost* code_cache_host) = 0;
};

} // namespace blink
Expand Down
22 changes: 15 additions & 7 deletions third_party/blink/renderer/core/loader/document_loader.cc
Expand Up @@ -1691,13 +1691,8 @@ void DocumentLoader::StartLoadingResponse() {
return;
}

bool use_isolated_code_cache =
RuntimeEnabledFeatures::CacheInlineScriptCodeEnabled() &&
ShouldUseIsolatedCodeCache(mojom::blink::RequestContextType::HYPERLINK,
response_);

// The |cached_metadata_handler_| is created, even when
// |use_isolated_code_cache| is false to support the parts that don't
// |UseIsolatedCodeCache()| is false to support the parts that don't
// go throught the site-isolated-code-cache.
auto cached_metadata_sender = CachedMetadataSender::Create(
response_, blink::mojom::CodeCacheType::kJavascript, requestor_origin_);
Expand All @@ -1706,7 +1701,7 @@ void DocumentLoader::StartLoadingResponse() {
WTF::TextEncoding(), std::move(cached_metadata_sender));

CodeCacheHost* code_cache_host = nullptr;
if (use_isolated_code_cache) {
if (UseIsolatedCodeCache()) {
code_cache_host = GetCodeCacheHost();
DCHECK(code_cache_host);
}
Expand Down Expand Up @@ -2188,6 +2183,13 @@ void DocumentLoader::CommitNavigation() {
DCHECK_EQ(frame_->Tree().ChildCount(), 0u);
state_ = kCommitted;

if (body_loader_ && !loading_main_document_from_mhtml_archive_ &&
!loading_url_as_empty_document_ && url_.ProtocolIsInHTTPFamily() &&
UseIsolatedCodeCache() &&
base::FeatureList::IsEnabled(features::kEarlyCodeCache)) {
body_loader_->StartLoadingCodeCache(GetCodeCacheHost());
}

// Prepare a DocumentInit before clearing the frame, because it may need to
// inherit an aliased security context.
Document* owner_document = nullptr;
Expand Down Expand Up @@ -2714,6 +2716,12 @@ ContentSecurityPolicy* DocumentLoader::CreateCSP() {
return csp;
}

bool DocumentLoader::UseIsolatedCodeCache() {
return RuntimeEnabledFeatures::CacheInlineScriptCodeEnabled() &&
ShouldUseIsolatedCodeCache(mojom::blink::RequestContextType::HYPERLINK,
response_);
}

bool& GetDisableCodeCacheForTesting() {
static bool disable_code_cache_for_testing = false;
return disable_code_cache_for_testing;
Expand Down
3 changes: 3 additions & 0 deletions third_party/blink/renderer/core/loader/document_loader.h
Expand Up @@ -481,6 +481,9 @@ class CORE_EXPORT DocumentLoader : public GarbageCollected<DocumentLoader>,
// Computes and creates CSP for this document.
ContentSecurityPolicy* CreateCSP();

// Whether the isolated code cache should be used for this document.
bool UseIsolatedCodeCache();

// Params are saved in constructor and are cleared after StartLoading().
// TODO(dgozman): remove once StartLoading is merged with constructor.
std::unique_ptr<WebNavigationParams> params_;
Expand Down
Expand Up @@ -138,32 +138,58 @@ void NavigationBodyLoader::StartLoadingBody(
std::move(response_head_), PreviewsTypes::PREVIEWS_OFF);

if (code_cache_host) {
code_cache_loader_ = WebCodeCacheLoader::Create(code_cache_host);
code_cache_loader_->FetchFromCodeCache(
mojom::CodeCacheType::kJavascript, original_url_,
base::BindOnce(&NavigationBodyLoader::CodeCacheReceived,
weak_factory_.GetWeakPtr(), base::TimeTicks::Now(),
response_head_response_time));
if (code_cache_data_) {
ContinueWithCodeCache(base::TimeTicks::Now(),
response_head_response_time);
return;
}

// Save these for when the code cache is ready.
code_cache_wait_start_time_ = base::TimeTicks::Now();
response_head_response_time_ = response_head_response_time;

// If the code cache loader hasn't been created yet the request hasn't
// started, so start it now.
if (!code_cache_loader_)
StartLoadingCodeCache(code_cache_host);
return;
}

BindURLLoaderAndStartLoadingResponseBodyIfPossible();
}

void NavigationBodyLoader::CodeCacheReceived(
void NavigationBodyLoader::StartLoadingCodeCache(
CodeCacheHost* code_cache_host) {
code_cache_loader_ = WebCodeCacheLoader::Create(code_cache_host);
code_cache_loader_->FetchFromCodeCache(
mojom::CodeCacheType::kJavascript, original_url_,
base::BindOnce(&NavigationBodyLoader::CodeCacheReceived,
weak_factory_.GetWeakPtr()));
}

void NavigationBodyLoader::CodeCacheReceived(base::Time response_time,
mojo_base::BigBuffer data) {
code_cache_data_ = std::move(data);
code_cache_response_time_ = response_time;
if (!code_cache_wait_start_time_.is_null()) {
ContinueWithCodeCache(code_cache_wait_start_time_,
response_head_response_time_);
}
}

void NavigationBodyLoader::ContinueWithCodeCache(
base::TimeTicks start_time,
base::Time response_head_response_time,
base::Time response_time,
mojo_base::BigBuffer data) {
base::Time response_head_response_time) {
base::UmaHistogramTimes(
base::StrCat({"Navigation.CodeCacheTime.",
is_main_frame_ ? "MainFrame" : "Subframe"}),
base::TimeTicks::Now() - start_time);

// Check that the times match to ensure that the code cache data is for this
// response. See https://crbug.com/1099587.
if (response_head_response_time == response_time && client_) {
if (response_head_response_time == code_cache_response_time_ && client_) {
base::WeakPtr<NavigationBodyLoader> weak_self = weak_factory_.GetWeakPtr();
client_->BodyCodeCacheReceived(std::move(data));
client_->BodyCodeCacheReceived(std::move(*code_cache_data_));
if (!weak_self)
return;
}
Expand Down
Expand Up @@ -63,7 +63,7 @@ class NavigationBodyLoader : public WebNavigationBodyLoader,
//
// StartLoadingBody
// request code cache
// CodeCacheReceived
// ContinueWithCodeCache
// notify client about cache
// BindURLLoaderAndContinue
// OnStartLoadingResponseBody
Expand All @@ -83,6 +83,7 @@ class NavigationBodyLoader : public WebNavigationBodyLoader,
void SetDefersLoading(WebLoaderFreezeMode mode) override;
void StartLoadingBody(WebNavigationBodyLoader::Client* client,
CodeCacheHost* code_cache_host) override;
void StartLoadingCodeCache(CodeCacheHost* code_cache_host) override;

// network::mojom::URLLoaderClient implementation.
void OnReceiveEarlyHints(network::mojom::EarlyHintsPtr early_hints) override;
Expand All @@ -100,10 +101,9 @@ class NavigationBodyLoader : public WebNavigationBodyLoader,
mojo::ScopedDataPipeConsumerHandle handle) override;
void OnComplete(const network::URLLoaderCompletionStatus& status) override;

void CodeCacheReceived(base::TimeTicks start_time,
base::Time response_head_response_time,
base::Time response_time,
mojo_base::BigBuffer data);
void CodeCacheReceived(base::Time response_time, mojo_base::BigBuffer data);
void ContinueWithCodeCache(base::TimeTicks start_time,
base::Time response_head_response_time);
void BindURLLoaderAndContinue();
void OnConnectionClosed();
void OnReadable(MojoResult unused);
Expand Down Expand Up @@ -163,6 +163,18 @@ class NavigationBodyLoader : public WebNavigationBodyLoader,

const bool is_main_frame_;

// The time the loader started waiting for the code cache. If this is
// non-null, |ContinueWithCodeCache()| should be called when the cache is
// available.
base::TimeTicks code_cache_wait_start_time_;
// The response time from the response head.
base::Time response_head_response_time_;

// These fields will be filled with the code cache response to be used when
// needed.
base::Time code_cache_response_time_;
absl::optional<mojo_base::BigBuffer> code_cache_data_;

base::WeakPtrFactory<NavigationBodyLoader> weak_factory_{this};
};

Expand Down
Expand Up @@ -47,6 +47,9 @@ void StaticDataNavigationBodyLoader::StartLoadingBody(
Continue();
}

void StaticDataNavigationBodyLoader::StartLoadingCodeCache(
CodeCacheHost* code_cache_host) {}

void StaticDataNavigationBodyLoader::Continue() {
if (freeze_mode_ != LoaderFreezeMode::kNone || !client_ || is_in_continue_)
return;
Expand Down
Expand Up @@ -29,6 +29,7 @@ class PLATFORM_EXPORT StaticDataNavigationBodyLoader
void SetDefersLoading(LoaderFreezeMode) override;
void StartLoadingBody(WebNavigationBodyLoader::Client*,
CodeCacheHost* host) override;
void StartLoadingCodeCache(CodeCacheHost* code_cache_host) override;

private:
void Continue();
Expand Down

0 comments on commit 038cd96

Please sign in to comment.