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

Navigation: Fix performance regression #58513

Merged
merged 13 commits into from Feb 2, 2024
Merged

Navigation: Fix performance regression #58513

merged 13 commits into from Feb 2, 2024

Conversation

scruffian
Copy link
Contributor

What?

This is another attempt at #58506.

In #55605 we changed the navigation rendering logic so that inner_blocks were rendered multiple times. This updates that logic so that inner_blocks are only rendered once.

Why?

To improve performance.

How?

Instead of calling render every time we want to check that a navigation has a submenu, we now save that as a member variable on the class. This means we only need to call render once for each inner block.

There should be a more performant way to determine if a navigation contains submenus.

Testing Instructions

Check that a navigation block with submenus displays as on trunk.

@scruffian scruffian added the [Type] Performance Related to performance efforts label Jan 31, 2024
@scruffian scruffian self-assigned this Jan 31, 2024
@draganescu
Copy link
Contributor

I did a bit of an analysis.

We have a "function bag" class WP_Navigation_Block_Renderer, and its entry point is WP_Navigation_Block_Renderer::render.

Here is the flow that appears in the code:

  • WP_Navigation_Block_Renderer::render
    • static::get_inner_blocks
    • static::handle_view_script_module_loading
      • static::is_interactive (1)
        • static::has_submenus (1)
    • static::get_nav_wrapper_attributes
      • static::is_interactive (2)
        • static::has_submenus (2)
    • static::get_wrapper_markup
      • static::get_inner_blocks_html
        • static::has_submenus (3)
        • static::is_interactive (3)
          • static::has_submenus (4)
      • static::is_responsive ? static::get_responsive_container_markup
        • static::is_interactive (4)
          • static::has_submenus (5)

We can see above that has_submenus which renders every inner_blocks is called 5 times, but 4 out of five is because of the check for is_interactive.

Either we fix is_interactive so know the previous has_submenus result or we come up with a more efficient way to check for submenus. get_inner_blocks results in a nice WP_Block_List which holds this answer and is already computed (once).

scruffian and others added 2 commits February 1, 2024 11:20
Co-authored-by: Andrei Draganescu <me@andreidraganescu.info>
Copy link
Member

@oandregal oandregal left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice! Thanks for looking into this, it fixes the issue: the navigation block is back to rendering the inner blocks once.

Trunk This PR
Total (ms) 631 532
gutenberg_render_block_core_navigation (ms) 103 16
# calls to WP_Block->render 439 434
# calls to gutenberg_render_block_core_page_list 6 1

I don't want to share % of performance, because this analysis is using a profiler (xdebug). This is good for understanding whether it fixes the issue, but not for gauging the impact in production. I'll share this later.

@scruffian scruffian enabled auto-merge (squash) February 1, 2024 12:51
@oandregal
Copy link
Member

I'm sharing my before/after cachegrind files: cachegrind-files.zip. Anyone can open them with a tool such as qcachegrind. This 6 minutes video by XDebug's main developer explains the gist of how to navigate and understand them. They look like this:

Before (trunk) After (branch)
Captura de ecrã 2024-02-01, às 14 08 13 Captura de ecrã 2024-02-01, às 14 08 28

This is the step-by-step process I used to get them, so anyone can replicate.

  1. Set up a production environment:
# Create a `.wp-env.override.json` with the following contents.
{
  "config": {
    "WP_DEBUG": false,
    "SCRIPT_DEBUG": false
  }
}
  1. Build & start the env with XDEBUG profile enabled:
npm install && npm run build
npm run wp-env start -- --xdebug=profile
  1. Use the theme test data. Download the theme test data, and manually upload it to Settings > Import > WordPress importer. This step is not strictly necessary, though it helps stress-testing the navigation block. We need to incorporate it to our automated performance tests, otherwise, changes like this would go unnoticed again.
  2. Activate TwentyTwentyThree. This is the same theme in use by Gutenberg & Core tests.
  3. Log out and visit the front-end of your site at localhost:8888.
  4. Take the cachegrind files generated by xdebug:
# List the files. They should be something like cachegrind.out.PID.gz.
docker exec -it `docker ps -f name=e-wordpress -q` ls -lat --time-style=+%H:%M:%S /tmp/

# Take the latest one, which corresponds with the front-page load.
docker cp `docker ps -f name=e-wordpress -q`:'/tmp/cachegrind.out.PID.gz' ~/Desktop/
gzip -d ~/Desktop/cachegrind.out.PID.gz
  1. Open with any tool to inspect. For example, qcachegrind.

@oandregal
Copy link
Member

  1. [webkit] › editor/blocks/navigation-frontend-interactivity.spec.js:462:3 › Navigation block - Frontend interactivity › Page list block (firefox, webkit) › page-list submenu user interactions

There are some e2e errors related to navigation.

Copy link

github-actions bot commented Feb 2, 2024

The following accounts have interacted with this PR and/or linked issues. I will continue to update these lists as activity occurs. You can also manually ask me to refresh this list by adding the props-bot label.

Core SVN

If you're a Core Committer, use this list when committing to wordpress-develop in SVN:

Props: scruffian, andraganescu, oandregal.

GitHub Merge commits

If you're merging code through a pull request on GitHub, copy and paste the following into the bottom of the merge commit message.

Co-authored-by: scruffian <scruffian@git.wordpress.org>
Co-authored-by: draganescu <andraganescu@git.wordpress.org>
Co-authored-by: oandregal <oandregal@git.wordpress.org>

To understand the WordPress project's expectations around crediting contributors, please review the Contributor Attribution page in the Core Handbook.

@scruffian scruffian merged commit 6cd0cba into trunk Feb 2, 2024
56 checks passed
@scruffian scruffian deleted the fix/nav-performance branch February 2, 2024 13:17
@github-actions github-actions bot added this to the Gutenberg 17.7 milestone Feb 2, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
[Type] Performance Related to performance efforts
Projects
Development

Successfully merging this pull request may close these issues.

None yet

3 participants