summaryrefslogtreecommitdiff
path: root/chromium/third_party/blink/renderer/core/timing
diff options
context:
space:
mode:
authorAllan Sandfeld Jensen <allan.jensen@qt.io>2021-10-26 13:57:00 +0200
committerAllan Sandfeld Jensen <allan.jensen@qt.io>2021-11-02 11:31:01 +0000
commit1943b3c2a1dcee36c233724fc4ee7613d71b9cf6 (patch)
tree8c1b5f12357025c197da5427ae02cfdc2f3570d6 /chromium/third_party/blink/renderer/core/timing
parent21ba0c5d4bf8fba15dddd97cd693bad2358b77fd (diff)
downloadqtwebengine-chromium-1943b3c2a1dcee36c233724fc4ee7613d71b9cf6.tar.gz
BASELINE: Update Chromium to 94.0.4606.111
Change-Id: I924781584def20fc800bedf6ff41fdb96c438193 Reviewed-by: Allan Sandfeld Jensen <allan.jensen@qt.io>
Diffstat (limited to 'chromium/third_party/blink/renderer/core/timing')
-rw-r--r--chromium/third_party/blink/renderer/core/timing/background_tracing_helper.cc17
-rw-r--r--chromium/third_party/blink/renderer/core/timing/build.gni4
-rw-r--r--chromium/third_party/blink/renderer/core/timing/dom_window_performance.h4
-rw-r--r--chromium/third_party/blink/renderer/core/timing/event_counts.idl2
-rw-r--r--chromium/third_party/blink/renderer/core/timing/event_timing.cc94
-rw-r--r--chromium/third_party/blink/renderer/core/timing/event_timing.h17
-rw-r--r--chromium/third_party/blink/renderer/core/timing/measure_memory/measure_memory_controller.cc41
-rw-r--r--chromium/third_party/blink/renderer/core/timing/memory_info.cc4
-rw-r--r--chromium/third_party/blink/renderer/core/timing/performance.cc121
-rw-r--r--chromium/third_party/blink/renderer/core/timing/performance.h31
-rw-r--r--chromium/third_party/blink/renderer/core/timing/performance.idl6
-rw-r--r--chromium/third_party/blink/renderer/core/timing/performance_event_timing.idl2
-rw-r--r--chromium/third_party/blink/renderer/core/timing/performance_mark.cc4
-rw-r--r--chromium/third_party/blink/renderer/core/timing/performance_navigation_timing.cc9
-rw-r--r--chromium/third_party/blink/renderer/core/timing/performance_navigation_timing.h2
-rw-r--r--chromium/third_party/blink/renderer/core/timing/performance_navigation_timing_activation_start.cc25
-rw-r--r--chromium/third_party/blink/renderer/core/timing/performance_navigation_timing_activation_start.h20
-rw-r--r--chromium/third_party/blink/renderer/core/timing/performance_navigation_timing_activation_start.idl11
-rw-r--r--chromium/third_party/blink/renderer/core/timing/performance_observer.cc3
-rw-r--r--chromium/third_party/blink/renderer/core/timing/performance_observer_init.idl2
-rw-r--r--chromium/third_party/blink/renderer/core/timing/performance_test.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/timing/performance_timing.cc20
-rw-r--r--chromium/third_party/blink/renderer/core/timing/performance_timing.h2
-rw-r--r--chromium/third_party/blink/renderer/core/timing/performance_user_timing.cc14
-rw-r--r--chromium/third_party/blink/renderer/core/timing/performance_user_timing.h1
-rw-r--r--chromium/third_party/blink/renderer/core/timing/profiler.cc39
-rw-r--r--chromium/third_party/blink/renderer/core/timing/profiler.h6
-rw-r--r--chromium/third_party/blink/renderer/core/timing/profiler.idl4
-rw-r--r--chromium/third_party/blink/renderer/core/timing/profiler_group.cc16
-rw-r--r--chromium/third_party/blink/renderer/core/timing/profiler_group.h5
-rw-r--r--chromium/third_party/blink/renderer/core/timing/profiler_init_options.idl2
-rw-r--r--chromium/third_party/blink/renderer/core/timing/responsiveness_metrics.cc204
-rw-r--r--chromium/third_party/blink/renderer/core/timing/responsiveness_metrics.h84
-rw-r--r--chromium/third_party/blink/renderer/core/timing/time_clamper.h6
-rw-r--r--chromium/third_party/blink/renderer/core/timing/window_performance.cc93
-rw-r--r--chromium/third_party/blink/renderer/core/timing/window_performance.h93
-rw-r--r--chromium/third_party/blink/renderer/core/timing/window_performance.idl2
-rw-r--r--chromium/third_party/blink/renderer/core/timing/window_performance_test.cc507
38 files changed, 1188 insertions, 331 deletions
diff --git a/chromium/third_party/blink/renderer/core/timing/background_tracing_helper.cc b/chromium/third_party/blink/renderer/core/timing/background_tracing_helper.cc
index 0202a46217c..319f6562b67 100644
--- a/chromium/third_party/blink/renderer/core/timing/background_tracing_helper.cc
+++ b/chromium/third_party/blink/renderer/core/timing/background_tracing_helper.cc
@@ -4,9 +4,9 @@
#include "third_party/blink/renderer/core/timing/background_tracing_helper.h"
+#include "base/cxx17_backports.h"
#include "base/feature_list.h"
#include "base/hash/md5.h"
-#include "base/stl_util.h"
#include "base/sys_byteorder.h"
#include "base/trace_event/typed_macros.h"
#include "third_party/blink/public/common/features.h"
@@ -173,17 +173,26 @@ void BackgroundTracingHelper::MaybeEmitBackgroundTracingPerformanceMarkEvent(
if (!mark_hashes_->Contains(mark_hash))
return;
- // Emit the trace event. We emit hashes and strings to facilitate local trace
+ // Emit the trace events. We emit hashes and strings to facilitate local trace
// consumption. However, the strings will be stripped and only the hashes
// shipped externally.
- TRACE_EVENT("blink", "performance.mark", [&](perfetto::EventContext ctx) {
+
+ auto event_lambda = [&](perfetto::EventContext ctx) {
auto* event = ctx.event<perfetto::protos::pbzero::ChromeTrackEvent>();
auto* data = event->set_chrome_hashed_performance_mark();
data->set_site_hash(site_hash_);
data->set_site(site_.Ascii());
data->set_mark_hash(mark_hash);
data->set_mark(mark_name_ascii);
- });
+ };
+
+ // For additional context, also emit a paired event marking *when* the
+ // performance.mark was actually created.
+ TRACE_EVENT_INSTANT("blink", "performance.mark.created", event_lambda);
+
+ // Emit an event with the actual timestamp associated with the mark.
+ TRACE_EVENT_INSTANT("blink", "performance.mark", mark.UnsafeTimeForTraces(),
+ event_lambda);
// If this is a slow-reports trigger then fire it.
if (MarkNameIsTrigger(mark_name)) {
diff --git a/chromium/third_party/blink/renderer/core/timing/build.gni b/chromium/third_party/blink/renderer/core/timing/build.gni
index c12d93beb64..c39d5d343c2 100644
--- a/chromium/third_party/blink/renderer/core/timing/build.gni
+++ b/chromium/third_party/blink/renderer/core/timing/build.gni
@@ -39,6 +39,8 @@ blink_core_sources_timing = [
"performance_navigation.h",
"performance_navigation_timing.cc",
"performance_navigation_timing.h",
+ "performance_navigation_timing_activation_start.cc",
+ "performance_navigation_timing_activation_start.h",
"performance_observer.cc",
"performance_observer.h",
"performance_observer_entry_list.cc",
@@ -59,6 +61,8 @@ blink_core_sources_timing = [
"profiler_group.h",
"background_tracing_helper.cc",
"background_tracing_helper.h",
+ "responsiveness_metrics.cc",
+ "responsiveness_metrics.h",
"task_attribution_timing.cc",
"task_attribution_timing.h",
"time_clamper.cc",
diff --git a/chromium/third_party/blink/renderer/core/timing/dom_window_performance.h b/chromium/third_party/blink/renderer/core/timing/dom_window_performance.h
index 26be96f656c..bcb8383b6f6 100644
--- a/chromium/third_party/blink/renderer/core/timing/dom_window_performance.h
+++ b/chromium/third_party/blink/renderer/core/timing/dom_window_performance.h
@@ -5,7 +5,6 @@
#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_TIMING_DOM_WINDOW_PERFORMANCE_H_
#define THIRD_PARTY_BLINK_RENDERER_CORE_TIMING_DOM_WINDOW_PERFORMANCE_H_
-#include "base/macros.h"
#include "third_party/blink/renderer/core/core_export.h"
#include "third_party/blink/renderer/core/timing/window_performance.h"
#include "third_party/blink/renderer/platform/heap/handle.h"
@@ -25,6 +24,8 @@ class CORE_EXPORT DOMWindowPerformance final
static WindowPerformance* performance(LocalDOMWindow&);
explicit DOMWindowPerformance(LocalDOMWindow&);
+ DOMWindowPerformance(const DOMWindowPerformance&) = delete;
+ DOMWindowPerformance& operator=(const DOMWindowPerformance&) = delete;
void Trace(Visitor*) const override;
@@ -32,7 +33,6 @@ class CORE_EXPORT DOMWindowPerformance final
WindowPerformance* performance();
Member<WindowPerformance> performance_;
- DISALLOW_COPY_AND_ASSIGN(DOMWindowPerformance);
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/timing/event_counts.idl b/chromium/third_party/blink/renderer/core/timing/event_counts.idl
index a78ac1fdc8a..9da127ce83c 100644
--- a/chromium/third_party/blink/renderer/core/timing/event_counts.idl
+++ b/chromium/third_party/blink/renderer/core/timing/event_counts.idl
@@ -1,4 +1,4 @@
-[Exposed=Window, RuntimeEnabled=EventTiming]
+[Exposed=Window]
interface EventCounts {
readonly maplike<DOMString, unsigned long long>;
};
diff --git a/chromium/third_party/blink/renderer/core/timing/event_timing.cc b/chromium/third_party/blink/renderer/core/timing/event_timing.cc
index 4f57dcb2401..95143ba9c06 100644
--- a/chromium/third_party/blink/renderer/core/timing/event_timing.cc
+++ b/chromium/third_party/blink/renderer/core/timing/event_timing.cc
@@ -14,7 +14,6 @@
#include "third_party/blink/renderer/core/loader/interactive_detector.h"
#include "third_party/blink/renderer/core/timing/dom_window_performance.h"
#include "third_party/blink/renderer/core/timing/performance_event_timing.h"
-#include "third_party/blink/renderer/platform/runtime_enabled_features.h"
namespace blink {
namespace {
@@ -30,17 +29,14 @@ bool ShouldLogEvent(const Event& event) {
event.type() == event_type_names::kPointerup ||
event.type() == event_type_names::kClick ||
event.type() == event_type_names::kKeydown ||
- event.type() == event_type_names::kMousedown;
+ event.type() == event_type_names::kMousedown ||
+ event.type() == event_type_names::kMouseup;
}
bool ShouldReportForEventTiming(WindowPerformance* performance) {
if (!performance->FirstInputDetected())
return true;
- if (!RuntimeEnabledFeatures::EventTimingEnabled(
- performance->GetExecutionContext()))
- return false;
-
return (!performance->IsEventTimingBufferFull() ||
performance->HasObserverFor(PerformanceEntry::kEvent));
}
@@ -48,13 +44,31 @@ bool ShouldReportForEventTiming(WindowPerformance* performance) {
} // namespace
EventTiming::EventTiming(base::TimeTicks processing_start,
- base::TimeTicks event_timestamp,
WindowPerformance* performance,
- bool should_log_event)
+ const Event& event)
: processing_start_(processing_start),
- event_timestamp_(event_timestamp),
performance_(performance),
- should_log_event_(should_log_event) {}
+ event_(&event) {
+ performance_->SetCurrentEventTimingEvent(&event);
+}
+
+// static
+void EventTiming::HandleInputDelay(LocalDOMWindow* window, const Event& event) {
+ auto* pointer_event = DynamicTo<PointerEvent>(&event);
+ base::TimeTicks event_timestamp =
+ pointer_event ? pointer_event->OldestPlatformTimeStamp()
+ : event.PlatformTimeStamp();
+
+ base::TimeTicks processing_start = Now();
+ if (ShouldLogEvent(event) && event.isTrusted()) {
+ InteractiveDetector* interactive_detector =
+ InteractiveDetector::From(*window->document());
+ if (interactive_detector) {
+ interactive_detector->HandleForInputDelay(event, event_timestamp,
+ processing_start);
+ }
+ }
+}
// static
bool EventTiming::IsEventTypeForEventTiming(const Event& event) {
@@ -80,7 +94,16 @@ bool EventTiming::IsEventTypeForEventTiming(const Event& event) {
std::unique_ptr<EventTiming> EventTiming::Create(LocalDOMWindow* window,
const Event& event) {
auto* performance = DOMWindowPerformance::performance(*window);
- if (!performance || !IsEventTypeForEventTiming(event))
+ if (!performance || !event.isTrusted() ||
+ (!IsEventTypeForEventTiming(event) &&
+ event.type() != event_type_names::kPointermove))
+ return nullptr;
+
+ // Most events track their performance in EventDispatcher::Dispatch but
+ // some event types which can be filtered are tracked at the point
+ // where they may be filtered. This condition check ensures we don't create
+ // two EventTiming objects for the same Event.
+ if (performance->GetCurrentEventTimingEvent() == &event)
return nullptr;
bool should_report_for_event_timing = ShouldReportForEventTiming(performance);
@@ -89,39 +112,38 @@ std::unique_ptr<EventTiming> EventTiming::Create(LocalDOMWindow* window,
if (!should_report_for_event_timing && !should_log_event)
return nullptr;
- auto* pointer_event = DynamicTo<PointerEvent>(&event);
- base::TimeTicks event_timestamp =
- pointer_event ? pointer_event->OldestPlatformTimeStamp()
- : event.PlatformTimeStamp();
-
base::TimeTicks processing_start = Now();
-
- if (should_log_event) {
- InteractiveDetector* interactive_detector =
- InteractiveDetector::From(*window->document());
- if (interactive_detector) {
- interactive_detector->HandleForInputDelay(event, event_timestamp,
- processing_start);
- }
- }
-
return should_report_for_event_timing
- ? std::make_unique<EventTiming>(processing_start, event_timestamp,
- performance, should_log_event)
+ ? std::make_unique<EventTiming>(processing_start, performance,
+ event)
: nullptr;
}
-void EventTiming::DidDispatchEvent(const Event& event, Document& document) {
- Node* target = event.target() ? event.target()->ToNode() : nullptr;
- base::TimeTicks processing_end = Now();
- performance_->RegisterEventTiming(event.type(), event_timestamp_,
- processing_start_, processing_end,
- event.cancelable(), target);
-}
-
// static
void EventTiming::SetTickClockForTesting(const base::TickClock* clock) {
g_clock_for_testing = clock;
}
+EventTiming::~EventTiming() {
+ absl::optional<int> key_code = absl::nullopt;
+ if (event_->IsKeyboardEvent())
+ key_code = DynamicTo<KeyboardEvent>(event_.Get())->keyCode();
+
+ absl::optional<PointerId> pointer_id = absl::nullopt;
+ const PointerEvent* pointer_event = DynamicTo<PointerEvent>(event_.Get());
+ if (pointer_event)
+ pointer_id = pointer_event->pointerId();
+
+ base::TimeTicks event_timestamp =
+ pointer_event ? pointer_event->OldestPlatformTimeStamp()
+ : event_->PlatformTimeStamp();
+
+ // Register Event Timing for the event.
+ performance_->RegisterEventTiming(
+ event_->type(), event_timestamp, processing_start_, Now(),
+ event_->cancelable(),
+ event_->target() ? event_->target()->ToNode() : nullptr, key_code,
+ pointer_id);
+}
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/timing/event_timing.h b/chromium/third_party/blink/renderer/core/timing/event_timing.h
index aa83fd3097c..59a8627d92f 100644
--- a/chromium/third_party/blink/renderer/core/timing/event_timing.h
+++ b/chromium/third_party/blink/renderer/core/timing/event_timing.h
@@ -26,16 +26,19 @@ class CORE_EXPORT EventTiming final {
// Processes an event that will be dispatched. Notifies the
// InteractiveDetector if it needs to be logged into input delay histograms.
// Returns an object only if the event is relevant for the EventTiming API.
+ // This object should be constructed before the event is dispatched and
+ // destructed after dispatch so that we can calculate the input delay and
+ // other latency values correctly.
static std::unique_ptr<EventTiming> Create(LocalDOMWindow*, const Event&);
explicit EventTiming(base::TimeTicks processing_start,
- base::TimeTicks event_timestamp,
WindowPerformance* performance,
- bool should_log);
-
- // Notifies the Performance object that the event has been dispatched.
- void DidDispatchEvent(const Event&, Document& document);
+ const Event& event);
+ ~EventTiming();
+ EventTiming(const EventTiming&) = delete;
+ EventTiming& operator=(const EventTiming&) = delete;
+ static void HandleInputDelay(LocalDOMWindow* window, const Event& event);
// The caller owns the |clock| which must outlive the EventTiming.
static void SetTickClockForTesting(const base::TickClock* clock);
@@ -50,9 +53,7 @@ class CORE_EXPORT EventTiming final {
Persistent<WindowPerformance> performance_;
- bool should_log_event_;
-
- DISALLOW_COPY_AND_ASSIGN(EventTiming);
+ Persistent<const Event> event_;
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/timing/measure_memory/measure_memory_controller.cc b/chromium/third_party/blink/renderer/core/timing/measure_memory/measure_memory_controller.cc
index 66a0568caf0..79ce17f9aaa 100644
--- a/chromium/third_party/blink/renderer/core/timing/measure_memory/measure_memory_controller.cc
+++ b/chromium/third_party/blink/renderer/core/timing/measure_memory/measure_memory_controller.cc
@@ -11,7 +11,7 @@
#include "third_party/blink/public/common/features.h"
#include "third_party/blink/public/platform/platform.h"
#include "third_party/blink/renderer/bindings/core/v8/script_promise.h"
-#include "third_party/blink/renderer/bindings/core/v8/to_v8_for_core.h"
+#include "third_party/blink/renderer/bindings/core/v8/to_v8_traits.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_memory_attribution.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_memory_attribution_container.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_memory_breakdown_entry.h"
@@ -46,6 +46,7 @@ namespace {
// String constants used for building the result.
constexpr const char* kCrossOriginUrl = "cross-origin-url";
+constexpr const char* kMemoryTypeCanvas = "Canvas";
constexpr const char* kMemoryTypeDom = "DOM";
constexpr const char* kMemoryTypeJavaScript = "JavaScript";
constexpr const char* kMemoryTypeShared = "Shared";
@@ -184,7 +185,6 @@ ScriptPromise MeasureMemoryController::StartMeasurement(
return ScriptPromise(script_state, promise_resolver->GetPromise());
}
-
namespace {
// Satisfies the requirements of UniformRandomBitGenerator from C++ standard.
@@ -237,11 +237,13 @@ MemoryAttribution* ConvertAttribution(
result->setUrl(kCrossOriginUrl);
}
result->setScope(ConvertScope(attribution->scope));
- result->setContainer(ConvertContainer(attribution));
+ if (auto* container = ConvertContainer(attribution)) {
+ result->setContainer(container);
+ }
return result;
}
-MemoryBreakdownEntry* ConvertBreakdown(
+MemoryBreakdownEntry* ConvertJavaScriptBreakdown(
const WebMemoryBreakdownEntryPtr& breakdown_entry) {
auto* result = MemoryBreakdownEntry::Create();
DCHECK(breakdown_entry->memory);
@@ -255,6 +257,20 @@ MemoryBreakdownEntry* ConvertBreakdown(
return result;
}
+MemoryBreakdownEntry* ConvertCanvasBreakdown(
+ const WebMemoryBreakdownEntryPtr& breakdown_entry) {
+ auto* result = MemoryBreakdownEntry::Create();
+ DCHECK(breakdown_entry->canvas_memory);
+ result->setBytes(breakdown_entry->canvas_memory->bytes);
+ HeapVector<Member<MemoryAttribution>> attribution;
+ for (const auto& entry : breakdown_entry->attribution) {
+ attribution.push_back(ConvertAttribution(entry));
+ }
+ result->setAttribution(attribution);
+ result->setTypes({WTF::AtomicString(kMemoryTypeCanvas)});
+ return result;
+}
+
MemoryBreakdownEntry* CreateUnattributedBreakdown(
const WebMemoryUsagePtr& memory,
const WTF::String& memory_type) {
@@ -280,8 +296,13 @@ MemoryMeasurement* ConvertResult(const WebMemoryMeasurementPtr& measurement) {
HeapVector<Member<MemoryBreakdownEntry>> breakdown;
for (const auto& entry : measurement->breakdown) {
// Skip breakdowns that didn't get a measurement.
- if (entry->memory)
- breakdown.push_back(ConvertBreakdown(entry));
+ if (entry->memory) {
+ breakdown.push_back(ConvertJavaScriptBreakdown(entry));
+ }
+ // Skip breakdowns that didn't get a measurement.
+ if (entry->canvas_memory) {
+ breakdown.push_back(ConvertCanvasBreakdown(entry));
+ }
}
// Add breakdowns for memory that isn't attributed to an execution context.
breakdown.push_back(CreateUnattributedBreakdown(measurement->shared_memory,
@@ -369,14 +390,16 @@ void MeasureMemoryController::MeasurementComplete(
}
v8::HandleScope handle_scope(isolate_);
v8::Local<v8::Context> context = context_.NewLocal(isolate_);
+ ScriptState* script_state = ScriptState::From(context);
v8::Context::Scope context_scope(context);
v8::MicrotasksScope microtasks_scope(
isolate_, v8::MicrotasksScope::kDoNotRunMicrotasks);
- auto* result = ConvertResult(measurement);
+ MemoryMeasurement* result = ConvertResult(measurement);
v8::Local<v8::Promise::Resolver> promise_resolver =
promise_resolver_.NewLocal(isolate_);
- promise_resolver->Resolve(context, ToV8(result, promise_resolver, isolate_))
- .ToChecked();
+ v8::MaybeLocal<v8::Value> v8_result =
+ ToV8Traits<MemoryMeasurement>::ToV8(script_state, result);
+ promise_resolver->Resolve(context, v8_result.ToLocalChecked()).ToChecked();
promise_resolver_.Clear();
RecordWebMemoryUkm(context, measurement);
}
diff --git a/chromium/third_party/blink/renderer/core/timing/memory_info.cc b/chromium/third_party/blink/renderer/core/timing/memory_info.cc
index 9f8a31e1883..99df56a0dd5 100644
--- a/chromium/third_party/blink/renderer/core/timing/memory_info.cc
+++ b/chromium/third_party/blink/renderer/core/timing/memory_info.cc
@@ -32,7 +32,6 @@
#include <limits>
-#include "base/macros.h"
#include "base/time/default_tick_clock.h"
#include "third_party/blink/renderer/core/frame/local_frame.h"
#include "third_party/blink/renderer/core/frame/settings.h"
@@ -63,6 +62,8 @@ class HeapSizeCache {
public:
HeapSizeCache() : clock_(base::DefaultTickClock::GetInstance()) {}
+ HeapSizeCache(const HeapSizeCache&) = delete;
+ HeapSizeCache& operator=(const HeapSizeCache&) = delete;
void GetCachedHeapSize(HeapInfo& info, MemoryInfo::Precision precision) {
MaybeUpdate(precision);
@@ -109,7 +110,6 @@ class HeapSizeCache {
const base::TickClock* clock_;
HeapInfo info_;
- DISALLOW_COPY_AND_ASSIGN(HeapSizeCache);
};
// We quantize the sizes to make it more difficult for an attacker to see
diff --git a/chromium/third_party/blink/renderer/core/timing/performance.cc b/chromium/third_party/blink/renderer/core/timing/performance.cc
index cc63f8a3bae..a262da3c512 100644
--- a/chromium/third_party/blink/renderer/core/timing/performance.cc
+++ b/chromium/third_party/blink/renderer/core/timing/performance.cc
@@ -43,7 +43,6 @@
#include "third_party/blink/public/platform/platform.h"
#include "third_party/blink/renderer/bindings/core/v8/script_promise.h"
#include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h"
-#include "third_party/blink/renderer/bindings/core/v8/string_or_performance_measure_options.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_object_builder.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_performance_mark_options.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_performance_measure_options.h"
@@ -83,7 +82,6 @@
#include "third_party/blink/renderer/platform/loader/fetch/resource_response.h"
#include "third_party/blink/renderer/platform/loader/fetch/resource_timing_info.h"
#include "third_party/blink/renderer/platform/network/http_parsers.h"
-#include "third_party/blink/renderer/platform/runtime_enabled_features.h"
#include "third_party/blink/renderer/platform/weborigin/security_origin.h"
#include "third_party/blink/renderer/platform/wtf/std_lib_extras.h"
#include "v8/include/v8-metrics.h"
@@ -92,6 +90,10 @@ namespace blink {
namespace {
+// LongTask API can be a source of many events. Filter on Performance object
+// level before reporting to UKM to smooth out recorded events over all pages.
+constexpr size_t kLongTaskUkmSampleInterval = 100;
+
const SecurityOrigin* GetSecurityOrigin(ExecutionContext* context) {
if (context)
return context->GetSecurityOrigin();
@@ -129,32 +131,6 @@ void RecordLongTaskUkm(ExecutionContext* execution_context,
.Record(execution_context->UkmRecorder());
}
-#if !defined(USE_BLINK_V8_BINDING_NEW_IDL_UNION)
-V8UnionPerformanceMeasureOptionsOrString*
-StringOrPerformanceMeasureOptionsToNewV8Union(
- const StringOrPerformanceMeasureOptions& value) {
- if (value.IsString()) {
- return MakeGarbageCollected<V8UnionPerformanceMeasureOptionsOrString>(
- value.GetAsString());
- }
- if (value.IsPerformanceMeasureOptions()) {
- return MakeGarbageCollected<V8UnionPerformanceMeasureOptionsOrString>(
- value.GetAsPerformanceMeasureOptions());
- }
- return nullptr;
-}
-#endif // !defined(USE_BLINK_V8_BINDING_NEW_IDL_UNION)
-
-// TODO(crbug.com/1181288): Remove the old IDL union version.
-V8UnionDoubleOrString* StringOrDoubleToV8UnionDoubleOrString(
- const StringOrDouble& value) {
- if (value.IsString())
- return MakeGarbageCollected<V8UnionDoubleOrString>(value.GetAsString());
- if (value.IsDouble())
- return MakeGarbageCollected<V8UnionDoubleOrString>(value.GetAsDouble());
- return nullptr;
-}
-
} // namespace
using PerformanceObserverVector = HeapVector<Member<PerformanceObserver>>;
@@ -704,7 +680,6 @@ void Performance::AddElementTimingBuffer(PerformanceElementTiming& entry) {
}
void Performance::AddEventTimingBuffer(PerformanceEventTiming& entry) {
- DCHECK(RuntimeEnabledFeatures::EventTimingEnabled(GetExecutionContext()));
if (!IsEventTimingBufferFull()) {
event_timing_buffer_.push_back(&entry);
}
@@ -772,9 +747,12 @@ void Performance::AddLongTaskTiming(base::TimeTicks start_time,
} else {
UseCounter::Count(execution_context, WebFeature::kLongTaskBufferFull);
}
- RecordLongTaskUkm(execution_context,
- base::TimeDelta::FromMillisecondsD(dom_high_res_start_time),
- end_time - start_time);
+ if ((++long_task_counter_ % kLongTaskUkmSampleInterval) == 0) {
+ RecordLongTaskUkm(
+ execution_context,
+ base::TimeDelta::FromMillisecondsD(dom_high_res_start_time),
+ end_time - start_time);
+ }
NotifyObserversOfEntry(*entry);
}
@@ -788,12 +766,12 @@ PerformanceMark* Performance::mark(ScriptState* script_state,
const AtomicString& mark_name,
PerformanceMarkOptions* mark_options,
ExceptionState& exception_state) {
- DEFINE_STATIC_LOCAL(const AtomicString, mark_fully_loaded,
- ("mark_fully_loaded"));
- DEFINE_STATIC_LOCAL(const AtomicString, mark_fully_visible,
- ("mark_fully_visible"));
- DEFINE_STATIC_LOCAL(const AtomicString, mark_interactive,
- ("mark_interactive"));
+ DEFINE_THREAD_SAFE_STATIC_LOCAL(const AtomicString, mark_fully_loaded,
+ ("mark_fully_loaded"));
+ DEFINE_THREAD_SAFE_STATIC_LOCAL(const AtomicString, mark_fully_visible,
+ ("mark_fully_visible"));
+ DEFINE_THREAD_SAFE_STATIC_LOCAL(const AtomicString, mark_interactive,
+ ("mark_interactive"));
if (mark_options &&
(mark_options->hasStartTime() || mark_options->hasDetail())) {
UseCounter::Count(GetExecutionContext(), WebFeature::kUserTimingL3);
@@ -850,7 +828,6 @@ PerformanceMeasure* Performance::measure(ScriptState* script_state,
exception_state);
}
-#if defined(USE_BLINK_V8_BINDING_NEW_IDL_UNION)
PerformanceMeasure* Performance::measure(
ScriptState* script_state,
const AtomicString& measure_name,
@@ -859,20 +836,7 @@ PerformanceMeasure* Performance::measure(
return MeasureInternal(script_state, measure_name, start_or_options,
absl::nullopt, exception_state);
}
-#else // defined(USE_BLINK_V8_BINDING_NEW_IDL_UNION)
-PerformanceMeasure* Performance::measure(
- ScriptState* script_state,
- const AtomicString& measure_name,
- const StringOrPerformanceMeasureOptions& start_or_options,
- ExceptionState& exception_state) {
- return MeasureInternal(
- script_state, measure_name,
- StringOrPerformanceMeasureOptionsToNewV8Union(start_or_options),
- absl::nullopt, exception_state);
-}
-#endif // defined(USE_BLINK_V8_BINDING_NEW_IDL_UNION)
-#if defined(USE_BLINK_V8_BINDING_NEW_IDL_UNION)
PerformanceMeasure* Performance::measure(
ScriptState* script_state,
const AtomicString& measure_name,
@@ -882,19 +846,6 @@ PerformanceMeasure* Performance::measure(
return MeasureInternal(script_state, measure_name, start_or_options,
absl::optional<String>(end), exception_state);
}
-#else // defined(USE_BLINK_V8_BINDING_NEW_IDL_UNION)
-PerformanceMeasure* Performance::measure(
- ScriptState* script_state,
- const AtomicString& measure_name,
- const StringOrPerformanceMeasureOptions& start_or_options,
- const String& end,
- ExceptionState& exception_state) {
- return MeasureInternal(
- script_state, measure_name,
- StringOrPerformanceMeasureOptionsToNewV8Union(start_or_options),
- absl::optional<String>(end), exception_state);
-}
-#endif // defined(USE_BLINK_V8_BINDING_NEW_IDL_UNION)
// |MeasureInternal| exists to unify the arguments from different
// `performance.measure()` overloads into a consistent form, then delegate to
@@ -947,18 +898,12 @@ PerformanceMeasure* Performance::MeasureInternal(
return nullptr;
}
- V8UnionDoubleOrString* start = nullptr;
- if (options->hasStart()) {
- start = StringOrDoubleToV8UnionDoubleOrString(options->start());
- }
+ V8UnionDoubleOrString* start = options->getStartOr(nullptr);
absl::optional<double> duration;
if (options->hasDuration()) {
duration = options->duration();
}
- V8UnionDoubleOrString* end = nullptr;
- if (options->hasEnd()) {
- end = StringOrDoubleToV8UnionDoubleOrString(options->end());
- }
+ V8UnionDoubleOrString* end = options->getEndOr(nullptr);
return MeasureWithDetail(
script_state, measure_name, start, duration, end,
@@ -1004,34 +949,6 @@ void Performance::clearMeasures(const AtomicString& measure_name) {
GetUserTiming().ClearMeasures(measure_name);
}
-ScriptPromise Performance::profile(ScriptState* script_state,
- const ProfilerInitOptions* options,
- ExceptionState& exception_state) {
- auto* execution_context = ExecutionContext::From(script_state);
- DCHECK(execution_context);
- DCHECK(
- RuntimeEnabledFeatures::ExperimentalJSProfilerEnabled(execution_context));
-
- bool can_profile = false;
- if (LocalDOMWindow* window = LocalDOMWindow::From(script_state)) {
- can_profile = ProfilerGroup::CanProfile(window, &exception_state,
- ReportOptions::kReportOnFailure);
- }
-
- if (!can_profile)
- return ScriptPromise();
-
- auto* profiler_group = ProfilerGroup::From(script_state->GetIsolate());
- DCHECK(profiler_group);
-
- auto* profiler = profiler_group->CreateProfiler(
- script_state, *options, time_origin_, exception_state);
- if (exception_state.HadException())
- return ScriptPromise();
-
- return ScriptPromise::Cast(script_state, ToV8(profiler, script_state));
-}
-
void Performance::RegisterPerformanceObserver(PerformanceObserver& observer) {
observer_filter_options_ |= observer.FilterOptions();
observers_.insert(&observer);
@@ -1051,8 +968,6 @@ void Performance::UpdatePerformanceObserverFilterOptions() {
}
void Performance::NotifyObserversOfEntry(PerformanceEntry& entry) const {
- DCHECK(entry.EntryTypeEnum() != PerformanceEntry::kEvent ||
- RuntimeEnabledFeatures::EventTimingEnabled(GetExecutionContext()));
bool observer_found = false;
for (auto& observer : observers_) {
if (observer->FilterOptions() & entry.EntryTypeEnum() &&
diff --git a/chromium/third_party/blink/renderer/core/timing/performance.h b/chromium/third_party/blink/renderer/core/timing/performance.h
index a3c9924825b..32c9894e3d8 100644
--- a/chromium/third_party/blink/renderer/core/timing/performance.h
+++ b/chromium/third_party/blink/renderer/core/timing/performance.h
@@ -34,7 +34,6 @@
#include "base/single_thread_task_runner.h"
#include "third_party/blink/public/mojom/timing/resource_timing.mojom-blink.h"
-#include "third_party/blink/renderer/bindings/core/v8/string_or_double.h"
#include "third_party/blink/renderer/core/core_export.h"
#include "third_party/blink/renderer/core/dom/dom_high_res_time_stamp.h"
#include "third_party/blink/renderer/core/dom/events/event_target.h"
@@ -73,14 +72,12 @@ class PerformanceMeasure;
class PerformanceNavigation;
class PerformanceObserver;
class PerformanceTiming;
-class ProfilerInitOptions;
class ResourceResponse;
class ResourceTimingInfo;
class ScriptPromise;
class ScriptState;
class ScriptValue;
class SecurityOrigin;
-class StringOrPerformanceMeasureOptions;
class UserTiming;
class V8ObjectBuilder;
class V8UnionDoubleOrString;
@@ -145,9 +142,7 @@ class CORE_EXPORT Performance : public EventTargetWithInlineData {
DOMHighResTimeStamp timeOrigin() const;
// Internal getter method for the time origin value.
- double GetTimeOrigin() const {
- return time_origin_.since_origin().InSecondsF();
- }
+ base::TimeTicks GetTimeOriginInternal() const { return time_origin_; }
PerformanceEntryVector getEntries();
// Get BufferedEntriesByType will return all entries in the buffer regardless
@@ -268,43 +263,22 @@ class CORE_EXPORT Performance : public EventTargetWithInlineData {
const AtomicString& measure_name,
ExceptionState&);
-#if defined(USE_BLINK_V8_BINDING_NEW_IDL_UNION)
PerformanceMeasure* measure(
ScriptState* script_state,
const AtomicString& measure_name,
const V8UnionPerformanceMeasureOptionsOrString* start_or_options,
ExceptionState& exception_state);
-#else // defined(USE_BLINK_V8_BINDING_NEW_IDL_UNION)
- PerformanceMeasure* measure(
- ScriptState*,
- const AtomicString& measure_name,
- const StringOrPerformanceMeasureOptions& start_or_options,
- ExceptionState&);
-#endif // defined(USE_BLINK_V8_BINDING_NEW_IDL_UNION)
-#if defined(USE_BLINK_V8_BINDING_NEW_IDL_UNION)
PerformanceMeasure* measure(
ScriptState* script_state,
const AtomicString& measure_name,
const V8UnionPerformanceMeasureOptionsOrString* start_or_options,
const String& end,
ExceptionState& exception_state);
-#else // defined(USE_BLINK_V8_BINDING_NEW_IDL_UNION)
- PerformanceMeasure* measure(
- ScriptState*,
- const AtomicString& measure_name,
- const StringOrPerformanceMeasureOptions& start_or_options,
- const String& end,
- ExceptionState&);
-#endif // defined(USE_BLINK_V8_BINDING_NEW_IDL_UNION)
void clearMeasures(const AtomicString& measure_name);
void clearMeasures() { return clearMeasures(AtomicString()); }
- ScriptPromise profile(ScriptState*,
- const ProfilerInitOptions*,
- ExceptionState&);
-
void UnregisterPerformanceObserver(PerformanceObserver&);
void RegisterPerformanceObserver(PerformanceObserver&);
void UpdatePerformanceObserverFilterOptions();
@@ -431,6 +405,9 @@ class CORE_EXPORT Performance : public EventTargetWithInlineData {
// See crbug.com/1181774.
Member<BackgroundTracingHelper> background_tracing_helper_;
+
+ // Running counter for LongTask observations.
+ size_t long_task_counter_ = 0;
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/timing/performance.idl b/chromium/third_party/blink/renderer/core/timing/performance.idl
index 7088dff953c..c5d098ae474 100644
--- a/chromium/third_party/blink/renderer/core/timing/performance.idl
+++ b/chromium/third_party/blink/renderer/core/timing/performance.idl
@@ -71,12 +71,8 @@ interface Performance : EventTarget {
// a dedicated worker is included in the result of the API call in Window.
[MeasureAs=MeasureMemory, Exposed=(Window,ServiceWorker,SharedWorker), CallWith=ScriptState, RuntimeEnabled=MeasureMemory, RaisesException, CrossOriginIsolated] Promise<MemoryMeasurement> measureUserAgentSpecificMemory();
- // JS Self-Profiling API
- // https://github.com/WICG/js-self-profiling/
- [MeasureAs=JSSelfProfiling, CallWith=ScriptState, RuntimeEnabled=ExperimentalJSProfiler, RaisesException] Promise<Profiler> profile(ProfilerInitOptions options);
-
// Event Timing
- [Exposed=Window, SameObject, SaveSameObject, RuntimeEnabled=EventTiming] readonly attribute EventCounts eventCounts;
+ [Exposed=Window, SameObject, SaveSameObject] readonly attribute EventCounts eventCounts;
[CallWith=ScriptState, ImplementedAs=toJSONForBinding] object toJSON();
};
diff --git a/chromium/third_party/blink/renderer/core/timing/performance_event_timing.idl b/chromium/third_party/blink/renderer/core/timing/performance_event_timing.idl
index 17b3db120b1..68cef848abc 100644
--- a/chromium/third_party/blink/renderer/core/timing/performance_event_timing.idl
+++ b/chromium/third_party/blink/renderer/core/timing/performance_event_timing.idl
@@ -8,7 +8,7 @@ interface PerformanceEventTiming : PerformanceEntry {
readonly attribute DOMHighResTimeStamp processingStart;
readonly attribute DOMHighResTimeStamp processingEnd;
readonly attribute boolean cancelable;
- [RuntimeEnabled=EventTiming] readonly attribute Node? target;
+ readonly attribute Node? target;
[CallWith=ScriptState, ImplementedAs=toJSONForBinding] object toJSON();
};
diff --git a/chromium/third_party/blink/renderer/core/timing/performance_mark.cc b/chromium/third_party/blink/renderer/core/timing/performance_mark.cc
index 487e2f98a69..30ec9b574f0 100644
--- a/chromium/third_party/blink/renderer/core/timing/performance_mark.cc
+++ b/chromium/third_party/blink/renderer/core/timing/performance_mark.cc
@@ -58,8 +58,8 @@ PerformanceMark* PerformanceMark::Create(ScriptState* script_state,
// GetTimeOrigin() returns seconds from the monotonic clock's origin..
// Trace events timestamps accept seconds (as a double) based on
// CurrentTime::monotonicallyIncreasingTime().
- unsafe_start_for_traces = trace_event::ToTraceTimestamp(
- performance->GetTimeOrigin() + start / 1000.0);
+ unsafe_start_for_traces = performance->GetTimeOriginInternal() +
+ base::TimeDelta::FromMillisecondsD(start);
} else {
start = performance->now();
unsafe_start_for_traces = base::TimeTicks::Now();
diff --git a/chromium/third_party/blink/renderer/core/timing/performance_navigation_timing.cc b/chromium/third_party/blink/renderer/core/timing/performance_navigation_timing.cc
index fa42819274c..67ee52f97be 100644
--- a/chromium/third_party/blink/renderer/core/timing/performance_navigation_timing.cc
+++ b/chromium/third_party/blink/renderer/core/timing/performance_navigation_timing.cc
@@ -13,7 +13,9 @@
#include "third_party/blink/renderer/core/loader/document_loader.h"
#include "third_party/blink/renderer/core/performance_entry_names.h"
#include "third_party/blink/renderer/core/timing/performance.h"
+#include "third_party/blink/renderer/core/timing/performance_navigation_timing_activation_start.h"
#include "third_party/blink/renderer/platform/loader/fetch/resource_timing_info.h"
+#include "third_party/blink/renderer/platform/runtime_enabled_features.h"
#include "third_party/blink/renderer/platform/weborigin/kurl.h"
namespace blink {
@@ -318,5 +320,12 @@ void PerformanceNavigationTiming::BuildJSONValue(
builder.AddNumber("loadEventEnd", loadEventEnd());
builder.AddString("type", type());
builder.AddNumber("redirectCount", redirectCount());
+
+ if (RuntimeEnabledFeatures::Prerender2Enabled(
+ ExecutionContext::From(builder.GetScriptState()))) {
+ builder.AddNumber(
+ "activationStart",
+ PerformanceNavigationTimingActivationStart::activationStart(*this));
+ }
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/timing/performance_navigation_timing.h b/chromium/third_party/blink/renderer/core/timing/performance_navigation_timing.h
index 1c5f76ef0b1..ca71acbeef2 100644
--- a/chromium/third_party/blink/renderer/core/timing/performance_navigation_timing.h
+++ b/chromium/third_party/blink/renderer/core/timing/performance_navigation_timing.h
@@ -69,6 +69,8 @@ class CORE_EXPORT PerformanceNavigationTiming final
void BuildJSONValue(V8ObjectBuilder&) const override;
private:
+ friend class PerformanceNavigationTimingActivationStart;
+
static AtomicString GetNavigationType(WebNavigationType, const Document*);
const DocumentTiming* GetDocumentTiming() const;
diff --git a/chromium/third_party/blink/renderer/core/timing/performance_navigation_timing_activation_start.cc b/chromium/third_party/blink/renderer/core/timing/performance_navigation_timing_activation_start.cc
new file mode 100644
index 00000000000..504088e7d71
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/timing/performance_navigation_timing_activation_start.cc
@@ -0,0 +1,25 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/core/timing/performance_navigation_timing_activation_start.h"
+
+#include "third_party/blink/renderer/core/loader/document_load_timing.h"
+#include "third_party/blink/renderer/core/timing/performance.h"
+
+namespace blink {
+
+// static
+DOMHighResTimeStamp PerformanceNavigationTimingActivationStart::activationStart(
+ const PerformanceNavigationTiming& performance_navigation_timing) {
+ DocumentLoadTiming* timing =
+ performance_navigation_timing.GetDocumentLoadTiming();
+ if (!timing)
+ return 0.0;
+ return Performance::MonotonicTimeToDOMHighResTimeStamp(
+ performance_navigation_timing.TimeOrigin(), timing->ActivationStart(),
+ false /* allow_negative_value */,
+ performance_navigation_timing.CrossOriginIsolatedCapability());
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/timing/performance_navigation_timing_activation_start.h b/chromium/third_party/blink/renderer/core/timing/performance_navigation_timing_activation_start.h
new file mode 100644
index 00000000000..c42f599967c
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/timing/performance_navigation_timing_activation_start.h
@@ -0,0 +1,20 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_TIMING_PERFORMANCE_NAVIGATION_TIMING_ACTIVATION_START_H_
+#define THIRD_PARTY_BLINK_RENDERER_CORE_TIMING_PERFORMANCE_NAVIGATION_TIMING_ACTIVATION_START_H_
+
+#include "third_party/blink/renderer/core/timing/performance_navigation_timing.h"
+
+namespace blink {
+
+class PerformanceNavigationTimingActivationStart final {
+ public:
+ static DOMHighResTimeStamp activationStart(
+ const PerformanceNavigationTiming& performance_navigation_timing);
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_CORE_TIMING_PERFORMANCE_NAVIGATION_TIMING_ACTIVATION_START_H_
diff --git a/chromium/third_party/blink/renderer/core/timing/performance_navigation_timing_activation_start.idl b/chromium/third_party/blink/renderer/core/timing/performance_navigation_timing_activation_start.idl
new file mode 100644
index 00000000000..62f799de902
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/timing/performance_navigation_timing_activation_start.idl
@@ -0,0 +1,11 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// https://jeremyroman.github.io/alternate-loading-modes/#performance-navigation-timing-extension
+[
+ ImplementedAs=PerformanceNavigationTimingActivationStart,
+ RuntimeEnabled=Prerender2
+] partial interface PerformanceNavigationTiming {
+ readonly attribute DOMHighResTimeStamp activationStart;
+}; \ No newline at end of file
diff --git a/chromium/third_party/blink/renderer/core/timing/performance_observer.cc b/chromium/third_party/blink/renderer/core/timing/performance_observer.cc
index 60a2ac86d78..bbff4d6bd3c 100644
--- a/chromium/third_party/blink/renderer/core/timing/performance_observer.cc
+++ b/chromium/third_party/blink/renderer/core/timing/performance_observer.cc
@@ -59,8 +59,7 @@ Vector<AtomicString> PerformanceObserver::supportedEntryTypes(
auto* execution_context = ExecutionContext::From(script_state);
if (execution_context->IsWindow()) {
supportedEntryTypes.push_back(performance_entry_names::kElement);
- if (RuntimeEnabledFeatures::EventTimingEnabled(execution_context))
- supportedEntryTypes.push_back(performance_entry_names::kEvent);
+ supportedEntryTypes.push_back(performance_entry_names::kEvent);
supportedEntryTypes.push_back(performance_entry_names::kFirstInput);
supportedEntryTypes.push_back(
performance_entry_names::kLargestContentfulPaint);
diff --git a/chromium/third_party/blink/renderer/core/timing/performance_observer_init.idl b/chromium/third_party/blink/renderer/core/timing/performance_observer_init.idl
index f4169cd8cfa..ee124eae41a 100644
--- a/chromium/third_party/blink/renderer/core/timing/performance_observer_init.idl
+++ b/chromium/third_party/blink/renderer/core/timing/performance_observer_init.idl
@@ -8,5 +8,5 @@ dictionary PerformanceObserverInit {
sequence<DOMString> entryTypes;
DOMString type;
boolean buffered = false;
- [RuntimeEnabled=EventTiming] DOMHighResTimeStamp durationThreshold;
+ DOMHighResTimeStamp durationThreshold;
};
diff --git a/chromium/third_party/blink/renderer/core/timing/performance_test.cc b/chromium/third_party/blink/renderer/core/timing/performance_test.cc
index 6555f4e7b06..09efdb6cc7c 100644
--- a/chromium/third_party/blink/renderer/core/timing/performance_test.cc
+++ b/chromium/third_party/blink/renderer/core/timing/performance_test.cc
@@ -7,8 +7,6 @@
#include "base/test/metrics/histogram_tester.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/public/platform/task_type.h"
-#include "third_party/blink/renderer/bindings/core/v8/string_or_double.h"
-#include "third_party/blink/renderer/bindings/core/v8/string_or_performance_measure_options.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_testing.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_performance_observer_callback.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_performance_observer_init.h"
diff --git a/chromium/third_party/blink/renderer/core/timing/performance_timing.cc b/chromium/third_party/blink/renderer/core/timing/performance_timing.cc
index 78383485335..7a3716503a7 100644
--- a/chromium/third_party/blink/renderer/core/timing/performance_timing.cc
+++ b/chromium/third_party/blink/renderer/core/timing/performance_timing.cc
@@ -63,7 +63,8 @@ static uint64_t ToIntegerMilliseconds(base::TimeDelta duration,
PerformanceTiming::PerformanceTiming(ExecutionContext* context)
: ExecutionContextClient(context) {
- cross_origin_isolated_capability_ = context->CrossOriginIsolatedCapability();
+ cross_origin_isolated_capability_ =
+ context && context->CrossOriginIsolatedCapability();
}
uint64_t PerformanceTiming::navigationStart() const {
@@ -354,12 +355,12 @@ PerformanceTiming::BackForwardCacheRestore() const {
WTF::Vector<BackForwardCacheRestoreTiming> restore_timings(
navigation_starts.size());
- for (size_t i = 0; i < restore_timings.size(); i++) {
+ for (wtf_size_t i = 0; i < restore_timings.size(); i++) {
restore_timings[i].navigation_start =
MonotonicTimeToIntegerMilliseconds(navigation_starts[i]);
restore_timings[i].first_paint =
MonotonicTimeToIntegerMilliseconds(first_paints[i]);
- for (size_t j = 0; j < request_animation_frames[i].size(); j++) {
+ for (wtf_size_t j = 0; j < request_animation_frames[i].size(); j++) {
restore_timings[i].request_animation_frames[j] =
MonotonicTimeToIntegerMilliseconds(request_animation_frames[i][j]);
}
@@ -639,6 +640,19 @@ absl::optional<base::TimeTicks> PerformanceTiming::LastPortalActivatedPaint()
return timing->LastPortalActivatedPaint();
}
+absl::optional<base::TimeDelta> PerformanceTiming::PrerenderActivationStart()
+ const {
+ DocumentLoadTiming* timing = GetDocumentLoadTiming();
+ if (!timing)
+ return absl::nullopt;
+
+ base::TimeTicks activation_start = timing->ActivationStart();
+ if (activation_start.is_null())
+ return absl::nullopt;
+
+ return timing->MonotonicTimeToZeroBasedDocumentTime(activation_start);
+}
+
absl::optional<base::TimeTicks> PerformanceTiming::UnloadStart() const {
DocumentLoadTiming* timing = GetDocumentLoadTiming();
if (!timing)
diff --git a/chromium/third_party/blink/renderer/core/timing/performance_timing.h b/chromium/third_party/blink/renderer/core/timing/performance_timing.h
index 484844bc784..a5c7172ae0a 100644
--- a/chromium/third_party/blink/renderer/core/timing/performance_timing.h
+++ b/chromium/third_party/blink/renderer/core/timing/performance_timing.h
@@ -196,6 +196,8 @@ class CORE_EXPORT PerformanceTiming final : public ScriptWrappable,
// The time of the first paint after a portal activation.
absl::optional<base::TimeTicks> LastPortalActivatedPaint() const;
+ // The start time of the prerender activation navigation.
+ absl::optional<base::TimeDelta> PrerenderActivationStart() const;
typedef uint64_t (PerformanceTiming::*PerformanceTimingGetter)() const;
using NameToAttributeMap = HashMap<AtomicString, PerformanceTimingGetter>;
diff --git a/chromium/third_party/blink/renderer/core/timing/performance_user_timing.cc b/chromium/third_party/blink/renderer/core/timing/performance_user_timing.cc
index 2bf5070bc21..887e3330450 100644
--- a/chromium/third_party/blink/renderer/core/timing/performance_user_timing.cc
+++ b/chromium/third_party/blink/renderer/core/timing/performance_user_timing.cc
@@ -109,7 +109,8 @@ double UserTiming::FindExistingMarkStartTime(const AtomicString& mark_name,
}
PerformanceTiming::PerformanceTimingGetter timing_function =
- PerformanceTiming::GetAttributeMapping().at(mark_name);
+ PerformanceTiming::GetAttributeMapping().DeprecatedAtOrEmptyValue(
+ mark_name);
if (!timing_function) {
exception_state.ThrowDOMException(
DOMExceptionCode::kSyntaxError,
@@ -176,15 +177,8 @@ base::TimeTicks UserTiming::GetPerformanceMarkUnsafeTimeForTraces(
return mark->UnsafeTimeForTraces();
}
}
-
- // User timing events are stored as integer milliseconds from the start of
- // navigation.
- // GetTimeOrigin() returns seconds from the monotonic clock's origin..
- // Trace events timestamps accept seconds (as a double) based on
- // CurrentTime::monotonicallyIncreasingTime().
- double start_time_in_seconds = start_time / 1000.0;
- return trace_event::ToTraceTimestamp(performance_->GetTimeOrigin() +
- start_time_in_seconds);
+ return performance_->GetTimeOriginInternal() +
+ base::TimeDelta::FromMillisecondsD(start_time);
}
PerformanceMeasure* UserTiming::Measure(ScriptState* script_state,
diff --git a/chromium/third_party/blink/renderer/core/timing/performance_user_timing.h b/chromium/third_party/blink/renderer/core/timing/performance_user_timing.h
index c4a983f6e2c..2ed451c7f3a 100644
--- a/chromium/third_party/blink/renderer/core/timing/performance_user_timing.h
+++ b/chromium/third_party/blink/renderer/core/timing/performance_user_timing.h
@@ -26,6 +26,7 @@
#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_TIMING_PERFORMANCE_USER_TIMING_H_
#define THIRD_PARTY_BLINK_RENDERER_CORE_TIMING_PERFORMANCE_USER_TIMING_H_
+#include "third_party/abseil-cpp/absl/types/optional.h"
#include "third_party/blink/renderer/core/timing/performance.h"
#include "third_party/blink/renderer/core/timing/performance_timing.h"
#include "third_party/blink/renderer/platform/heap/heap_allocator.h"
diff --git a/chromium/third_party/blink/renderer/core/timing/profiler.cc b/chromium/third_party/blink/renderer/core/timing/profiler.cc
index a48c173fa73..0bee7aedb0b 100644
--- a/chromium/third_party/blink/renderer/core/timing/profiler.cc
+++ b/chromium/third_party/blink/renderer/core/timing/profiler.cc
@@ -6,15 +6,52 @@
#include "third_party/blink/renderer/core/dom/dom_exception.h"
#include "third_party/blink/renderer/core/execution_context/execution_context.h"
+#include "third_party/blink/renderer/core/frame/local_dom_window.h"
+#include "third_party/blink/renderer/core/timing/dom_window_performance.h"
#include "third_party/blink/renderer/core/timing/profiler_group.h"
#include "third_party/blink/renderer/platform/bindings/script_forbidden_scope.h"
namespace blink {
+Profiler* Profiler::Create(ScriptState* script_state,
+ const ProfilerInitOptions* options,
+ ExceptionState& exception_state) {
+ auto* execution_context = ExecutionContext::From(script_state);
+ DCHECK(execution_context);
+ DCHECK(
+ RuntimeEnabledFeatures::ExperimentalJSProfilerEnabled(execution_context));
+
+ Performance* performance = nullptr;
+ bool can_profile = false;
+ if (LocalDOMWindow* window = LocalDOMWindow::From(script_state)) {
+ can_profile = ProfilerGroup::CanProfile(window, &exception_state,
+ ReportOptions::kReportOnFailure);
+ performance = DOMWindowPerformance::performance(*window);
+ }
+
+ if (!can_profile) {
+ DCHECK(exception_state.HadException());
+ return nullptr;
+ }
+
+ DCHECK(performance);
+
+ auto* profiler_group = ProfilerGroup::From(script_state->GetIsolate());
+ DCHECK(profiler_group);
+
+ auto* profiler = profiler_group->CreateProfiler(
+ script_state, *options, performance->GetTimeOriginInternal(),
+ exception_state);
+ if (exception_state.HadException())
+ return nullptr;
+
+ return profiler;
+}
+
void Profiler::Trace(Visitor* visitor) const {
visitor->Trace(profiler_group_);
visitor->Trace(script_state_);
- ScriptWrappable::Trace(visitor);
+ EventTargetWithInlineData::Trace(visitor);
}
void Profiler::DisposeAsync() {
diff --git a/chromium/third_party/blink/renderer/core/timing/profiler.h b/chromium/third_party/blink/renderer/core/timing/profiler.h
index b5e9074a052..da8590ca532 100644
--- a/chromium/third_party/blink/renderer/core/timing/profiler.h
+++ b/chromium/third_party/blink/renderer/core/timing/profiler.h
@@ -19,7 +19,9 @@
namespace blink {
+class ExceptionState;
class ScriptState;
+class ProfilerInitOptions;
// A web-exposed JS sampling profiler created via blink::ProfilerGroup,
// wrapping a handle to v8::CpuProfiler. Records samples periodically from the
@@ -44,6 +46,10 @@ class CORE_EXPORT Profiler final : public EventTargetWithInlineData {
~Profiler() override = default;
+ static Profiler* Create(ScriptState*,
+ const ProfilerInitOptions*,
+ ExceptionState&);
+
void Trace(Visitor* visitor) const override;
void DisposeAsync();
diff --git a/chromium/third_party/blink/renderer/core/timing/profiler.idl b/chromium/third_party/blink/renderer/core/timing/profiler.idl
index 4ffdc531ad7..649f08798aa 100644
--- a/chromium/third_party/blink/renderer/core/timing/profiler.idl
+++ b/chromium/third_party/blink/renderer/core/timing/profiler.idl
@@ -3,9 +3,11 @@
// found in the LICENSE file.
// https://wicg.github.io/js-self-profiling/#the-profiler-interface
-[Exposed=(Window,Worker), RuntimeEnabled=ExperimentalJSProfiler]
+[Exposed=Window, RuntimeEnabled=ExperimentalJSProfiler]
interface Profiler : EventTarget {
readonly attribute DOMHighResTimeStamp sampleInterval;
readonly attribute boolean stopped;
+
+ [MeasureAs=JSSelfProfiling, CallWith=ScriptState, RaisesException] constructor(ProfilerInitOptions options);
[CallWith=ScriptState] Promise<ProfilerTrace> stop();
};
diff --git a/chromium/third_party/blink/renderer/core/timing/profiler_group.cc b/chromium/third_party/blink/renderer/core/timing/profiler_group.cc
index d404c852317..090068ee1dc 100644
--- a/chromium/third_party/blink/renderer/core/timing/profiler_group.cc
+++ b/chromium/third_party/blink/renderer/core/timing/profiler_group.cc
@@ -80,18 +80,6 @@ bool ProfilerGroup::CanProfile(LocalDOMWindow* local_window,
return false;
}
- // Bypass COOP/COEP checks when the |--disable-web-security| flag is present.
- auto* local_frame = local_window->GetFrame();
- DCHECK(local_frame);
- if (local_frame->GetSettings()->GetWebSecurityEnabled() &&
- !local_window->CrossOriginIsolatedCapability()) {
- if (exception_state) {
- exception_state->ThrowSecurityError(
- "performance.profile() requires COOP+COEP (web.dev/coop-coep)");
- }
- return false;
- }
-
return true;
}
@@ -182,9 +170,7 @@ Profiler* ProfilerGroup::CreateProfiler(ScriptState* script_state,
String profiler_id = NextProfilerId();
v8::CpuProfilingOptions options(
- v8::kLeafNodeLineNumbers,
- init_options.hasMaxBufferSize() ? init_options.maxBufferSize()
- : v8::CpuProfilingOptions::kNoSampleLimit,
+ v8::kLeafNodeLineNumbers, init_options.maxBufferSize(),
static_cast<int>(sample_interval_us), script_state->GetContext());
v8::CpuProfilingStatus status = cpu_profiler_->StartProfiling(
diff --git a/chromium/third_party/blink/renderer/core/timing/profiler_group.h b/chromium/third_party/blink/renderer/core/timing/profiler_group.h
index 5b91224cc64..d673d0d6ec6 100644
--- a/chromium/third_party/blink/renderer/core/timing/profiler_group.h
+++ b/chromium/third_party/blink/renderer/core/timing/profiler_group.h
@@ -5,7 +5,6 @@
#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_TIMING_PROFILER_GROUP_H_
#define THIRD_PARTY_BLINK_RENDERER_CORE_TIMING_PROFILER_GROUP_H_
-#include "base/macros.h"
#include "base/time/time.h"
#include "third_party/blink/renderer/core/core_export.h"
#include "third_party/blink/renderer/core/execution_context/security_context.h"
@@ -47,6 +46,8 @@ class CORE_EXPORT ProfilerGroup
static base::TimeDelta GetBaseSampleInterval();
ProfilerGroup(v8::Isolate* isolate);
+ ProfilerGroup(const ProfilerGroup&) = delete;
+ ProfilerGroup& operator=(const ProfilerGroup&) = delete;
~ProfilerGroup() override;
Profiler* CreateProfiler(ScriptState* script_state,
@@ -93,8 +94,6 @@ class CORE_EXPORT ProfilerGroup
// A set of observers, one for each ExecutionContext that has profiling
// enabled.
HeapHashSet<Member<ProfilingContextObserver>> context_observers_;
-
- DISALLOW_COPY_AND_ASSIGN(ProfilerGroup);
};
class DiscardedSamplesDelegate : public v8::DiscardedSamplesDelegate {
diff --git a/chromium/third_party/blink/renderer/core/timing/profiler_init_options.idl b/chromium/third_party/blink/renderer/core/timing/profiler_init_options.idl
index a9f2ab00498..e904e48c9b9 100644
--- a/chromium/third_party/blink/renderer/core/timing/profiler_init_options.idl
+++ b/chromium/third_party/blink/renderer/core/timing/profiler_init_options.idl
@@ -5,5 +5,5 @@
// https://wicg.github.io/js-self-profiling/#dom-profilerinitoptions
dictionary ProfilerInitOptions {
required DOMHighResTimeStamp sampleInterval;
- unsigned long maxBufferSize;
+ required unsigned long maxBufferSize;
};
diff --git a/chromium/third_party/blink/renderer/core/timing/responsiveness_metrics.cc b/chromium/third_party/blink/renderer/core/timing/responsiveness_metrics.cc
new file mode 100644
index 00000000000..7b638a1650d
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/timing/responsiveness_metrics.cc
@@ -0,0 +1,204 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/core/timing/responsiveness_metrics.h"
+
+#include "base/rand_util.h"
+#include "services/metrics/public/cpp/ukm_builders.h"
+#include "services/metrics/public/cpp/ukm_recorder.h"
+
+namespace blink {
+
+namespace {
+// Minimum potentially generated value for UKM sampling.
+constexpr int kMinValueForSampling = 1;
+// Maximum potentially generated value for UKM sampling.
+constexpr int kMaxValueForSampling = 100;
+// UKM sampling rate. The sampling strategy is 1/N.
+constexpr int kUkmSamplingRate = 10;
+
+base::TimeDelta MaxEventDuration(
+ WTF::Vector<ResponsivenessMetrics::EventTimestamps> timestamps) {
+ base::TimeDelta max_duration =
+ timestamps[0].end_time - timestamps[0].start_time;
+ for (WTF::wtf_size_t i = 1; i < timestamps.size(); ++i) {
+ max_duration = std::max(max_duration,
+ timestamps[i].end_time - timestamps[i].start_time);
+ }
+ return max_duration;
+}
+
+base::TimeDelta TotalEventDuration(
+ // timestamps is sorted by the start_time of EventTimestamps.
+ WTF::Vector<ResponsivenessMetrics::EventTimestamps> timestamps) {
+ // TODO(crbug.com/1229668): Once the event timestamp bug is fixed, add a
+ // DCHECK(IsSorted) here.
+ base::TimeDelta total_duration =
+ timestamps[0].end_time - timestamps[0].start_time;
+ base::TimeTicks current_end_time = timestamps[0].end_time;
+ for (WTF::wtf_size_t i = 1; i < timestamps.size(); ++i) {
+ total_duration += timestamps[i].end_time - timestamps[i].start_time;
+ if (timestamps[i].start_time < current_end_time) {
+ total_duration -= std::min(current_end_time, timestamps[i].end_time) -
+ timestamps[i].start_time;
+ }
+ current_end_time = std::max(current_end_time, timestamps[i].end_time);
+ }
+ return total_duration;
+}
+} // namespace
+
+ResponsivenessMetrics::ResponsivenessMetrics() = default;
+ResponsivenessMetrics::~ResponsivenessMetrics() = default;
+
+void ResponsivenessMetrics::RecordUserInteractionUKM(
+ LocalDOMWindow* window,
+ UserInteractionType interaction_type,
+ base::TimeDelta max_event_duration,
+ base::TimeDelta total_event_duration) {
+ if (!window)
+ return;
+
+ ukm::UkmRecorder* ukm_recorder = window->UkmRecorder();
+ ukm::SourceId source_id = window->UkmSourceID();
+ if (source_id != ukm::kInvalidSourceId &&
+ (!sampling_ || base::RandInt(kMinValueForSampling,
+ kMaxValueForSampling) <= kUkmSamplingRate)) {
+ ukm::builders::Responsiveness_UserInteraction(source_id)
+ .SetInteractionType(static_cast<int>(interaction_type))
+ .SetMaxEventDuration(max_event_duration.InMilliseconds())
+ .SetTotalEventDuration(total_event_duration.InMilliseconds())
+ .Record(ukm_recorder);
+ }
+}
+
+void ResponsivenessMetrics::NotifyPotentialDrag() {
+ is_drag_ = pending_pointer_down_timestamps_.has_value() &&
+ !pending_pointer_up_timestamps_.has_value();
+}
+
+void ResponsivenessMetrics::RecordPerInteractionLatency(
+ LocalDOMWindow* window,
+ const AtomicString& event_type,
+ absl::optional<int> key_code,
+ absl::optional<PointerId> pointer_id,
+ EventTimestamps event_timestamps) {
+ // Keyboard interactions.
+ if (key_code.has_value()) {
+ RecordKeyboardInteractions(window, event_type, key_code.value(),
+ event_timestamps);
+ }
+ // Tap(Click) or Drag.
+ if (pointer_id.has_value()) {
+ RecordTapOrClickOrDrag(window, event_type, event_timestamps);
+ }
+}
+
+void ResponsivenessMetrics::FlushPendingInteraction(LocalDOMWindow* window) {
+ // For tap delay, the click can be dropped. We will measure the latency
+ // without any click data.
+ if (pending_pointer_down_timestamps_.has_value() &&
+ pending_pointer_up_timestamps_.has_value()) {
+ WTF::Vector<EventTimestamps> timestamps;
+ // Insertion order matters for latency computation.
+ timestamps.push_back(pending_pointer_down_timestamps_.value());
+ timestamps.push_back(pending_pointer_up_timestamps_.value());
+ RecordUserInteractionUKM(window,
+ is_drag_ ? UserInteractionType::kDrag
+ : UserInteractionType::kTapOrClick,
+ MaxEventDuration(timestamps),
+ TotalEventDuration(timestamps));
+ }
+ ResetPendingPointers();
+}
+
+void ResponsivenessMetrics::ResetPendingPointers() {
+ is_drag_ = false;
+ pending_pointer_down_timestamps_.reset();
+ pending_pointer_up_timestamps_.reset();
+}
+
+// For multi-finger touch, we record the innermost pair of pointerdown and
+// pointerup.
+// TODO(hbsong): Record one interaction per pointer id.
+void ResponsivenessMetrics::RecordTapOrClickOrDrag(
+ LocalDOMWindow* window,
+ const AtomicString& event_type,
+ EventTimestamps event_timestamps) {
+ if (event_type == event_type_names::kPointercancel) {
+ pending_pointer_down_timestamps_.reset();
+ } else if (event_type == event_type_names::kPointerdown) {
+ FlushPendingInteraction(window);
+ pending_pointer_down_timestamps_ = event_timestamps;
+ } else if (event_type == event_type_names::kPointerup &&
+ pending_pointer_down_timestamps_.has_value() &&
+ !pending_pointer_up_timestamps_.has_value()) {
+ pending_pointer_up_timestamps_ = event_timestamps;
+ } else if (event_type == event_type_names::kClick) {
+ WTF::Vector<EventTimestamps> timestamps;
+ // Insertion order matters for latency computation.
+ if (pending_pointer_down_timestamps_.has_value()) {
+ timestamps.push_back(pending_pointer_down_timestamps_.value());
+ }
+ if (pending_pointer_up_timestamps_.has_value()) {
+ timestamps.push_back(pending_pointer_up_timestamps_.value());
+ }
+ timestamps.push_back(event_timestamps);
+ RecordUserInteractionUKM(window,
+ is_drag_ ? UserInteractionType::kDrag
+ : UserInteractionType::kTapOrClick,
+ MaxEventDuration(timestamps),
+ TotalEventDuration(timestamps));
+ ResetPendingPointers();
+ }
+}
+
+void ResponsivenessMetrics::RecordKeyboardInteractions(
+ LocalDOMWindow* window,
+ const AtomicString& event_type,
+ int key_code,
+ EventTimestamps event_timestamps) {
+ if (event_type == event_type_names::kKeydown) {
+ if (key_down_timestamps_map_.find(key_code) !=
+ key_down_timestamps_map_.end()) {
+ // Found a previous key_down with the same keycode, which means a key is
+ // being held down. We regard the duration of the keydown as an
+ // interaction level latency.
+ EventTimestamps key_down_timestamps =
+ key_down_timestamps_map_.at(key_code);
+ base::TimeDelta event_duration =
+ key_down_timestamps.end_time - key_down_timestamps.start_time;
+ RecordUserInteractionUKM(window, UserInteractionType::kKeyboard,
+ event_duration, event_duration);
+ }
+ key_down_timestamps_map_[key_code] = event_timestamps;
+ } else if (event_type == event_type_names::kKeyup) {
+ if (key_down_timestamps_map_.find(key_code) !=
+ key_down_timestamps_map_.end()) {
+ // Found a previous key_down with the same keycode as keyup.
+ // We calculate the interaction latency based on the durations of keydown
+ // and keyup.
+ EventTimestamps key_down_timestamps =
+ key_down_timestamps_map_.at(key_code);
+ WTF::Vector<EventTimestamps> timestamps;
+ // Insertion order matters for latency computation.
+ timestamps.push_back(key_down_timestamps);
+ timestamps.push_back(event_timestamps);
+ RecordUserInteractionUKM(window, UserInteractionType::kKeyboard,
+ MaxEventDuration(timestamps),
+ TotalEventDuration(timestamps));
+ // Remove the stale keydown.
+ key_down_timestamps_map_.erase(key_code);
+ } else {
+ // Can't find a corresponding keydown. We regard the duration of the keyup
+ // as an interaction latency.
+ base::TimeDelta event_duration =
+ event_timestamps.end_time - event_timestamps.start_time;
+ RecordUserInteractionUKM(window, UserInteractionType::kKeyboard,
+ event_duration, event_duration);
+ }
+ }
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/timing/responsiveness_metrics.h b/chromium/third_party/blink/renderer/core/timing/responsiveness_metrics.h
new file mode 100644
index 00000000000..0f18ada4f98
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/timing/responsiveness_metrics.h
@@ -0,0 +1,84 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_TIMING_RESPONSIVENESS_METRICS_H_
+#define THIRD_PARTY_BLINK_RENDERER_CORE_TIMING_RESPONSIVENESS_METRICS_H_
+
+#include <unordered_map>
+
+#include "third_party/blink/renderer/core/events/pointer_event.h"
+#include "third_party/blink/renderer/core/frame/local_dom_window.h"
+
+namespace blink {
+
+// Enum class for user interaction types. It's used in UKM and should not be
+// changed.
+enum class UserInteractionType { kKeyboard = 0, kTapOrClick = 1, kDrag = 2 };
+
+class ResponsivenessMetrics {
+ public:
+ ResponsivenessMetrics();
+ ~ResponsivenessMetrics();
+
+ // Timestamps for input events.
+ struct EventTimestamps {
+ // The event creation time.
+ base::TimeTicks start_time;
+ // The time when the first display update caused by the input event was
+ // performed.
+ base::TimeTicks end_time;
+ };
+
+ // Track ongoing user interactions and calculate the latency when an
+ // interaction is completed. The latency data for each interaction will be
+ // recored in UKM.
+ void RecordPerInteractionLatency(LocalDOMWindow* window,
+ const AtomicString& event_type,
+ absl::optional<int> key_code,
+ absl::optional<PointerId> pointer_id,
+ EventTimestamps event_timestamps);
+
+ // Stop UKM sampling for testing.
+ void StopUkmSamplingForTesting() { sampling_ = false; }
+
+ // The use might be dragging. The function will be called whenever we have a
+ // pointermove.
+ void NotifyPotentialDrag();
+
+ private:
+ // Record UKM for user interaction latencies.
+ void RecordUserInteractionUKM(LocalDOMWindow* window,
+ UserInteractionType interaction_type,
+ base::TimeDelta max_event_duration,
+ base::TimeDelta total_devent_duration);
+
+ void RecordKeyboardInteractions(LocalDOMWindow* window,
+ const AtomicString& event_type,
+ int key_code,
+ EventTimestamps event_timestamps);
+
+ // Might not be accurate for multi-fingers touch.
+ void RecordTapOrClickOrDrag(LocalDOMWindow* window,
+ const AtomicString& event_type,
+ EventTimestamps event_timestamps);
+ // Flush the latency data for pending tap or drag.
+ void FlushPendingInteraction(LocalDOMWindow* window);
+
+ // Reset the latency data for pointer events.
+ void ResetPendingPointers();
+
+ // Variables for per-interaction latencies.
+ std::unordered_map<int, EventTimestamps> key_down_timestamps_map_;
+
+ absl::optional<EventTimestamps> pending_pointer_up_timestamps_;
+ absl::optional<EventTimestamps> pending_pointer_down_timestamps_;
+ bool is_drag_ = false;
+
+ // Whether to perform UKM sampling.
+ bool sampling_ = true;
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_CORE_TIMING_RESPONSIVENESS_METRICS_H_
diff --git a/chromium/third_party/blink/renderer/core/timing/time_clamper.h b/chromium/third_party/blink/renderer/core/timing/time_clamper.h
index 7504ab11664..05908af8f07 100644
--- a/chromium/third_party/blink/renderer/core/timing/time_clamper.h
+++ b/chromium/third_party/blink/renderer/core/timing/time_clamper.h
@@ -5,7 +5,7 @@
#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_TIMING_TIME_CLAMPER_H_
#define THIRD_PARTY_BLINK_RENDERER_CORE_TIMING_TIME_CLAMPER_H_
-#include "base/macros.h"
+#include "base/time/time.h"
#include "build/build_config.h"
#include "third_party/blink/renderer/core/core_export.h"
#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
@@ -22,6 +22,8 @@ class CORE_EXPORT TimeClamper {
static constexpr int kFineResolutionMicroseconds = 5;
TimeClamper();
+ TimeClamper(const TimeClamper&) = delete;
+ TimeClamper& operator=(const TimeClamper&) = delete;
// Deterministically clamp the time value |time_microseconds| to a fixed
// interval to prevent timing attacks. See
@@ -41,8 +43,6 @@ class CORE_EXPORT TimeClamper {
static inline uint64_t MurmurHash3(uint64_t value);
uint64_t secret_;
-
- DISALLOW_COPY_AND_ASSIGN(TimeClamper);
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/timing/window_performance.cc b/chromium/third_party/blink/renderer/core/timing/window_performance.cc
index eddf6d27a08..4c1a84ecf36 100644
--- a/chromium/third_party/blink/renderer/core/timing/window_performance.cc
+++ b/chromium/third_party/blink/renderer/core/timing/window_performance.cc
@@ -41,6 +41,8 @@
#include "third_party/blink/renderer/bindings/core/v8/v8_object_builder.h"
#include "third_party/blink/renderer/core/dom/document.h"
#include "third_party/blink/renderer/core/dom/qualified_name.h"
+#include "third_party/blink/renderer/core/events/keyboard_event.h"
+#include "third_party/blink/renderer/core/events/pointer_event.h"
#include "third_party/blink/renderer/core/frame/local_dom_window.h"
#include "third_party/blink/renderer/core/frame/local_frame.h"
#include "third_party/blink/renderer/core/html/html_frame_owner_element.h"
@@ -56,6 +58,7 @@
#include "third_party/blink/renderer/core/timing/performance_event_timing.h"
#include "third_party/blink/renderer/core/timing/performance_observer.h"
#include "third_party/blink/renderer/core/timing/performance_timing.h"
+#include "third_party/blink/renderer/core/timing/responsiveness_metrics.h"
#include "third_party/blink/renderer/core/timing/visibility_state_entry.h"
#include "third_party/blink/renderer/platform/heap/persistent.h"
#include "third_party/blink/renderer/platform/instrumentation/use_counter.h"
@@ -94,6 +97,8 @@ AtomicString GetFrameOwnerType(HTMLFrameOwnerElement* frame_owner) {
return "frame";
case mojom::blink::FrameOwnerElementType::kPortal:
return "portal";
+ case mojom::blink::FrameOwnerElementType::kFencedframe:
+ return "fencedframe";
}
NOTREACHED();
return "";
@@ -169,6 +174,10 @@ WindowPerformance::WindowPerformance(LocalDOMWindow* window)
}
}
+void WindowPerformance::EventData::Trace(Visitor* visitor) const {
+ visitor->Trace(event_timing_);
+}
+
WindowPerformance::~WindowPerformance() = default;
ExecutionContext* WindowPerformance::GetExecutionContext() const {
@@ -237,11 +246,12 @@ void WindowPerformance::BuildJSONValue(V8ObjectBuilder& builder) const {
}
void WindowPerformance::Trace(Visitor* visitor) const {
- visitor->Trace(event_timings_);
+ visitor->Trace(events_data_);
visitor->Trace(first_pointer_down_event_timing_);
visitor->Trace(event_counts_);
visitor->Trace(navigation_);
visitor->Trace(timing_);
+ visitor->Trace(current_event_);
Performance::Trace(visitor);
PerformanceMonitor::Client::Trace(visitor);
ExecutionContextClient::Trace(visitor);
@@ -342,43 +352,35 @@ void WindowPerformance::ReportLongTask(base::TimeTicks start_time,
}
}
-void WindowPerformance::RegisterEventTiming(const AtomicString& event_type,
- base::TimeTicks start_time,
- base::TimeTicks processing_start,
- base::TimeTicks processing_end,
- bool cancelable,
- Node* target) {
+void WindowPerformance::RegisterEventTiming(
+ const AtomicString& event_type,
+ base::TimeTicks start_time,
+ base::TimeTicks processing_start,
+ base::TimeTicks processing_end,
+ bool cancelable,
+ Node* target,
+ absl::optional<int> key_code,
+ absl::optional<PointerId> pointer_id) {
// |start_time| could be null in some tests that inject input.
DCHECK(!processing_start.is_null());
DCHECK(!processing_end.is_null());
DCHECK_GE(processing_end, processing_start);
if (!DomWindow())
return;
-
- // Count non-pointerevent Events. Avoid double counting pointerevents
- // because we count them in pointer_event_manager.cc. Note click, auxclick and
- // contextmenu are PointerEvent but the dispatch process of them are different
- // from other PointerEvent.
- if (event_type != event_type_names::kPointerover &&
- event_type != event_type_names::kPointerenter &&
- event_type != event_type_names::kPointerdown &&
- event_type != event_type_names::kPointerup &&
- event_type != event_type_names::kPointercancel &&
- event_type != event_type_names::kPointerout &&
- event_type != event_type_names::kPointerleave &&
- event_type != event_type_names::kGotpointercapture &&
- event_type != event_type_names::kLostpointercapture) {
- eventCounts()->Add(event_type);
+ if (event_type == event_type_names::kPointermove) {
+ NotifyPotentialDrag();
+ SetCurrentEventTimingEvent(nullptr);
+ return;
}
-
+ eventCounts()->Add(event_type);
PerformanceEventTiming* entry = PerformanceEventTiming::Create(
event_type, MonotonicTimeToDOMHighResTimeStamp(start_time),
MonotonicTimeToDOMHighResTimeStamp(processing_start),
MonotonicTimeToDOMHighResTimeStamp(processing_end), cancelable, target);
// Add |entry| to the end of the queue along with the frame index at which is
// is being queued to know when to queue a presentation promise for it.
- event_timings_.push_back(entry);
- event_frames_.push_back(frame_index_);
+ events_data_.push_back(
+ EventData::Create(entry, frame_index_, start_time, key_code, pointer_id));
bool should_queue_presentation_promise = false;
// If there are no pending presentation promises, we should queue one. This
// ensures that |event_timings_| are processed even if the Blink lifecycle
@@ -400,37 +402,43 @@ void WindowPerformance::RegisterEventTiming(const AtomicString& event_type,
last_registered_frame_index_ = frame_index_;
++pending_presentation_promise_count_;
}
+ SetCurrentEventTimingEvent(nullptr);
}
-void WindowPerformance::ReportEventTimings(uint64_t frame_index,
- WebSwapResult result,
- base::TimeTicks timestamp) {
+void WindowPerformance::ReportEventTimings(
+ uint64_t frame_index,
+ WebSwapResult result,
+ base::TimeTicks presentation_timestamp) {
DCHECK(pending_presentation_promise_count_);
--pending_presentation_promise_count_;
- // |event_timings_| and |event_frames_| should always have the same size.
- DCHECK(event_timings_.size() == event_frames_.size());
- if (event_timings_.IsEmpty())
+ if (events_data_.IsEmpty())
return;
if (!DomWindow())
return;
InteractiveDetector* interactive_detector =
InteractiveDetector::From(*(DomWindow()->document()));
- bool event_timing_enabled =
- RuntimeEnabledFeatures::EventTimingEnabled(GetExecutionContext());
- DOMHighResTimeStamp end_time = MonotonicTimeToDOMHighResTimeStamp(timestamp);
- while (!event_timings_.IsEmpty()) {
- PerformanceEventTiming* entry = event_timings_.front();
- uint64_t entry_frame_index = event_frames_.front();
+ DOMHighResTimeStamp end_time =
+ MonotonicTimeToDOMHighResTimeStamp(presentation_timestamp);
+ while (!events_data_.IsEmpty()) {
+ auto event_data = events_data_.front();
+ PerformanceEventTiming* entry = event_data->GetEventTiming();
+ uint64_t entry_frame_index = event_data->GetFrameIndex();
+ base::TimeTicks event_timestamp = event_data->GetEventTimestamp();
+ absl::optional<int> key_code = event_data->GetKeyCode();
+ absl::optional<PointerId> pointer_id = event_data->GetPointerId();
// If the entry was queued at a frame index that is larger than
// |frame_index|, then we've reached the end of the entries that we can
// process during this callback.
if (entry_frame_index > frame_index)
break;
- event_timings_.pop_front();
- event_frames_.pop_front();
+ events_data_.pop_front();
+ ResponsivenessMetrics::EventTimestamps event_timestamps = {
+ event_timestamp, presentation_timestamp};
+ responsiveness_metrics_.RecordPerInteractionLatency(
+ DomWindow(), entry->name(), key_code, pointer_id, event_timestamps);
int duration_in_ms = std::round((end_time - entry->startTime()) / 8) * 8;
base::TimeDelta input_delay = base::TimeDelta::FromMillisecondsD(
entry->processingStart() - entry->startTime());
@@ -473,8 +481,6 @@ void WindowPerformance::ReportEventTimings(uint64_t frame_index,
PerformanceEventTiming::CreateFirstInputTiming(entry));
}
}
- if (!event_timing_enabled)
- continue;
if (HasObserverFor(PerformanceEntry::kEvent)) {
UseCounter::Count(GetExecutionContext(),
@@ -555,7 +561,6 @@ void WindowPerformance::PageVisibilityChanged() {
}
EventCounts* WindowPerformance::eventCounts() {
- DCHECK(RuntimeEnabledFeatures::EventTimingEnabled(GetExecutionContext()));
if (!event_counts_)
event_counts_ = MakeGarbageCollected<EventCounts>();
return event_counts_;
@@ -584,4 +589,8 @@ void WindowPerformance::OnPaintFinished() {
++frame_index_;
}
+void WindowPerformance::NotifyPotentialDrag() {
+ responsiveness_metrics_.NotifyPotentialDrag();
+}
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/timing/window_performance.h b/chromium/third_party/blink/renderer/core/timing/window_performance.h
index 44bac04a32c..93d1f69191d 100644
--- a/chromium/third_party/blink/renderer/core/timing/window_performance.h
+++ b/chromium/third_party/blink/renderer/core/timing/window_performance.h
@@ -35,14 +35,17 @@
#include "base/rand_util.h"
#include "third_party/blink/public/web/web_swap_result.h"
#include "third_party/blink/renderer/core/core_export.h"
+#include "third_party/blink/renderer/core/events/pointer_event.h"
#include "third_party/blink/renderer/core/execution_context/execution_context_lifecycle_observer.h"
#include "third_party/blink/renderer/core/frame/performance_monitor.h"
#include "third_party/blink/renderer/core/page/page_visibility_observer.h"
#include "third_party/blink/renderer/core/timing/event_counts.h"
+#include "third_party/blink/renderer/core/timing/event_timing.h"
#include "third_party/blink/renderer/core/timing/memory_info.h"
#include "third_party/blink/renderer/core/timing/performance.h"
#include "third_party/blink/renderer/core/timing/performance_navigation.h"
#include "third_party/blink/renderer/core/timing/performance_timing.h"
+#include "third_party/blink/renderer/core/timing/responsiveness_metrics.h"
#include "third_party/blink/renderer/platform/heap/heap_allocator.h"
namespace blink {
@@ -55,6 +58,52 @@ class CORE_EXPORT WindowPerformance final : public Performance,
public PageVisibilityObserver {
friend class WindowPerformanceTest;
+ class EventData : public GarbageCollected<EventData> {
+ public:
+ EventData(PerformanceEventTiming* event_timing,
+ uint64_t frame,
+ base::TimeTicks event_timestamp,
+ absl::optional<int> key_code,
+ absl::optional<PointerId> pointer_id)
+ : event_timing_(event_timing),
+ frame_(frame),
+ event_timestamp_(event_timestamp),
+ key_code_(key_code),
+ pointer_id_(pointer_id) {}
+
+ static EventData* Create(PerformanceEventTiming* event_timing,
+ uint64_t frame,
+ base::TimeTicks event_timestamp,
+ absl::optional<int> key_code,
+ absl::optional<PointerId> pointer_id) {
+ return MakeGarbageCollected<EventData>(
+ event_timing, frame, event_timestamp, key_code, pointer_id);
+ }
+ ~EventData() = default;
+ void Trace(Visitor*) const;
+ PerformanceEventTiming* GetEventTiming() { return event_timing_; }
+ uint64_t GetFrameIndex() { return frame_; }
+ base::TimeTicks GetEventTimestamp() { return event_timestamp_; }
+ absl::optional<int> GetKeyCode() { return key_code_; }
+ absl::optional<PointerId> GetPointerId() { return pointer_id_; }
+
+ private:
+ // Event PerformanceEventTiming entry that has not been sent to observers
+ // yet: the event dispatch has been completed but the presentation promise
+ // used to determine |duration| has not yet been resolved.
+ Member<PerformanceEventTiming> event_timing_;
+ // Frame index in which the entry in |event_timing_| were added.
+ uint64_t frame_;
+ // The event creation timestamp.
+ base::TimeTicks event_timestamp_;
+ // Keycode for the event. If the event is not a keyboard event, the keycode
+ // wouldn't be set.
+ absl::optional<int> key_code_;
+ // PointerId for the event. If the event is not a pointer event, the
+ // PointerId wouldn't be set.
+ absl::optional<PointerId> pointer_id_;
+ };
+
public:
explicit WindowPerformance(LocalDOMWindow*);
~WindowPerformance() override;
@@ -78,7 +127,9 @@ class CORE_EXPORT WindowPerformance final : public Performance,
base::TimeTicks processing_start,
base::TimeTicks processing_end,
bool cancelable,
- Node*);
+ Node*,
+ absl::optional<int> key_code,
+ absl::optional<PointerId> pointer_id);
void OnPaintFinished();
@@ -107,6 +158,17 @@ class CORE_EXPORT WindowPerformance final : public Performance,
void Trace(Visitor*) const override;
+ ResponsivenessMetrics& GetResponsivenessMetrics() {
+ return responsiveness_metrics_;
+ }
+
+ void NotifyPotentialDrag();
+
+ void SetCurrentEventTimingEvent(const Event* event) {
+ current_event_ = event;
+ }
+ const Event* GetCurrentEventTimingEvent() { return current_event_; }
+
private:
PerformanceNavigationTiming* CreateNavigationTimingInstance() override;
@@ -123,11 +185,12 @@ class CORE_EXPORT WindowPerformance final : public Performance,
void BuildJSONValue(V8ObjectBuilder&) const override;
- // Method called once presentation promise is resolved. It will add all event
- // timings that have not been added since the last presentation promise.
+ // Method called once presentation promise for a frame is resolved. It will
+ // add all event timings that have not been added since the last presentation
+ // promise.
void ReportEventTimings(uint64_t frame_index,
WebSwapResult result,
- base::TimeTicks timestamp);
+ base::TimeTicks presentation_timestamp);
void DispatchFirstInputTiming(PerformanceEventTiming* entry);
@@ -138,19 +201,10 @@ class CORE_EXPORT WindowPerformance final : public Performance,
uint64_t last_registered_frame_index_ = 0;
// Number of pending presentation promises.
uint16_t pending_presentation_promise_count_ = 0;
- // PerformanceEventTiming entries that have not been sent to observers yet:
- // the event dispatch has been completed but the presentation promise used to
- // determine |duration| has not yet been resolved. It is handled as a queue:
- // FIFO.
- HeapDeque<Member<PerformanceEventTiming>> event_timings_;
- // Entries corresponding to frame indices in which the entries in
- // |event_timings_| were added. This could be combined with |event_timings_|
- // into a single deque, but PerformanceEventTiming is GarbageCollected so it
- // would need to be a HeapDeque. HeapDeque does not allow std::pair as its
- // type, so we would have to add a new wrapper GarbageCollected class that
- // contains the PerformanceEventTiming object as well as the frame index. This
- // is more work than having two separate deques.
- Deque<uint64_t> event_frames_;
+ // Store all event timing and latency related data, including
+ // PerformanceEventTiming, frame_index, keycode and pointerId. We use the data
+ // to calculate events latencies.
+ HeapDeque<Member<EventData>> events_data_;
Member<PerformanceEventTiming> first_pointer_down_event_timing_;
Member<EventCounts> event_counts_;
mutable Member<PerformanceNavigation> navigation_;
@@ -158,6 +212,11 @@ class CORE_EXPORT WindowPerformance final : public Performance,
absl::optional<base::TimeDelta> pending_pointer_down_input_delay_;
absl::optional<base::TimeDelta> pending_pointer_down_processing_time_;
absl::optional<base::TimeDelta> pending_pointer_down_time_to_next_paint_;
+
+ // Calculate responsiveness metrics and record UKM for them.
+ ResponsivenessMetrics responsiveness_metrics_;
+ // The event we are currently processing.
+ WeakMember<const Event> current_event_;
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/timing/window_performance.idl b/chromium/third_party/blink/renderer/core/timing/window_performance.idl
index b55f5b40642..efebb32ca90 100644
--- a/chromium/third_party/blink/renderer/core/timing/window_performance.idl
+++ b/chromium/third_party/blink/renderer/core/timing/window_performance.idl
@@ -9,5 +9,5 @@
[
ImplementedAs=DOMWindowPerformance
] partial interface Window {
- [Affects=Nothing, Replaceable] readonly attribute Performance performance;
+ [Replaceable] readonly attribute Performance performance;
};
diff --git a/chromium/third_party/blink/renderer/core/timing/window_performance_test.cc b/chromium/third_party/blink/renderer/core/timing/window_performance_test.cc
index 62ca695d3b7..37336dd18f1 100644
--- a/chromium/third_party/blink/renderer/core/timing/window_performance_test.cc
+++ b/chromium/third_party/blink/renderer/core/timing/window_performance_test.cc
@@ -5,8 +5,8 @@
#include "third_party/blink/renderer/core/timing/window_performance.h"
#include "base/test/test_mock_time_task_runner.h"
+#include "services/metrics/public/cpp/ukm_builders.h"
#include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/blink/renderer/bindings/core/v8/string_or_double.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_core.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_testing.h"
#include "third_party/blink/renderer/core/dom/document_init.h"
@@ -18,18 +18,25 @@
#include "third_party/blink/renderer/core/loader/document_loader.h"
#include "third_party/blink/renderer/core/testing/dummy_page_holder.h"
#include "third_party/blink/renderer/core/testing/mock_policy_container_host.h"
+#include "third_party/blink/renderer/core/testing/scoped_fake_ukm_recorder.h"
#include "third_party/blink/renderer/core/timing/dom_window_performance.h"
#include "third_party/blink/renderer/platform/bindings/exception_state.h"
-#include "third_party/blink/renderer/platform/testing/runtime_enabled_features_test_helpers.h"
+#include "third_party/blink/renderer/platform/testing/unit_test_helpers.h"
namespace blink {
+using test::RunPendingTasks;
+
namespace {
base::TimeTicks GetTimeOrigin() {
return base::TimeTicks() + base::TimeDelta::FromSeconds(500);
}
+base::TimeTicks GetTimeStamp(int64_t time) {
+ return GetTimeOrigin() + base::TimeDelta::FromMilliseconds(time);
+}
+
} // namespace
class WindowPerformanceTest : public testing::Test {
@@ -90,16 +97,23 @@ class WindowPerformanceTest : public testing::Test {
performance_->SetClocksForTesting(test_task_runner_->GetMockClock(),
test_task_runner_->GetMockTickClock());
performance_->time_origin_ = GetTimeOrigin();
+ // Stop UKM sampling for testing.
+ performance_->GetResponsivenessMetrics().StopUkmSamplingForTesting();
}
ScriptState* GetScriptState() const {
return ToScriptStateForMainWorld(page_holder_->GetDocument().GetFrame());
}
+ ukm::TestUkmRecorder* GetUkmRecorder() {
+ return scoped_fake_ukm_recorder_.recorder();
+ }
+
uint64_t frame_counter = 1;
Persistent<WindowPerformance> performance_;
std::unique_ptr<DummyPageHolder> page_holder_;
scoped_refptr<base::TestMockTimeTaskRunner> test_task_runner_;
+ ScopedFakeUkmRecorder scoped_fake_ukm_recorder_;
};
TEST_F(WindowPerformanceTest, LongTaskObserverInstrumentation) {
@@ -237,7 +251,6 @@ TEST_F(WindowPerformanceTest, EnsureEntryListOrder) {
}
TEST_F(WindowPerformanceTest, EventTimingEntryBuffering) {
- ScopedEventTimingForTest event_timing(true);
EXPECT_TRUE(page_holder_->GetFrame().Loader().GetDocumentLoader());
base::TimeTicks start_time =
@@ -247,7 +260,7 @@ TEST_F(WindowPerformanceTest, EventTimingEntryBuffering) {
base::TimeTicks processing_end =
GetTimeOrigin() + base::TimeDelta::FromSecondsD(3.8);
performance_->RegisterEventTiming("click", start_time, processing_start,
- processing_end, false, nullptr);
+ processing_end, false, nullptr, 4, 4);
base::TimeTicks swap_time =
GetTimeOrigin() + base::TimeDelta::FromSecondsD(6.0);
SimulateSwapPromise(swap_time);
@@ -259,7 +272,7 @@ TEST_F(WindowPerformanceTest, EventTimingEntryBuffering) {
->GetTiming()
.MarkLoadEventStart();
performance_->RegisterEventTiming("click", start_time, processing_start,
- processing_end, true, nullptr);
+ processing_end, true, nullptr, 4, 4);
SimulateSwapPromise(swap_time);
EXPECT_EQ(2u, performance_->getBufferedEntriesByType("event").size());
@@ -267,13 +280,12 @@ TEST_F(WindowPerformanceTest, EventTimingEntryBuffering) {
GetFrame()->DetachDocument();
EXPECT_FALSE(page_holder_->GetFrame().Loader().GetDocumentLoader());
performance_->RegisterEventTiming("click", start_time, processing_start,
- processing_end, false, nullptr);
+ processing_end, false, nullptr, 4, 4);
SimulateSwapPromise(swap_time);
EXPECT_EQ(3u, performance_->getBufferedEntriesByType("event").size());
}
TEST_F(WindowPerformanceTest, Expose100MsEvents) {
- ScopedEventTimingForTest event_timing(true);
base::TimeTicks start_time =
GetTimeOrigin() + base::TimeDelta::FromSeconds(1);
base::TimeTicks processing_start =
@@ -281,12 +293,12 @@ TEST_F(WindowPerformanceTest, Expose100MsEvents) {
base::TimeTicks processing_end =
processing_start + base::TimeDelta::FromMilliseconds(10);
performance_->RegisterEventTiming("mousedown", start_time, processing_start,
- processing_end, false, nullptr);
+ processing_end, false, nullptr, 4, 4);
base::TimeTicks start_time2 =
start_time + base::TimeDelta::FromMicroseconds(200);
performance_->RegisterEventTiming("click", start_time2, processing_start,
- processing_end, false, nullptr);
+ processing_end, false, nullptr, 4, 4);
// The swap time is 100.1 ms after |start_time| but only 99.9 ms after
// |start_time2|.
@@ -300,8 +312,6 @@ TEST_F(WindowPerformanceTest, Expose100MsEvents) {
}
TEST_F(WindowPerformanceTest, EventTimingDuration) {
- ScopedEventTimingForTest event_timing(true);
-
base::TimeTicks start_time =
GetTimeOrigin() + base::TimeDelta::FromMilliseconds(1000);
base::TimeTicks processing_start =
@@ -309,24 +319,24 @@ TEST_F(WindowPerformanceTest, EventTimingDuration) {
base::TimeTicks processing_end =
GetTimeOrigin() + base::TimeDelta::FromMilliseconds(1002);
performance_->RegisterEventTiming("click", start_time, processing_start,
- processing_end, false, nullptr);
+ processing_end, false, nullptr, 4, 4);
base::TimeTicks short_swap_time =
GetTimeOrigin() + base::TimeDelta::FromMilliseconds(1003);
SimulateSwapPromise(short_swap_time);
EXPECT_EQ(0u, performance_->getBufferedEntriesByType("event").size());
performance_->RegisterEventTiming("click", start_time, processing_start,
- processing_end, true, nullptr);
+ processing_end, true, nullptr, 4, 4);
base::TimeTicks long_swap_time =
GetTimeOrigin() + base::TimeDelta::FromMilliseconds(2000);
SimulateSwapPromise(long_swap_time);
EXPECT_EQ(1u, performance_->getBufferedEntriesByType("event").size());
performance_->RegisterEventTiming("click", start_time, processing_start,
- processing_end, true, nullptr);
+ processing_end, true, nullptr, 4, 4);
SimulateSwapPromise(short_swap_time);
performance_->RegisterEventTiming("click", start_time, processing_start,
- processing_end, false, nullptr);
+ processing_end, false, nullptr, 4, 4);
SimulateSwapPromise(long_swap_time);
EXPECT_EQ(2u, performance_->getBufferedEntriesByType("event").size());
}
@@ -334,8 +344,6 @@ TEST_F(WindowPerformanceTest, EventTimingDuration) {
// Test the case where multiple events are registered and then their swap
// promise is resolved.
TEST_F(WindowPerformanceTest, MultipleEventsThenSwap) {
- ScopedEventTimingForTest event_timing(true);
-
size_t num_events = 10;
for (size_t i = 0; i < num_events; ++i) {
base::TimeTicks start_time =
@@ -345,7 +353,7 @@ TEST_F(WindowPerformanceTest, MultipleEventsThenSwap) {
base::TimeTicks processing_end =
start_time + base::TimeDelta::FromMilliseconds(200);
performance_->RegisterEventTiming("click", start_time, processing_start,
- processing_end, false, nullptr);
+ processing_end, false, nullptr, 4, 4);
EXPECT_EQ(0u, performance_->getBufferedEntriesByType("event").size());
}
base::TimeTicks swap_time =
@@ -367,7 +375,8 @@ TEST_F(WindowPerformanceTest, FirstInput) {
performance_->RegisterEventTiming(
input.event_type, GetTimeOrigin(),
GetTimeOrigin() + base::TimeDelta::FromMilliseconds(1),
- GetTimeOrigin() + base::TimeDelta::FromMilliseconds(2), false, nullptr);
+ GetTimeOrigin() + base::TimeDelta::FromMilliseconds(2), false, nullptr,
+ 4, 4);
SimulateSwapPromise(GetTimeOrigin() + base::TimeDelta::FromMilliseconds(3));
PerformanceEntryVector firstInputs =
performance_->getEntriesByType("first-input");
@@ -385,7 +394,8 @@ TEST_F(WindowPerformanceTest, FirstInputAfterIgnored) {
performance_->RegisterEventTiming(
event, GetTimeOrigin(),
GetTimeOrigin() + base::TimeDelta::FromMilliseconds(1),
- GetTimeOrigin() + base::TimeDelta::FromMilliseconds(2), false, nullptr);
+ GetTimeOrigin() + base::TimeDelta::FromMilliseconds(2), false, nullptr,
+ 4, 4);
SimulateSwapPromise(GetTimeOrigin() + base::TimeDelta::FromMilliseconds(3));
}
ASSERT_EQ(1u, performance_->getEntriesByType("first-input").size());
@@ -395,19 +405,16 @@ TEST_F(WindowPerformanceTest, FirstInputAfterIgnored) {
// Test that pointerdown followed by pointerup works as a 'firstInput'.
TEST_F(WindowPerformanceTest, FirstPointerUp) {
- base::TimeTicks start_time = GetTimeOrigin();
- base::TimeTicks processing_start =
- GetTimeOrigin() + base::TimeDelta::FromMilliseconds(1);
- base::TimeTicks processing_end =
- GetTimeOrigin() + base::TimeDelta::FromMilliseconds(2);
- base::TimeTicks swap_time =
- GetTimeOrigin() + base::TimeDelta::FromMilliseconds(3);
+ base::TimeTicks start_time = GetTimeStamp(0);
+ base::TimeTicks processing_start = GetTimeStamp(1);
+ base::TimeTicks processing_end = GetTimeStamp(2);
+ base::TimeTicks swap_time = GetTimeStamp(3);
performance_->RegisterEventTiming("pointerdown", start_time, processing_start,
- processing_end, false, nullptr);
+ processing_end, false, nullptr, 4, 4);
SimulateSwapPromise(swap_time);
EXPECT_EQ(0u, performance_->getEntriesByType("first-input").size());
performance_->RegisterEventTiming("pointerup", start_time, processing_start,
- processing_end, false, nullptr);
+ processing_end, false, nullptr, 4, 4);
SimulateSwapPromise(swap_time);
EXPECT_EQ(1u, performance_->getEntriesByType("first-input").size());
// The name of the entry should be "pointerdown".
@@ -415,4 +422,446 @@ TEST_F(WindowPerformanceTest, FirstPointerUp) {
1u, performance_->getEntriesByName("pointerdown", "first-input").size());
}
+TEST_F(WindowPerformanceTest, OneKeyboardInteraction) {
+ base::TimeTicks keydown_timestamp = GetTimeStamp(0);
+ // Keydown
+ base::TimeTicks processing_start_keydown = GetTimeStamp(1);
+ base::TimeTicks processing_end_keydown = GetTimeStamp(2);
+ base::TimeTicks swap_time_keydown = GetTimeStamp(5);
+ absl::optional<PointerId> pointer_id = absl::nullopt;
+ absl::optional<int> key_code = 2;
+ performance_->RegisterEventTiming(
+ "keydown", keydown_timestamp, processing_start_keydown,
+ processing_end_keydown, false, nullptr, key_code, pointer_id);
+ SimulateSwapPromise(swap_time_keydown);
+ // Keyup
+ base::TimeTicks keyup_timestamp = GetTimeStamp(3);
+ base::TimeTicks processing_start_keyup = GetTimeStamp(5);
+ base::TimeTicks processing_end_keyup = GetTimeStamp(6);
+ base::TimeTicks swap_time_keyup = GetTimeStamp(10);
+ performance_->RegisterEventTiming(
+ "keyup", keyup_timestamp, processing_start_keyup, processing_end_keyup,
+ false, nullptr, key_code, pointer_id);
+ SimulateSwapPromise(swap_time_keyup);
+
+ // Flush UKM logging mojo request.
+ RunPendingTasks();
+
+ // Check UKM recording.
+ auto merged_entries = GetUkmRecorder()->GetMergedEntriesByName(
+ ukm::builders::Responsiveness_UserInteraction::kEntryName);
+ EXPECT_EQ(1u, merged_entries.size());
+ for (const auto& kv : merged_entries) {
+ const ukm::mojom::UkmEntry* ukm_entry = kv.second.get();
+ GetUkmRecorder()->ExpectEntryMetric(
+ ukm_entry,
+ ukm::builders::Responsiveness_UserInteraction::kMaxEventDurationName,
+ 7);
+ GetUkmRecorder()->ExpectEntryMetric(
+ ukm_entry,
+ ukm::builders::Responsiveness_UserInteraction::kTotalEventDurationName,
+ 10);
+ GetUkmRecorder()->ExpectEntryMetric(
+ ukm_entry,
+ ukm::builders::Responsiveness_UserInteraction::kInteractionTypeName, 0);
+ }
+}
+
+TEST_F(WindowPerformanceTest, HoldingDownAKey) {
+ auto entries = GetUkmRecorder()->GetEntriesByName(
+ ukm::builders::Responsiveness_UserInteraction::kEntryName);
+ EXPECT_EQ(0u, entries.size());
+ base::TimeTicks keydown_timestamp = GetTimeOrigin();
+ base::TimeTicks processing_start_keydown = GetTimeStamp(1);
+ base::TimeTicks processing_end_keydown = GetTimeStamp(2);
+ base::TimeTicks swap_time_keydown = GetTimeStamp(5);
+ absl::optional<PointerId> pointer_id = absl::nullopt;
+ absl::optional<int> key_code = 2;
+ performance_->RegisterEventTiming(
+ "keydown", keydown_timestamp, processing_start_keydown,
+ processing_end_keydown, false, nullptr, key_code, pointer_id);
+ SimulateSwapPromise(swap_time_keydown);
+
+ // Second Keydown
+ keydown_timestamp = GetTimeStamp(1);
+ processing_start_keydown = GetTimeStamp(2);
+ processing_end_keydown = GetTimeStamp(3);
+ swap_time_keydown = GetTimeStamp(7);
+ performance_->RegisterEventTiming(
+ "keydown", keydown_timestamp, processing_start_keydown,
+ processing_end_keydown, false, nullptr, key_code, pointer_id);
+ SimulateSwapPromise(swap_time_keydown);
+
+ // Third Keydown
+ keydown_timestamp = GetTimeStamp(2);
+ processing_start_keydown = GetTimeStamp(3);
+ processing_end_keydown = GetTimeStamp(5);
+ swap_time_keydown = GetTimeStamp(9);
+ performance_->RegisterEventTiming(
+ "keydown", keydown_timestamp, processing_start_keydown,
+ processing_end_keydown, false, nullptr, key_code, pointer_id);
+ SimulateSwapPromise(swap_time_keydown);
+
+ // Keyup
+ base::TimeTicks keyup_timestamp = GetTimeStamp(3);
+ base::TimeTicks processing_start_keyup = GetTimeStamp(5);
+ base::TimeTicks processing_end_keyup = GetTimeStamp(6);
+ base::TimeTicks swap_time_keyup = GetTimeStamp(13);
+ performance_->RegisterEventTiming(
+ "keyup", keyup_timestamp, processing_start_keyup, processing_end_keyup,
+ false, nullptr, key_code, pointer_id);
+ SimulateSwapPromise(swap_time_keyup);
+
+ // Flush UKM logging mojo request.
+ RunPendingTasks();
+
+ // Check UKM recording.
+ entries = GetUkmRecorder()->GetEntriesByName(
+ ukm::builders::Responsiveness_UserInteraction::kEntryName);
+ EXPECT_EQ(3u, entries.size());
+ std::vector<std::pair<int, int>> expected_durations;
+ expected_durations.emplace_back(std::make_pair(5, 5));
+ expected_durations.emplace_back(std::make_pair(6, 6));
+ expected_durations.emplace_back(std::make_pair(10, 11));
+ for (std::size_t i = 0; i < entries.size(); ++i) {
+ auto* entry = entries[i];
+ GetUkmRecorder()->ExpectEntryMetric(
+ entry,
+ ukm::builders::Responsiveness_UserInteraction::kMaxEventDurationName,
+ expected_durations[i].first);
+ GetUkmRecorder()->ExpectEntryMetric(
+ entry,
+ ukm::builders::Responsiveness_UserInteraction::kTotalEventDurationName,
+ expected_durations[i].second);
+ GetUkmRecorder()->ExpectEntryMetric(
+ entry,
+ ukm::builders::Responsiveness_UserInteraction::kInteractionTypeName, 0);
+ }
+}
+
+TEST_F(WindowPerformanceTest, PressMultipleKeys) {
+ auto entries = GetUkmRecorder()->GetEntriesByName(
+ ukm::builders::Responsiveness_UserInteraction::kEntryName);
+ EXPECT_EQ(0u, entries.size());
+ // Press the first key.
+ base::TimeTicks keydown_timestamp = GetTimeOrigin();
+ base::TimeTicks processing_start_keydown = GetTimeStamp(1);
+ base::TimeTicks processing_end_keydown = GetTimeStamp(2);
+ base::TimeTicks swap_time_keydown = GetTimeStamp(5);
+ absl::optional<PointerId> pointer_id = absl::nullopt;
+ absl::optional<int> first_key_code = 2;
+ performance_->RegisterEventTiming(
+ "keydown", keydown_timestamp, processing_start_keydown,
+ processing_end_keydown, false, nullptr, first_key_code, pointer_id);
+ SimulateSwapPromise(swap_time_keydown);
+
+ // Press the second key.
+ processing_start_keydown = GetTimeStamp(2);
+ processing_end_keydown = GetTimeStamp(3);
+ swap_time_keydown = GetTimeStamp(7);
+ absl::optional<int> second_key_code = 4;
+ performance_->RegisterEventTiming(
+ "keydown", keydown_timestamp, processing_start_keydown,
+ processing_end_keydown, false, nullptr, second_key_code, pointer_id);
+ SimulateSwapPromise(swap_time_keydown);
+
+ // Release the first key.
+ base::TimeTicks keyup_timestamp = GetTimeStamp(3);
+ base::TimeTicks processing_start_keyup = GetTimeStamp(5);
+ base::TimeTicks processing_end_keyup = GetTimeStamp(6);
+ base::TimeTicks swap_time_keyup = GetTimeStamp(13);
+ performance_->RegisterEventTiming(
+ "keyup", keyup_timestamp, processing_start_keyup, processing_end_keyup,
+ false, nullptr, first_key_code, pointer_id);
+ SimulateSwapPromise(swap_time_keyup);
+
+ // Release the second key.
+ keyup_timestamp = GetTimeStamp(5);
+ processing_start_keyup = GetTimeStamp(5);
+ processing_end_keyup = GetTimeStamp(6);
+ swap_time_keyup = GetTimeStamp(20);
+ performance_->RegisterEventTiming(
+ "keyup", keyup_timestamp, processing_start_keyup, processing_end_keyup,
+ false, nullptr, second_key_code, pointer_id);
+ SimulateSwapPromise(swap_time_keyup);
+
+ // Flush UKM logging mojo request.
+ RunPendingTasks();
+
+ // Check UKM recording.
+ entries = GetUkmRecorder()->GetEntriesByName(
+ ukm::builders::Responsiveness_UserInteraction::kEntryName);
+ EXPECT_EQ(2u, entries.size());
+ std::vector<std::pair<int, int>> expected_durations;
+ expected_durations.emplace_back(std::make_pair(10, 13));
+ expected_durations.emplace_back(std::make_pair(15, 20));
+ for (std::size_t i = 0; i < entries.size(); ++i) {
+ auto* entry = entries[i];
+ GetUkmRecorder()->ExpectEntryMetric(
+ entry,
+ ukm::builders::Responsiveness_UserInteraction::kMaxEventDurationName,
+ expected_durations[i].first);
+ GetUkmRecorder()->ExpectEntryMetric(
+ entry,
+ ukm::builders::Responsiveness_UserInteraction::kTotalEventDurationName,
+ expected_durations[i].second);
+ GetUkmRecorder()->ExpectEntryMetric(
+ entry,
+ ukm::builders::Responsiveness_UserInteraction::kInteractionTypeName, 0);
+ }
+}
+
+TEST_F(WindowPerformanceTest, TapOrClick) {
+ // Pointerdown
+ base::TimeTicks pointerdwon_timestamp = GetTimeOrigin();
+ base::TimeTicks processing_start_pointerdown = GetTimeStamp(1);
+ base::TimeTicks processing_end_pointerdown = GetTimeStamp(2);
+ base::TimeTicks swap_time_pointerdown = GetTimeStamp(5);
+ absl::optional<PointerId> pointer_id = 4;
+ absl::optional<int> key_code = absl::nullopt;
+ performance_->RegisterEventTiming(
+ "pointerdown", pointerdwon_timestamp, processing_start_pointerdown,
+ processing_end_pointerdown, false, nullptr, key_code, pointer_id);
+ SimulateSwapPromise(swap_time_pointerdown);
+ // Pointerup
+ base::TimeTicks pointerup_timestamp = GetTimeStamp(3);
+ base::TimeTicks processing_start_pointerup = GetTimeStamp(5);
+ base::TimeTicks processing_end_pointerup = GetTimeStamp(6);
+ base::TimeTicks swap_time_pointerup = GetTimeStamp(10);
+ performance_->RegisterEventTiming(
+ "pointerup", pointerup_timestamp, processing_start_pointerup,
+ processing_end_pointerup, false, nullptr, key_code, pointer_id);
+ SimulateSwapPromise(swap_time_pointerup);
+ // Click
+ base::TimeTicks click_timestamp = GetTimeStamp(13);
+ base::TimeTicks processing_start_click = GetTimeStamp(15);
+ base::TimeTicks processing_end_click = GetTimeStamp(16);
+ base::TimeTicks swap_time_click = GetTimeStamp(20);
+ performance_->RegisterEventTiming(
+ "click", click_timestamp, processing_start_click, processing_end_click,
+ false, nullptr, key_code, pointer_id);
+ SimulateSwapPromise(swap_time_click);
+
+ // Flush UKM logging mojo request.
+ RunPendingTasks();
+
+ // Check UKM recording.
+ std::map<ukm::SourceId, ukm::mojom::UkmEntryPtr> merged_entries =
+ GetUkmRecorder()->GetMergedEntriesByName(
+ ukm::builders::Responsiveness_UserInteraction::kEntryName);
+ EXPECT_EQ(1u, merged_entries.size());
+ for (const auto& kv : merged_entries) {
+ const ukm::mojom::UkmEntry* ukm_entry = kv.second.get();
+ GetUkmRecorder()->ExpectEntryMetric(
+ ukm_entry,
+ ukm::builders::Responsiveness_UserInteraction::kMaxEventDurationName,
+ 7);
+ GetUkmRecorder()->ExpectEntryMetric(
+ ukm_entry,
+ ukm::builders::Responsiveness_UserInteraction::kTotalEventDurationName,
+ 17);
+ GetUkmRecorder()->ExpectEntryMetric(
+ ukm_entry,
+ ukm::builders::Responsiveness_UserInteraction::kInteractionTypeName, 1);
+ }
+}
+
+TEST_F(WindowPerformanceTest, Drag) {
+ // Pointerdown
+ base::TimeTicks pointerdwon_timestamp = GetTimeOrigin();
+ base::TimeTicks processing_start_pointerdown = GetTimeStamp(1);
+ base::TimeTicks processing_end_pointerdown = GetTimeStamp(2);
+ base::TimeTicks swap_time_pointerdown = GetTimeStamp(5);
+ absl::optional<PointerId> pointer_id = 4;
+ absl::optional<int> key_code = absl::nullopt;
+ performance_->RegisterEventTiming(
+ "pointerdown", pointerdwon_timestamp, processing_start_pointerdown,
+ processing_end_pointerdown, false, nullptr, key_code, pointer_id);
+ SimulateSwapPromise(swap_time_pointerdown);
+ // Notify drag.
+ performance_->NotifyPotentialDrag();
+ // Pointerup
+ base::TimeTicks pointerup_timestamp = GetTimeStamp(3);
+ base::TimeTicks processing_start_pointerup = GetTimeStamp(5);
+ base::TimeTicks processing_end_pointerup = GetTimeStamp(6);
+ base::TimeTicks swap_time_pointerup = GetTimeStamp(10);
+ performance_->RegisterEventTiming(
+ "pointerup", pointerup_timestamp, processing_start_pointerup,
+ processing_end_pointerup, false, nullptr, key_code, pointer_id);
+ SimulateSwapPromise(swap_time_pointerup);
+ // Click
+ base::TimeTicks click_timestamp = GetTimeStamp(13);
+ base::TimeTicks processing_start_click = GetTimeStamp(15);
+ base::TimeTicks processing_end_click = GetTimeStamp(16);
+ base::TimeTicks swap_time_click = GetTimeStamp(20);
+ performance_->RegisterEventTiming(
+ "click", click_timestamp, processing_start_click, processing_end_click,
+ false, nullptr, key_code, pointer_id);
+ SimulateSwapPromise(swap_time_click);
+
+ // Flush UKM logging mojo request.
+ RunPendingTasks();
+
+ // Check UKM recording.
+ std::map<ukm::SourceId, ukm::mojom::UkmEntryPtr> merged_entries =
+ GetUkmRecorder()->GetMergedEntriesByName(
+ ukm::builders::Responsiveness_UserInteraction::kEntryName);
+ EXPECT_EQ(1u, merged_entries.size());
+ for (const auto& kv : merged_entries) {
+ const ukm::mojom::UkmEntry* ukm_entry = kv.second.get();
+ GetUkmRecorder()->ExpectEntryMetric(
+ ukm_entry,
+ ukm::builders::Responsiveness_UserInteraction::kMaxEventDurationName,
+ 7);
+ GetUkmRecorder()->ExpectEntryMetric(
+ ukm_entry,
+ ukm::builders::Responsiveness_UserInteraction::kTotalEventDurationName,
+ 17);
+ GetUkmRecorder()->ExpectEntryMetric(
+ ukm_entry,
+ ukm::builders::Responsiveness_UserInteraction::kInteractionTypeName, 2);
+ }
+}
+
+TEST_F(WindowPerformanceTest, Scroll) {
+ // Pointerdown
+ base::TimeTicks pointerdown_timestamp = GetTimeOrigin();
+ base::TimeTicks processing_start_keydown = GetTimeStamp(1);
+ base::TimeTicks processing_end_keydown = GetTimeStamp(2);
+ base::TimeTicks swap_time_keydown = GetTimeStamp(5);
+ absl::optional<PointerId> pointer_id = 5;
+ absl::optional<int> key_code = absl::nullopt;
+ performance_->RegisterEventTiming(
+ "pointerdown", pointerdown_timestamp, processing_start_keydown,
+ processing_end_keydown, false, nullptr, key_code, pointer_id);
+ SimulateSwapPromise(swap_time_keydown);
+ // Pointercancel
+ base::TimeTicks pointerup_timestamp = GetTimeStamp(3);
+ base::TimeTicks processing_start_keyup = GetTimeStamp(5);
+ base::TimeTicks processing_end_keyup = GetTimeStamp(6);
+ base::TimeTicks swap_time_keyup = GetTimeStamp(10);
+ performance_->RegisterEventTiming(
+ "pointercancel", pointerup_timestamp, processing_start_keyup,
+ processing_end_keyup, false, nullptr, key_code, pointer_id);
+ SimulateSwapPromise(swap_time_keyup);
+
+ // Flush UKM logging mojo request.
+ RunPendingTasks();
+
+ // Check UKM recording.
+ std::map<ukm::SourceId, ukm::mojom::UkmEntryPtr> merged_entries =
+ GetUkmRecorder()->GetMergedEntriesByName(
+ ukm::builders::Responsiveness_UserInteraction::kEntryName);
+ EXPECT_EQ(0u, merged_entries.size());
+}
+
+TEST_F(WindowPerformanceTest, TouchesWithoutClick) {
+ base::TimeTicks pointerdown_timestamp = GetTimeOrigin();
+ // First Pointerdown
+ base::TimeTicks processing_start_pointerdown = GetTimeStamp(1);
+ base::TimeTicks processing_end_pointerdown = GetTimeStamp(2);
+ base::TimeTicks swap_time_pointerdown = GetTimeStamp(5);
+ absl::optional<PointerId> pointer_id = 4;
+ absl::optional<int> key_code = absl::nullopt;
+ performance_->RegisterEventTiming(
+ "pointerdown", pointerdown_timestamp, processing_start_pointerdown,
+ processing_end_pointerdown, false, nullptr, key_code, pointer_id);
+ SimulateSwapPromise(swap_time_pointerdown);
+
+ // Second Pointerdown
+ pointerdown_timestamp = GetTimeStamp(6);
+ processing_start_pointerdown = GetTimeStamp(7);
+ processing_end_pointerdown = GetTimeStamp(8);
+ swap_time_pointerdown = GetTimeStamp(15);
+ performance_->RegisterEventTiming(
+ "pointerdown", pointerdown_timestamp, processing_start_pointerdown,
+ processing_end_pointerdown, false, nullptr, key_code, pointer_id);
+ SimulateSwapPromise(swap_time_pointerdown);
+
+ // Flush UKM logging mojo request.
+ RunPendingTasks();
+
+ // Check UKM recording.
+ std::map<ukm::SourceId, ukm::mojom::UkmEntryPtr> merged_entries =
+ GetUkmRecorder()->GetMergedEntriesByName(
+ ukm::builders::Responsiveness_UserInteraction::kEntryName);
+ EXPECT_EQ(0u, merged_entries.size());
+}
+
+// For multi-touch, we only record the innermost pair of pointerdown and
+// pointerup.
+// TODO(hbsong): Record each touch by pointer_id separately.
+TEST_F(WindowPerformanceTest, MultiTouch) {
+ // First Pointerdown
+ base::TimeTicks pointerdown_timestamp = GetTimeOrigin();
+ base::TimeTicks processing_start_pointerdown = GetTimeStamp(1);
+ base::TimeTicks processing_end_pointerdown = GetTimeStamp(2);
+ base::TimeTicks swap_time_pointerdown = GetTimeStamp(5);
+ absl::optional<PointerId> pointer_id_1 = 4;
+ absl::optional<int> key_code = absl::nullopt;
+ performance_->RegisterEventTiming(
+ "pointerdown", pointerdown_timestamp, processing_start_pointerdown,
+ processing_end_pointerdown, false, nullptr, key_code, pointer_id_1);
+ SimulateSwapPromise(swap_time_pointerdown);
+ // Second Pointerdown
+ pointerdown_timestamp = GetTimeOrigin();
+ processing_start_pointerdown = GetTimeStamp(1);
+ processing_end_pointerdown = GetTimeStamp(2);
+ swap_time_pointerdown = GetTimeStamp(6);
+ absl::optional<PointerId> pointer_id_2 = 6;
+ performance_->RegisterEventTiming(
+ "pointerdown", pointerdown_timestamp, processing_start_pointerdown,
+ processing_end_pointerdown, false, nullptr, key_code, pointer_id_2);
+ SimulateSwapPromise(swap_time_pointerdown);
+
+ // First Pointerup
+ base::TimeTicks pointerup_timestamp = GetTimeStamp(3);
+ base::TimeTicks processing_start_pointerup = GetTimeStamp(5);
+ base::TimeTicks processing_end_pointerup = GetTimeStamp(6);
+ base::TimeTicks swap_time_pointerup = GetTimeStamp(9);
+ performance_->RegisterEventTiming(
+ "pointerup", pointerup_timestamp, processing_start_pointerup,
+ processing_end_pointerup, false, nullptr, key_code, pointer_id_2);
+ SimulateSwapPromise(swap_time_pointerup);
+
+ // Second Pointerup
+ pointerup_timestamp = GetTimeStamp(5);
+ processing_start_pointerup = GetTimeStamp(6);
+ processing_end_pointerup = GetTimeStamp(7);
+ swap_time_pointerup = GetTimeStamp(13);
+ performance_->RegisterEventTiming(
+ "pointerup", pointerup_timestamp, processing_start_pointerup,
+ processing_end_pointerup, false, nullptr, key_code, pointer_id_1);
+ SimulateSwapPromise(swap_time_pointerup);
+
+ // Click
+ base::TimeTicks click_timestamp = GetTimeStamp(13);
+ base::TimeTicks processing_start_click = GetTimeStamp(15);
+ base::TimeTicks processing_end_click = GetTimeStamp(16);
+ base::TimeTicks swap_time_click = GetTimeStamp(20);
+ performance_->RegisterEventTiming(
+ "click", click_timestamp, processing_start_click, processing_end_click,
+ false, nullptr, key_code, pointer_id_2);
+ SimulateSwapPromise(swap_time_click);
+
+ // Flush UKM logging mojo request.
+ RunPendingTasks();
+
+ // Check UKM recording.
+ auto entries = GetUkmRecorder()->GetEntriesByName(
+ ukm::builders::Responsiveness_UserInteraction::kEntryName);
+ EXPECT_EQ(1u, entries.size());
+ auto* entry = entries[0];
+ GetUkmRecorder()->ExpectEntryMetric(
+ entry,
+ ukm::builders::Responsiveness_UserInteraction::kMaxEventDurationName, 7);
+ GetUkmRecorder()->ExpectEntryMetric(
+ entry,
+ ukm::builders::Responsiveness_UserInteraction::kTotalEventDurationName,
+ 16);
+ GetUkmRecorder()->ExpectEntryMetric(
+ entry,
+ ukm::builders::Responsiveness_UserInteraction::kInteractionTypeName, 1);
+}
+
} // namespace blink