Open Bug 1901608 Opened 1 year ago Updated 1 year ago

In full-screen mode, hovering to reveal top toolbar causes jank from resizing the viewports of any tabs whose titles that you happen to hover (all of which resize to accomodate the space that the toolbar is briefly occupying)

Categories

(Firefox :: Tabbed Browser, defect, P3)

defect

Tracking

()

Performance Impact medium

People

(Reporter: dholbert, Unassigned, NeedInfo)

References

Details

(Keywords: perf:responsiveness)

Attachments

(5 files)

tl;dr: it seems we've got an optimization to defer browser-viewport-resizes for background tabs, but it's not getting properly applied when you're in fullscreen mode (F11)

STR:

  1. Open a Firefox window with 10 copies of testcase 1 part A (expensive-to-resize) in background tabs, and one copy of testcase 1 part B (snappy to resize) in foreground tab.
  2. Try resizing your window. Note that the foreground tab is snappy to respond (updating its resize-count and redrawing its viewport-border in a responsive way)
  3. Now hit F11 to fullscreen the window.
  4. Hover/unhover the top part of your screen, to reveal/hide the top toolbar. Compare the responsiveness to step 2.

ACTUAL RESULTS:
The viewport-resizes in step 4 (from hovering/unhovering the top of your screen) are much jankier than those in step 2. My hand-wavy guess at an explanation is that we're deferring the viewport-resizes for background tabs in step 2, but we're handling them synchronously in step 4 (at the cost of responsiveness in the foreground tab).

I'm using Firefox Nightly 128.0a1 (2024-06-09) (64-bit)

(Note: I'm spinning this off from bug 1528638 comment 5, for some jank that I can reproduce that I think matches what the user was describing there.)

In the attached screencast, you can see the reference "good" behavior at t=11s -- when I do a normal resize of the Firefox window, the foreground tab resizes very snappily, repainting its border snappily and updating its resize-count (with JS) with essentially no delay.

However, after I fullscreen the window with F11: the top-toolar-reveal viewport-resizes are much less snappy -- the foreground tab janks when repainting (as can be seen by delayed updates to the resize-counter in the page, and temporarily broken rendering at the bottom of the page -- either a missing bottom-border, or an extra stripe of white, from us failing to repaint the content in time when the viewport resizes, due to contention from all the resize work that's happening in background tabs).

Note, there's a little bit of randomness here -- i.e. you might need to hover/unhover the top of your screen several times before this reproduces. I think this randomness comes from:
(a) whether & how-many of the background tabs share the same process as the foreground tab.
(b) the order-in-which resize events are fired to the tabs that are in that process.

(And on a personal level, (c) how many cores you have; if you don't have many, then even resizes in other processes will cause contention with the foreground tab.)

In any case, you can make this bug more-reliably-bad by doing either or both of:

  • opening additional copies of the background tab (testcase 1 part A)
  • opening the testcase from your local filesystem (since I think we only spawn one process for file:/// URIs, rather than multiple processes-per-origin like we do for web content)

Here's a profile showing this bug reproducing several times, using versions of the testcase served from my local filesystem:
https://share.firefox.dev/3VyQyqs

All of the red jank bars in the content-process there are the relevant areas where we're stuck handling the (intentionally-slow) resize handler in a background tab, and we fail to repaint the foreground tab (showing e.g. a white bar at the bottom for a little while, as can be seen in the screenshots track).

See Also: → 1705215
Performance Impact: --- → ?

Impact note: this potentially makes Firefox pretty-painful for folks who use Firefox in full-screen mode (e.g. folks with small screens), AND have a lot of tabs open (and/or have a few expensive-to-resize background tabs). We have one such user in bug 1528638 comment 5, I think.

For such a user: each time they want to edit their URL (or do any other action with the top toolbar), they'll potentially trigger this bug and experience jank, even if their foreground tab is a trivial-to-resize/repaint.

For comparison & possibly fix-inspiration, we have another very-similar situation that does not trigger this bug: pressing "Alt", which (on Windows and Linux, in a regular not-fullscreen Firefox window) makes the menu-bar briefly appear and shrink the foreground tab's viewport. That "alt"-triggered toolbar-expansion does not cause any resize activity for background tabs. To illustrate that, here's a profile where I have this bug's set of tabs open, and I press "Alt" repeatedly for ~20 seconds (during which time the content process is responsive and barely active, which is great). Then at the very end of the profile, I switch to fullscreen mode and hover the top of my screen, which immediately triggers this bug with a huge burst of jank/activity:
https://share.firefox.dev/4es7mqC

Intuitively, it feels like these two "top-toolbar-reveal" actions (from Alt and hovering-the-top-of-fullscreen) should be the same in terms of cost/responsiveness (or could be made to be the same, at least).

(In reply to Daniel Holbert [:dholbert] from comment #7)

For comparison & possibly fix-inspiration, we have another very-similar situation that does not trigger this bug: pressing "Alt", which (on Windows and Linux, in a regular not-fullscreen Firefox window) makes the menu-bar briefly appear and shrink the foreground tab's viewport. That "alt"-triggered toolbar-expansion does not cause any resize activity for background tabs

None, not just less activity because this isn't animated? That seems surprising... at least I can't recall or find any optimization we've implemented there. We basically just set the toolbar's height to 0 when it's "inactive" (i.e. when Alt isn't pressed): https://searchfox.org/mozilla-central/rev/46d0387f0b582f00a5722c20d4e6b8693793631b/browser/themes/shared/browser-shared.css#328-338

Flags: needinfo?(dholbert)

There's no animation on the menubar appearing/disappearing. There's animation on the toolbars disappearing in fullscreen. It's a bit hard to see from the screenshot display in the profiler but ISTM that the jank at the end of https://share.firefox.dev/4es7mqC is from the animation/transition running when the toolbar disappears again. So I expect that the fact that we're animating this and causing layout flushes in the middle is what's causing this.

I don't know why the animation/transition is so much slower than the resize. To me, that smells like something that was optimized at a gecko level for window resizes. From a frontend perf PoV, it's kind of known that resizing things as part of an animation (rather than scaling) is always going to suck because it requires a full layout flush at every step of the transition/animation. But I'd expect the same to be true for the resize operation, and I don't know by what magic gecko is optimizing that, or how frontend would invoke the same magic for the fullscreen toolbar animations.

(obviously, making the fullscreen animation such that the toolbar appears on top of the webpage, so that there is only 1 content area resize ("snap") instead of N for N animation steps, would "fix" the perf problem, but I'd expect complaints from UX that the visual appearance of the animation is not satisfactory, which is what happened when we tried to do a similar thing for animating the review checker sidebar - in fact, the animation was deemed so unacceptable that it was removed entirely.)

(In reply to Dão Gottwald [:dao] from comment #8)

(In reply to Daniel Holbert [:dholbert] from comment #7)

For comparison & possibly fix-inspiration, we have another very-similar situation that does not trigger this bug: pressing "Alt", which (on Windows and Linux, in a regular not-fullscreen Firefox window) makes the menu-bar briefly appear and shrink the foreground tab's viewport. That "alt"-triggered toolbar-expansion does not cause any resize activity for background tabs

None, not just less activity because this isn't animated? That seems surprising

Correct, none -- no activity for background tab viewport-resizes. (Any such activity would result in the intentionally-expensive 1-second-busy-loop being tripped, which would manifest as a red jank bar. And there are no such bars in my profile during the section where I'm pressing "Alt" repeatedly.)

(In reply to :Gijs (he/him) from comment #9)

From a frontend perf PoV, it's kind of known that resizing things as part of an animation (rather than scaling) is always going to suck because it requires a full layout flush at every step of the transition/animation. But I'd expect the same to be true for the resize operation, and I don't know by what magic gecko is optimizing that, or how frontend would invoke the same magic for the fullscreen toolbar animations.

So, this^ known-issue that you're describing is unrelated to the badness that we're hitting here. This bug here is not a case where each layout flush has a moderate cost and we're chaining together a bunch of them which leads to jank. Rather: in this bug, I've set things up such that any viewport-resize-at-all in a background tab will lead to exactly 1 second of jank (in that tab's content process); and we are triggering those 1s janks specifically for fullscreen-window top-toolbar-reveals in particular (for some of them at least), and not for other sorts of viewport-resizes that I've been able to find/test.

Flags: needinfo?(dholbert)

I'm about to hop into a meeting, but afterwards I'll try to capture a pernosco trace, to try to figure out more about what causes this to happen in this particular case.

Flags: needinfo?(dholbert)
Flags: needinfo?(dholbert)
Flags: needinfo?(dholbert)

Aha, so in the process of trying to capture this in pernosco, I think I isolated a step that's required here, which I hadn't previously appreciated:

I think jank here comes from background tabs that I inadvertently hover when revealing the top toolbar; and when I hover them, we trigger "tab warming" which makes them get ready to render, and they fire their window resize event. When you move your mouse to the top of the screen (step 4 of my STR), you'll likely end up hovering an arbitrary spot in the tab-strip (you can't really predict where, since you can't see the tab-strip until your mouse gets there). And in my STR, the inadvertently hovered tab is usually one of the expensive-to-resize background tabs.

I can actually trigger this same slowness with "Alt" menubar-appearance as well (despite what I said in comment 7), if I take the additional action of hovering over one of the expensive-to-resize background tabs after I've made the menubar appear. That's not a particularly interesting/common use-case, though.

Fullscreen top-toolbar-reveal seems to be uniquely a bit of a footgun for this pitfall because
(a) viewport resizes are inherently part of the way-that-you-see-your-tabstrip there (the tabstrip appearing causes your content area to shrink)
(b) you can't tell what tab you'll hover (i.e. what tab/tabs you might "warm") until it's too late; and once you've revealed the top toolbar, you're likely to mouse across other tab titles on your way to the tab that you actually want to click, potentially warming all of them as well. This ends up queuing up a bunch of work that potentially steals cycles from the foreground tab (or whatever tab you actually wanted to switch to) and causes jank.

I wonder if there are any heuristics around tab-warming that we might want to tune differently when we're in fullscreen?

Flags: needinfo?(dholbert)

So is there no jank at all in the fullscreen toolbar-showing case if you force the toolbar to show by using a keyboard shortcut instead of hover to show the toolbar, e.g. by pressing F6?

Flags: needinfo?(dholbert)

That's correct, based on some testing that I did just before comment 12 (I used Ctrl+L rather than F6, but I think it's equivalent). There's no jank from resizing background tabs when I use the keyboard to reveal the top-toolbar.

--> clarified bug summary, given new understanding of what's going on in comment 12.

Flags: needinfo?(dholbert)
Summary: In full-screen mode, revealing/hiding top toolbar causes jank from resizing all background tabs' viewports → In full-screen mode, hovering to reveal top toolbar causes jank from resizing the viewports of any tabs whose titles that you happen to hover (all of which resize to accomodate the space that the toolbar is briefly occupying)

Some potential solutions here:

  • Disable tab warming when in the full screen state. This is very simple to do, but has the drawback of potentially resulting in less responsive tab switches for fullscreen users.
  • Have a timer that waits for some threshold before warming a tab when in fullscreen. This means that users would have to be fairly slow with the mouse to trigger this particular bug, as they'd need to hover the various tabs for longer. So we'd potentially make this bug harder to hit.
  • Perhaps we can wait for all tabs to stop warming in the background before we begin the toolbar transition. This, however, may result in a UX where the toolbar does not seem as responsive because it waits before transitioning.
  • Defer warming for any tabs until the toolbar transition has completed.
Severity: -- → S3
Priority: -- → P3

Here are more details of mine about this issue:
👉 its size is the same as the top panel, so both the tabs bar and the toolbar
👉 the issue happens whenever the computer is processing pretty heavy tasks or Firefox has many tabs opened so even the simplest page can show the blank section
👉 when the blank section appears, the page can't be interacted in any way until it returns to its normal state
👉 the issue is mostly obvious in full-screen to me (because I'm always in full-screen) but anyway, as suggested, can be seen even by dragging a window border (so Firefox in window mode) pretty fast because dragging slowly the blank most likely won't be noticeable/won't appear at all

2 screenshots from Discord (where this issue is always noticeable), plus a new unknown additional blank (probably due to the user's long info table):
👉 https://drive.google.com/file/d/1SiAOI_94QJIsC-11QoguHnIqQQV2tgZ7/view?usp=sharing
👉 https://drive.google.com/file/d/1LxxariNwbapWiG7CvZWgtTCXb8CLuXtq/view?usp=sharing

Thanks for the interest on this bug, it's so annoying 😤 and I want it out from Firefox 👾💥🔫😠.

(In reply to Mike Conley (:mconley) (:⚙️) from comment #15)

  • Disable tab warming when in the full screen state. This is very simple to do, but has the drawback of potentially resulting in less responsive tab switches for fullscreen users.

In current Nightly, I think disabling these two prefs is necessary/sufficient to avoid this (for now):

browser.tabs.remote.warmup.enabled
browser.tabs.hoverPreview.enabled

Tab hover-preview causes layout to flush in the background tabs as well, and it's enabled by default in Nightly.

Defer warming for any tabs until the toolbar transition has completed.

I'm not sure that this would help with the issues here. The toolbar open transition is pretty instant (though the close transition is slow/animated sometimes), and I don't think I'm currently seeing multiple resize events fired from the transition itself, for warmed background tabs.

(In reply to Luca from comment #16)

👉 the issue is mostly obvious in full-screen [...] but anyway, as suggested, can be seen even by dragging a window border (so Firefox in window mode) pretty fast because dragging slowly the blank most likely won't be noticeable/won't appear at all

Just to set expectations here: this part (blank area appearing at the bounds when dragging to resize the browser) is unlikely to be fixed in general here. It's something that can in some cases be optimized/improved, but it depends very much on what the foreground page is, and the performance characteristics of laying out that page.

The underlying issue is that there are two things going on when you resize the browser: (1) we repaint the window itself, and (2) we repaint the web content inside of it. We try to keep part (1) extremely fast so that the resize operation feels responsive, but sometimes part (2) cannot be quite as fast, if the page is complex and/or has tons of content that's slow-to-relayout-into-a-resized-viewport for whatever reason. If part (2) is slow, then we have no choice but to fill the newly-created browser-window-area with some sort of solid color until we've got the web content repainted.

If you see specific cases where Firefox is slower to redraw than other browsers in response to window-resizes for a particular website, please file specific separate bugs on those, since they might be cases where the site is doing something that we need to optimize.

For this particular bug, the special thing that's happening is that we're spending extra time doing unnecessary resizes of background tabs (particularly in fullscreen mode), which causes extra work for us and makes part (2) extra slow -- that's the thing that I'm seeking to focus on here.

I'm having a lot of trouble reconciling this:

(In reply to Daniel Holbert [:dholbert] from comment #10)

So, this^ known-issue that you're describing is unrelated to the badness that we're hitting here. This bug here is not a case where each layout flush has a moderate cost and we're chaining together a bunch of them which leads to jank. Rather: in this bug, I've set things up such that any viewport-resize-at-all in a background tab will lead to exactly 1 second of jank (in that tab's content process); and we are triggering those 1s janks specifically for fullscreen-window top-toolbar-reveals in particular (for some of them at least), and not for other sorts of viewport-resizes that I've been able to find/test.

with this:

(In reply to Daniel Holbert [:dholbert] from comment #17)

I'm not sure that this would help with the issues here. The toolbar open transition is pretty instant (though the close transition is slow/animated sometimes), and I don't think I'm currently seeing multiple resize events fired from the transition itself, for warmed background tabs.

One of them seems to say that the issue is resizing warmed background tabs when showing the toolbar, and one of them seems to say it's not.

I'm sure I'm missing something but I'm not sure what...

Flags: needinfo?(dholbert)

I'm guessing the confusing/ambiguous bit was this quote from comment 17: "The toolbar open transition is pretty instant" -- sorry, my language wasn't precise there. By "pretty instant" I did not mean to say that it's good and responsive, though that's perhaps what it sounded like. :) I was just talking about whether or not that toolbar-open toggle is smoothly animated over some measurable time-duration vs. a "toggle" between two sizes (and I was saying that it's the latter). I was replying to mconley's suggestion about waiting "until the toolbar transition has completed", and my point was that this wouldn't be a particularly meaningful/useful wait, because the toolbar opens immediately as soon as your mouse reaches the top of the screen, at which point your mouse will be hovering or moving across some arbitrary background tab(s) and warming them, which causes them to relayout in the background at the reduced size with the toolbar's space subtracted, which potentially causes jank in your foreground tab, immediately and/or when you mouse away from the toolbar (at which point the warmed tabs have to relayout again).

(Let me know if there's something else that was confusing; I'm happy to clarify more over slack if that's easier, too.)

Flags: needinfo?(dholbert)

Chatting to :dholbert out of band, I think our consensus is that:

  1. we should at least immediately un-warm the tabs before we start hiding the tabstrip. That way, the last-known-size for the tab will be the size of the viewport with the toolbar visible, and the next time we warm the tab there won't be a resize. This avoids a "ping-pong" scenario where we do a layout pass for the size-with-toolbars when we warm, then when the toolbar hides we do another layout pass for the size-without-toolbars, and then the next time the user hovers tabs and we warm them, we do the same set of passes again. If the last-known-state for the tab remains the size-with-toolbars then the next time we try to warm the tab, it won't have to process a resize and so it won't suck so much.
  2. it would still be desirable to reduce the number of tab-warming-induced resize-janks the first time we warm the tabs in fullscreen. Fullscreen is worse than "normal" mode both because of the autohidden toolbar causing the different content area sizes and thus resizes in the first place, but also because in the fullscreen case, if you're switching tabs by mouse, you're kinda forced to hover all of them when trying to find the right tab to switch to, as moving the mouse outside of the narrow toolbar strip hides the controls again. It's not obvious that not warming at all is better, as that means we pay the cost when switching to the tab, and in extreme cases will show a spinner. But perhaps in the fullscreen situation with autohidden toolbars, we can only start warming when we hover the same tab for N ms or onmousedown (whichever comes first), or some other heuristic.

Mike, are these ideas feasible?

Flags: needinfo?(mconley)

Here's another testcase for easier testing here. This one simply logs to the terminal whenever it detects a viewport resize (using window.dump() which is off-by-default).

STR here:

  1. Start Firefox Nightly from a terminal (to be able to see window.dump output)
  2. Set about:config pref browser.dom.window.dump.enabled to true.
  3. Open this testcase in a background tab (e.g. open it, and then open another tab with https://example.org/ )
  4. Make a mental note of the last bit of output in your terminal (or clear it, or manually type in some sort of markers or newlines, so you can distinguish messages-after-this-point).
  5. Hit F11 to enter fullscreen.
  6. Hover/unhover your tabstrip, being sure to hover the background tab.
  7. Repeat step 6 as much as you like, and then check your terminal to see many resizes happened while the tab was in the background.

To my slight surprise: right now, these STR only show one resize when the tab is in the background in fullscreen mode. So maybe we already sort of do suggestion #1 from Gijs' just-posted comment 21? (EDIT: no, these STR do actually show multiple resizes. I was only seeing one resize when I first tested this, only because I forgot that I had turned off tab warming in the profile that I was using for testing here. :) )

(I edited my previous comment to strike out the a chunk that was wrong, where I had initially thought I wasn't seeing many resizes. It turned out that I had just disabled tab warming while testing and forgot about it. :))

Here's a screencast of testcase 2, showing resizing happening for that testcase, in a background tab, when I've hovered its tab-title. (This happens in the second half of the screencast, starting at ~t=15s.)

This shows that we do in fact get a whole bunch of resizes for the toolbar-hide transition, which was news to me. (This contradicts what I said at the end of comment 10, and contradicts my " I don't think I'm currently seeing multiple resize events fired from the transition itself, for warmed background tabs" in comment 17. I think I wasn't seeing this in my original expensive testcase-1 setup because the background tab was slow enough to resize that it just janked for the whole transition, or something along those lines. Anyway: the presence of multiple resize events here make this bug all-the-more-worth-fixing.)

Anyway, this screencast and testcase 2 are just meant to be supporting evidence/food-for-thought for the suggestions in comment 21.

The Performance Impact Calculator has determined this bug's performance impact to be medium. If you'd like to request re-triage, you can reset the Performance Impact flag to "?" or needinfo the triage sheriff.

Platforms: Windows
Impact on browser: Causes noticeable jank
Configuration: Specific but common
[x] Able to reproduce locally

Performance Impact: ? → medium
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Created:
Updated:
Size: