Chromium Code Reviews| 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..eec0537c927988d1288652f53545feba52df1328 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,116 @@ 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, |
| +void PerformanceMonitor::reportGenericViolation( |
| ExecutionContext* context, |
| - const String& messageText, |
| + Violation violation, |
| + const String& text, |
| + double time, |
| std::unique_ptr<SourceLocation> location) { |
| - PerformanceMonitor* performanceMonitor = |
| + 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, |
| + std::move(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 frame->performanceMonitor(); |
| +} |
| + |
| +// static |
| +PerformanceMonitor* PerformanceMonitor::instrumentingMonitor( |
| + const ExecutionContext* context) { |
| + PerformanceMonitor* monitor = PerformanceMonitor::monitor(context); |
| return monitor->m_enabled ? monitor : nullptr; |
| } |
| PerformanceMonitor::PerformanceMonitor(LocalFrame* localRoot) |
| - : m_localRoot(localRoot) {} |
| + : m_localRoot(localRoot) { |
| + for (size_t i = 0; i < kAfterLast; ++i) |
|
caseq
2016/11/09 00:41:11
std::fill(std::begin(m_thresholds), std::end(m_thr
pfeldman
2016/11/09 01:39:14
Done.
|
| + m_thresholds[i] = 0; |
| +} |
| PerformanceMonitor::~PerformanceMonitor() { |
| - m_webPerformanceObservers.clear(); |
| m_loggingEnabled = false; |
| updateInstrumentation(); |
| } |
| -void PerformanceMonitor::setLoggingEnabled(bool enabled) { |
| - m_loggingEnabled = enabled; |
| +void PerformanceMonitor::subscribe(Violation violation, |
| + double threshold, |
| + Client* client) { |
| + ClientThresholds* clientThresholds = m_subscriptions.get(violation); |
| + if (!clientThresholds) { |
| + clientThresholds = new ClientThresholds(); |
| + m_subscriptions.set(violation, clientThresholds); |
|
caseq
2016/11/09 00:41:11
DCHECK(violation < kAfterLast)?
pfeldman
2016/11/09 01:39:14
Done.
|
| + } |
| + (*clientThresholds).set(client, threshold); |
|
caseq
2016/11/09 00:41:11
clientThresholds->set(client, threshold)
pfeldman
2016/11/09 01:39:14
Done.
|
| + updateInstrumentation(); |
| +} |
| + |
| +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); |
| + double oldThresholds[kAfterLast]; |
|
caseq
2016/11/09 00:41:11
bool longTaskObserverEnabled = !!m_thresholds[kLon
pfeldman
2016/11/09 01:39:14
Done.
|
| + for (size_t i = 0; i < kAfterLast; ++i) { |
| + oldThresholds[i] = m_thresholds[i]; |
| + m_thresholds[i] = 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] != !oldThresholds[kLongTask]) { |
| + 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 = false; |
|
caseq
2016/11/09 00:41:11
m_enabled = std::count(std::begin(m_thresholds), s
pfeldman
2016/11/09 01:39:14
Done.
|
| + for (size_t i = 0; i < kAfterLast; ++i) { |
| + if (m_thresholds[i]) { |
| + m_enabled = true; |
| + break; |
| + } |
| } |
| - m_enabled = shouldEnable; |
| } |
| void PerformanceMonitor::innerWillExecuteScript(ExecutionContext* context) { |
| @@ -227,110 +224,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 |