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

Performance for consecutive tab switching improvements #496

Open
krassowski opened this issue Dec 22, 2022 · 2 comments
Open

Performance for consecutive tab switching improvements #496

krassowski opened this issue Dec 22, 2022 · 2 comments
Labels
enhancement New feature or request performance Addresses performance

Comments

@krassowski
Copy link
Member

Problem

Some actions in the UI are expensive. When user navigates open tabs they may want to switch a few tabs ahead using a keyboard shortcut. Even with relatively low latency with windowed notebooks for any single tab, switch n tabs with large notebooks in a row may take too long for the user.

Related to jupyterlab/jupyterlab#4292 and jupyterlab/benchmarks#75

Proposed Solution

We could:

  1. aggregate consecutive switch tab requests if they appear within a debounce period and then switch to the final tab immediately
    • this means that for user who only switches one tab at a time the action will be slower (the time to switch will increase by the length of by the debounce period)
  2. delay the expensive operation of rendering the tab beyond the debounce period; in particular we could "fake it" by displaying a static screenshot of the tab in the state as it was when it was most recently rendered
    • the screenshot of visible portion of each tab could be generated when it gets hidden (and possibly compressed in a webworker on idle)
    • this implies a memory usage increase (as we are storing an extra PNG screenshot for each hidden tab)
    • unfortunately making screenshots of DOM nodes is hard;
      • it is easy for datagrid as it is just a canvas and we can read it off the buffer
      • for non-canvas elements we basically need to render to canvas, for example:
  3. use content-visibility on tab-level to improve performance of tab switch. While previous work in jupyterlab-benchmarks repository investigated using content-visibility on cell level, this could be even more beneficial on widget level (in the same manner as Use composition to improve tab switch #231)
  4. render a single main area widget in a panel in an iframe and use browser navigation for instantenious switching leveraging back-forward cache (https://web.dev/bfcache/)
  5. previously I suggested using Houdini CSS Layout API but I no longer believe that this particular API exposes enough data to implement the caching mechanism that we need

Additional comments:

  • (1) I could not find any examples of applications using this approach
  • (2) is a big ask for a lumino, especially if it involves bringing a new dependency. Maybe the better statement of the problem would be: lumino should allow to implement (2) in third-party extensions.
  • (3) is not currently not supported by Firefox but maybe we should include it and only enable on Chrome; the support in Firefox appears to be work-in-progress with some required APIs already implemented.
  • (4) is very high performance (DOM cache on browser level) but also highly disruptive and requires very careful managment of connections/requests etc

Additional context

Some browsers are also working on implementing another cache for closed tabs but this may be more difficult to leverage than back-froward cache.

Just if anyone was wondering, shadow-DOM does not help in this particular case (beyond reducing style recomputation scope) as it does not currently support any additional caching.

@krassowski krassowski added enhancement New feature or request status:Needs Triage performance Addresses performance labels Dec 22, 2022
@krassowski
Copy link
Member Author

krassowski commented Dec 22, 2022

(3) achieves impressive results for very heavy notebooks in Chrome. You can test it by running the following cell in IPython notebook:

%%html
<style>
.jp-MainAreaWidget.lm-Widget.lm-mod-hidden {
    content-visibility: hidden;
    display: block!important;
    z-index: -1;
}
</style>

To disable it switch the cell to raw. To re-enable switch it back to code and re-run.

Here is the comparison for tab switching obtained form ui-profiler with scenario parametrized as: [gh-9757-reproducer.ipynb, Launcher, all-html-elements.ipynb], 50 repeats, JupyterLab 3.6.0b:

hidden mode IQM [Q1 - Q3] mean min
display 3008.8 [2967.2 – 3174.4] ms 3086.7 ms 2698.9 ms
content-visibility 547.9 [539.5 – 556.9] ms 568.6 ms 479.4 ms
scale 473.5 [467.8 – 481.2] ms 516.9 ms 461.7 ms

Launchers in my setup have 32 cards.

To confirm that this is not a mistake, I re-run the benchmarks and and the results were in agreement (see details).

hidden mode IQM [Q1 - Q3] mean min
display 3107.7 [3020.8 – 3216.2] ms 3145.7 ms 2910.8 ms
content-visibility 616.6 [604.3 – 632.9] ms 655.0 ms 570.4 ms
scale 511.4 [499.6 – 534.5] ms 588.7 ms 480.4 ms

Lightweight scenarios

Ok, so content-visibility is great for very heavy notebooks. How does it behave in lightweight (e.g. Launcher) or moderate scenarios (a small notebook)?

Previously we saw a performance drop for scale mode when many tabs are open. We can reproduce this by looking at an increasing number of launchers:

by # launchers 10 20 30
display 425.5 [419.5 – 434.6] 1019 [1008.3 – 1034] 1907.2 [1883.6 – 1933.5]
content-visibility 386.6 [379.0 – 396.8] 982.7 [967.2 – 994.6] 1904.9 [1874.3 – 1935.8]
scale 381.0 [376.3 – 386.6] 1038.9 [1021.9 – 1058.5] 1912.9 [1894.9 – 1933.3]

while scale is faster for 10 lightweight tabs, it becomes the slowest for 20 and 30 tabs. At 30 tabs the differences are less notable.

When looking at notebooks (each with 20 code cells), content-visibility is a clean winner, irrespective of the number of tabs to traverse.

by # notebooks 10 20 30
display 1646.0 [1581.3 – 1724.2] 4311.4 [4180.0 – 4450.3] 8192.9 [7927.9 – 8493.6]
content-visibility 1446.1 [1361.8 – 1532.3] 4202.8 [4064.8 – 4372.9] 7736.7 [7360.8 – 7939.1]
scale 1643.6 [1572.2 – 1720.4] 4768.5 [4616.5 – 4942.2] 9977.1 [9821.7 – 10152]

In any case, the gains for lightweight scenarios are not as impressive.

@krassowski
Copy link
Member Author

Importantly, scale mode is no longer default in JupyterLab because it was breaking behaviour of tabs when tabs with iframes/PDFs were open in Chromium browsers. I now verified that this does not affect content-visibility (for scale mode I did reproduce the problem with iframes but not with PDFs, maybe it got fixed since).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request performance Addresses performance
Projects
None yet
Development

No branches or pull requests

1 participant