First input events should never be filtered |
||||||||
Issue descriptionTo compute FID correctly, we must always report the first input via the EventTiming API. To do so, the current proposal is to always plumb the first* input from the browser to the renderer. This should have a fairly insignificant cost (communication costs plus code ran on the renderer until the input is optimized out). To see why this matters, suppose we do not always report FID (ie, FID comes from events that hit the renderer). If a website adds a trivial event handler that forces all inputs to be sent to the renderer, then FID will be improved because now all first events are considered for FID - even those that previously did not have any event handlers. * possibly more than the first because pointer-down followed by pointer-up require both.
,
Dec 13
> Is this proposal referring to forgoing this optimization for the first [set of] input? Or something else? Yes. > I feel like this might actually be significant, since the page is likely to be doing a flurry of tasks towards the beginning of the page-load. It's true that the page will be busy during page load but the hope is that the overhead is very low which makes the impact low, even if this occurs early. > Why would installing an event-handler *improve* the FID? If anything, it should make it worse (since the FID will include the time to run the JS handler)? It should increase the real FID, but it could decrease the FID values reported by the API if we don't always plumb the first input. Let's go over an example. Suppose that originally 20% of first inputs for a website have event handlers, which take 20ms to run on average. Then the reported FID for this website is on average 20ms plus the queueing time (time to process the event) because inputs without event handlers are ignored so the 'first' will be the first one with an event handler. Then suppose that the website adds trivial event handlers so that now every input will be plumbed to the renderer. Let's say handling these trivial event handlers take 1ms to run on average. Then the average FID reported will be 0.8*1 + 0.2*20 = 4.8 ms, a much smaller value! Of course, the 'real' FID will be larger once the website adds trivial event handlers.
,
Dec 13
Note: the previous example was about first input 'handling' since I've included event handler durations. First input delay per se is defined as processingStart - event timestamp. Always plumbing the first inputs will still affect this metric. If we do not, then a the first inputs for a website with only some event handlers will probably see a lower FID than it should because the 'first inputs' will be later on the page load and thus be processed faster. Whereas the same page adding a trivial event handler will have a more accurate and higher FID.
,
Dec 14
This seems like a good change to me as it's more closely aligned with the user's first FID experience as well. Thanks for moving this forward! Agree with Ilya on thread that we should target 73. I believe FID evaluations for Ampersand are blocked on this since it's likely to have a significant impact on reported FID for many pages.
,
Dec 14
I'm going OOO so assigning to charliea@ for now.
,
Dec 18
,
Dec 19
bmcquade@, is there an Ampersand launch bug that should be blocked on this given comment 4?
,
Dec 19
,
Dec 19
Quick update: today I started a doc that examines the reasons that we're currently filtering input in the browser main thread and renderer compositor threads. In doing so, I found one case that I'm not sure that we're ever hitting in the browser main thread. If we do, though, then there are ramifications for first input timing. Given that, I created a test page to verify that my understanding of browser main input filtering is correct and learned how to test remotely on an Android device. I'll keep folks updated on how it goes and any other first input progress.
,
Jan 8
,
Jan 8
,
Jan 10
,
Jan 14
Quick update: nzolghadr@, npm@, and I have been looking a lot at how we can accomplish this in the past few days. dtapuska@ had a pretty genius way to circumvent event filtering until we have our first input: just add a C++ event listener in the renderer compositor thread. Because all event filtering is done on the basis of whether there's an event listener, doing this will ensure that all inputs reach the renderer compositor until we find our first meaningful input, at which point we can deattach that event listener. This is a lot more elegant solution than special casing all filtering checkpoints to see until first input is seen. I'm going to be drafting a design sketch today that gives a better idea of what this will look like at the code level.
,
Jan 15
Another quick update: the implementation is now pretty much complete for the above solution, but I'm running into an issue where the solution only works the first time that I test it after opening Chrome. I'll work on debugging the issue tomorrow.
,
Jan 16
(6 days ago)
I grinded away at this for another few hours, and here's what I've got so far: - The workaround is working as intended the first time that we reach first input in a given tab - The second time that I try it in a given tab, the pointer down event is getting filtered After adding logging, it seems like the pointerdown event is getting filtered somewhere after InputHandlerProxy::HandleInputEventWithLatencyInfo() and somewhere before reaching the main thread event queue.
,
Jan 16
(6 days ago)
I don't follow the problem: the second input in a page is allowed to be filtered, no? Can you be more precise about what the problem is? Do you have a WIP CL to help debug?
,
Jan 17
(5 days ago)
Sorry, it's not the second input on a page that's being filtered, but rather the second page that's run within a given tab.
Here are the steps I'm using to repro the problem locally:
- Build, install patched version of Chromium to an Android device
- Open devtools for attached Android device through chrome:inspect?tracing
- Open a test page with no attached event listeners
- Put finger down, drag it slightly, raise finger.
- Note that window.performance.getEntryByType("firstInput") returns a result, as it should
- Refresh the page
- Put finger down, drag it slightly, raise finger.
- Note that window.performance.getEntryByType("firstInput") does NOT return a result (a bug)
Adding some basic logging indicates that the reason behind this is that the pointerdown event is getting filtered somewhere after InputHandlerProxy::HandleInputEventWithLatencyInfo(). The problem goes away if I open a new tab, with the pointerdown event once again successfully reaching the renderer main thread.
Right now, I'm basically manually bisecting the input pipeline in order to determine where the filtering is happening.
,
Jan 17
(5 days ago)
Hmm that's odd, but thanks for the thorough testing. I'd double check that the event listener is also being added in that reload
,
Jan 17
(5 days ago)
I'm slowly homing in on the problem area of code: it looks like the compositor hit test (InputHandlerProxy::HitTestTouchEvent()) is returning an EventDisposition of DID_HANDLE_NON_BLOCKING for the first load, and DROP_EVENT for subsequent loads. This is ultimately causing the difference in behavior. Now I'm looking into why that is. |
||||||||
►
Sign in to add a comment |
||||||||
Comment 1 by sadrul@chromium.org
, Dec 13