How to measure or profile the cost of CSS rules

classic Classic list List threaded Threaded
4 messages Options
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

How to measure or profile the cost of CSS rules

Kan-Ru Chen (陳侃如)
Hi list,

The two things we most want to know while profiling Firefox OS app
launch time are (1) what styles had been changed (2) why did the restyle
take so long.

Gaia apps are designed around event dispatches and one event could
trigger many style changes from anywhere from the code base. It is hard
to know what styles had been changed, for example class added or
removed, and what rules had actually been matched. This leads to the
second question. From the gecko profile we usually find both the
selector matching and style recalc take considerable amount of time. So
I guess we could start from reducing the expensive selectors then trying
to reduce the matched elements. Without knowing which rules had actually
been matched, we don't know how to optimize the CSS rules.

So, do you know a way to collect this kind of information, preferably
from WebIDE?

  Kanru
_______________________________________________
dev-tech-layout mailing list
[hidden email]
https://lists.mozilla.org/listinfo/dev-tech-layout
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: How to measure or profile the cost of CSS rules

Cameron McCormack-4
Kan-Ru Chen (陳侃如):

> The two things we most want to know while profiling Firefox OS app
> launch time are (1) what styles had been changed (2) why did the restyle
> take so long.
>
> Gaia apps are designed around event dispatches and one event could
> trigger many style changes from anywhere from the code base. It is hard
> to know what styles had been changed, for example class added or
> removed, and what rules had actually been matched. This leads to the
> second question. From the gecko profile we usually find both the
> selector matching and style recalc take considerable amount of time. So
> I guess we could start from reducing the expensive selectors then trying
> to reduce the matched elements. Without knowing which rules had actually
> been matched, we don't know how to optimize the CSS rules.
>
> So, do you know a way to collect this kind of information, preferably
> from WebIDE?

I don’t know whether any of this information is surfaced in WebIDE; I’ll
let someone else answer that.  But we could build interfaces to expose
this information, if it’s not already exposed.

For (1), checking whether a given element matched a different set of
style rules, at the time that we assign a new style context to an
element, is cheap; we can just compare the old and the new rule node.
We could have an nsIDOMUtils method that allows devtools to register a
listener for style change events, and then RestyleManager can just
gather up the elements’ whose styles changed during a given restyle and
invoke the callback.

For (2), there’s a few different things that combine to cause a total
restyle time, but I’m under the impression the major factor is the
number of new style contexts we resolved (style computation is
expensive) and secondarily by the number of selector matching operations
we have to do.  Some simple things we could do are have a counter for
the number of new style contexts that are created – even if they didn’t
represent a different set of styles, which (1) would capture – and maybe
a counter for the number of elements that were traversed while doing
selector matching?

How many elements actually need to have selector matching run and get
restyled is a function of the particular DOM manipulations that are done
and the selectors that are in the style sheet.  That’s represented by
the restyle hint that gets generated in response to a DOM manipulation.
We could expose this to devtools too, by allowing a listener to be
registered that is invoked for each call to
RestyleTracker::AddPendingRestyle (that method takes an Element and an
nsRestyleHint).

I’m thinking it’d be useful if that listener could tell devtools which
specific selector caused the given restyle hint, too.  For example if
you had:

  .x { }

in your style sheet and you toggled .x on an element, you’d generate an
eRestyle_Self, which basically means “run selector matching on that
element, then recompute its styles, then traverse to descendants
recomputing their styles without doing selector matching, until we come
to a descendant where we can prove we can never get different styles”.

OTOH if you had:

  .x .y .z { }

and toggle .x on an element, you’d generate (eRestyle_Self |
eRestyle_SomeDescendants), which (just recently) means “run selector
matching on that element and recompute its styles, as before, but
additionally traverse to descendants until you find one that matches .z,
and then re-run selector matching on that one, restyle it, and traverse
to descendants recomputing styles without selector matching, until we
come to a descendant of the .z where we can prove we never get
difference styles”.  Whew. :-)

And even worse:

  :not(.x .y) { }

where the presence of the :not() means that toggling .x on an element
means we will re-run selector matching and recompute styles on all
descendants of the element.

So exposing the specific selector that caused a more expensive restyle
hint to be generated is something that we could do.  (Exposing the
entire set of selectors that could influence the restyle hint is not
something we could do easily at the time we’re processing the DOM
modification, but exposing one that caused the restyle hint to be as
expensive as it was is possible.)

I guess that’s all to say that with the (1) and (2) information exposed
to devtools, and some knowledge about what kinds of selectors cause what
kinds of restyle hints, you’ll probably be in a better position to know
what’s causing restyle performance problems.  (I have a feeling that
restyle hints are recorded on restyle events in the profiler?  But I
haven’t looked recently.)

--
Cameron McCormack ≝ http://mcc.id.au/
_______________________________________________
dev-tech-layout mailing list
[hidden email]
https://lists.mozilla.org/listinfo/dev-tech-layout
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: How to measure or profile the cost of CSS rules

Kan-Ru Chen (陳侃如)
Cameron McCormack <[hidden email]> writes:

> Kan-Ru Chen (陳侃如):
>> The two things we most want to know while profiling Firefox OS app
>> launch time are (1) what styles had been changed (2) why did the restyle
>> take so long.
>>
>> Gaia apps are designed around event dispatches and one event could
>> trigger many style changes from anywhere from the code base. It is hard
>> to know what styles had been changed, for example class added or
>> removed, and what rules had actually been matched. This leads to the
>> second question. From the gecko profile we usually find both the
>> selector matching and style recalc take considerable amount of time. So
>> I guess we could start from reducing the expensive selectors then trying
>> to reduce the matched elements. Without knowing which rules had actually
>> been matched, we don't know how to optimize the CSS rules.
>>
>> So, do you know a way to collect this kind of information, preferably
>> from WebIDE?
>
> I don’t know whether any of this information is surfaced in WebIDE; I’ll
> let someone else answer that.  But we could build interfaces to expose
> this information, if it’s not already exposed.

Thanks for the very detailed answer!

So in other words, we could do the following:

(1) Collect the elements that have styles changed by comparing the rule
node or style context. We could report them to devtools and maybe also
list the changed style for each of them.

(2) Record DOM manipulations and the restyle hints they generated via a
specific selector. Then count the element traversed while doing selector
matching. Also count the number of new style context resolved. We can
then sort the report by these numbers.

Does this make sense?

  Kanru
_______________________________________________
dev-tech-layout mailing list
[hidden email]
https://lists.mozilla.org/listinfo/dev-tech-layout
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: How to measure or profile the cost of CSS rules

Cameron McCormack-4
Kan-Ru Chen (陳侃如):
> So in other words, we could do the following:
>
> (1) Collect the elements that have styles changed by comparing the rule
> node or style context. We could report them to devtools and maybe also
> list the changed style for each of them.

Yes.  There might be some trickiness around keeping the old style
context around, if we needed to provide that to devtools too.  Providing
just a list of elements whose styles changed should be simple.

My feeling though is that (2) might help you more than (1).

> (2) Record DOM manipulations and the restyle hints they generated via a
> specific selector. Then count the element traversed while doing selector
> matching. Also count the number of new style context resolved. We can
> then sort the report by these numbers.
>
> Does this make sense?

Something like this, although hopefully we can avoid recording what the
DOM manipulations are, as there’d be many places in our DOM code we’d need to
change.

Looking at the restyle code, we do have some information being reported
to the profiler.  Here is where we record the backtrace for a restyle
hint:

https://dxr.mozilla.org/mozilla-central/rev/0b69d304f861d0038fb78f1d52b0f5d13ef7c6fe/layout/base/RestyleTracker.h#459

and here is where we report them:

https://dxr.mozilla.org/mozilla-central/rev/0b69d304f861d0038fb78f1d52b0f5d13ef7c6fe/layout/base/RestyleTracker.cpp#349
https://dxr.mozilla.org/mozilla-central/rev/0b69d304f861d0038fb78f1d52b0f5d13ef7c6fe/layout/base/RestyleTracker.cpp#398

So maybe we can append the selector traversal counts and style context
creation counts to it there.  The backtrace should be enough to point at
the particular DOM operation in the script that caused the restyle to be
added.

It looks like the data on the profiler tracing entry, besides the
backtrace, is just a string.  So I don’t know how feasible it is to
report the particular style rules that caused a given restyle hint to be
generated on it.

Having just the selector traversal and style context creation count data
on the profiler tracing entries will help you find which DOM operations
caused the most expensive restyles, but they won’t tell you why, unless
you know which style rule’s existence caused the particular restyle hint
to be generated.

Benoit:  Does extending the tracing entry here with additional data
sound like the right thing to do?  Is it possible to attach a pointer to
a refcounted object (the style rule) to the tracing entry, so that
devtools could say add a link that jumps from the restyle tracing entry
back to the rule in the style sheet?  If not then I guess we could just
serialize the selector and add it to the entry’s string data, which
might be enough to go on.

(Also I had a feeling we might already report nsRestyleHint values
through the profiler somewhere – is that right?)

--
Cameron McCormack ≝ http://mcc.id.au/
_______________________________________________
dev-tech-layout mailing list
[hidden email]
https://lists.mozilla.org/listinfo/dev-tech-layout
Loading...