blob: 2a5fee87e9be4343aec564bea62249bd7da2e3e1 [file] [log] [blame]
/*
* Copyright (C) 2011 Google, Inc. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY GOOGLE INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GOOGLE INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "third_party/blink/renderer/core/loader/document_load_timing.h"
#include "base/memory/scoped_refptr.h"
#include "base/time/default_clock.h"
#include "base/time/default_tick_clock.h"
#include "third_party/blink/renderer/core/frame/local_frame.h"
#include "third_party/blink/renderer/core/inspector/identifiers_factory.h"
#include "third_party/blink/renderer/core/loader/document_loader.h"
#include "third_party/blink/renderer/platform/instrumentation/tracing/trace_event.h"
#include "third_party/blink/renderer/platform/weborigin/security_origin.h"
namespace blink {
DocumentLoadTiming::DocumentLoadTiming(DocumentLoader& document_loader)
: redirect_count_(0),
has_cross_origin_redirect_(false),
has_same_origin_as_previous_document_(false),
clock_(base::DefaultClock::GetInstance()),
tick_clock_(base::DefaultTickClock::GetInstance()),
document_loader_(document_loader) {}
void DocumentLoadTiming::Trace(blink::Visitor* visitor) {
visitor->Trace(document_loader_);
}
void DocumentLoadTiming::SetTickClockForTesting(
const base::TickClock* tick_clock) {
tick_clock_ = tick_clock;
}
void DocumentLoadTiming::SetClockForTesting(const base::Clock* clock) {
clock_ = clock;
}
// TODO(csharrison): Remove the null checking logic in a later patch.
LocalFrame* DocumentLoadTiming::GetFrame() const {
return document_loader_ ? document_loader_->GetFrame() : nullptr;
}
void DocumentLoadTiming::NotifyDocumentTimingChanged() {
if (document_loader_)
document_loader_->DidChangePerformanceTiming();
}
void DocumentLoadTiming::EnsureReferenceTimesSet() {
if (reference_wall_time_.is_zero()) {
reference_wall_time_ =
base::TimeDelta::FromSecondsD(clock_->Now().ToDoubleT());
}
if (reference_monotonic_time_.is_null())
reference_monotonic_time_ = tick_clock_->NowTicks();
}
base::TimeDelta DocumentLoadTiming::MonotonicTimeToZeroBasedDocumentTime(
base::TimeTicks monotonic_time) const {
if (monotonic_time.is_null() || reference_monotonic_time_.is_null())
return base::TimeDelta();
return monotonic_time - reference_monotonic_time_;
}
base::TimeDelta DocumentLoadTiming::MonotonicTimeToPseudoWallTime(
base::TimeTicks monotonic_time) const {
if (monotonic_time.is_null() || reference_monotonic_time_.is_null())
return base::TimeDelta();
return monotonic_time + reference_wall_time_ - reference_monotonic_time_;
}
void DocumentLoadTiming::MarkNavigationStart() {
// Allow the embedder to override navigationStart before we record it if
// they have a more accurate timestamp.
if (!navigation_start_.is_null()) {
DCHECK(!reference_monotonic_time_.is_null());
DCHECK(!reference_wall_time_.is_zero());
return;
}
DCHECK(reference_monotonic_time_.is_null());
DCHECK(reference_wall_time_.is_zero());
EnsureReferenceTimesSet();
navigation_start_ = reference_monotonic_time_;
TRACE_EVENT_MARK_WITH_TIMESTAMP2(
"blink.user_timing", "navigationStart", navigation_start_, "frame",
ToTraceValue(GetFrame()), "data", GetNavigationStartTracingData());
NotifyDocumentTimingChanged();
}
std::unique_ptr<TracedValue> DocumentLoadTiming::GetNavigationStartTracingData()
const {
auto data = std::make_unique<TracedValue>();
data->SetString("documentLoaderURL",
document_loader_ ? document_loader_->Url().GetString() : "");
data->SetBoolean("isLoadingMainFrame",
GetFrame() ? GetFrame()->IsMainFrame() : false);
data->SetString("navigationId",
IdentifiersFactory::LoaderId(document_loader_));
return data;
}
void DocumentLoadTiming::SetNavigationStart(base::TimeTicks navigation_start) {
// |m_referenceMonotonicTime| and |m_referenceWallTime| represent
// navigationStart. We must set these to the current time if they haven't
// been set yet in order to have a valid reference time in both units.
EnsureReferenceTimesSet();
navigation_start_ = navigation_start;
TRACE_EVENT_MARK_WITH_TIMESTAMP2(
"blink.user_timing", "navigationStart", navigation_start_, "frame",
ToTraceValue(GetFrame()), "data", GetNavigationStartTracingData());
// The reference times are adjusted based on the embedder's navigationStart.
DCHECK(!reference_monotonic_time_.is_null());
DCHECK(!reference_wall_time_.is_zero());
reference_wall_time_ = MonotonicTimeToPseudoWallTime(navigation_start);
reference_monotonic_time_ = navigation_start;
NotifyDocumentTimingChanged();
}
void DocumentLoadTiming::SetInputStart(base::TimeTicks input_start) {
input_start_ = input_start;
NotifyDocumentTimingChanged();
}
void DocumentLoadTiming::AddRedirect(const KURL& redirecting_url,
const KURL& redirected_url) {
redirect_count_++;
// Note: we update load timings for redirects in WebDocumentLoaderImpl::
// UpdateNavigation, hence updating no timings here.
// Check if the redirected url is allowed to access the redirecting url's
// timing information.
scoped_refptr<const SecurityOrigin> redirected_security_origin =
SecurityOrigin::Create(redirected_url);
has_cross_origin_redirect_ |=
!redirected_security_origin->CanRequest(redirecting_url);
}
void DocumentLoadTiming::SetRedirectStart(base::TimeTicks redirect_start) {
redirect_start_ = redirect_start;
TRACE_EVENT_MARK_WITH_TIMESTAMP1("blink.user_timing", "redirectStart",
redirect_start_, "frame",
ToTraceValue(GetFrame()));
NotifyDocumentTimingChanged();
}
void DocumentLoadTiming::SetRedirectEnd(base::TimeTicks redirect_end) {
redirect_end_ = redirect_end;
TRACE_EVENT_MARK_WITH_TIMESTAMP1("blink.user_timing", "redirectEnd",
redirect_end_, "frame",
ToTraceValue(GetFrame()));
NotifyDocumentTimingChanged();
}
void DocumentLoadTiming::MarkUnloadEventStart(base::TimeTicks start_time) {
unload_event_start_ = start_time;
TRACE_EVENT_MARK_WITH_TIMESTAMP1("blink.user_timing", "unloadEventStart",
start_time, "frame",
ToTraceValue(GetFrame()));
NotifyDocumentTimingChanged();
}
void DocumentLoadTiming::MarkUnloadEventEnd(base::TimeTicks end_time) {
unload_event_end_ = end_time;
TRACE_EVENT_MARK_WITH_TIMESTAMP1("blink.user_timing", "unloadEventEnd",
end_time, "frame", ToTraceValue(GetFrame()));
NotifyDocumentTimingChanged();
}
void DocumentLoadTiming::MarkFetchStart() {
SetFetchStart(tick_clock_->NowTicks());
}
void DocumentLoadTiming::SetFetchStart(base::TimeTicks fetch_start) {
fetch_start_ = fetch_start;
TRACE_EVENT_MARK_WITH_TIMESTAMP1("blink.user_timing", "fetchStart",
fetch_start_, "frame",
ToTraceValue(GetFrame()));
NotifyDocumentTimingChanged();
}
void DocumentLoadTiming::SetResponseEnd(base::TimeTicks response_end) {
response_end_ = response_end;
TRACE_EVENT_MARK_WITH_TIMESTAMP1("blink.user_timing", "responseEnd",
response_end_, "frame",
ToTraceValue(GetFrame()));
NotifyDocumentTimingChanged();
}
void DocumentLoadTiming::MarkLoadEventStart() {
load_event_start_ = tick_clock_->NowTicks();
TRACE_EVENT_MARK_WITH_TIMESTAMP1("blink.user_timing", "loadEventStart",
load_event_start_, "frame",
ToTraceValue(GetFrame()));
NotifyDocumentTimingChanged();
}
void DocumentLoadTiming::MarkLoadEventEnd() {
load_event_end_ = tick_clock_->NowTicks();
TRACE_EVENT_MARK_WITH_TIMESTAMP1("blink.user_timing", "loadEventEnd",
load_event_end_, "frame",
ToTraceValue(GetFrame()));
NotifyDocumentTimingChanged();
}
void DocumentLoadTiming::MarkRedirectEnd() {
redirect_end_ = tick_clock_->NowTicks();
TRACE_EVENT_MARK_WITH_TIMESTAMP1("blink.user_timing", "redirectEnd",
redirect_end_, "frame",
ToTraceValue(GetFrame()));
NotifyDocumentTimingChanged();
}
} // namespace blink