| Index: third_party/WebKit/Source/core/frame/PerformanceMonitor.cpp
|
| diff --git a/third_party/WebKit/Source/core/frame/PerformanceMonitor.cpp b/third_party/WebKit/Source/core/frame/PerformanceMonitor.cpp
|
| index 79c29beb4a2fbddbb550923788613bd85b9981c0..b4949cedf9d84b798ab425346c4a523a3b09e2b6 100644
|
| --- a/third_party/WebKit/Source/core/frame/PerformanceMonitor.cpp
|
| +++ b/third_party/WebKit/Source/core/frame/PerformanceMonitor.cpp
|
| @@ -5,63 +5,15 @@
|
| #include "core/frame/PerformanceMonitor.h"
|
|
|
| #include "bindings/core/v8/SourceLocation.h"
|
| -#include "core/InstrumentingAgents.h"
|
| #include "core/dom/Document.h"
|
| #include "core/dom/ExecutionContext.h"
|
| -#include "core/frame/DOMWindow.h"
|
| #include "core/frame/Frame.h"
|
| -#include "core/frame/FrameConsole.h"
|
| #include "core/frame/LocalFrame.h"
|
| -#include "core/frame/UseCounter.h"
|
| -#include "core/inspector/ConsoleMessage.h"
|
| -#include "core/timing/DOMWindowPerformance.h"
|
| -#include "core/timing/Performance.h"
|
| #include "public/platform/Platform.h"
|
| #include "wtf/CurrentTime.h"
|
|
|
| namespace blink {
|
|
|
| -namespace {
|
| -static const double kLongTaskThresholdMillis = 50.0;
|
| -static const double kLongTaskWarningThresholdMillis = 150.0;
|
| -
|
| -static const double kSyncLayoutThresholdMillis = 30.0;
|
| -static const double kSyncLayoutWarningThresholdMillis = 60.0;
|
| -
|
| -static const char kUnknownAttribution[] = "unknown";
|
| -static const char kAmbugiousAttribution[] = "multiple-contexts";
|
| -static const char kSameOriginAttribution[] = "same-origin";
|
| -static const char kAncestorAttribution[] = "cross-origin-ancestor";
|
| -static const char kDescendantAttribution[] = "cross-origin-descendant";
|
| -static const char kCrossOriginAttribution[] = "cross-origin-unreachable";
|
| -
|
| -bool canAccessOrigin(Frame* frame1, Frame* frame2) {
|
| - SecurityOrigin* securityOrigin1 =
|
| - frame1->securityContext()->getSecurityOrigin();
|
| - SecurityOrigin* securityOrigin2 =
|
| - frame2->securityContext()->getSecurityOrigin();
|
| - return securityOrigin1->canAccess(securityOrigin2);
|
| -}
|
| -
|
| -} // namespace
|
| -
|
| -// static
|
| -void PerformanceMonitor::performanceObserverAdded(Performance* performance) {
|
| - LocalFrame* frame = performance->frame();
|
| - PerformanceMonitor* monitor = frame->performanceMonitor();
|
| - monitor->m_webPerformanceObservers.add(performance);
|
| - monitor->updateInstrumentation();
|
| -}
|
| -
|
| -// static
|
| -void PerformanceMonitor::performanceObserverRemoved(Performance* performance) {
|
| - LocalFrame* frame = performance->frame();
|
| - DCHECK(frame);
|
| - PerformanceMonitor* monitor = frame->performanceMonitor();
|
| - monitor->m_webPerformanceObservers.remove(performance);
|
| - monitor->updateInstrumentation();
|
| -}
|
| -
|
| // static
|
| void PerformanceMonitor::willExecuteScript(ExecutionContext* context) {
|
| PerformanceMonitor* performanceMonitor =
|
| @@ -111,71 +63,105 @@ void PerformanceMonitor::didRecalculateStyle(Document* document) {
|
| }
|
|
|
| // static
|
| -bool PerformanceMonitor::enabled(ExecutionContext* context) {
|
| - return PerformanceMonitor::instrumentingMonitor(context);
|
| -}
|
| -
|
| -// static
|
| -void PerformanceMonitor::logViolation(MessageLevel level,
|
| - ExecutionContext* context,
|
| - const String& messageText) {
|
| - PerformanceMonitor* performanceMonitor =
|
| +double PerformanceMonitor::threshold(ExecutionContext* context,
|
| + Violation violation) {
|
| + PerformanceMonitor* monitor =
|
| PerformanceMonitor::instrumentingMonitor(context);
|
| - if (performanceMonitor)
|
| - performanceMonitor->logViolation(level, messageText);
|
| + return monitor ? monitor->m_thresholds[violation] : 0;
|
| }
|
|
|
| // static
|
| -void PerformanceMonitor::logViolation(
|
| - MessageLevel level,
|
| - ExecutionContext* context,
|
| - const String& messageText,
|
| - std::unique_ptr<SourceLocation> location) {
|
| - PerformanceMonitor* performanceMonitor =
|
| +void PerformanceMonitor::reportGenericViolation(ExecutionContext* context,
|
| + Violation violation,
|
| + const String& text,
|
| + double time,
|
| + SourceLocation* location) {
|
| + PerformanceMonitor* monitor =
|
| PerformanceMonitor::instrumentingMonitor(context);
|
| - if (performanceMonitor)
|
| - performanceMonitor->logViolation(level, messageText, std::move(location));
|
| + if (!monitor)
|
| + return;
|
| + ClientThresholds* clientThresholds = monitor->m_subscriptions.get(violation);
|
| + if (!clientThresholds)
|
| + return;
|
| + for (const auto& it : *clientThresholds) {
|
| + if (it.value < time)
|
| + it.key->reportGenericViolation(violation, text, time, location);
|
| + }
|
| }
|
|
|
| // static
|
| -PerformanceMonitor* PerformanceMonitor::instrumentingMonitor(
|
| - ExecutionContext* context) {
|
| +PerformanceMonitor* PerformanceMonitor::monitor(
|
| + const ExecutionContext* context) {
|
| if (!context->isDocument())
|
| return nullptr;
|
| LocalFrame* frame = toDocument(context)->frame();
|
| if (!frame)
|
| return nullptr;
|
| - PerformanceMonitor* monitor = frame->performanceMonitor();
|
| - return monitor->m_enabled ? monitor : nullptr;
|
| + return frame->performanceMonitor();
|
| +}
|
| +
|
| +// static
|
| +PerformanceMonitor* PerformanceMonitor::instrumentingMonitor(
|
| + const ExecutionContext* context) {
|
| + PerformanceMonitor* monitor = PerformanceMonitor::monitor(context);
|
| + return monitor && monitor->m_enabled ? monitor : nullptr;
|
| }
|
|
|
| PerformanceMonitor::PerformanceMonitor(LocalFrame* localRoot)
|
| - : m_localRoot(localRoot) {}
|
| + : m_localRoot(localRoot) {
|
| + std::fill(std::begin(m_thresholds), std::end(m_thresholds), 0);
|
| +}
|
|
|
| PerformanceMonitor::~PerformanceMonitor() {
|
| - m_webPerformanceObservers.clear();
|
| - m_loggingEnabled = false;
|
| + m_subscriptions.clear();
|
| + updateInstrumentation();
|
| +}
|
| +
|
| +void PerformanceMonitor::subscribe(Violation violation,
|
| + double threshold,
|
| + Client* client) {
|
| + DCHECK(violation < kAfterLast);
|
| + ClientThresholds* clientThresholds = m_subscriptions.get(violation);
|
| + if (!clientThresholds) {
|
| + clientThresholds = new ClientThresholds();
|
| + m_subscriptions.set(violation, clientThresholds);
|
| + }
|
| + clientThresholds->set(client, threshold);
|
| updateInstrumentation();
|
| }
|
|
|
| -void PerformanceMonitor::setLoggingEnabled(bool enabled) {
|
| - m_loggingEnabled = enabled;
|
| +void PerformanceMonitor::unsubscribeAll(Client* client) {
|
| + for (const auto& it : m_subscriptions)
|
| + it.value->remove(client);
|
| updateInstrumentation();
|
| }
|
|
|
| void PerformanceMonitor::updateInstrumentation() {
|
| - bool shouldEnable = m_loggingEnabled || m_webPerformanceObservers.size();
|
| - if (shouldEnable == m_enabled)
|
| - return;
|
| - if (shouldEnable) {
|
| - UseCounter::count(m_localRoot, UseCounter::LongTaskObserver);
|
| - Platform::current()->currentThread()->addTaskTimeObserver(this);
|
| - Platform::current()->currentThread()->addTaskObserver(this);
|
| - } else {
|
| - Platform::current()->currentThread()->removeTaskTimeObserver(this);
|
| - Platform::current()->currentThread()->removeTaskObserver(this);
|
| + bool longTaskObserverEnabled = !!m_thresholds[kLongTask];
|
| + std::fill(std::begin(m_thresholds), std::end(m_thresholds), 0);
|
| +
|
| + for (const auto& it : m_subscriptions) {
|
| + Violation violation = static_cast<Violation>(it.key);
|
| + ClientThresholds* clientThresholds = it.value;
|
| + for (const auto& clientThreshold : *clientThresholds) {
|
| + if (!m_thresholds[violation] ||
|
| + m_thresholds[violation] > clientThreshold.value)
|
| + m_thresholds[violation] = clientThreshold.value;
|
| + }
|
| + }
|
| +
|
| + if (!m_thresholds[kLongTask] != !longTaskObserverEnabled) {
|
| + if (m_thresholds[kLongTask]) {
|
| + Platform::current()->currentThread()->addTaskTimeObserver(this);
|
| + Platform::current()->currentThread()->addTaskObserver(this);
|
| + } else {
|
| + Platform::current()->currentThread()->removeTaskTimeObserver(this);
|
| + Platform::current()->currentThread()->removeTaskObserver(this);
|
| + }
|
| }
|
| - m_enabled = shouldEnable;
|
| +
|
| + m_enabled = std::count(std::begin(m_thresholds), std::end(m_thresholds), 0) <
|
| + static_cast<int>(kAfterLast);
|
| }
|
|
|
| void PerformanceMonitor::innerWillExecuteScript(ExecutionContext* context) {
|
| @@ -227,110 +213,36 @@ void PerformanceMonitor::willProcessTask() {
|
| }
|
|
|
| void PerformanceMonitor::didProcessTask() {
|
| - if (m_perTaskStyleAndLayoutTime * 1000 < kSyncLayoutThresholdMillis)
|
| + double threshold = m_thresholds[kLongLayout];
|
| + if (!threshold || m_perTaskStyleAndLayoutTime < threshold)
|
| return;
|
|
|
| - if (m_loggingEnabled) {
|
| - logViolation(
|
| - m_perTaskStyleAndLayoutTime * 1000 < kSyncLayoutWarningThresholdMillis
|
| - ? InfoMessageLevel
|
| - : WarningMessageLevel,
|
| - String::format("Forced reflow while executing JavaScript took %ldms.",
|
| - lround(m_perTaskStyleAndLayoutTime * 1000)));
|
| + ClientThresholds* clientThresholds = m_subscriptions.get(kLongLayout);
|
| + DCHECK(clientThresholds);
|
| + for (const auto& it : *clientThresholds) {
|
| + if (it.value < m_perTaskStyleAndLayoutTime)
|
| + it.key->reportLongLayout(m_perTaskStyleAndLayoutTime);
|
| }
|
| }
|
|
|
| void PerformanceMonitor::ReportTaskTime(scheduler::TaskQueue*,
|
| double startTime,
|
| double endTime) {
|
| - double taskTimeMs = (endTime - startTime) * 1000;
|
| - if (taskTimeMs < kLongTaskThresholdMillis)
|
| + double taskTime = endTime - startTime;
|
| + if (!m_thresholds[kLongTask] || taskTime < m_thresholds[kLongTask])
|
| return;
|
|
|
| - for (Performance* performance : m_webPerformanceObservers) {
|
| - if (!performance->frame())
|
| - continue;
|
| - std::pair<String, DOMWindow*> attribution =
|
| - sanitizedAttribution(m_frameContexts, performance->frame());
|
| - performance->addLongTaskTiming(startTime, endTime, attribution.first,
|
| - attribution.second);
|
| - }
|
| - if (m_loggingEnabled) {
|
| - logViolation(taskTimeMs < kLongTaskWarningThresholdMillis
|
| - ? InfoMessageLevel
|
| - : WarningMessageLevel,
|
| - String::format("Long running JavaScript task took %ldms.",
|
| - lround(taskTimeMs)));
|
| - }
|
| -}
|
| -
|
| -void PerformanceMonitor::logViolation(MessageLevel level,
|
| - const String& messageText) {
|
| - ConsoleMessage* message =
|
| - ConsoleMessage::create(ViolationMessageSource, level, messageText);
|
| - m_localRoot->console().addMessage(message);
|
| -}
|
| -
|
| -void PerformanceMonitor::logViolation(
|
| - MessageLevel level,
|
| - const String& messageText,
|
| - std::unique_ptr<SourceLocation> location) {
|
| - ConsoleMessage* message = ConsoleMessage::create(
|
| - ViolationMessageSource, level, messageText, std::move(location));
|
| - m_localRoot->console().addMessage(message);
|
| -}
|
| -
|
| -/**
|
| - * Report sanitized name based on cross-origin policy.
|
| - * See detailed Security doc here: http://bit.ly/2duD3F7
|
| - */
|
| -std::pair<String, DOMWindow*> PerformanceMonitor::sanitizedAttribution(
|
| - const HeapHashSet<Member<Frame>>& frames,
|
| - Frame* observerFrame) {
|
| - if (frames.size() == 0) {
|
| - // Unable to attribute as no script was involved.
|
| - return std::make_pair(kUnknownAttribution, nullptr);
|
| - }
|
| - if (frames.size() > 1) {
|
| - // Unable to attribute, multiple script execution contents were involved.
|
| - return std::make_pair(kAmbugiousAttribution, nullptr);
|
| - }
|
| - // Exactly one culprit location, attribute based on origin boundary.
|
| - DCHECK_EQ(1u, frames.size());
|
| - Frame* culpritFrame = *frames.begin();
|
| - DCHECK(culpritFrame);
|
| - if (canAccessOrigin(observerFrame, culpritFrame)) {
|
| - // From accessible frames or same origin, return culprit location URL.
|
| - return std::make_pair(kSameOriginAttribution, culpritFrame->domWindow());
|
| - }
|
| - // For cross-origin, if the culprit is the descendant or ancestor of
|
| - // observer then indicate the *closest* cross-origin frame between
|
| - // the observer and the culprit, in the corresponding direction.
|
| - if (culpritFrame->tree().isDescendantOf(observerFrame)) {
|
| - // If the culprit is a descendant of the observer, then walk up the tree
|
| - // from culprit to observer, and report the *last* cross-origin (from
|
| - // observer) frame. If no intermediate cross-origin frame is found, then
|
| - // report the culprit directly.
|
| - Frame* lastCrossOriginFrame = culpritFrame;
|
| - for (Frame* frame = culpritFrame; frame != observerFrame;
|
| - frame = frame->tree().parent()) {
|
| - if (!canAccessOrigin(observerFrame, frame)) {
|
| - lastCrossOriginFrame = frame;
|
| - }
|
| - }
|
| - return std::make_pair(kDescendantAttribution,
|
| - lastCrossOriginFrame->domWindow());
|
| - }
|
| - if (observerFrame->tree().isDescendantOf(culpritFrame)) {
|
| - return std::make_pair(kAncestorAttribution, nullptr);
|
| + ClientThresholds* clientThresholds = m_subscriptions.get(kLongTask);
|
| + for (const auto& it : *clientThresholds) {
|
| + if (it.value < taskTime)
|
| + it.key->reportLongTask(startTime, endTime, m_frameContexts);
|
| }
|
| - return std::make_pair(kCrossOriginAttribution, nullptr);
|
| }
|
|
|
| DEFINE_TRACE(PerformanceMonitor) {
|
| visitor->trace(m_localRoot);
|
| visitor->trace(m_frameContexts);
|
| - visitor->trace(m_webPerformanceObservers);
|
| + visitor->trace(m_subscriptions);
|
| }
|
|
|
| } // namespace blink
|
|
|