INP discrepancy due to testing harness
Maintainers usually reply within 1 day
Nobody has claimed this yet.
Assessment
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Newbie friendliness
- 35/100
- Issue type
- Bug
- Clarity
- Mostly clear
- Activity status
- Active
- Tech stack
- javascript, typescript
- Domain
- performance, testing-qa
Research direction
Start by reading the testing harness and its INP measurement flow, then compare traces for synchronous URL updates and deferred updates on headless Linux versus a full Chrome instance. The report is a hypothesis rather than a confirmed diagnosis, and names no files or tests. Done means identifying whether the harness causes the discrepancy and documenting or addressing a reproducible cause.
Written by the indexing model from the issue text.
Description
I found a problem with the way INP (Event Timing, or "interaction breakdown"), i'm not 100% sure about it, and not sure how solvable it is.
Here is my understanding:
when Chrome is software-rendered (headless on Linux, and also headed on a virtual display), updating the URL on click makes the browser repaint its own UI (toolbar / URL bar), and the page's next frame is held until that browser-UI frame is ready. That wait gets counted in presentation delay. It penalizes any framework that pushes the URL synchronously on click (i.e. only tanstack in the current list, the others only update the URL once the route is ready). On my server it's about 2 - 3 ms added to tanstack's time.
I tried deferring the URL update by one task and the penalty is gone. And for comparison, I also tried forcing React Router to update the URL during the click and it also loses 2 - 3 ms.
Testing on a full chrome instance, on my macbook, this penalty doesn't exist.
I found this because I was trying to lower our INP score, and found that in tests I was capped, even removing almost everything, i couldn't get the number to go down beyond a point, and this is my best theory so far
🤖 Below is an explanation of this mechanism by an agent (it's talking about #8602 because that's the PR where I was working on link performance)
The frame cannot be shown before the browser's own toolbar frame is ready, and that takes about 12 ms from the click.
Where the 12 ms comes from
From the traces on Linux, for TanStack on #8602:
| Step | Time after the click |
|---|---|
The native pushState runs |
about 3 ms |
| The browser process receives the navigation | about 4 to 5 ms |
| It updates the toolbar, then lays out, paints and rasterizes its UI | about 7 ms of work |
| The browser's UI frame is submitted | about 10 ms |
| The display draws and presents | about 3 ms more |
| Earliest possible presentation | about 12.5 to 13 ms |
That chain does not depend on when the next frame tick falls. The toolbar repaint is slow there because it is rasterized on the CPU.
The page's own frame is usually ready well before that, around 9 ms. The trace shows the display holding it with the message "More damage expected soon". My reading is that the display composes the page and the browser UI into one picture, and waits for a surface that has announced an update, up to a deadline. The wait itself is measured. The reason for it is my interpretation of that message.
Why that averages out to 2 to 3 ms
Without the pushState, latency depends on luck: where the click lands relative to the next frame tick.
- A lucky click, just before a tick, finishes in about 7 ms.
- An unlucky one, just after a tick, takes 17 ms or more.
With the push inside the click, the lucky cases are no longer possible. Every click that would have finished between 7 and 12 ms is pushed up to about 12.5 ms. The unlucky ones were already slower than that and are unaffected.
In the arms without the in-click push, about half the runs finished under 12 ms, averaging around 9 to 10 ms. Pushing those up to 12.5 costs about 3 ms each, on half the runs. That gives roughly 1.5 to 2 ms on the mean, which is the bulk of what we measured. The rest comes from runs slightly above the floor that also waited a little for the toolbar frame.
So the same mechanism gives both numbers:
| What you look at | What you see |
|---|---|
| The fastest runs | a hard floor near 12.5 ms |
| The mean | about 2 to 3 ms worse |
| The slowest runs | no difference |
It also shows in the spread. TanStack's latencies were bunched together, with a standard deviation of 2.6 ms, against 4 to 5 ms for the others. Its low tail is cut off and its high tail is not.
Why this explains #8602's small unthrottled gain
On main, the click handler took about 7 ms, so it was still running while the browser repainted its toolbar. The two overlapped, and the floor was hidden behind the processing time. #8602 cut processing by 4 ms, which exposed the floor. The handler now finishes at 3 ms and then waits for a frame that cannot arrive before 12.5.
Why it vanishes on the Mac
The toolbar chain takes just as long there, 6 to 13 ms. The difference is that the display does not wait for it. It presented the page's frame about 0.1 ms after the renderer submitted it, in every arm.
- Dominant language
- TypeScript
- Stars
- 42
- Forks
- 16
- Avg merge
- 13h 56m
- Merged PRs (30d)
- 141
Getting set up
- Ships a Dockerfile or Docker Compose file
- Has a pull request template
- Read the contributing guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
More from e18e/framework-tracker
-
documentation
Difficulty 2/5 1-3 hours Newbie friendliness 70/100
e18e/framework-tracker#640 ·
Maintainers usually reply within 1 day
-
documentation
Difficulty 3/5 1-2 days Newbie friendliness 45/100
e18e/framework-tracker#666 ·
Maintainers usually reply within 1 day
-
Variance ChartsOpendocumentation
Difficulty 5/5 Over a week Newbie friendliness 35/100
e18e/framework-tracker#665 ·
Maintainers usually reply within 1 day
-
TanStack Bar ChartOpendocumentation
Difficulty 4/5 3-5 days Newbie friendliness 45/100
e18e/framework-tracker#664 ·
Maintainers usually reply within 1 day
-
TanStack Line ChartOpendocumentation
Difficulty 4/5 1-2 days Newbie friendliness 45/100
e18e/framework-tracker#663 ·
Maintainers usually reply within 1 day
All issues in e18e/framework-tracker
Similar issues
-
Difficulty 2/5 1-3 hours Newbie friendliness 74/100
Maintainers usually reply within 1 day
-
Difficulty 2/5 1-3 hours Newbie friendliness 65/100
OpenPetsHQ/openpets#273 ·
Maintainers usually reply within 1 day
-
Difficulty 2/5 1-3 hours Newbie friendliness 76/100
fritzprix/libr-agent#2161 ·
Maintainers usually reply within 1 day
-
Difficulty 2/5 1-3 hours Newbie friendliness 83/100
blackboardsh/electrobun#581 ·
-
backlog-skill effort:xs frontend infra ready-for-agent
Difficulty 2/5 1-3 hours Newbie friendliness 74/100
LucasSantana-Dev/Lucky#2862 ·
Maintainers usually reply within 1 day