w3c / user-timing

User Timing
https://w3c.github.io/user-timing/
Other
26 stars 24 forks source link

Marking and measuring style computation, layout calculations, etc #88

Open andyearnshaw opened 2 years ago

andyearnshaw commented 2 years ago

My team and I have recently undertaken some work to try and improve the performance of a component that triggers a lot of DOM mutations in a single animation frame. We've instrumented the code to make use of marks and measures, but one area that is a fairly big problem for us is style computation/recalculation and layout.

Take the following (simplified) code, for example:

requestAnimationFrame(() => {
  performance.mark("updateElements:start");
  updateElements(cachedElements, nextData);
  performance.mark("updateElements:end");
});

If updateElements() does simple things with the elements like updating attributes or text content, then our performance measurements are fine. However, if they do things like change class names, position or other styles, our performance measurements do not capture the side effects caused by this and it's difficult to automate collection of such measurements. This is somewhat understandable, since other code on the page could have triggered those side effects rather than our code. However, if we're running in an isolated, predictable environment, then we can know that only our code triggered a style/layout computation.

This is sort of how we're tackling this at the moment:

requestAnimationFrame(() => {
  performance.mark("updateElements:start");
  updateElements(cachedElements, nextData);
  performance.mark("updateElements:end");
  setTimeout(() => {
    performance.mark("frame:end");
  });
});

Measuring between updateElements:end and frame:end gives us a rough idea of the time taken for the browser to compute all the changes, but it's missing important detail and it can run quite late. Is there scope for something that could help with this?

yoavweiss commented 2 years ago

Thanks for the detailed issue! I think that reporting layout times is something that can be useful to help people understand the cost of their styling decisions. /cc @chrishtr for opinions on that front

I suspect that figuring out the layout costs of specific DOM changes may be a harder sell, as it may not align with how implementations are performing layout.

mmocny commented 2 years ago

I love this request. I don't know how viable it is to expose, but I think it would be very useful.

Ideally we could expose the total amount of time spend after ALL requestAnimationFrame() calls finish (which the script above doesn't guarantee) until the COMMIT stage of rendering is complete (i.e. the main thread rendering Task is finished).

(FWIW insights into this stage specifically would be especially useful alongside Event Timing and Paint Timing as well.)

noamr commented 2 years ago

I like the idea! Need to take a close look to see if exposing something so fine-grained may expose user environment or cross-origin resources via timing attacks. But I think this type of information, that is exposed today in DevTools, could also benefit RUM a lot if we get it right.

nhelfman commented 2 years ago

I feel this idea has some relation to items on other proposals:

  1. EventTiming API - https://github.com/w3c/event-timing/issues/109
  2. JS-Self-Profiling - markers - https://github.com/WICG/js-self-profiling/blob/main/markers.md

Being able to measure frame end time after some code execution is valuable and will help with certain investigations we are encounter on a regular basis (Microsoft Office Online). From our experience and production measurements of many millions of samples, using the mentioned setTimeout() technique is very inaccurate since sometimes the callback may fire over 100ms after the paint happened since it has relatively low priority.

Another technical solution have been proposed, which is possibly more accurate is using MessageChannel (https://www.webperf.tips/tip/measuring-paint-time/). This method, although more accurate still not guaranteeing high accuracy and requires relatively high effort from developers.

In general, I think addressing the need of frame timing measurements is important if we can do it without introducing any new security risks.

mmocny commented 2 years ago

Great conversation at Web Perf WG today, clearly there is appetite here.

One question that came up: Is the context of this request specific to User Interactions (Event Timing) and/or specific Element paints (Element Timing), or is it necessary to expose this information for every single Animation Frame?

Exposing something for the former could be easier, and could come as additions to existing specs. It may be something specific to focus on as a first deliverable here.

nicjansma commented 2 years ago

Summary of the May 12 W3C WebPerf discussion: