Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Spec to record "next paint time" #35

Open
bmaurer opened this issue Aug 2, 2017 · 6 comments
Open

Spec to record "next paint time" #35

bmaurer opened this issue Aug 2, 2017 · 6 comments

Comments

@bmaurer
Copy link

bmaurer commented Aug 2, 2017

This is a followup to:

https://groups.google.com/a/chromium.org/d/msgid/progressive-web-metrics/CAHTsfZD1zJp6unenAyu%2BKoDJLAfKG41Mm2mmbT9gUKzoMvnxWQ%40mail.gmail.com

At Facebook when we measure performance, we want to know when the user sees the thing that we're measuring. For example, we don't care when newsfeed was put in the DOM, we want to know when the pixels painted on the screen. So far the best way we've discovered to do this is doing a rAF and then within that rAF a setTimeout(0). the rAF ensures we capture everything within the frame and the spec runs setTimeouts from within a rAF in the next frame.

This heuristic has a number of problems:

  • It behaves poorly when the tab is in the background, etc (because browsers often delay frames/timeouts in these cases)
  • We'd ideally like to know if no drawing was necessary

Tim's event timing proposal is based on the idea of measuring the "time to next paint". It'd be great to standardize this concept and create a simple API for measuring it. The way I envision this API working is that it would provide a promise for a high resolution timestamp of the time when all the DOM mutations that have currently been done are painted on the screen. If the browser does not intend to immediately render these (eg because the tab is backgrounded and it will defer drawing to a later time or because no drawing is necessary) the promise will return null.

@igrigorik
Copy link
Member

The way I envision this API working is that it would provide a promise for a high resolution timestamp of the time when all the DOM mutations that have currently been done are painted on the screen.

I doubt we can provide this as high-resolution time, as it opens up all kinds of paint-timing attacks. The "imprecise" nature of rAF -> setTimeout(0), or double-rAF technique, is probably the best we can offer here. Ditto for explicit notifications of "no drawing was necessary", as that would provide an explicit signal for ~visited attacks; don't think we can offer this.

Given the above.. I'm not sure we can do much here? @toddreifsteck wdyt?

@bmaurer
Copy link
Author

bmaurer commented Aug 2, 2017

I'm sure we can find some middle ground here to avoid side channel attacks. Some compromises I could think of are:

  1. Giving the timestamp of the style / layout calculation (which you could in theory trigger yourself by querying the height of the document)
  2. Only including the paint time if the paint time is over X milliseconds (on the theory that a long paint would be observable via a high frequency timeout)
  3. fuzzing the timestamp that is returned.

Ultimately performance is about measuring the time at which the user sees something -- right now there's not a lot of heuristics to do this. We've found that rAF + setTimeout has way more variance than we'd like (eg due to background tabs). Even something that was a better supported version of rAF + setTimeout would help

@spanicker
Copy link

For the issue with when page is in background: this is easy enough to filter out based on pagevisibility - no?

@spanicker
Copy link

"no drawing was necessary" does not mean that the rendering pipeline did not need to run, in fact it could have run upto one of N points. for some background see this doc

@igrigorik
Copy link
Member

@tdresser could some of the work you're investigating with Event Timing be helpful in this discussion? Or, more broadly, anything we want to investigate or pursue here from your perspective?

@tdresser
Copy link

I'm digging into solutions to the general set of problems here for event timing.

We can't let you know when no drawing was necessary, for the security reasons discussed above.

There's two main things an API could potentially improve over rAF+setTimeout(0):

Behavior in background.
As spanicker mentions, pagevisibility should let you exclude these cases. I think exclusion is probably correct?

Knowledge of compositing time.

You can polyfill something pretty good here today by injecting an iframe with a FP listener, but it's quite ugly.

My preference would be to tackle this after we've sorted out event timing. Assuming we can sort out the security / privacy concerns there, I'd like to:

  • Provide an ergonomic approach to get the next time main is done drawing a frame, and when pixels hit the screen (using simulated timestamps if no frame was produced).
  • Provide a long frame API, similar to long tasks, which provides the same information for long frames in the performance timeline.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants