Commit e9a081ab authored by kouhei@chromium.org's avatar kouhei@chromium.org

[Invalidation Tracking] Trace StyleInvalidator setNeedsStyleRecalc

This patch adds a set of trace events to track reason when
StyleInvalidator invokes Node::setNeedsStyleRecalc. One of the trace events is guaranteed to be issued before StyleInvalidator issues setNeedsStyleRecalc on the node. The trace events come with InspectorStyleInvalidatorInvalidateEvent, which contains inspector node id, human readable reason string, and optionally the tagName/id/class/attr/invalidationList involved.

This is to be used from devtools so we post process and find the StyleInvalidator trace event on the given node to see the detailed reason for why StyleInvalidator decided issue setNeedsStyleRecalc on the node.

BUG=410701

Committed: https://src.chromium.org/viewvc/blink?view=rev&revision=183177

Review URL: https://codereview.chromium.org/580373002

git-svn-id: svn://svn.chromium.org/blink/trunk@183643 bbb929c8-8fbe-4397-9dbb-9b2b20218538
parent bda3b72d
......@@ -33,9 +33,24 @@
#include "core/css/resolver/StyleResolver.h"
#include "core/dom/Element.h"
#include "core/inspector/InspectorTraceEvents.h"
#include "platform/TracedValue.h"
#include "wtf/Compiler.h"
#include "wtf/text/StringBuilder.h"
namespace blink {
static const unsigned char* s_tracingEnabled = nullptr;
#define TRACE_STYLE_INVALIDATOR_INVALIDATION_SELECTORPART_IF_ENABLED(element, reason, singleSelectorPart) \
if (UNLIKELY(*s_tracingEnabled)) \
TRACE_STYLE_INVALIDATOR_INVALIDATION_SELECTORPART(element, reason, singleSelectorPart);
void DescendantInvalidationSet::cacheTracingFlag()
{
s_tracingEnabled = TRACE_EVENT_API_GET_CATEGORY_ENABLED(TRACE_DISABLED_BY_DEFAULT("devtools.timeline.invalidationTracking"));
}
DescendantInvalidationSet::DescendantInvalidationSet()
: m_allDescendantsMightBeInvalid(false)
, m_customPseudoInvalid(false)
......@@ -48,24 +63,32 @@ bool DescendantInvalidationSet::invalidatesElement(Element& element) const
if (m_allDescendantsMightBeInvalid)
return true;
if (m_tagNames && m_tagNames->contains(element.tagQName().localName()))
if (m_tagNames && m_tagNames->contains(element.tagQName().localName())) {
TRACE_STYLE_INVALIDATOR_INVALIDATION_SELECTORPART_IF_ENABLED(element, InvalidationSetMatchedTagName, element.tagQName().localName());
return true;
}
if (element.hasID() && m_ids && m_ids->contains(element.idForStyleResolution()))
if (element.hasID() && m_ids && m_ids->contains(element.idForStyleResolution())) {
TRACE_STYLE_INVALIDATOR_INVALIDATION_SELECTORPART_IF_ENABLED(element, InvalidationSetMatchedId, element.idForStyleResolution());
return true;
}
if (element.hasClass() && m_classes) {
const SpaceSplitString& classNames = element.classNames();
for (const auto& className : *m_classes) {
if (classNames.contains(className))
if (classNames.contains(className)) {
TRACE_STYLE_INVALIDATOR_INVALIDATION_SELECTORPART_IF_ENABLED(element, InvalidationSetMatchedClass, className);
return true;
}
}
}
if (element.hasAttributes() && m_attributes) {
for (const auto& attribute : *m_attributes) {
if (element.hasAttribute(attribute))
if (element.hasAttribute(attribute)) {
TRACE_STYLE_INVALIDATOR_INVALIDATION_SELECTORPART_IF_ENABLED(element, InvalidationSetMatchedAttribute, attribute);
return true;
}
}
}
......@@ -189,33 +212,54 @@ void DescendantInvalidationSet::trace(Visitor* visitor)
#endif
}
#ifndef NDEBUG
void DescendantInvalidationSet::show() const
void DescendantInvalidationSet::toTracedValue(TracedValue* value) const
{
fprintf(stderr, "DescendantInvalidationSet { ");
value->beginDictionary();
if (m_allDescendantsMightBeInvalid)
fprintf(stderr, "* ");
value->setBoolean("allDescendantsMightBeInvalid", true);
if (m_customPseudoInvalid)
fprintf(stderr, "::custom ");
value->setBoolean("customPseudoInvalid", true);
if (m_treeBoundaryCrossing)
fprintf(stderr, "::shadow/deep/ ");
value->setBoolean("treeBoundaryCrossing", true);
if (m_ids) {
value->beginArray("ids");
for (const auto& id : *m_ids)
fprintf(stderr, "#%s ", id.ascii().data());
value->pushString(id);
value->endArray();
}
if (m_classes) {
value->beginArray("classes");
for (const auto& className : *m_classes)
fprintf(stderr, ".%s ", className.ascii().data());
value->pushString(className);
value->endArray();
}
if (m_tagNames) {
value->beginArray("tagNames");
for (const auto& tagName : *m_tagNames)
fprintf(stderr, "<%s> ", tagName.ascii().data());
value->pushString(tagName);
value->endArray();
}
if (m_attributes) {
value->beginArray("attributes");
for (const auto& attribute : *m_attributes)
fprintf(stderr, "[%s] ", attribute.ascii().data());
value->pushString(attribute);
value->endArray();
}
fprintf(stderr, "}\n");
value->endDictionary();
}
#ifndef NDEBUG
void DescendantInvalidationSet::show() const
{
RefPtr<TracedValue> value = TracedValue::create();
toTracedValue(value.get());
fprintf(stderr, "%s\n", value->asTraceFormat().ascii().data());
}
#endif // NDEBUG
......
......@@ -42,6 +42,7 @@
namespace blink {
class Element;
class TracedValue;
// Tracks data to determine which elements of a DOM subtree need to have style
// recalculated.
......@@ -52,6 +53,8 @@ public:
return adoptRefWillBeNoop(new DescendantInvalidationSet);
}
static void cacheTracingFlag();
bool invalidatesElement(Element&) const;
void combine(const DescendantInvalidationSet& other);
......@@ -74,6 +77,8 @@ public:
void trace(Visitor*);
void toTracedValue(TracedValue*) const;
#ifndef NDEBUG
void show() const;
#endif
......
......@@ -13,10 +13,17 @@
#include "core/dom/ElementTraversal.h"
#include "core/dom/shadow/ElementShadow.h"
#include "core/dom/shadow/ShadowRoot.h"
#include "core/inspector/InspectorTraceEvents.h"
#include "core/rendering/RenderObject.h"
namespace blink {
static const unsigned char* s_tracingEnabled = nullptr;
#define TRACE_STYLE_INVALIDATOR_INVALIDATION_IF_ENABLED(element, reason) \
if (UNLIKELY(*s_tracingEnabled)) \
TRACE_STYLE_INVALIDATOR_INVALIDATION(element, reason);
void StyleInvalidator::invalidate(Document& document)
{
RecursionData recursionData;
......@@ -63,6 +70,8 @@ void StyleInvalidator::clearPendingInvalidations()
StyleInvalidator::StyleInvalidator()
{
s_tracingEnabled = TRACE_EVENT_API_GET_CATEGORY_ENABLED(TRACE_DISABLED_BY_DEFAULT("devtools.timeline.invalidationTracking"));
DescendantInvalidationSet::cacheTracingFlag();
}
StyleInvalidator::~StyleInvalidator()
......@@ -82,12 +91,14 @@ void StyleInvalidator::RecursionData::pushInvalidationSet(const DescendantInvali
m_invalidateCustomPseudo = invalidationSet.customPseudoInvalid();
}
bool StyleInvalidator::RecursionData::matchesCurrentInvalidationSets(Element& element)
ALWAYS_INLINE bool StyleInvalidator::RecursionData::matchesCurrentInvalidationSets(Element& element)
{
ASSERT(!m_wholeSubtreeInvalid);
if (m_invalidateCustomPseudo && element.shadowPseudoId() != nullAtom)
if (m_invalidateCustomPseudo && element.shadowPseudoId() != nullAtom) {
TRACE_STYLE_INVALIDATOR_INVALIDATION_IF_ENABLED(element, InvalidateCustomPseudo);
return true;
}
for (const auto& invalidationSet : m_invalidationSets) {
if (invalidationSet->invalidatesElement(element))
......@@ -97,7 +108,7 @@ bool StyleInvalidator::RecursionData::matchesCurrentInvalidationSets(Element& el
return false;
}
bool StyleInvalidator::checkInvalidationSetsAgainstElement(Element& element, StyleInvalidator::RecursionData& recursionData)
ALWAYS_INLINE bool StyleInvalidator::checkInvalidationSetsAgainstElement(Element& element, StyleInvalidator::RecursionData& recursionData)
{
if (element.styleChangeType() >= SubtreeStyleChange || recursionData.wholeSubtreeInvalid()) {
recursionData.setWholeSubtreeInvalid();
......@@ -108,9 +119,15 @@ bool StyleInvalidator::checkInvalidationSetsAgainstElement(Element& element, Sty
for (const auto& invalidationSet : *invalidationList)
recursionData.pushInvalidationSet(*invalidationSet);
// FIXME: It's really only necessary to clone the render style for this element, not full style recalc.
if (UNLIKELY(*s_tracingEnabled)) {
TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline.invalidationTracking"),
"StyleInvalidatorInvalidationTracking",
"data", InspectorStyleInvalidatorInvalidateEvent::invalidationList(element, *invalidationList));
}
return true;
}
}
return recursionData.matchesCurrentInvalidationSets(element);
}
......@@ -148,10 +165,12 @@ bool StyleInvalidator::invalidate(Element& element, StyleInvalidator::RecursionD
element.setNeedsStyleRecalc(recursionData.wholeSubtreeInvalid() ? SubtreeStyleChange : LocalStyleChange, StyleChangeReasonForTracing::create(StyleChangeReason::StyleInvalidator));
} else if (recursionData.hasInvalidationSets() && someChildrenNeedStyleRecalc) {
// Clone the RenderStyle in order to preserve correct style sharing, if possible. Otherwise recalc style.
if (RenderObject* renderer = element.renderer())
if (RenderObject* renderer = element.renderer()) {
renderer->setStyleInternal(RenderStyle::clone(renderer->style()));
else
} else {
TRACE_STYLE_INVALIDATOR_INVALIDATION_IF_ENABLED(element, PreventStyleSharingForParent);
element.setNeedsStyleRecalc(LocalStyleChange, StyleChangeReasonForTracing::create(StyleChangeReason::StyleInvalidator));
}
}
element.clearChildNeedsStyleInvalidation();
......
......@@ -8,6 +8,7 @@
#include "bindings/core/v8/ScriptCallStackFactory.h"
#include "bindings/core/v8/ScriptGCEvent.h"
#include "bindings/core/v8/ScriptSourceCode.h"
#include "core/css/invalidation/DescendantInvalidationSet.h"
#include "core/dom/StyleChangeReason.h"
#include "core/events/Event.h"
#include "core/frame/FrameView.h"
......@@ -66,6 +67,45 @@ void setNodeInfo(TracedValue* value, Node* node, const char* idFieldName, const
}
const char InspectorStyleInvalidatorInvalidateEvent::ElementHasPendingInvalidationList[] = "Element has pending invalidation list";
const char InspectorStyleInvalidatorInvalidateEvent::InvalidateCustomPseudo[] = "Invalidate custom pseudo element.";
const char InspectorStyleInvalidatorInvalidateEvent::InvalidationSetMatchedAttribute[] = "Invalidation set matched attribute.";
const char InspectorStyleInvalidatorInvalidateEvent::InvalidationSetMatchedClass[] = "Invalidation set matched class.";
const char InspectorStyleInvalidatorInvalidateEvent::InvalidationSetMatchedId[] = "Invalidation set matched id.";
const char InspectorStyleInvalidatorInvalidateEvent::InvalidationSetMatchedTagName[] = "Invalidation set matched tagName.";
const char InspectorStyleInvalidatorInvalidateEvent::PreventStyleSharingForParent[] = "Prevent style sharing for parent.";
PassRefPtr<TracedValue> InspectorStyleInvalidatorInvalidateEvent::fillCommonPart(Element& element, const char* reason)
{
RefPtr<TracedValue> value = TracedValue::create();
value->setString("frame", toHexString(element.document().frame()));
setNodeInfo(value.get(), &element, "nodeId", "nodeName");
value->setString("reason", reason);
return value.release();
}
PassRefPtr<TraceEvent::ConvertableToTraceFormat> InspectorStyleInvalidatorInvalidateEvent::data(Element& element, const char* reason)
{
return fillCommonPart(element, reason);
}
PassRefPtr<TraceEvent::ConvertableToTraceFormat> InspectorStyleInvalidatorInvalidateEvent::selectorPart(Element& element, const char* reason, const String& selectorPart)
{
RefPtr<TracedValue> value = fillCommonPart(element, reason);
value->setString("selectorPart", selectorPart);
return value.release();
}
PassRefPtr<TraceEvent::ConvertableToTraceFormat> InspectorStyleInvalidatorInvalidateEvent::invalidationList(Element& element, const WillBeHeapVector<RefPtrWillBeMember<DescendantInvalidationSet> >& invalidationList)
{
RefPtr<TracedValue> value = fillCommonPart(element, ElementHasPendingInvalidationList);
value->beginArray("invalidationList");
for (const auto& invalidationSet : invalidationList)
invalidationSet->toTracedValue(value.get());
value->endArray();
return value.release();
}
PassRefPtr<TraceEvent::ConvertableToTraceFormat> InspectorStyleRecalcInvalidationTrackingEvent::data(Node* node, const StyleChangeReasonForTracing& reason)
{
ASSERT(node);
......
......@@ -7,11 +7,15 @@
#include "platform/EventTracer.h"
#include "platform/TraceEvent.h"
#include "platform/heap/Handle.h"
#include "wtf/Forward.h"
#include "wtf/Functional.h"
namespace blink {
class DescendantInvalidationSet;
class Document;
class Element;
class Event;
class ExecutionContext;
class FrameView;
......@@ -29,6 +33,7 @@ class ResourceResponse;
class ScriptCallStack;
class ScriptSourceCode;
class StyleChangeReasonForTracing;
class TracedValue;
class WorkerThread;
class XMLHttpRequest;
......@@ -43,6 +48,38 @@ public:
static PassRefPtr<TraceEvent::ConvertableToTraceFormat> data(Node*, const StyleChangeReasonForTracing&);
};
class InspectorStyleInvalidatorInvalidateEvent {
public:
static const char ElementHasPendingInvalidationList[];
static const char InvalidateCustomPseudo[];
static const char InvalidationSetMatchedAttribute[];
static const char InvalidationSetMatchedClass[];
static const char InvalidationSetMatchedId[];
static const char InvalidationSetMatchedTagName[];
static const char PreventStyleSharingForParent[];
static PassRefPtr<TraceEvent::ConvertableToTraceFormat> data(Element&, const char* reason);
static PassRefPtr<TraceEvent::ConvertableToTraceFormat> selectorPart(Element&, const char* reason, const String&);
static PassRefPtr<TraceEvent::ConvertableToTraceFormat> invalidationList(Element&, const WillBeHeapVector<RefPtrWillBeMember<DescendantInvalidationSet> >&);
private:
static PassRefPtr<TracedValue> fillCommonPart(Element&, const char* reason);
};
#define TRACE_STYLE_INVALIDATOR_INVALIDATION(element, reason) \
TRACE_EVENT_INSTANT1( \
TRACE_DISABLED_BY_DEFAULT("devtools.timeline.invalidationTracking"), \
"StyleInvalidatorInvalidationTracking", \
"data", \
InspectorStyleInvalidatorInvalidateEvent::data((element), (InspectorStyleInvalidatorInvalidateEvent::reason)))
#define TRACE_STYLE_INVALIDATOR_INVALIDATION_SELECTORPART(element, reason, singleSelectorPart) \
TRACE_EVENT_INSTANT1( \
TRACE_DISABLED_BY_DEFAULT("devtools.timeline.invalidationTracking"), \
"StyleInvalidatorInvalidationTracking", \
"data", \
InspectorStyleInvalidatorInvalidateEvent::selectorPart((element), (InspectorStyleInvalidatorInvalidateEvent::reason), (singleSelectorPart)))
class InspectorLayoutInvalidationTrackingEvent {
public:
static PassRefPtr<TraceEvent::ConvertableToTraceFormat> data(const RenderObject*);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment