Gutenberg: PEG.js based parser introduced a performance regression

Created on 2 Jul 2017  路  6Comments  路  Source: WordPress/gutenberg

After updating the plugin on a site I noticed a performance decrease by 2-3 seconds.

$ wp profile stage --fields=stage,time,cache_ratio
+------------+---------+-------------+
| stage      | time    | cache_ratio |
+------------+---------+-------------+
| bootstrap  | 1.0175s | 88.3%       |
| main_query | 0.025s  | 90.74%      |
| template   | 4.3431s | 93.54%      |
+------------+---------+-------------+
| total (3)  | 5.3856s | 90.86%      |
+------------+---------+-------------+

vs.

$ wp profile stage --fields=stage,time,cache_ratio --skip-plugins=gutenberg
+------------+---------+-------------+
| stage      | time    | cache_ratio |
+------------+---------+-------------+
| bootstrap  | 1.0935s | 88.09%      |
| main_query | 0.0206s | 90.74%      |
| template   | 0.3426s | 93.54%      |
+------------+---------+-------------+
| total (3)  | 1.4567s | 90.79%      |
+------------+---------+-------------+

Checking further

wp profile stage template --fields=hook,time,cache_ratio
+--------------------------+---------+-------------+
| hook                     | time    | cache_ratio |
+--------------------------+---------+-------------+
| template_redirect:before | 0.001s  |             |
| template_redirect        | 0.0239s | 98.46%      |
| template_include:before  | 0.0008s | 100%        |
| template_include         | 0s      |             |
| wp_head:before           | 0.0028s | 100%        |
| wp_head                  | 0.0904s | 98.31%      |
| loop_start:before        | 0.0287s | 93.58%      |
| loop_start               | 0s      |             |
| loop_end:before          | 3.1046s | 91.02%      |
| loop_end                 | 0s      |             |
| wp_footer:before         | 0.0607s | 92.7%       |
| wp_footer                | 0.0017s | 100%        |
| wp_footer:after          | 0.0002s |             |
+--------------------------+---------+-------------+
| total (13)               | 3.315s  | 96.76%      |
+--------------------------+---------+-------------+

So I removed the filter on the_content and the load was back to normal. I also reverted the do_blocks() function to the previous version and the load was still normal. But once the PEG version is in use the page load increases by ~3 seconds.

_Will investigate further to get the exact cause for this._

[Feature] Parsing [Priority] High [Type] Bug

All 6 comments

Sounds like it would be a good idea to bail early when there are absolutely no blocks in a post, e.g. by doing a simple strpos() or regex search.

Looks like it just gets slower the more content you have. You can test with http://www.loremipsum.de/index_e.html. I started with 5 paragraphs and increased the content by 5 more paragraphs for each test.

358 words: 0.062175989151001s
921 words: 0.33092999458313s
1438 words: 0.77467513084412s
1793 words: 1.1339340209961s

This was foreseen as almost unavoidable. The grammar is both designed to be above-all easy to read and implement (so that more-performant versions can be built from it) and also built for JS consumption. PHP is a pretty bad platform on which to generate the parser due to the ways that the semantics of function calling and closures work. Instead we should prefer a hand-written parser that implements the necessary parts of the grammar for the server side.

I suspect some of the performance problems here are more related to #1611. I will look into a fix using the existing setup and I am confident that we can achieve a reasonable result here.

PHP is a pretty bad platform on which to generate the parser due to the ways that the semantics of function calling and closures work.

There are no closures in the generated parser - I've removed them from the code because they are not supported on PHP 5.2.

I am also skeptical that function calling semantics are the problem. Can you elaborate on that?

Instead we should prefer a hand-written parser that implements the necessary parts of the grammar for the server side.

It is mandatory that client and server parsing behave the same way. I see two ways to achieve this:

  1. Use the same grammar to do the parsing on the client and the server. Ensure correct behavior first, then address performance concerns.
  2. Put thorough test cases in place to ensure the same parse results on the client and the server. This is in a better place now after #1152, but there are still no tests for error cases: invalid nesting of blocks, malformed delimiters, etc. We cannot change to a different server-side parser without first implementing these tests.

We also having the similar issue of the slow parser cause php maximum execution timeout.
And since the parser use filter the_content, it cause very slow post indexing to Elasticsearch using ElasticPress plugin.

Steps to Reproduce

  1. Activate Gutenberg and add 2 content from the demo content
  2. Save & Publish post
  3. Sync Post to Elasticsearch with ElasticPress

I'm using the Gutenberg v0.3.0 and use Gutenberg Demo content.

I'll implement a fix for this in time for this week's release.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

mhenrylucero picture mhenrylucero  路  3Comments

jasmussen picture jasmussen  路  3Comments

aaronjorbin picture aaronjorbin  路  3Comments

maddisondesigns picture maddisondesigns  路  3Comments

jasmussen picture jasmussen  路  3Comments