-
Notifications
You must be signed in to change notification settings - Fork 2.7k
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
Improve caching for theme.json
processing
#3418
Improve caching for theme.json
processing
#3418
Conversation
This is now in a good enough state we could consider merging, though there are some places where we can squeeze some more ms. I still need to fix tests as well. |
Thank you @oandregal! Unfortunately, it looks like unit tests are currently failing. A number of quite different methods seem to be affected, so I wasn't able to figure out the root cause at a quick glance... |
@oandregal Can you please add some unit tests for this change. 101 lines change to a very important class, should include some unit tests. |
@@ -272,7 +321,7 @@ public static function get_theme_data( $deprecated = array(), $options = array() | |||
public static function get_block_data() { | |||
$registry = WP_Block_Type_Registry::get_instance(); | |||
$blocks = $registry->get_all_registered(); | |||
$config = array( 'version' => 1 ); | |||
$config = array( 'version' => 2 ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you explain this change?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a bug I found while working in this PR. I can prepare a different PR if that's preferred but thought it was so minor it didn't merit one.
This sets the version of the theme.json
schema used by the data stored in the blocks. We introduced version 2 in WordPress 5.9 and blocks only gained this functionality in this release, so we should be using the latest. In practice, because we're using the version 2 to store data in the blocks, probably we won't notice anything. Though this is still a dormant bug waiting to happen, and I rather do the right thing now. See docs.
Love the feedback from @peterwilsoncc and @mukeshpanchal27 |
@ockham this is now ready. The numbers are back to 6.0 levels. I've updated the issue description with the performance results of calls to the main APIs people use to interact with There are opportunities to squeeze a bit more ms, specially in translation (I tried, but tests failed for reasons I didn't understand and thought it was too risky for now, can prepare a follow-up PR if I find a way). More opportunities in reducing the number of calls to |
@spacedmonkey This is the performance results for this function (I shared the xdebug profiles in the issue description for anyone to visualize with their tool of choice):
The times it takes the operation in the three setups I've tried does not indicate this is a bottleneck: it takes about the same amount of time per call. Though the number of times it's called does, and it indicates the issue is higher-up. This is what I saw when zooming out a bit (call hierarchy for one path, via kcachegrind):
My point is that |
I forgot to test the latest changes manually per the issue instructions:
Probably some other random tests related to global styles won't hurt. I'm now far from the computer and can't do it myself, but wanted to leave this note for reviewers. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks @oandregal Left some review comments.
@oandregal Please check #3418 (review) |
I tested this myself manually using TT2 and TT3 themes. I tested empty state for each theme and updating the user values from the global styles' sidebar (selecting a style variation, specific changes to some blocks, etc.). I've also tested a localized WordPress to make sure translations are picked up. It's working as expected. |
@@ -189,19 +243,21 @@ public static function get_theme_data( $deprecated = array(), $options = array() | |||
|
|||
$options = wp_parse_args( $options, array( 'with_supports' => true ) ); | |||
|
|||
$theme_json_data = static::read_json_file( static::get_file_path_from_theme( 'theme.json' ) ); | |||
$theme_json_data = static::translate( $theme_json_data, wp_get_theme()->get( 'TextDomain' ) ); | |||
if ( null === static::$theme || ! static::has_same_registered_blocks( 'theme' ) ) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The only change here is running this code conditionally. The code within has not changed, it's only tabbed.
We have dozens of unit tests for this code already that cover the existing behavior (wpThemeJsonResolver.php, wpThemeJson.php, wpThemeJsonSchema.php, wpGetGlobalStylesheet.php). I've been using them to drive changes in this PR as they were failing at the beginning. Having "more test" sounds good to me. At the same time, I also want to be mindful of the time and resources we all have to move this forward, so in the name of efficiency I'd like to ask: what additional tests do we need that are a blocker for merging? |
There are not unit tests for the following methods.
I don't think we have enough coverage to merge this change. Tests to prove that methods above do as expected. Check cleaning caches was as expected and code is not being run again after cache working as expected. There are basically no changes to WordPress that should not come along with a unit test. Something this important NEEDS them before the mege. |
Currently looking at test coverage for the changes in this PR. |
Okay, here's what I've done:
What else is needed?
IMO This PR is ready "enough" for RC1 with the condition that more tests and testing will happen by 6.1 RC2. Why? It's a significant enough performance regression to warrant getting it fixed. More extenders typically test during the RC cycle. So releasing as part of RC1 gives more testing and feedback exposure for any additional unknowns or work that may be needed. |
Amazing, thank you very much for testing, @hellofromtonya!
Awesome, exactly my thinking 👍
I agree 100%. I wish I could've helped more getting this across the finish line, but I'm very very grateful we got this ready for RC1. Thanks again also to @oandregal for this fix, and your thorough profiling! I'll make a note to add more test coverage before RC2. |
* Removes "we" words * Adds data type to `@param` * Improves readability and consistency
Committed via changeset https://core.trac.wordpress.org/changeset/54493. |
I'm still investigating this for further improvement and have created #3441 as a follow-up. |
@c4rl0sbr4v0 @michalczaplinski Since I'll be AFK tomorrow, would y'all mind working with @hellofromtonya to add unit test coverage (see #3418 (comment) and #3418 (comment)) in a follow-up PR? (Let's maybe also file a Trac ticket targeting 6.1 to have it on file.) |
Related:
theme.json
processing gutenberg#44772Props @ockham @aristath
What
This PR tries to address some performance regressions introduced in WordPress 6.1.
During the beta cycle, we removed some of the existing caching for theme.json processing (see #3408 and #3359). The rationale for this was that this code was now used before all the blocks are registered (aka get template data, etc.) and resulted in stale cache that created issues (see WordPress/gutenberg#44434 and WordPress/gutenberg#44619). We limited it to only reads from the file system. As pointed out in the Gutenberg's issue, this introduced a big impact in performance that this PR is trying to reduce.
Why
It's a very noticeable degradation that stems from changes done in this cycle.
How
Caches the calculated data for core, theme, and user based on the blocks that are registered. If the blocks haven't changed since the last time we calculated the data for each origin, we return the cached data. Otherwise, we recalculate it.
Essentially, this brings back the cache we had, but refreshing it when the blocks have changed.
Performance improvements
The test I'm doing for profiling performance is loading the "Hello World" post as a logged-out user. These are the numbers in the different setups.
wp_get_global_settings
wp_get_global_stylesheet
wp_get_global_styles_svg_filters
wp_add_global_styles_for_blocks
WP_Theme_JSON_Resolver::get_core_data
WP_Theme_JSON_Resolver::get_block_data
WP_Theme_JSON_Resolver::get_theme_data
WP_Theme_JSON_Resolver::get_user_data
WP_Theme_JSON_Resolver::get_merged_data
These numbers can be seen in the cachegrind data that follows:
You can take this data and open it with any visualizer of your choice (kcachegrind, webgrind, etc.). As with the client performance numbers, the exact ms are not as important as the variance between them. I also share below how to reproduce this for anyone interested.
How to reproduce the performance results
Enable xdebug profiling:
.env
file and setLOCAL_PHP_XDEBUG=true
, andLOCAL_PHP_XDEBUG_MODE=develop,debug,profile
. For WordPress 6.0, copyXDEBUG_MODE=develop,debug,profile
in thedocker-compose.yml
file instead (see below).docker-compose.yml
file and addXDEBUG_CONFIG=profiler_output_name=cachegrind.out.%R
.http://localhost:8889/?p=1
(this loads the "Hello World" post)./tmp/cachegrind.out.*
. Verify those files exist. You may use this commandRead the profiling reports using webgrind:
wp-content/plugins/webgrind
of thewordpress-develop
repo.wordpress-develop
environment normally.trunk
and in the 6.0 branch.Alternatively, you can read the profiling reports using kcachegrind (linux, probably qcachegrind can do the same for mac & windows?), which allows for loading the xdebug files directly so you can easily compare branches:
/tmp/cachegrind.out.*
) somewhere outside the docker container. Do the same for the files generated for trunk and 6.0 (be aware that the files will overwrite each other, so copy before changing branches).How to test
Make sure automated test pass.
Manually test that global styles still works as expected by using the TT2 or TT3 themes and updating some block styles via the global styles sidebar.